New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

web-audio-api-player

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

web-audio-api-player - npm Package Compare versions

Comparing version 5.1.0-beta.4 to 5.1.0

63

dist/index.js

@@ -56,2 +56,3 @@ /******************************************************************************

this.duration = null;
this.durationSetManually = false;
this.firstTimePlayed = true;

@@ -72,3 +73,6 @@ this.isConnectToPlayerGain = false;

this.loop = soundAttributes.loop || false;
this.duration = soundAttributes.duration || null;
if (!isNaN(soundAttributes.duration)) {
this.duration = soundAttributes.duration;
this.durationSetManually = true;
}
if (typeof soundAttributes.onLoading === 'function') {

@@ -130,3 +134,5 @@ this.onLoading = soundAttributes.onLoading;

this.audioBufferDate = new Date();
this.duration = this.getDuration();
if (!this.durationSetManually) {
this.duration = this.audioBuffer.duration;
}
}

@@ -160,2 +166,24 @@ }

}
setDuration(duration) {
if (!isNaN(duration)) {
this.duration = duration;
this.durationSetManually = true;
}
}
setLoop(loop) {
this.loop = loop;
if (this.state === PlayerSound.SOUND_STATE_PLAYING) {
if (this.sourceNode !== null) {
if (this.sourceNode instanceof AudioBufferSourceNode) {
this.sourceNode.loop = loop;
}
else if (this.sourceNode instanceof MediaElementAudioSourceNode) {
this.sourceNode.mediaElement.loop = loop;
}
}
}
}
getLoop() {
return this.loop;
}
_generateSoundId() {

@@ -461,3 +489,5 @@ return Date.now().toString(36) + Math.random().toString(36).substring(2);

const audioContext = yield this.getAudioContext();
this._audioNodes.gainNode.gain.setTargetAtTime(gainValue, audioContext.currentTime, 0.1);
const timeConstantInMilliseconds = (!isNaN(this._options.volumeTransitionTime) && this._options.volumeTransitionTime > 0) ? this._options.volumeTransitionTime : 100;
const timeConstantInSeconds = timeConstantInMilliseconds / 1000;
this._audioNodes.gainNode.gain.setTargetAtTime(gainValue, audioContext.currentTime, timeConstantInSeconds);
}

@@ -592,2 +622,3 @@ });

addAudioElementsToDom: false,
volumeTransitionTime: 100,
};

@@ -628,2 +659,3 @@ const options = Object.assign({}, defaultOptions, playerOptions);

addAudioElementsToDom: this._options.addAudioElementsToDom,
volumeTransitionTime: this._options.volumeTransitionTime,
};

@@ -701,2 +733,5 @@ return audioOptions;

return __awaiter(this, void 0, void 0, function* () {
if (soundPositionInPercent < 0 || soundPositionInPercent > 100) {
throw new Error('soundPositionInPercent must be a number >= 0 and <= 100');
}
const currentSound = this._getSoundFromQueue({ whichSound: PlayerCore.CURRENT_SOUND });

@@ -718,2 +753,5 @@ if (currentSound !== null) {

if (currentSound !== null) {
if (!isNaN(currentSound.duration) && (soundPositionInSeconds > Math.ceil(currentSound.duration))) {
console.warn('soundPositionInSeconds > sound duration');
}
if (currentSound.onSeeking !== null) {

@@ -769,3 +807,3 @@ const playTime = soundPositionInSeconds;

sound.isReadyToPLay = true;
if (!isNaN(sound.audioElement.duration)) {
if (!isNaN(sound.audioElement.duration) && !sound.durationSetManually) {
sound.duration = sound.audioElement.duration;

@@ -786,3 +824,5 @@ }

}
sound.duration = sound.audioElement.duration;
if (!sound.durationSetManually) {
sound.duration = sound.audioElement.duration;
}
if (loadingPercentage === 100) {

@@ -829,2 +869,5 @@ sound.isBuffering = false;

const audioBuffer = yield this._playerAudio.decodeAudio(arrayBufferCopy);
if (!sound.durationSetManually) {
sound.duration = audioBuffer.duration;
}
sound.audioBuffer = audioBuffer;

@@ -834,3 +877,2 @@ sound.isBuffering = false;

sound.audioBufferDate = new Date();
sound.duration = audioBuffer.duration;
sound.isReadyToPLay = true;

@@ -921,2 +963,5 @@ });

if (sound.playTimeOffset > 0) {
if (sound.playTimeOffset > Math.ceil(sound.duration)) {
console.warn('playTimeOffset > sound duration');
}
sound.elapsedPlayTime = sound.playTimeOffset;

@@ -947,2 +992,5 @@ sound.sourceNode.start(0, sound.playTimeOffset);

if (sound.playTimeOffset > 0) {
if (sound.playTimeOffset > Math.ceil(sound.duration)) {
console.warn('playTimeOffset > duration');
}
sound.audioElement.currentTime = sound.playTimeOffset;

@@ -1305,2 +1353,5 @@ }

}
getCurrentSound() {
return this._getSoundFromQueue({ whichSound: PlayerCore.CURRENT_SOUND });
}
}

@@ -1307,0 +1358,0 @@ PlayerCore.WHERE_IN_QUEUE_AT_END = 'append';

2

dist/index.min.js

@@ -1,2 +0,2 @@

function e(e,t,i,o){return new(i||(i=Promise))((function(n,s){function u(e){try{r(o.next(e))}catch(e){s(e)}}function d(e){try{r(o.throw(e))}catch(e){s(e)}}function r(e){var t;e.done?n(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(u,d)}r((o=o.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class t{constructor(e){this.url=null,this.codec=null,this.loop=!1,this.sourceNode=null,this.gainNode=null,this.isReadyToPLay=!1,this.isBuffered=!1,this.isBuffering=!1,this.audioElement=null,this.audioBuffer=null,this.arrayBuffer=null,this.audioBufferDate=null,this.playTimeOffset=0,this.startTime=0,this.elapsedPlayTime=0,this.playTime=0,this.playedTimePercentage=0,this.state="sound_state_stopped",this.loadingProgress=0,this.duration=null,this.firstTimePlayed=!0,this.isConnectToPlayerGain=!1,Array.isArray(e.source)?this.source=e.source:this.source=[e.source],void 0!==e.id?this.id=e.id:this.id=this._generateSoundId(),this.loop=e.loop||!1,this.duration=e.duration||null,"function"==typeof e.onLoading?this.onLoading=e.onLoading:this.onLoading=null,"function"==typeof e.onPlaying?this.onPlaying=e.onPlaying:this.onPlaying=null,"function"==typeof e.onStarted?this.onStarted=e.onStarted:this.onStarted=null,"function"==typeof e.onEnded?this.onEnded=e.onEnded:this.onEnded=null,"function"==typeof e.onStopped?this.onStopped=e.onStopped:this.onStopped=null,"function"==typeof e.onPaused?this.onPaused=e.onPaused:this.onPaused=null,"function"==typeof e.onResumed?this.onResumed=e.onResumed:this.onResumed=null,"function"==typeof e.onSeeking?this.onSeeking=e.onSeeking:this.onSeeking=null,e.arrayBuffer instanceof ArrayBuffer&&(this.arrayBuffer=e.arrayBuffer),e.audioBuffer instanceof AudioBuffer&&(this.audioBuffer=e.audioBuffer,this.isBuffering=!1,this.isBuffered=!0,this.audioBufferDate=new Date,this.duration=this.getDuration())}getCurrentTime(){let e;null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.sourceNode.context.currentTime-this.startTime+this.elapsedPlayTime:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.currentTime));return Math.round(100*(e+Number.EPSILON))/100}getDuration(){let e;null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.audioBuffer.duration:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.duration));return Math.round(100*(e+Number.EPSILON))/100}_generateSoundId(){return Date.now().toString(36)+Math.random().toString(36).substring(2)}}t.SOUND_STATE_STOPPED="sound_state_stopped",t.SOUND_STATE_PAUSED="sound_state_paused",t.SOUND_STATE_PLAYING="sound_state_playing",t.SOUND_STATE_SEEKING="sound_state_seeking";class i{constructor(e){this._audioContext=null,this._volume=null,this._audioNodes={gainNode:null},this._audioElement=null,this._mediaElementAudioSourceNode=null,this._isAudioUnlocked=!1,this._isAudioUnlocking=!1,this._options=e,this._initialize()}_initialize(){this._options.unlockAudioOnFirstUserInteraction&&this._addFirstUserInteractionEventListeners()}getAudioNodes(){return this._audioNodes}decodeAudio(t){return e(this,void 0,void 0,(function*(){const e=yield this.getAudioContext();return yield e.decodeAudioData(t)}))}_createAudioContext(){if(this._audioContext instanceof AudioContext)return;const e=window.AudioContext||window.webkitAudioContext;null!==this._options.audioContext?this._audioContext=this._options.audioContext:this._audioContext=new e}_addFirstUserInteractionEventListeners(){this._options.unlockAudioOnFirstUserInteraction&&(document.addEventListener("keydown",this.unlockAudio.bind(this)),document.addEventListener("mousedown",this.unlockAudio.bind(this)),document.addEventListener("pointerdown",this.unlockAudio.bind(this)),document.addEventListener("pointerup",this.unlockAudio.bind(this)),document.addEventListener("touchend",this.unlockAudio.bind(this)))}_removeFirstUserInteractionEventListeners(){this._options.unlockAudioOnFirstUserInteraction&&(document.removeEventListener("keydown",this.unlockAudio.bind(this)),document.removeEventListener("mousedown",this.unlockAudio.bind(this)),document.removeEventListener("pointerdown",this.unlockAudio.bind(this)),document.removeEventListener("pointerup",this.unlockAudio.bind(this)),document.removeEventListener("touchend",this.unlockAudio.bind(this)))}unlockAudio(){return new Promise(((e,t)=>{if(this._isAudioUnlocking)return e();if(this._isAudioUnlocked)return e();if(this._isAudioUnlocking=!0,"player_mode_audio"===this._options.loadPlayerMode){const e=!0;this._createAudioElement(e).catch((e=>(this._isAudioUnlocking=!1,t())))}this.getAudioContext().then((()=>{const t=this._audioContext.createBuffer(1,1,22050);let i=this._audioContext.createBufferSource();i.onended=()=>(i.disconnect(0),this._removeFirstUserInteractionEventListeners(),i.disconnect(0),i.buffer=null,i=null,this._isAudioUnlocked=!0,this._isAudioUnlocking=!1,e()),i.buffer=t,i.connect(this._audioContext.destination),i.start(0)})).catch((e=>(this._isAudioUnlocking=!1,t())))}))}_createAudioElementAndSource(){return e(this,void 0,void 0,(function*(){yield this._createAudioElement(),yield this._createMediaElementAudioSourceNode()}))}_createAudioElement(t){return e(this,void 0,void 0,(function*(){if(null===this._audioElement||!0===t){const e=new Audio;e.controls=!1,e.autoplay=!1,e.preload="metadata",e.volume=1,e.id="web-audio-api-player",this._audioElement=e,this._options.addAudioElementsToDom&&document.body.appendChild(e)}}))}getAudioElement(){return e(this,void 0,void 0,(function*(){return null===this._audioElement&&(yield this._createAudioElementAndSource()),this._audioElement}))}getAudioContext(){return e(this,void 0,void 0,(function*(){return null===this._audioContext||"closed"===this._audioContext.state?yield this._createAudioContext():"suspended"===this._audioContext.state&&(yield this.unfreezeAudioContext()),this._audioContext}))}unfreezeAudioContext(){return void 0===this._audioContext.resume?Promise.resolve():this._audioContext.resume()}freezeAudioContext(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.suspend()}isAudioContextFrozen(){return"suspended"===this._audioContext.state}detectAudioContextSupport(){let e=!1;return(void 0!==window.webkitAudioContext||"undefined"!=typeof AudioContext)&&(e=!0),e}detectAudioElementSupport(){return!!document.createElement("audio").canPlayType}_createAudioBufferSourceNode(){return e(this,void 0,void 0,(function*(){return(yield this.getAudioContext()).createBufferSource()}))}_createMediaElementAudioSourceNode(){return e(this,void 0,void 0,(function*(){if(null===this._mediaElementAudioSourceNode&&null!==this._audioElement){const e=yield this.getAudioContext();this._mediaElementAudioSourceNode=e.createMediaElementSource(this._audioElement)}}))}_destroyMediaElementAudioSourceNode(){null!==this._mediaElementAudioSourceNode&&(void 0!==this._mediaElementAudioSourceNode.mediaElement&&this._mediaElementAudioSourceNode.mediaElement.remove(),this._mediaElementAudioSourceNode.disconnect(),this._mediaElementAudioSourceNode=null)}_destroyAudioBufferSourceNode(){null!==this._mediaElementAudioSourceNode&&this._mediaElementAudioSourceNode.disconnect()}_destroyAudioContext(){return e(this,void 0,void 0,(function*(){null!==this._audioContext&&"closed"!==this._audioContext.state&&(yield this._audioContext.close(),this._audioContext=null)}))}shutDown(t){return e(this,void 0,void 0,(function*(){this._removeFirstUserInteractionEventListeners(),t.forEach((e=>{this.disconnectSound(e)})),this._destroyMediaElementAudioSourceNode(),this._destroyAudioBufferSourceNode(),this._disconnectPlayerGainNode(),yield this._destroyAudioContext()}))}_getPlayerGainNode(){return e(this,void 0,void 0,(function*(){let e;if(this._audioNodes.gainNode instanceof GainNode)e=this._audioNodes.gainNode;else{const t=yield this.getAudioContext();e=t.createGain(),this._initializeVolume(e),e.connect(t.destination),this._audioNodes.gainNode=e}return e}))}_disconnectPlayerGainNode(){null!==this._audioNodes.gainNode&&(this._audioNodes.gainNode.disconnect(),this._audioNodes.gainNode=null)}connectSound(t,i){return e(this,void 0,void 0,(function*(){if(t.isConnectToPlayerGain)return;if("player_mode_ajax"===this._options.loadPlayerMode){const e=yield this._createAudioBufferSourceNode();t.gainNode=e.context.createGain(),e.connect(t.gainNode),e.loop=t.loop,e.onended=i,t.sourceNode=e}else"player_mode_audio"===this._options.loadPlayerMode&&(yield this._createAudioElementAndSource(),t.gainNode=this._mediaElementAudioSourceNode.context.createGain(),this._mediaElementAudioSourceNode.connect(t.gainNode),this._mediaElementAudioSourceNode.mediaElement.loop=t.loop,this._mediaElementAudioSourceNode.mediaElement.onended=i,t.sourceNode=this._mediaElementAudioSourceNode);t.gainNode.gain.value=1;const e=yield this._getPlayerGainNode();t.gainNode.connect(e),t.isConnectToPlayerGain=!0}))}disconnectSound(t){return e(this,void 0,void 0,(function*(){t.isConnectToPlayerGain&&(null!==t.sourceNode&&(t.sourceNode.disconnect(),t.sourceNode=null),null!==t.gainNode&&(t.gainNode.disconnect(),t.gainNode=null,t.isConnectToPlayerGain=!1),null!==t.audioElement&&(t.audioElement=null))}))}_changePlayerGainValue(t){return e(this,void 0,void 0,(function*(){if(this._audioNodes.gainNode instanceof GainNode){const e=yield this.getAudioContext();this._audioNodes.gainNode.gain.setTargetAtTime(t,e.currentTime,.1)}}))}setVolume(t,i=!0){return e(this,void 0,void 0,(function*(){this._options.persistVolume&&i&&localStorage.setItem("WebAudioAPIPlayerVolume",t.toString());const e=t/100;if(this._audioNodes.gainNode instanceof GainNode){e!==Math.round(100*(this._audioNodes.gainNode.gain.value+Number.EPSILON))/100&&(yield this._changePlayerGainValue(e))}return this._volume=t,t}))}getVolume(){let e;if(null!==this._volume)e=this._volume;else{if(this._options.persistVolume){const t=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume"));isNaN(t)||(e=t)}void 0===e&&(e=this._options.volume),this._volume=e}return e}_initializeVolume(e){if(this._options.persistVolume){const t=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume")),i=t/100;isNaN(t)||(e.gain.value=i),this._volume=t}if(null===this._volume){const t=this._options.volume/100;e.gain.value=t,this._volume=this._options.volume}}}class o{getArrayBuffer(e){return new Promise((function(t,i){const o=new XMLHttpRequest;o.open("GET",e.url,!0),o.responseType="arraybuffer",o.onload=function(){o.status>=200&&o.status<=299?t(o.response):i(new Error(o.statusText+"(status:"+o.status+")"))},o.onprogress=function(t){const i=100/(t.total/t.loaded),o=Math.round(i);e.loadingProgress=o,null!==e.onLoading&&e.onLoading(o,t.total,t.loaded)},o.onerror=function(e){i(e)},o.send()}))}}class n{constructor(e={}){this._playingProgressRequestId=null,this._postMuteVolume=null,this._progressTrigger=(e,i)=>{const o=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(e.id===o.id&&o.state===t.SOUND_STATE_PLAYING){if(i-this._playingProgressPreviousTimestamp>=this._options.playingProgressIntervalTime){const t=e.getCurrentTime(),o=e.getDuration();if(!isNaN(t)&&!isNaN(o)){let n=0;if(0!==t){const e=t/o*100;n=Math.round(e)}e.playedTimePercentage=n,e.playTime=t,e.onPlaying(n,o,t),this._playingProgressPreviousTimestamp=i}}this._playingProgressRequestId=window.requestAnimationFrame((t=>{this._progressTrigger(e,t)}))}};const i={volume:80,loopQueue:!1,loopSong:!1,soundsBaseUrl:"",playingProgressIntervalTime:200,playNextOnEnded:!0,stopOnReset:!0,visibilityAutoMute:!1,unlockAudioOnFirstUserInteraction:!1,persistVolume:!0,loadPlayerMode:"player_mode_audio",audioContext:null,addAudioElementsToDom:!1},o=Object.assign({},i,e);this._queue=[],this._currentIndex=0,this._options=o,this._playingProgressPreviousTimestamp=0,this._initialize()}_initialize(){const e=this._audioOptions();switch(this._playerAudio=new i(e),this._options.loadPlayerMode){case n.PLAYER_MODE_AUDIO:if(!this._playerAudio.detectAudioContextSupport())throw new Error("audio context is not supported by this device");if(!this._playerAudio.detectAudioElementSupport())throw new Error("audio element is not supported by this device");break;case n.PLAYER_MODE_AJAX:if(!this._playerAudio.detectAudioContextSupport())throw new Error("audio context is not supported by this device")}}_audioOptions(){return{audioContext:this._options.audioContext,unlockAudioOnFirstUserInteraction:this._options.unlockAudioOnFirstUserInteraction,volume:this._options.volume,persistVolume:this._options.persistVolume,loadPlayerMode:this._options.loadPlayerMode,addAudioElementsToDom:this._options.addAudioElementsToDom}}addSoundToQueue({soundAttributes:e,whereInQueue:i="append"}){const o=new t(e);switch(i){case n.WHERE_IN_QUEUE_AT_END:this._appendSoundToQueue(o);break;case n.WHERE_IN_QUEUE_AT_START:this._prependSoundToQueue(o)}return o}_appendSoundToQueue(e){this._queue.push(e)}_prependSoundToQueue(e){this._queue.unshift(e)}resetQueue(){return e(this,void 0,void 0,(function*(){this._options.stopOnReset&&(yield this.stop()),this._queue.forEach((e=>{this._playerAudio.disconnectSound(e)})),this._queue=[]}))}reset(){this.resetQueue().catch((e=>{}))}getQueue(){return this._queue}setVolume(e){this._playerAudio.setVolume(e).catch((e=>{}))}getVolume(){return this._playerAudio.getVolume()}setLoopQueue(e){this._options.loopQueue=e}getLoopQueue(){return this._options.loopQueue}mute(){const e=this.getVolume();this._playerAudio.setVolume(0,!1).catch((e=>{})),this._postMuteVolume=e}unMute(){this._playerAudio.setVolume(this._postMuteVolume,!1).catch((e=>{})),this._postMuteVolume=null}isMuted(){return null!==this._postMuteVolume}setPosition(t){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){let i=e.getDuration();(null===i||isNaN(i))&&(yield this._loadSound(e),i=e.getDuration());const o=i/100*t;this.setPositionInSeconds(o)}}))}setPositionInSeconds(i){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){if(null!==e.onSeeking){const t=i,o=e.getDuration(),n=t/o*100,s=Math.round(n);e.onSeeking(s,o,t)}e.state===t.SOUND_STATE_PLAYING?(e.playTime=i,this._options.loadPlayerMode===n.PLAYER_MODE_AJAX?(e.elapsedPlayTime=i,yield this._stop(e,t.SOUND_STATE_SEEKING)):this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO&&(e.state=t.SOUND_STATE_SEEKING,yield this._play(e))):(e.playTime=i,e.state=t.SOUND_STATE_SEEKING)}}))}_loadSound(t){return e(this,void 0,void 0,(function*(){switch(this._options.loadPlayerMode){case n.PLAYER_MODE_AUDIO:yield this._loadSoundUsingAudioElement(t);break;case n.PLAYER_MODE_AJAX:yield this._loadSoundUsingRequest(t);case n.PLAYER_MODE_FETCH:}}))}_loadSoundUsingAudioElement(t){return new Promise(((i,o)=>{const{url:n,codec:s=null}=this._findBestSource(t.source);t.url=n,t.codec=s,null!==t.url?this._playerAudio.getAudioElement().then((o=>{t.audioElement=o;const n=()=>e(this,void 0,void 0,(function*(){return t.audioElement.removeEventListener("canplaythrough",n),t.isReadyToPLay=!0,isNaN(t.audioElement.duration)||(t.duration=t.audioElement.duration),i()}));t.audioElement.addEventListener("canplaythrough",n),t.audioElement.onprogress=()=>{if(t.audioElement.buffered.length){const e=t.getDuration(),i=t.audioElement.buffered.end(0),o=100/(e/i),n=Math.round(o);t.loadingProgress=n,null!==t.onLoading&&t.onLoading(n,e,i),t.duration=t.audioElement.duration,100===n&&(t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date)}},t.audioElement.crossOrigin="anonymous",t.audioElement.src=t.url,t.audioElement.load()})).catch(o):o(new Error("sound has no url"))}))}_loadSoundUsingRequest(t){return e(this,void 0,void 0,(function*(){if(null!==t.arrayBuffer)return yield this._decodeSound({sound:t});const{url:e,codec:i=null}=this._findBestSource(t.source);if(t.url=e,t.codec=i,null===t.url)throw new Error("sound has no url");{const e=new o;t.isBuffering=!0;const i=yield e.getArrayBuffer(t);t.arrayBuffer=i,yield this._decodeSound({sound:t})}}))}_decodeSound({sound:t}){return e(this,void 0,void 0,(function*(){const e=t.arrayBuffer.slice(0),i=yield this._playerAudio.decodeAudio(e);t.audioBuffer=i,t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date,t.duration=i.duration,t.isReadyToPLay=!0}))}manuallyUnlockAudio(){return e(this,void 0,void 0,(function*(){yield this._playerAudio.unlockAudio()}))}play({whichSound:i,playTimeOffset:o}={}){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND}),s=this._getSoundFromQueue({whichSound:i,updateIndex:!0});return null===s?s:null!==e&&e.state===t.SOUND_STATE_PLAYING&&e.id===s.id?(isNaN(o)||this.setPositionInSeconds(o),s):(null===e||e.state!==t.SOUND_STATE_PLAYING&&e.state!==t.SOUND_STATE_PAUSED||e.id===s.id||(yield this._stop(e,t.SOUND_STATE_STOPPED)),isNaN(o)?s.playTimeOffset=0:s.playTimeOffset=o,null===s.sourceNode&&(yield this._playerAudio.connectSound(s,(()=>{this._onEnded()}))),s.isReadyToPLay||(yield this._loadSound(s)),yield this._play(s),s)}))}_play(i){return e(this,void 0,void 0,(function*(){this._playerAudio.isAudioContextFrozen()&&(yield this._playerAudio.unfreezeAudioContext()),i.playTimeOffset>0&&(i.playTime=i.playTimeOffset),this._options.loadPlayerMode===n.PLAYER_MODE_AJAX?yield this._playAudioBuffer(i):this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO&&(yield this._playMediaElementAudio(i)),i.state=t.SOUND_STATE_PLAYING,this._triggerSoundCallbacks(i)}))}_playAudioBuffer(i){return e(this,void 0,void 0,(function*(){if(i.sourceNode instanceof AudioBufferSourceNode){i.startTime=i.sourceNode.context.currentTime,i.sourceNode.buffer=i.audioBuffer;try{i.state===t.SOUND_STATE_SEEKING||i.state===t.SOUND_STATE_PAUSED&&0===i.playTimeOffset?i.sourceNode.start(0,i.playTime):i.playTimeOffset>0?(i.elapsedPlayTime=i.playTimeOffset,i.sourceNode.start(0,i.playTimeOffset)):i.sourceNode.start()}catch(e){throw new Error(e)}}}))}_playMediaElementAudio(i){return e(this,void 0,void 0,(function*(){if(i.sourceNode instanceof MediaElementAudioSourceNode)return i.state===t.SOUND_STATE_SEEKING||i.state===t.SOUND_STATE_PAUSED&&0===i.playTimeOffset?i.audioElement.currentTime=i.playTime:i.playTimeOffset>0?i.audioElement.currentTime=i.playTimeOffset:i.audioElement.currentTime=0,yield i.audioElement.play()}))}_triggerSoundCallbacks(e){null===e.onResumed||e.firstTimePlayed||e.onResumed(e.playTime),null!==e.onStarted&&e.firstTimePlayed&&(e.firstTimePlayed=!1,e.onStarted(e.playTimeOffset)),null!==e.onPlaying?(this._playingProgressPreviousTimestamp=0,this._progressTrigger(e,0)):this._playingProgressRequestId=null}_onEnded(){return e(this,void 0,void 0,(function*(){if(this._options.playNextOnEnded){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){if(this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO||this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&e.state===t.SOUND_STATE_PLAYING){let t=!1;null!==this._getSoundFromQueue({whichSound:n.PLAY_SOUND_NEXT})&&(t=!0),t||(yield this._playerAudio.freezeAudioContext()),null!==e.onEnded&&e.onEnded(t);try{yield this.next()}catch(e){}}if(this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&e.state===t.SOUND_STATE_SEEKING)try{yield this.play(e)}catch(e){}}}}))}_getSoundFromQueue({whichSound:e,updateIndex:t=!1}={}){let i=null,o=null;if(0===this._queue.length)return i;switch(void 0===e&&(e=n.CURRENT_SOUND),e){case n.CURRENT_SOUND:o=this._currentIndex,i=this._queue[o];break;case n.PLAY_SOUND_NEXT:void 0!==this._queue[this._currentIndex+1]?(o=this._currentIndex+1,i=this._queue[o]):this._options.loopQueue&&(o=0,i=this._queue[o]);break;case n.PLAY_SOUND_PREVIOUS:void 0!==this._queue[this._currentIndex-1]?(o=this._currentIndex-1,i=this._queue[o]):this._options.loopQueue&&(o=this._queue.length-1,i=this._queue[o]);break;case n.PLAY_SOUND_FIRST:this._queue.length>0&&(o=0,i=this._queue[o]);break;case n.PLAY_SOUND_LAST:this._queue.length>0&&(o=this._queue.length-1,i=this._queue[o]);break;default:[i,o]=this._findSoundById({soundId:e})}return null!==o&&t&&(this._currentIndex=o),i}_findSoundById({soundId:e}){let t=null,i=0;return this._queue.some(((o,n)=>{if(o.id===e)return t=o,i=n,!0})),[t,i]}_findBestSource(e){const t={url:null,codec:null};let i;i=Array.isArray(e)?e:[e];let o=0;for(;o<i.length;){const e=i[o];let n="";""!==this._options.soundsBaseUrl&&(n=this._options.soundsBaseUrl),n+=e.url;let s=!0;if(null!==e.codec&&(s=this._checkCodecSupport(e.codec)),s){if(e.isPreferred){t.url=n,t.codec=e.codec;break}t.url=n,t.codec=e.codec}o++}return t}_checkCodecSupport(e){let t,i="";switch(e){case"ogg":case"oga":t=['audio/ogg; codecs="vorbis"'];break;case"mp3":t=['audio/mpeg; codecs="mp3"'];break;case"opus":t=['audio/ogg; codecs="opus"','audio/webm; codecs="opus"'];break;case"wav":t=['audio/wav; codecs="1"'];break;case"m4a":t=["audio/m4a;","audio/x-m4a;"];break;case"m4p":t=["audio/m4p;","audio/x-m4p;"];break;case"caf":t=["audio/x-caf;"];break;case"aac":t=["audio/aac;"];break;case"weba":case"webm":t=['audio/webm; codecs="vorbis"'];break;case"flac":t=["audio/flac;","audio/x-flac;"];break;default:i="unrecognised codec"}if(i)throw new Error(i);return this._checkMimeTypesSupport(t)}_checkMimeTypesSupport(e){const t=new Audio;let i=!1;return e.forEach((e=>{t.canPlayType(e).replace(/^no$/,"")&&(i=!0)})),i}pause(){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null===e)return;if(e.state===t.SOUND_STATE_PAUSED)return;const i=e.getCurrentTime();return e.playTime=i,this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&(e.elapsedPlayTime=i),null!==e.onPaused&&e.onPaused(e.playTime),yield this._stop(e,t.SOUND_STATE_PAUSED),e}))}stop(){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e&&e.state!==t.SOUND_STATE_STOPPED)return yield this._playerAudio.freezeAudioContext(),null!==e.onStopped&&e.onStopped(e.playTime),yield this._stop(e,t.SOUND_STATE_STOPPED),e}))}_stop(i,o){return e(this,void 0,void 0,(function*(){null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressRequestId=null),i.state=o,null!==i.sourceNode&&(i.sourceNode instanceof AudioBufferSourceNode&&(i.sourceNode.stop(0),yield this._playerAudio.disconnectSound(i)),i.sourceNode instanceof MediaElementAudioSourceNode&&i.audioElement.pause()),o===t.SOUND_STATE_STOPPED&&(i.isReadyToPLay=!1,i.firstTimePlayed=!0,i.startTime=0,i.elapsedPlayTime=0,i.playTime=0,i.playedTimePercentage=0,yield this._playerAudio.disconnectSound(i))}))}next(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_NEXT})}))}previous(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_PREVIOUS})}))}first(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_FIRST})}))}last(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_LAST})}))}setVisibilityAutoMute(e){this._options.visibilityAutoMute=e,e?document.addEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1):document.removeEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1)}getVisibilityAutoMute(){return this._options.visibilityAutoMute}_handleVisibilityChange(){let e;void 0!==document.hidden?e="hidden":void 0!==document.msHidden?e="msHidden":void 0!==document.webkitHidden&&(e="webkitHidden"),document[e]?this.mute():this.unMute()}disconnect(){return e(this,void 0,void 0,(function*(){null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressRequestId=null),yield this._playerAudio.shutDown(this._queue)}))}getAudioContext(){return e(this,void 0,void 0,(function*(){return yield this._playerAudio.getAudioContext()}))}}n.WHERE_IN_QUEUE_AT_END="append",n.WHERE_IN_QUEUE_AT_START="prepend",n.PLAY_SOUND_NEXT="next",n.PLAY_SOUND_PREVIOUS="previous",n.PLAY_SOUND_FIRST="first",n.PLAY_SOUND_LAST="last",n.CURRENT_SOUND="current",n.PLAYER_MODE_AUDIO="player_mode_audio",n.PLAYER_MODE_AJAX="player_mode_ajax",n.PLAYER_MODE_FETCH="player_mode_fetch";export{n as PlayerCore,t as PlayerSound};
function e(e,t,i,o){return new(i||(i=Promise))((function(n,u){function s(e){try{r(o.next(e))}catch(e){u(e)}}function d(e){try{r(o.throw(e))}catch(e){u(e)}}function r(e){var t;e.done?n(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(s,d)}r((o=o.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class t{constructor(e){this.url=null,this.codec=null,this.loop=!1,this.sourceNode=null,this.gainNode=null,this.isReadyToPLay=!1,this.isBuffered=!1,this.isBuffering=!1,this.audioElement=null,this.audioBuffer=null,this.arrayBuffer=null,this.audioBufferDate=null,this.playTimeOffset=0,this.startTime=0,this.elapsedPlayTime=0,this.playTime=0,this.playedTimePercentage=0,this.state="sound_state_stopped",this.loadingProgress=0,this.duration=null,this.durationSetManually=!1,this.firstTimePlayed=!0,this.isConnectToPlayerGain=!1,Array.isArray(e.source)?this.source=e.source:this.source=[e.source],void 0!==e.id?this.id=e.id:this.id=this._generateSoundId(),this.loop=e.loop||!1,isNaN(e.duration)||(this.duration=e.duration,this.durationSetManually=!0),"function"==typeof e.onLoading?this.onLoading=e.onLoading:this.onLoading=null,"function"==typeof e.onPlaying?this.onPlaying=e.onPlaying:this.onPlaying=null,"function"==typeof e.onStarted?this.onStarted=e.onStarted:this.onStarted=null,"function"==typeof e.onEnded?this.onEnded=e.onEnded:this.onEnded=null,"function"==typeof e.onStopped?this.onStopped=e.onStopped:this.onStopped=null,"function"==typeof e.onPaused?this.onPaused=e.onPaused:this.onPaused=null,"function"==typeof e.onResumed?this.onResumed=e.onResumed:this.onResumed=null,"function"==typeof e.onSeeking?this.onSeeking=e.onSeeking:this.onSeeking=null,e.arrayBuffer instanceof ArrayBuffer&&(this.arrayBuffer=e.arrayBuffer),e.audioBuffer instanceof AudioBuffer&&(this.audioBuffer=e.audioBuffer,this.isBuffering=!1,this.isBuffered=!0,this.audioBufferDate=new Date,this.durationSetManually||(this.duration=this.audioBuffer.duration))}getCurrentTime(){let e;null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.sourceNode.context.currentTime-this.startTime+this.elapsedPlayTime:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.currentTime));return Math.round(100*(e+Number.EPSILON))/100}getDuration(){let e;null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.audioBuffer.duration:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.duration));return Math.round(100*(e+Number.EPSILON))/100}setDuration(e){isNaN(e)||(this.duration=e,this.durationSetManually=!0)}setLoop(e){this.loop=e,this.state===t.SOUND_STATE_PLAYING&&null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?this.sourceNode.loop=e:this.sourceNode instanceof MediaElementAudioSourceNode&&(this.sourceNode.mediaElement.loop=e))}getLoop(){return this.loop}_generateSoundId(){return Date.now().toString(36)+Math.random().toString(36).substring(2)}}t.SOUND_STATE_STOPPED="sound_state_stopped",t.SOUND_STATE_PAUSED="sound_state_paused",t.SOUND_STATE_PLAYING="sound_state_playing",t.SOUND_STATE_SEEKING="sound_state_seeking";class i{constructor(e){this._audioContext=null,this._volume=null,this._audioNodes={gainNode:null},this._audioElement=null,this._mediaElementAudioSourceNode=null,this._isAudioUnlocked=!1,this._isAudioUnlocking=!1,this._options=e,this._initialize()}_initialize(){this._options.unlockAudioOnFirstUserInteraction&&this._addFirstUserInteractionEventListeners()}getAudioNodes(){return this._audioNodes}decodeAudio(t){return e(this,void 0,void 0,(function*(){const e=yield this.getAudioContext();return yield e.decodeAudioData(t)}))}_createAudioContext(){if(this._audioContext instanceof AudioContext)return;const e=window.AudioContext||window.webkitAudioContext;null!==this._options.audioContext?this._audioContext=this._options.audioContext:this._audioContext=new e}_addFirstUserInteractionEventListeners(){this._options.unlockAudioOnFirstUserInteraction&&(document.addEventListener("keydown",this.unlockAudio.bind(this)),document.addEventListener("mousedown",this.unlockAudio.bind(this)),document.addEventListener("pointerdown",this.unlockAudio.bind(this)),document.addEventListener("pointerup",this.unlockAudio.bind(this)),document.addEventListener("touchend",this.unlockAudio.bind(this)))}_removeFirstUserInteractionEventListeners(){this._options.unlockAudioOnFirstUserInteraction&&(document.removeEventListener("keydown",this.unlockAudio.bind(this)),document.removeEventListener("mousedown",this.unlockAudio.bind(this)),document.removeEventListener("pointerdown",this.unlockAudio.bind(this)),document.removeEventListener("pointerup",this.unlockAudio.bind(this)),document.removeEventListener("touchend",this.unlockAudio.bind(this)))}unlockAudio(){return new Promise(((e,t)=>{if(this._isAudioUnlocking)return e();if(this._isAudioUnlocked)return e();if(this._isAudioUnlocking=!0,"player_mode_audio"===this._options.loadPlayerMode){const e=!0;this._createAudioElement(e).catch((e=>(this._isAudioUnlocking=!1,t())))}this.getAudioContext().then((()=>{const t=this._audioContext.createBuffer(1,1,22050);let i=this._audioContext.createBufferSource();i.onended=()=>(i.disconnect(0),this._removeFirstUserInteractionEventListeners(),i.disconnect(0),i.buffer=null,i=null,this._isAudioUnlocked=!0,this._isAudioUnlocking=!1,e()),i.buffer=t,i.connect(this._audioContext.destination),i.start(0)})).catch((e=>(this._isAudioUnlocking=!1,t())))}))}_createAudioElementAndSource(){return e(this,void 0,void 0,(function*(){yield this._createAudioElement(),yield this._createMediaElementAudioSourceNode()}))}_createAudioElement(t){return e(this,void 0,void 0,(function*(){if(null===this._audioElement||!0===t){const e=new Audio;e.controls=!1,e.autoplay=!1,e.preload="metadata",e.volume=1,e.id="web-audio-api-player",this._audioElement=e,this._options.addAudioElementsToDom&&document.body.appendChild(e)}}))}getAudioElement(){return e(this,void 0,void 0,(function*(){return null===this._audioElement&&(yield this._createAudioElementAndSource()),this._audioElement}))}getAudioContext(){return e(this,void 0,void 0,(function*(){return null===this._audioContext||"closed"===this._audioContext.state?yield this._createAudioContext():"suspended"===this._audioContext.state&&(yield this.unfreezeAudioContext()),this._audioContext}))}unfreezeAudioContext(){return void 0===this._audioContext.resume?Promise.resolve():this._audioContext.resume()}freezeAudioContext(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.suspend()}isAudioContextFrozen(){return"suspended"===this._audioContext.state}detectAudioContextSupport(){let e=!1;return(void 0!==window.webkitAudioContext||"undefined"!=typeof AudioContext)&&(e=!0),e}detectAudioElementSupport(){return!!document.createElement("audio").canPlayType}_createAudioBufferSourceNode(){return e(this,void 0,void 0,(function*(){return(yield this.getAudioContext()).createBufferSource()}))}_createMediaElementAudioSourceNode(){return e(this,void 0,void 0,(function*(){if(null===this._mediaElementAudioSourceNode&&null!==this._audioElement){const e=yield this.getAudioContext();this._mediaElementAudioSourceNode=e.createMediaElementSource(this._audioElement)}}))}_destroyMediaElementAudioSourceNode(){null!==this._mediaElementAudioSourceNode&&(void 0!==this._mediaElementAudioSourceNode.mediaElement&&this._mediaElementAudioSourceNode.mediaElement.remove(),this._mediaElementAudioSourceNode.disconnect(),this._mediaElementAudioSourceNode=null)}_destroyAudioBufferSourceNode(){null!==this._mediaElementAudioSourceNode&&this._mediaElementAudioSourceNode.disconnect()}_destroyAudioContext(){return e(this,void 0,void 0,(function*(){null!==this._audioContext&&"closed"!==this._audioContext.state&&(yield this._audioContext.close(),this._audioContext=null)}))}shutDown(t){return e(this,void 0,void 0,(function*(){this._removeFirstUserInteractionEventListeners(),t.forEach((e=>{this.disconnectSound(e)})),this._destroyMediaElementAudioSourceNode(),this._destroyAudioBufferSourceNode(),this._disconnectPlayerGainNode(),yield this._destroyAudioContext()}))}_getPlayerGainNode(){return e(this,void 0,void 0,(function*(){let e;if(this._audioNodes.gainNode instanceof GainNode)e=this._audioNodes.gainNode;else{const t=yield this.getAudioContext();e=t.createGain(),this._initializeVolume(e),e.connect(t.destination),this._audioNodes.gainNode=e}return e}))}_disconnectPlayerGainNode(){null!==this._audioNodes.gainNode&&(this._audioNodes.gainNode.disconnect(),this._audioNodes.gainNode=null)}connectSound(t,i){return e(this,void 0,void 0,(function*(){if(t.isConnectToPlayerGain)return;if("player_mode_ajax"===this._options.loadPlayerMode){const e=yield this._createAudioBufferSourceNode();t.gainNode=e.context.createGain(),e.connect(t.gainNode),e.loop=t.loop,e.onended=i,t.sourceNode=e}else"player_mode_audio"===this._options.loadPlayerMode&&(yield this._createAudioElementAndSource(),t.gainNode=this._mediaElementAudioSourceNode.context.createGain(),this._mediaElementAudioSourceNode.connect(t.gainNode),this._mediaElementAudioSourceNode.mediaElement.loop=t.loop,this._mediaElementAudioSourceNode.mediaElement.onended=i,t.sourceNode=this._mediaElementAudioSourceNode);t.gainNode.gain.value=1;const e=yield this._getPlayerGainNode();t.gainNode.connect(e),t.isConnectToPlayerGain=!0}))}disconnectSound(t){return e(this,void 0,void 0,(function*(){t.isConnectToPlayerGain&&(null!==t.sourceNode&&(t.sourceNode.disconnect(),t.sourceNode=null),null!==t.gainNode&&(t.gainNode.disconnect(),t.gainNode=null,t.isConnectToPlayerGain=!1),null!==t.audioElement&&(t.audioElement=null))}))}_changePlayerGainValue(t){return e(this,void 0,void 0,(function*(){if(this._audioNodes.gainNode instanceof GainNode){const e=yield this.getAudioContext(),i=(!isNaN(this._options.volumeTransitionTime)&&this._options.volumeTransitionTime>0?this._options.volumeTransitionTime:100)/1e3;this._audioNodes.gainNode.gain.setTargetAtTime(t,e.currentTime,i)}}))}setVolume(t,i=!0){return e(this,void 0,void 0,(function*(){this._options.persistVolume&&i&&localStorage.setItem("WebAudioAPIPlayerVolume",t.toString());const e=t/100;if(this._audioNodes.gainNode instanceof GainNode){e!==Math.round(100*(this._audioNodes.gainNode.gain.value+Number.EPSILON))/100&&(yield this._changePlayerGainValue(e))}return this._volume=t,t}))}getVolume(){let e;if(null!==this._volume)e=this._volume;else{if(this._options.persistVolume){const t=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume"));isNaN(t)||(e=t)}void 0===e&&(e=this._options.volume),this._volume=e}return e}_initializeVolume(e){if(this._options.persistVolume){const t=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume")),i=t/100;isNaN(t)||(e.gain.value=i),this._volume=t}if(null===this._volume){const t=this._options.volume/100;e.gain.value=t,this._volume=this._options.volume}}}class o{getArrayBuffer(e){return new Promise((function(t,i){const o=new XMLHttpRequest;o.open("GET",e.url,!0),o.responseType="arraybuffer",o.onload=function(){o.status>=200&&o.status<=299?t(o.response):i(new Error(o.statusText+"(status:"+o.status+")"))},o.onprogress=function(t){const i=100/(t.total/t.loaded),o=Math.round(i);e.loadingProgress=o,null!==e.onLoading&&e.onLoading(o,t.total,t.loaded)},o.onerror=function(e){i(e)},o.send()}))}}class n{constructor(e={}){this._playingProgressRequestId=null,this._postMuteVolume=null,this._progressTrigger=(e,i)=>{const o=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(e.id===o.id&&o.state===t.SOUND_STATE_PLAYING){if(i-this._playingProgressPreviousTimestamp>=this._options.playingProgressIntervalTime){const t=e.getCurrentTime(),o=e.getDuration();if(!isNaN(t)&&!isNaN(o)){let n=0;if(0!==t){const e=t/o*100;n=Math.round(e)}e.playedTimePercentage=n,e.playTime=t,e.onPlaying(n,o,t),this._playingProgressPreviousTimestamp=i}}this._playingProgressRequestId=window.requestAnimationFrame((t=>{this._progressTrigger(e,t)}))}};const i={volume:80,loopQueue:!1,loopSong:!1,soundsBaseUrl:"",playingProgressIntervalTime:200,playNextOnEnded:!0,stopOnReset:!0,visibilityAutoMute:!1,unlockAudioOnFirstUserInteraction:!1,persistVolume:!0,loadPlayerMode:"player_mode_audio",audioContext:null,addAudioElementsToDom:!1,volumeTransitionTime:100},o=Object.assign({},i,e);this._queue=[],this._currentIndex=0,this._options=o,this._playingProgressPreviousTimestamp=0,this._initialize()}_initialize(){const e=this._audioOptions();switch(this._playerAudio=new i(e),this._options.loadPlayerMode){case n.PLAYER_MODE_AUDIO:if(!this._playerAudio.detectAudioContextSupport())throw new Error("audio context is not supported by this device");if(!this._playerAudio.detectAudioElementSupport())throw new Error("audio element is not supported by this device");break;case n.PLAYER_MODE_AJAX:if(!this._playerAudio.detectAudioContextSupport())throw new Error("audio context is not supported by this device")}}_audioOptions(){return{audioContext:this._options.audioContext,unlockAudioOnFirstUserInteraction:this._options.unlockAudioOnFirstUserInteraction,volume:this._options.volume,persistVolume:this._options.persistVolume,loadPlayerMode:this._options.loadPlayerMode,addAudioElementsToDom:this._options.addAudioElementsToDom,volumeTransitionTime:this._options.volumeTransitionTime}}addSoundToQueue({soundAttributes:e,whereInQueue:i="append"}){const o=new t(e);switch(i){case n.WHERE_IN_QUEUE_AT_END:this._appendSoundToQueue(o);break;case n.WHERE_IN_QUEUE_AT_START:this._prependSoundToQueue(o)}return o}_appendSoundToQueue(e){this._queue.push(e)}_prependSoundToQueue(e){this._queue.unshift(e)}resetQueue(){return e(this,void 0,void 0,(function*(){this._options.stopOnReset&&(yield this.stop()),this._queue.forEach((e=>{this._playerAudio.disconnectSound(e)})),this._queue=[]}))}reset(){this.resetQueue().catch((e=>{}))}getQueue(){return this._queue}setVolume(e){this._playerAudio.setVolume(e).catch((e=>{}))}getVolume(){return this._playerAudio.getVolume()}setLoopQueue(e){this._options.loopQueue=e}getLoopQueue(){return this._options.loopQueue}mute(){const e=this.getVolume();this._playerAudio.setVolume(0,!1).catch((e=>{})),this._postMuteVolume=e}unMute(){this._playerAudio.setVolume(this._postMuteVolume,!1).catch((e=>{})),this._postMuteVolume=null}isMuted(){return null!==this._postMuteVolume}setPosition(t){return e(this,void 0,void 0,(function*(){if(t<0||t>100)throw new Error("soundPositionInPercent must be a number >= 0 and <= 100");const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){let i=e.getDuration();(null===i||isNaN(i))&&(yield this._loadSound(e),i=e.getDuration());const o=i/100*t;this.setPositionInSeconds(o)}}))}setPositionInSeconds(i){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){if(!isNaN(e.duration)&&Math.ceil(e.duration),null!==e.onSeeking){const t=i,o=e.getDuration(),n=t/o*100,u=Math.round(n);e.onSeeking(u,o,t)}e.state===t.SOUND_STATE_PLAYING?(e.playTime=i,this._options.loadPlayerMode===n.PLAYER_MODE_AJAX?(e.elapsedPlayTime=i,yield this._stop(e,t.SOUND_STATE_SEEKING)):this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO&&(e.state=t.SOUND_STATE_SEEKING,yield this._play(e))):(e.playTime=i,e.state=t.SOUND_STATE_SEEKING)}}))}_loadSound(t){return e(this,void 0,void 0,(function*(){switch(this._options.loadPlayerMode){case n.PLAYER_MODE_AUDIO:yield this._loadSoundUsingAudioElement(t);break;case n.PLAYER_MODE_AJAX:yield this._loadSoundUsingRequest(t);case n.PLAYER_MODE_FETCH:}}))}_loadSoundUsingAudioElement(t){return new Promise(((i,o)=>{const{url:n,codec:u=null}=this._findBestSource(t.source);t.url=n,t.codec=u,null!==t.url?this._playerAudio.getAudioElement().then((o=>{t.audioElement=o;const n=()=>e(this,void 0,void 0,(function*(){return t.audioElement.removeEventListener("canplaythrough",n),t.isReadyToPLay=!0,isNaN(t.audioElement.duration)||t.durationSetManually||(t.duration=t.audioElement.duration),i()}));t.audioElement.addEventListener("canplaythrough",n),t.audioElement.onprogress=()=>{if(t.audioElement.buffered.length){const e=t.getDuration(),i=t.audioElement.buffered.end(0),o=100/(e/i),n=Math.round(o);t.loadingProgress=n,null!==t.onLoading&&t.onLoading(n,e,i),t.durationSetManually||(t.duration=t.audioElement.duration),100===n&&(t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date)}},t.audioElement.crossOrigin="anonymous",t.audioElement.src=t.url,t.audioElement.load()})).catch(o):o(new Error("sound has no url"))}))}_loadSoundUsingRequest(t){return e(this,void 0,void 0,(function*(){if(null!==t.arrayBuffer)return yield this._decodeSound({sound:t});const{url:e,codec:i=null}=this._findBestSource(t.source);if(t.url=e,t.codec=i,null===t.url)throw new Error("sound has no url");{const e=new o;t.isBuffering=!0;const i=yield e.getArrayBuffer(t);t.arrayBuffer=i,yield this._decodeSound({sound:t})}}))}_decodeSound({sound:t}){return e(this,void 0,void 0,(function*(){const e=t.arrayBuffer.slice(0),i=yield this._playerAudio.decodeAudio(e);t.durationSetManually||(t.duration=i.duration),t.audioBuffer=i,t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date,t.isReadyToPLay=!0}))}manuallyUnlockAudio(){return e(this,void 0,void 0,(function*(){yield this._playerAudio.unlockAudio()}))}play({whichSound:i,playTimeOffset:o}={}){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND}),u=this._getSoundFromQueue({whichSound:i,updateIndex:!0});return null===u?u:null!==e&&e.state===t.SOUND_STATE_PLAYING&&e.id===u.id?(isNaN(o)||this.setPositionInSeconds(o),u):(null===e||e.state!==t.SOUND_STATE_PLAYING&&e.state!==t.SOUND_STATE_PAUSED||e.id===u.id||(yield this._stop(e,t.SOUND_STATE_STOPPED)),isNaN(o)?u.playTimeOffset=0:u.playTimeOffset=o,null===u.sourceNode&&(yield this._playerAudio.connectSound(u,(()=>{this._onEnded()}))),u.isReadyToPLay||(yield this._loadSound(u)),yield this._play(u),u)}))}_play(i){return e(this,void 0,void 0,(function*(){this._playerAudio.isAudioContextFrozen()&&(yield this._playerAudio.unfreezeAudioContext()),i.playTimeOffset>0&&(i.playTime=i.playTimeOffset),this._options.loadPlayerMode===n.PLAYER_MODE_AJAX?yield this._playAudioBuffer(i):this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO&&(yield this._playMediaElementAudio(i)),i.state=t.SOUND_STATE_PLAYING,this._triggerSoundCallbacks(i)}))}_playAudioBuffer(i){return e(this,void 0,void 0,(function*(){if(i.sourceNode instanceof AudioBufferSourceNode){i.startTime=i.sourceNode.context.currentTime,i.sourceNode.buffer=i.audioBuffer;try{i.state===t.SOUND_STATE_SEEKING||i.state===t.SOUND_STATE_PAUSED&&0===i.playTimeOffset?i.sourceNode.start(0,i.playTime):i.playTimeOffset>0?(i.playTimeOffset,Math.ceil(i.duration),i.elapsedPlayTime=i.playTimeOffset,i.sourceNode.start(0,i.playTimeOffset)):i.sourceNode.start()}catch(e){throw new Error(e)}}}))}_playMediaElementAudio(i){return e(this,void 0,void 0,(function*(){if(i.sourceNode instanceof MediaElementAudioSourceNode)return i.state===t.SOUND_STATE_SEEKING||i.state===t.SOUND_STATE_PAUSED&&0===i.playTimeOffset?i.audioElement.currentTime=i.playTime:i.playTimeOffset>0?(i.playTimeOffset,Math.ceil(i.duration),i.audioElement.currentTime=i.playTimeOffset):i.audioElement.currentTime=0,yield i.audioElement.play()}))}_triggerSoundCallbacks(e){null===e.onResumed||e.firstTimePlayed||e.onResumed(e.playTime),null!==e.onStarted&&e.firstTimePlayed&&(e.firstTimePlayed=!1,e.onStarted(e.playTimeOffset)),null!==e.onPlaying?(this._playingProgressPreviousTimestamp=0,this._progressTrigger(e,0)):this._playingProgressRequestId=null}_onEnded(){return e(this,void 0,void 0,(function*(){if(this._options.playNextOnEnded){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e){if(this._options.loadPlayerMode===n.PLAYER_MODE_AUDIO||this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&e.state===t.SOUND_STATE_PLAYING){let t=!1;null!==this._getSoundFromQueue({whichSound:n.PLAY_SOUND_NEXT})&&(t=!0),t||(yield this._playerAudio.freezeAudioContext()),null!==e.onEnded&&e.onEnded(t);try{yield this.next()}catch(e){}}if(this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&e.state===t.SOUND_STATE_SEEKING)try{yield this.play(e)}catch(e){}}}}))}_getSoundFromQueue({whichSound:e,updateIndex:t=!1}={}){let i=null,o=null;if(0===this._queue.length)return i;switch(void 0===e&&(e=n.CURRENT_SOUND),e){case n.CURRENT_SOUND:o=this._currentIndex,i=this._queue[o];break;case n.PLAY_SOUND_NEXT:void 0!==this._queue[this._currentIndex+1]?(o=this._currentIndex+1,i=this._queue[o]):this._options.loopQueue&&(o=0,i=this._queue[o]);break;case n.PLAY_SOUND_PREVIOUS:void 0!==this._queue[this._currentIndex-1]?(o=this._currentIndex-1,i=this._queue[o]):this._options.loopQueue&&(o=this._queue.length-1,i=this._queue[o]);break;case n.PLAY_SOUND_FIRST:this._queue.length>0&&(o=0,i=this._queue[o]);break;case n.PLAY_SOUND_LAST:this._queue.length>0&&(o=this._queue.length-1,i=this._queue[o]);break;default:[i,o]=this._findSoundById({soundId:e})}return null!==o&&t&&(this._currentIndex=o),i}_findSoundById({soundId:e}){let t=null,i=0;return this._queue.some(((o,n)=>{if(o.id===e)return t=o,i=n,!0})),[t,i]}_findBestSource(e){const t={url:null,codec:null};let i;i=Array.isArray(e)?e:[e];let o=0;for(;o<i.length;){const e=i[o];let n="";""!==this._options.soundsBaseUrl&&(n=this._options.soundsBaseUrl),n+=e.url;let u=!0;if(null!==e.codec&&(u=this._checkCodecSupport(e.codec)),u){if(e.isPreferred){t.url=n,t.codec=e.codec;break}t.url=n,t.codec=e.codec}o++}return t}_checkCodecSupport(e){let t,i="";switch(e){case"ogg":case"oga":t=['audio/ogg; codecs="vorbis"'];break;case"mp3":t=['audio/mpeg; codecs="mp3"'];break;case"opus":t=['audio/ogg; codecs="opus"','audio/webm; codecs="opus"'];break;case"wav":t=['audio/wav; codecs="1"'];break;case"m4a":t=["audio/m4a;","audio/x-m4a;"];break;case"m4p":t=["audio/m4p;","audio/x-m4p;"];break;case"caf":t=["audio/x-caf;"];break;case"aac":t=["audio/aac;"];break;case"weba":case"webm":t=['audio/webm; codecs="vorbis"'];break;case"flac":t=["audio/flac;","audio/x-flac;"];break;default:i="unrecognised codec"}if(i)throw new Error(i);return this._checkMimeTypesSupport(t)}_checkMimeTypesSupport(e){const t=new Audio;let i=!1;return e.forEach((e=>{t.canPlayType(e).replace(/^no$/,"")&&(i=!0)})),i}pause(){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null===e)return;if(e.state===t.SOUND_STATE_PAUSED)return;const i=e.getCurrentTime();return e.playTime=i,this._options.loadPlayerMode===n.PLAYER_MODE_AJAX&&(e.elapsedPlayTime=i),null!==e.onPaused&&e.onPaused(e.playTime),yield this._stop(e,t.SOUND_STATE_PAUSED),e}))}stop(){return e(this,void 0,void 0,(function*(){const e=this._getSoundFromQueue({whichSound:n.CURRENT_SOUND});if(null!==e&&e.state!==t.SOUND_STATE_STOPPED)return yield this._playerAudio.freezeAudioContext(),null!==e.onStopped&&e.onStopped(e.playTime),yield this._stop(e,t.SOUND_STATE_STOPPED),e}))}_stop(i,o){return e(this,void 0,void 0,(function*(){null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressRequestId=null),i.state=o,null!==i.sourceNode&&(i.sourceNode instanceof AudioBufferSourceNode&&(i.sourceNode.stop(0),yield this._playerAudio.disconnectSound(i)),i.sourceNode instanceof MediaElementAudioSourceNode&&i.audioElement.pause()),o===t.SOUND_STATE_STOPPED&&(i.isReadyToPLay=!1,i.firstTimePlayed=!0,i.startTime=0,i.elapsedPlayTime=0,i.playTime=0,i.playedTimePercentage=0,yield this._playerAudio.disconnectSound(i))}))}next(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_NEXT})}))}previous(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_PREVIOUS})}))}first(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_FIRST})}))}last(){return e(this,void 0,void 0,(function*(){return yield this.play({whichSound:n.PLAY_SOUND_LAST})}))}setVisibilityAutoMute(e){this._options.visibilityAutoMute=e,e?document.addEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1):document.removeEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1)}getVisibilityAutoMute(){return this._options.visibilityAutoMute}_handleVisibilityChange(){let e;void 0!==document.hidden?e="hidden":void 0!==document.msHidden?e="msHidden":void 0!==document.webkitHidden&&(e="webkitHidden"),document[e]?this.mute():this.unMute()}disconnect(){return e(this,void 0,void 0,(function*(){null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressRequestId=null),yield this._playerAudio.shutDown(this._queue)}))}getAudioContext(){return e(this,void 0,void 0,(function*(){return yield this._playerAudio.getAudioContext()}))}getCurrentSound(){return this._getSoundFromQueue({whichSound:n.CURRENT_SOUND})}}n.WHERE_IN_QUEUE_AT_END="append",n.WHERE_IN_QUEUE_AT_START="prepend",n.PLAY_SOUND_NEXT="next",n.PLAY_SOUND_PREVIOUS="previous",n.PLAY_SOUND_FIRST="first",n.PLAY_SOUND_LAST="last",n.CURRENT_SOUND="current",n.PLAYER_MODE_AUDIO="player_mode_audio",n.PLAYER_MODE_AJAX="player_mode_ajax",n.PLAYER_MODE_FETCH="player_mode_fetch";export{n as PlayerCore,t as PlayerSound};
//# sourceMappingURL=index.min.js.map

@@ -10,2 +10,3 @@ import { ISound } from './sound';

addAudioElementsToDom: boolean;
volumeTransitionTime: number;
}

@@ -12,0 +13,0 @@ export interface IAudioNodes {

@@ -24,2 +24,3 @@ import { ISound, ISoundAttributes, ISoundSource, typeSoundStates } from './sound';

addAudioElementsToDom?: boolean;
volumeTransitionTime?: number;
}

@@ -113,3 +114,4 @@ export interface ISoundsQueueOptions {

getAudioContext(): Promise<AudioContext>;
getCurrentSound(): ISound;
}
export {};

@@ -65,4 +65,8 @@ declare const SOUND_STATE_STOPPED = "sound_state_stopped";

isConnectToPlayerGain: boolean;
durationSetManually: boolean;
getCurrentTime(): number;
getDuration(): number;
setDuration(duration: number): void;
setLoop(loop: boolean): void;
getLoop(): boolean;
}

@@ -96,2 +100,3 @@ export declare class PlayerSound implements ISound {

duration: number;
durationSetManually: boolean;
firstTimePlayed: boolean;

@@ -110,4 +115,7 @@ isConnectToPlayerGain: boolean;

getDuration(): number;
setDuration(duration: number): void;
setLoop(loop: boolean): void;
getLoop(): boolean;
protected _generateSoundId(): string;
}
export {};
{
"name": "web-audio-api-player",
"version": "5.1.0-beta.4",
"version": "5.1.0",
"description": "web audio api player",

@@ -5,0 +5,0 @@ "keywords": [

@@ -85,3 +85,3 @@ [![npm version](https://img.shields.io/npm/v/web-audio-api-player.svg?style=flat)](https://www.npmjs.com/package/web-audio-api-player)

the only two attributes that are mandatory are the source array and the sound id, the source only needs one entry but for demonstration purposes I added two here, the first one is the song encoded as an mp3 and the second source is the same song but this time it has is encoded using the ogg codec, a third source option is **isPreferred**, it tells the player that if the browser has support for both codecs but that it should preferrably use ogg over mp3, the id can be any numeric value, it can be usefull if you have additional song data stored somewhere, for example if you have the related band name info, the songs music genre and so on, for example stored in a database and want to display that data in the UI while the song is being played
the only two attributes that are mandatory are the source array and the sound id, the source only needs one entry but for demonstration purposes I added two here, the first one is the song encoded as an mp3 and the second source is the same song but this time it has is encoded using the ogg codec, a third source option is **isPreferred**, it tells the player that if the browser has support for both codecs but that it should preferably use ogg over mp3, the id can be any numeric value, it can be useful if you have additional song data stored somewhere, for example if you have the related band name info, the songs music genre and so on, for example stored in a database and want to display that data in the UI while the song is being played

@@ -231,31 +231,4 @@ Note: for a full list of all available sound attributes check out the [sound attributes chapter](#sound-attributes)

* addAudioElementsToDom: [boolean] (default: false) when audio elements get created, they are by default offscreen (not added to the DOM), if you want the audio elements to be added to the DOM set this option to true
* volumeTransitionTime: [number] (default: 100) value in milliseconds, by default the volume if changed will not go instantly from the old value to the new value but there is transition where it fades from current to new value, use this option to increase or decrease the transition duration
### sound attributes
Note: if you use typescript, import the **ISoundAttributes** interface along with the playerCore, this makes it a lot easier to see what sound attributes are available and what the type of each value is
**sound options:**
* source: [(ISoundSource)[] | ISoundSource] (optional if an AudioBuffer or ArrayBuffer is provided instead else mandatory) a single sound source or an array of sound sources, an **ISoundSource** object consists of 3 values:
* **url** [string] is the base url defined in the player options + the path defined here or you add the full url here, the URL will get used by the player to load the sound when needed
* **codec** [string] the codec that got used to encode the sound, this allowed the player to check if that codec is supported by the browser and it also allows the player to decide which source to use if multiple sources have been defined
* **isPreferred** [boolean] (optional) the player will use the first source that has a codec this is supported by the browser, if more than one codec is supported it will take the source that is marked as **isPreferred**
* id: [number | string] (optional, if none is set the player will generate one) unique id for the sound, can be used as a reference to link sound data which is not part of the sound object itself to an external source, for example if you have sound info stored in a database, set the sound id to the database id and you have a link between the two, it also allows you to call the player.play funtion using the sound id as argument to play that sound
* loop: [boolean] (optional, default false) if the sound playback should loop when it reaches the end of sound
* audioBuffer: [AudioBuffer] (optional) if you want to inject your own custom [AudioBuffer](https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer) to be used instead of the default one the player will create
* arrayBuffer: [ArrayBuffer] (optional) if you want to inject your own custom [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) to be used instead of the default one the player will create
* duration: [number] (optional) if you know the duration of the sound and want to tell the player about it early, in [PLAYER_MODE_AJAX](#player_mode_ajax) the player will need to wait for the sound to be fully loaded until it can determine the duration
**sound callbacks:**
* onLoading(loadingPercentage, total, loaded): [function] (optional) a callback funtion that will get triggered at intervals during the loading process of a sound, the interval duration can be changed using the [player option "playingProgressIntervalTime"](#player-options), the callback has three parameters, **loadingPercentage** is the percentage that has been loaded so far (number ranging from 0 to 100)
* if the player mode is [PLAYER_MODE_AUDIO](#player_mode_audio), then **total** is an integer telling you the total song duration in seconds ([MDN HTMLMediaElement duration](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration)), **loaded** is an integer that tells you the amount that already got loaded (buffered end) in seconds ([MDN HTMLMediaElement timerange end](https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges/end)), if you prefer to use the raw values I recommend you use the **sound.audioElement.buffered** and read them perciodically yourself
* if the player mode is [PLAYER_MODE_AJAX](#player_mode_ajax), then **total** is an integer telling you the total bytes that will get loaded ([MDN ProgressEvent total](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/total)), **loaded** is an integer that tells you the amount of bytes that already got loaded ([MDN ProgressEvent loaded](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/loaded))
* onPlaying(playingPercentage, duration, playTime)): [function] (optional) a callback funtion that will get triggered at intervals while the sound is playing, the callback has three parameters, **playingPercentage** is the percentage that has been played so far (number ranging from 0 to 100), **duration** is the total song duration, playTime is the current time in seconds that have been played
* onEnded(willPlayNext): [function] (optional) a callback funtion that will get triggered when the end of the sound is reached, returns one parameter **willPlayNext** which is a boolean, true if there is a next song in the internal queue that will get played or false if no next sound will get played
* onStarted(playTimeOffset): [function] (optional) a callback funtion that will get triggered when the sound playback starts, returned value is the playTimeOffset of the song, usually playTimeOffset is zero unless you explicitly set it to be something else
* onStopped(playTime): [function] (optional) a callback funtion that will get triggered when the sound playback is stopped (the difference between pause and stop is that stop will free the resources needed to play a song), returns one parameter **playTime** which is the current sound position in seconds
* onPaused(playTime): [function] (optional) a callback funtion that will get triggered when the sound playback is being paused (use pause instead of stop if there is a reason to assume that the playback will be resumed at anytime, if this can't be assumed it is recommended to call stop), returns one parameter **playTime** which is the current sound position in seconds
* onResumed(playTime): [function] (optional) a callback funtion that will get triggered when the sound playback gets resumed after if got set to pause, returns one parameter **playTime** which is the current sound position in seconds
### player functions

@@ -326,3 +299,3 @@

* mute() sets the volume to 0
* unMute() resets the volume to it's previous value
* unMute() resets the volume to its previous value
* isMuted() a boolean value, true if the volume is currently muted else false

@@ -335,7 +308,44 @@ * setPosition(soundPositionInPercent: number) used to change the position of the song that is currently playing in percent, so a number ranging from 0 to 100, returns a promise

* getAudioContext() get the current audioContext that is being used by the player [MDN audiocontext](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext)
* getCurrentSound() returns the current sound, can be useful if you want to do things in your UI like getCurrentSound().getLoop() to check if the loop feature is on or off for the current song
* manuallyUnlockAudio() this method can be used on mobile to unlock audio, you need to call this function inside an event handler that got triggered by the user, so for example an "onClick" event could call this function to unlock audio, calling this function programmatically without any user interaction will not unlock audio, an alternative if you don't want to implement this yourself is to enable the [player option](#player-options) called **unlockAudioOnFirstUserInteraction**, for more info about this check out the chapter ["locked audio on mobile"](#locked-audio-on-mobile)
### sound attributes
Note: if you use typescript, import the **ISoundAttributes** interface along with the playerCore, this makes it a lot easier to see what sound attributes are available and what the type of each value is
**sound options:**
* source: [(ISoundSource)[] | ISoundSource] (optional if an AudioBuffer or ArrayBuffer is provided instead else mandatory) a single sound source or an array of sound sources, an **ISoundSource** object consists of 3 values:
* **url** [string] is the base url defined in the player options + the path defined here or you add the full url here, the URL will get used by the player to load the sound when needed
* **codec** [string] the codec that got used to encode the sound, this allowed the player to check if that codec is supported by the browser and it also allows the player to decide which source to use if multiple sources have been defined
* **isPreferred** [boolean] (optional) the player will use the first source that has a codec this is supported by the browser, if more than one codec is supported it will take the source that is marked as **isPreferred**
* id: [number | string] (optional, if none is set the player will generate one) unique id for the sound, can be used as a reference to link sound data which is not part of the sound object itself to an external source, for example if you have sound info stored in a database, set the sound id to the database id and you have a link between the two, it also allows you to call the player.play function using the sound id as argument to play that sound
* loop: [boolean] (optional, default false) if the sound playback should loop when it reaches the end of sound
* audioBuffer: [AudioBuffer] (optional) if you want to inject your own custom [AudioBuffer](https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer) to be used instead of the default one the player will create
* arrayBuffer: [ArrayBuffer] (optional) if you want to inject your own custom [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) to be used instead of the default one the player will create
* duration: [number] (optional) if you know the duration of the sound and want to tell the player about it early, in [PLAYER_MODE_AJAX](#player_mode_ajax) the player will need to wait for the sound to be fully loaded until it can determine the duration
**sound callbacks:**
* onLoading(loadingPercentage, total, loaded): [function] (optional) a callback function that will get triggered at intervals during the loading process of a sound, the interval duration can be changed using the [player option "playingProgressIntervalTime"](#player-options), the callback has three parameters, **loadingPercentage** is the percentage that has been loaded so far (number ranging from 0 to 100)
* if the player mode is [PLAYER_MODE_AUDIO](#player_mode_audio), then **total** is an integer telling you the total song duration in seconds ([MDN HTMLMediaElement duration](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration)), **loaded** is an integer that tells you the amount that already got loaded (buffered end) in seconds ([MDN HTMLMediaElement timerange end](https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges/end)), if you prefer to use the raw values I recommend you use the **sound.audioElement.buffered** and read them periodically yourself
* if the player mode is [PLAYER_MODE_AJAX](#player_mode_ajax), then **total** is an integer telling you the total bytes that will get loaded ([MDN ProgressEvent total](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/total)), **loaded** is an integer that tells you the amount of bytes that already got loaded ([MDN ProgressEvent loaded](https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/loaded))
* onPlaying(playingPercentage, duration, playTime)): [function] (optional) a callback function that will get triggered at intervals while the sound is playing, the callback has three parameters, **playingPercentage** is the percentage that has been played so far (number ranging from 0 to 100), **duration** is the total song duration, playTime is the current time in seconds that have been played
* onEnded(willPlayNext): [function] (optional) a callback function that will get triggered when the end of the sound is reached, returns one parameter **willPlayNext** which is a boolean, true if there is a next song in the internal queue that will get played or false if no next sound will get played
* onStarted(playTimeOffset): [function] (optional) a callback function that will get triggered when the sound playback starts, returned value is the playTimeOffset of the song, usually playTimeOffset is zero unless you explicitly set it to be something else
* onStopped(playTime): [function] (optional) a callback function that will get triggered when the sound playback is stopped (the difference between pause and stop is that stop will free the resources needed to play a song), returns one parameter **playTime** which is the current sound position in seconds
* onPaused(playTime): [function] (optional) a callback function that will get triggered when the sound playback is being paused (use pause instead of stop if there is a reason to assume that the playback will be resumed at anytime, if this can't be assumed it is recommended to call stop), returns one parameter **playTime** which is the current sound position in seconds
* onResumed(playTime): [function] (optional) a callback function that will get triggered when the sound playback gets resumed after if got set to pause, returns one parameter **playTime** which is the current sound position in seconds
### sound functions
* getCurrentTime() returns the current playTime
* getDuration() returns the duration of the sound
* setDuration(duration: number) you can set the duration of a sound manually, this avoids having to wait for the sound to be loaded to know it's duration, might be useful depending on the kind of UI you are building
* setLoop(loop: boolean) allows you to change the initial value for "loop sound", by default loop is false, use this to change the loop value after the sound got added to queue
* getLoop() returns a boolean telling you what the current value for "loop sound" is
### locked audio on mobile
All mobile browsers prevent playing sounds (songs) if no user gesture has happend yet. This means that on mobile you can NOT play sounds (songs) programmatically (this is also the reason why the autoplay attribute on an audio element does not auto play a song on mobile and also the reason videos will only autoplay if they are muted)
All mobile browsers prevent playing sounds (songs) if no user gesture has happened yet. This means that on mobile you can NOT play sounds (songs) programmatically (this is also the reason why the autoplay attribute on an audio element does not auto play a song on mobile and also the reason videos will only autoplay if they are muted)

@@ -354,3 +364,3 @@ Note: If the user clicks on a play button and call player.play() then audio will play just fine, this chapter is about audio not playing when calling player.play() before the user interacted with the page (app)

* solution 1: there is a [player option](#player-options) called **unlockAudioOnFirstUserInteraction**, set it to true when initializing the player and the player will add user interaction listeners to the html document, on the first user interaction the player catches, it will attempt to unlock audio, after audio is unlocked you will be able to call the players play() function programmatically and it will not throw an error anywore
* solution 1: there is a [player option](#player-options) called **unlockAudioOnFirstUserInteraction**, set it to true when initializing the player and the player will add user interaction listeners to the html document, on the first user interaction the player catches, it will attempt to unlock audio, after audio is unlocked you will be able to call the players play() function programmatically and it will not throw an error anymore

@@ -361,3 +371,3 @@ * solution 2: there is a [player function](#player-functions) called **manuallyUnlockAudio()** that you can use to attempt to unlock audio on mobile, this function MUST be played inside an event handler that got triggered by a user interaction, events that you can use are for example "keydown" (excluding the Escape key and possibly some keys reserved by the browser or OS), "mousedown", "pointerdown" or "pointerup" (but only if the pointerType is "mouse") and "touchend"

#### differencies clarification
#### player modes differences clarification

@@ -380,5 +390,5 @@ Note: You might have read (like I did) a lot of outdated web audio articles which stated the web audio element lacks a lot of features the web audio API and that hence it is not suited to create complex audio software or for example be used in games where you might want to add effects and filters to sounds. This is not true anymore and especially not true for this library. Yes the audio element if used as a standalone lacks a lot of features. But this library does combine the web audio element with the web audio API, meaning that no matter what mode you chose the sound will be converted to an AudioSourceNode.

If you build something like a music player, it is probably best to use the PLAYER_MODE_AUDIO as you might to want to start playing the sound (song) as quickly as possible and don't care if it has fully loaded. This mode is ideal for big files that don't get loaded all at once (streaming). The audio mode (via the audio element) has support for partial content (http code 206) this means with this mode the song will start playing as soon as enough data has been buffered even though the song has not been fully loaded yet (it will load more data from the server in the background as the song progresses). The loading progress callback will return a percentage, which represents the amount of data that got loaded so far, which means it might not represent the loading state of the full song. If you want to display what parts of the song have been loaded more accuratly (display the time range(s) that got loaded) I recommend using a [2D canvas element](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D) and to get the ranges that have been loaded, I recommend you use the **audioElement** property of a song to get the audioElement that is loading the song and then read the [audioElement.buffered](https://developer.mozilla.org/en-US/docs/Web/Guide/Audio_and_video_delivery/buffering_seeking_time_ranges) value(s).
If you build something like a music player, it is probably best to use the PLAYER_MODE_AUDIO as you might want to start playing the sound (song) as quickly as possible and don't care if it has fully loaded. This mode is ideal for big files that don't get loaded all at once (streaming). The audio mode (via the audio element) has support for partial content (http code 206) this means with this mode the song will start playing as soon as enough data has been buffered even though the song has not been fully loaded yet (it will load more data from the server in the background as the song progresses). The loading progress callback will return a percentage, which represents the amount of data that got loaded so far, which means it might not represent the loading state of the full song. If you want to display what parts of the song have been loaded more accurately (display the time range(s) that got loaded) I recommend using a [2D canvas element](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D) and to get the ranges that have been loaded, I recommend you use the **audioElement** property of a song to get the audioElement that is loading the song and then read the [audioElement.buffered](https://developer.mozilla.org/en-US/docs/Web/Guide/Audio_and_video_delivery/buffering_seeking_time_ranges) value(s).
You can use the PLAYER_MODE_AJAX if for example you want to build something that has a lot (of small sounds that get loaded all at once) and eventually get (pre-)loaded and maybe cached by you (you can inject an array buffer that you loaded yourself or even a audio buffer you already decoded to the player via the sound attributes). Use this mode if you prefer to wait until the song has fully loaded and then gets played. Its progress callback is straight forward, when the loading progress callback gets triggered by the player, you can use the percentage value and pass it to a progress bar. To display the loading progress you could for example use a [HTML progress element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress), you can find a such example in the .
You can use the PLAYER_MODE_AJAX if for example you want to build something that has a lot (of small sounds that get loaded all at once) and eventually get (pre-)loaded and maybe cached by you (you can inject an array buffer that you loaded yourself or even a audio buffer you already decoded to the player via the sound attributes). Use this mode if you prefer to wait until the song has fully loaded and then gets played. Its progress callback is straight forward, when the loading progress callback gets triggered by the player, you can use the percentage value and pass it to a progress bar. To display the loading progress you could for example use a [HTML progress element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress), you can find such an example in the [simple player example](./examples/simple-player/README.md).

@@ -393,3 +403,3 @@ ### advanced usage

## read more: W3C sources and MDN documetation
## read more

@@ -465,11 +475,14 @@ * [W3C Recommendation, 17 June 2021](https://www.w3.org/TR/webaudio/)

* add onDurationChange / onLoopChange callbacks to song(s)!?
* add loop song, loop queue, loop off examples to simple player example
* for audio mode, add option for songs "crossOrigin" to be set to "use-credentials" (https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) instead of "anonymous", "anonymous" could be kept as default value, also do the same for XHR calls (ajax mode) [XMLHttpRequest: withCredentials property](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
* add sound option to set the initial gain value of a sound, for now it is always 1 (1 = no change to loudness), (optional method that lets you define a modifier (or coefficient) per song by which the gain will be changed), useful if some songs are louder than others and you want to normalize the volume of all songs in a playlist to be similar
* add a song feature to fade out (current song) / fade in (next song) maybe two new options fadeInDuration and fadeOutDuration would be enough, if the values are set we do a fade
* add a shuffle songs feature, I thought about adding a PLAY_SHUFFLE(D) option for the play() function but then only the first song would be a random pick, so the player itself needs a shuffle mode which also shuffles the next songs, you need to be able to turn it on / off at any time
* add a loop song (<https://webaudio.github.io/web-audio-api/#looping-AudioBufferSourceNode>) feature (actually maybe this already works today, need to verify this), same for loop playlist (need to verify it works well before I remove this item from the TODOS)
* we have sound events, but would player event be useful, like onVolumeChange?
* use service worker to cache ajax requests when the player mode is ajax (audio buffer) <https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API>
* it would probably be useful to have a duration change callback (onDurationChange) for songs
* add sound option to set the initial gain value of a sound, for now it is always 1 (1 = no change to loudness), (optional method that lets you define a modifier (or coefficient) per song by which the gain will be changed), useful if some songs are louder than others and you want to normalize the volume of all songs in a playlist to be similar
* add a song feature to fade out (current song) / fade in (next song) maybe two new options fadeInDuration and fadeOutDuration would be enough
* today we have sound callbacks for events like "playing", "started"..., but would player callbacks be useful, we could add callbacks for things like an "onVolumeChange" event?
* is there a need to add more callbacks to songs, for native audio (element) events? [audio#events](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#events) ... are there equivalents for songs loaded in ajax mode
* add an example where dev custom audiocontext gets connected to an [AnalyserNode](https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode) or oscilator node and then passed to player (to which we then connect the song gainnode and then connect that audiocontext to the destination)
* instead of having sound properties like "isReadyToPLay, isBuffered, isBuffering" it would be better to use the SOUND_STATE_XXX constants
* add (stereo) panning (maybe add an example of how to do it by injecting an audiocontext that has the panningnode attached already) <https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode>
* use service worker to cache ajax requests when the player mode is ajax (audio buffer) <https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API>
* allow to add an array of sounds to queue all at once

@@ -480,8 +493,8 @@ * allow to add sound to queue after a sound by id (not just at beginning or end, as it is as of now)

* opt in feature to use the browser notification system to alert which song is being played (?)
* preload ArrayBuffers (or the audio buffer instead of array buffer) into indexeddb (first song, next song, current song if loop or previous is triggered ...), let the developer set the amount of preloaded ArrayBuffers, remove from "cache" by least used and by date when "cache" is full, maybe do such work using this browser feature [requestidlecallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback) (when available)
* cache songs for offline mode? indexeddb is not very big (filesystem?), check if doable because saving a playlist of songs might exhaust the free space (depending on the playlist size), maybe using service worker?
* option to preload the first song or more songs, would have to work for both player modes, would be most beneficial for ajax mode as song(s) can only play when fully loaded, need to check if preloading ArrayBuffers (or the already decoded audio buffer instead of array buffer) can be saved into indexeddb (the first song, maybe also the next song, or reuse the buffer (array) of the current song if loop is active), eventually it would be best to let the developer set the amount of preloaded ArrayBuffers he wants to store, but then I would also need a mechanism to remove them from "cache" at some point, maybe clear cache by least used or by date, maybe do such preloading work using this browser feature: ["requestidlecallback"](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback) (when available)
* cache songs for offline mode? indexeddb is probably not very big (save directly to the filesystem?), check if it is doable, because saving a playlist of songs might exhaust the free space the browser has (depending on the playlist size), maybe using a service worker to make such an operation in the background?
* some methods return a promise others don't, use promises for all to make it more consistent?
* [abort](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort) the loading of the sound if the user clicks play and then pause (or stop / next / previous) before the end of the buffering process
* add feature to be able to abort the XHR request, we could [abort](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort) the loading of the sound if the user clicks play and then pause (or stop / next / previous) before the end of the loading (buffering) process
* add new loadPlayerMode similar to XMLHttpRequest but that uses [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to get the sound / song data from server, fetch as of now is still young, it is not yet possible to get the loading progress (<https://stackoverflow.com/a/69400632/656689>)
* use suspend (audioContext) if for some time no sound was played? (and then resume needed?) ... to free device resources. As suspend returns a promise, does this mean suspending and resuming takes time? if so how much time does it take, based on that information we can decide after how much time it makes sense to suspend the ctx to save device resources, should this be an event of the player so that user can attach a callback to show a dialog like netflix (still wathcing?)
* use suspend (audioContext) if for some time no sound was played? (and then resume needed?) ... to free device resources. As suspend returns a promise, does this mean suspending and resuming takes time? If so, how much time does it take, based on that information we can decide after how much time it makes sense to suspend the ctx to save device resources, should this be an event of the player so that user can attach a callback to show a dialog like netflix (still watching?)
* use web workers, especially for the decoding of the ArrayBuffer into an AudioBuffer, to not block the main thread while decoding?

@@ -488,0 +501,0 @@ * add support for more codecs? Note: the player should check which codecs are supported by the browser and compare that list with the ones defined in the sound sources, then the player should use the first codec that is supported and that is marked as "isPreferred", if none is marked as "isPreferred" use the first sources codec that is supported

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc