text: 'use strict';
  
  var ReactNative = require('react-native');
  var RNSound = ReactNative.NativeModules.RNSound;
  var IsAndroid = RNSound.IsAndroid;
  var IsWindows = RNSound.IsWindows;
  var resolveAssetSource = require("react-native/Libraries/Image/resolveAssetSource");
  var eventEmitter = new ReactNative.NativeEventEmitter(RNSound);
  
  var nextKey = 0;
  
  function isRelativePath(path) {
    return !/^(\/|http(s?)|asset|file)/.test(path);
  }
  
  function calculateRelativeVolume(volume, pan) {
    // calculates a lower volume relative to the pan value
    const relativeVolume = (volume * (1 - Math.abs(pan)));
    return Number(relativeVolume.toFixed(1));
  }
  
  function setAndroidVolumes(sound) {
    // calculates the volumes for left and right channels
    if (sound._pan) {
      const relativeVolume = calculateRelativeVolume(sound._volume, sound._pan);
      if (sound._pan < 0) {
        // left is louder
        RNSound.setVolume(sound._key, sound._volume, relativeVolume);
      } else {
        // right is louder
        RNSound.setVolume(sound._key, relativeVolume, sound._volume);
      }
    } else {
      // no panning, same volume on both channels
      RNSound.setVolume(sound._key, sound._volume, sound._volume);
    }
  }
  
  function Sound(filename, basePath, onError, options) {
    var asset = resolveAssetSource(filename);
    if (asset) {
      this._filename = asset.uri;
      onError = basePath;
    } else {
      this._filename = basePath ? basePath + '/' + filename : filename;
  
      if (IsAndroid && !basePath && isRelativePath(filename)) {
        this._filename = filename.toLowerCase().replace(/\.[^.]+$/, '');
      }
    }
  
    this.registerOnPlay = function() {
      if (this.onPlaySubscription != null) {
        console.warn('On Play change event listener is already registered');
        return;
      }
  
      if (!IsWindows) {
        this.onPlaySubscription = eventEmitter.addListener(
          'onPlayChange',
          (param) => {
            const { isPlaying, playerKey } = param;
            if (playerKey === this._key) {
              if (isPlaying) {
                this._playing = true;
              }
              else {
                this._playing = false;
              }
            }
          },
        );
      }
    }
  
    this._loaded = false;
    this._key = nextKey++;
    this._playing = false;
    this._duration = -1;
    this._numberOfChannels = -1;
    this._volume = 1;
    this._pan = 0;
    this._numberOfLoops = 0;
    this._speed = 1;
    this._pitch = 1;
    RNSound.prepare(this._filename, this._key, options || {}, (error, props) => {
      if (props) {
        if (typeof props.duration === 'number') {
          this._duration = props.duration;
        }
        if (typeof props.numberOfChannels === 'number') {
          this._numberOfChannels = props.numberOfChannels;
        }
      }
      if (error === null) {
        this._loaded = true;
        this.registerOnPlay();
      }
      onError && onError(error, props);
    });
  }
  
  Sound.prototype.isLoaded = function() {
    return this._loaded;
  };
  
  Sound.prototype.play = function(onEnd) {
    if (this._loaded) {
      RNSound.play(this._key, onEnd ? (successfully) => onEnd(successfully) : null);
    } else {
      onEnd && onEnd(false);
    }
    return this;
  };
  
  Sound.prototype.pause = function(callback) {
    if (this._loaded) {
      RNSound.pause(this._key, () => {
        this._playing = false;
        callback && callback();
      });
    }
    return this;
  };
  
  Sound.prototype.stop = async function(): Promise<boolean> {
    if (this._loaded) {
      await RNSound.stop(this._key);
      this._playing = false;
    }
    return this;
  };
  
  Sound.prototype.reset = function() {
    if (this._loaded && IsAndroid) {
      RNSound.reset(this._key);
      this._playing = false;
    }
    return this;
  };
  
  Sound.prototype.release = function() {
    if (this._loaded) {
      RNSound.release(this._key);
      this._loaded = false;
      if (!IsWindows) {
        if (this.onPlaySubscription != null) {
          this.onPlaySubscription.remove();
          this.onPlaySubscription = null;
        }
      }
    }
    return this;
  };
  
  Sound.prototype.getFilename = function() {
    return this._filename;
  };
  
  Sound.prototype.getDuration = function() {
    return this._duration;
  };
  
  Sound.prototype.getNumberOfChannels = function() {
    return this._numberOfChannels;
  };
  
  Sound.prototype.getVolume = function() {
    return this._volume;
  };
  
  Sound.prototype.getSpeed = function() {
    return this._speed;
  };
  
  Sound.prototype.getPitch = function() {
    return this._pitch;
  };
  
  Sound.prototype.setVolume = function(value) {
    this._volume = value;
    if (this._loaded) {
      if (IsAndroid) {
        setAndroidVolumes(this)
      } else {
        RNSound.setVolume(this._key, value);
      }
    }
    return this;
  };
  
  Sound.prototype.setPan = function(value) {
    this._pan = value;
    if (this._loaded) {
      if (IsWindows) {
        throw new Error('#setPan not supported on windows');
      } else if (IsAndroid) {
        setAndroidVolumes(this)
      } else {
        RNSound.setPan(this._key, value);
      }
    }
    return this;
  };
  
  Sound.prototype.getSystemVolume = function(callback) {
    if(!IsWindows) {
      RNSound.getSystemVolume(callback);
    }
    return this;
  };
  
  Sound.prototype.setSystemVolume = function(value) {
    if (IsAndroid) {
      RNSound.setSystemVolume(value);
    }
    return this;
  };
  
  Sound.prototype.getPan = function() {
    return this._pan;
  };
  
  Sound.prototype.getNumberOfLoops = function() {
    return this._numberOfLoops;
  };
  
  Sound.prototype.setNumberOfLoops = function(value) {
    this._numberOfLoops = value;
    if (this._loaded) {
      if (IsAndroid || IsWindows) {
        RNSound.setLooping(this._key, !!value);
      } else {
        RNSound.setNumberOfLoops(this._key, value);
      }
    }
    return this;
  };
  
  Sound.prototype.setSpeed = function(value) {
    this._speed = value;
    if (this._loaded) {
      if (!IsWindows) {
        RNSound.setSpeed(this._key, value);
      }
    }
    return this;
  };
  
  Sound.prototype.setPitch = function(value) {
    this._pitch = value;
    if (this._loaded) {
      if (IsAndroid) {
        RNSound.setPitch(this._key, value);
      }
    }
    return this;
  };
  
  Sound.prototype.getCurrentTime = function(callback) {
    if (this._loaded) {
      RNSound.getCurrentTime(this._key, callback);
    }
  };
  
  Sound.prototype.setCurrentTime = function(value) {
    if (this._loaded) {
      RNSound.setCurrentTime(this._key, value);
    }
    return this;
  };
  
  // android only
  Sound.prototype.setSpeakerphoneOn = function(value) {
    if (IsAndroid) {
      RNSound.setSpeakerphoneOn(this._key, value);
    }
  };
  
  // ios only
  
  // This is deprecated.  Call the static one instead.
  
  Sound.prototype.setCategory = function(value) {
    Sound.setCategory(value, false, false);
  }
  
  Sound.prototype.isPlaying = function() {
    return this._playing;
  }
  
  Sound.enable = function(enabled) {
    RNSound.enable(enabled);
  };
  
  Sound.enableInSilenceMode = function(enabled) {
    if (!IsAndroid && !IsWindows) {
      RNSound.enableInSilenceMode(enabled);
    }
  };
  
  Sound.setActive = function(value) {
    if (!IsAndroid && !IsWindows) {
      RNSound.setActive(value);
    }
  };
  
  Sound.setCategory = function(value, mixWithOthers, carAudioSystem) {
    if (!IsWindows) {
      RNSound.setCategory(value, mixWithOthers, carAudioSystem);
    }
  };
  
  Sound.setMode = function(value) {
    if (!IsAndroid && !IsWindows) {
      RNSound.setMode(value);
    }
  };
  
  Sound.setSpeakerPhone = function(value) {
    if (!IsAndroid && !IsWindows) {
      RNSound.setSpeakerPhone(value)
    }
  }
  
  Sound.setAudioManagement = function(value) {
    if (!IsWindows) {
      RNSound.setAudioManagement(value);
    }
  }
  
  Sound.MAIN_BUNDLE = RNSound.MainBundlePath;
  Sound.DOCUMENT = RNSound.NSDocumentDirectory;
  Sound.LIBRARY = RNSound.NSLibraryDirectory;
  Sound.CACHES = RNSound.NSCachesDirectory;
  
  module.exports = Sound;
  