web-audio-api-player
Advanced tools
Comparing version 4.3.1 to 5.0.0
@@ -1,2 +0,2 @@ | ||
export { PlayerCore, ICoreOptions } from './library/core'; | ||
export { PlayerCore, ICoreOptions, ISoundsQueueOptions, IPlayOptions } from './library/core'; | ||
export { PlayerSound, ISoundAttributes, ISound } from './library/sound'; |
@@ -1,2 +0,2 @@ | ||
var e=function(t,o){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])},e(t,o)};function t(e,t,o,n){return new(o||(o=Promise))((function(i,u){function r(e){try{a(n.next(e))}catch(e){u(e)}}function s(e){try{a(n.throw(e))}catch(e){u(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(r,s)}a((n=n.apply(e,t||[])).next())}))}function o(e,t){var o,n,i,u,r={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return u={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function s(s){return function(a){return function(s){if(o)throw new TypeError("Generator is already executing.");for(;u&&(u=0,s[0]&&(r=0)),r;)try{if(o=1,n&&(i=2&s[0]?n.return:s[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,s[1])).done)return i;switch(n=0,i&&(s=[2&s[0],i.value]),s[0]){case 0:case 1:i=s;break;case 4:return r.label++,{value:s[1],done:!1};case 5:r.label++,n=s[1],s=[0];continue;case 7:s=r.ops.pop(),r.trys.pop();continue;default:if(!(i=r.trys,(i=i.length>0&&i[i.length-1])||6!==s[0]&&2!==s[0])){r=0;continue}if(3===s[0]&&(!i||s[1]>i[0]&&s[1]<i[3])){r.label=s[1];break}if(6===s[0]&&r.label<i[1]){r.label=i[1],i=s;break}if(i&&r.label<i[2]){r.label=i[2],r.ops.push(s);break}i[2]&&r.ops.pop(),r.trys.pop();continue}s=t.call(e,r)}catch(e){s=[6,e],n=0}finally{o=i=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,a])}}}var n=function(){function e(e){this.url=null,this.codec=null,this.audioBufferSourceNode=null,this.mediaElementAudioSourceNode=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.playTime=0,this.playedTimePercentage=0,this.state="sound_state_stopped",this.loadingProgress=0,this.duration=null,this.firstTimePlayed=!0,Array.isArray(e.source)?this.source=e.source:this.source=[e.source],this.id=e.id,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,"ArrayBuffer"===typeof e.arrayBuffer&&(this.arrayBuffer=e.arrayBuffer),"AudioBuffer"===typeof e.audioBuffer&&(this.audioBuffer=e.audioBuffer,this.isBuffering=!1,this.isBuffered=!0,this.audioBufferDate=new Date,this.duration=this.getDuration())}return e.prototype.getCurrentTime=function(){var e;return null!==this.audioBufferSourceNode?e=this.audioBufferSourceNode.context.currentTime:null!==this.mediaElementAudioSourceNode&&(e=this.audioElement.currentTime),e},e.prototype.getDuration=function(){var e;return null!==this.audioBufferSourceNode?e=this.audioBufferSourceNode.buffer.duration:null!==this.mediaElementAudioSourceNode&&(e=this.audioElement.duration),e},e.SOUND_STATE_STOPPED="sound_state_stopped",e.SOUND_STATE_PAUSED="sound_state_paused",e.SOUND_STATE_PLAYING="sound_state_playing",e}(),i=function(t){function o(e,n){var i=t.call(this,e)||this;return i.code=n||null,Object.setPrototypeOf(i,o.prototype),i}return function(t,o){if("function"!=typeof o&&null!==o)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");function n(){this.constructor=t}e(t,o),t.prototype=null===o?Object.create(o):(n.prototype=o.prototype,new n)}(o,t),o}(Error),u=function(){function e(e){this._audioContext=null,this._audioGraph=null,this.setPersistVolume(e.persistVolume),this._setAutoCreateContextOnFirstTouch(e.createAudioContextOnFirstUserInteraction),this.setLoadPlayerMode(e.loadPlayerMode),this.setAudioContext(e.customAudioContext),null===e.customAudioContext&&this._autoCreateAudioContextOnFirstUserInteraction(),this._createAudioContextOnFirstUserInteraction||this.getAudioContext().catch((function(){throw new i("audio context setup failed")})),this.setAudioGraph(e.customAudioGraph)}return e.prototype.decodeAudio=function(e){return t(this,void 0,void 0,(function(){var t,n;return o(this,(function(o){switch(o.label){case 0:return[4,this.getAudioContext()];case 1:return t=o.sent(),n=t.decodeAudioData(e),[2,Promise.resolve(n)]}}))}))},e.prototype._createAudioContext=function(){var e=this;return new Promise((function(t,o){var n=window.AudioContext||window.webkitAudioContext;try{e._audioContext=new n,t()}catch(e){o(e)}}))},e.prototype._autoCreateAudioContextRemoveListener=function(){document.removeEventListener("touchstart",this._autoCreateAudioContextRemoveListener.bind(this),!1),document.removeEventListener("touchend",this._autoCreateAudioContextRemoveListener.bind(this),!1),document.removeEventListener("mousedown",this._autoCreateAudioContextRemoveListener.bind(this),!1),this.getAudioContext().catch((function(){throw new i("audio context setup failed")}))},e.prototype._autoCreateAudioContextOnFirstUserInteraction=function(){this._createAudioContextOnFirstUserInteraction&&(document.addEventListener("touchstart",this._autoCreateAudioContextRemoveListener.bind(this),!1),document.addEventListener("touchend",this._autoCreateAudioContextRemoveListener.bind(this),!1),document.addEventListener("mousedown",this._autoCreateAudioContextRemoveListener.bind(this),!1))},e.prototype.getAudioContext=function(){var e=this;return new Promise((function(t,o){null===e._audioContext?e._createAudioContext().then((function(){t(e._audioContext)})).catch(o):"suspended"===e._audioContext.state?e._unfreezeAudioContext().then((function(){t(e._audioContext)})):"running"===e._audioContext.state&&t(e._audioContext)}))},e.prototype.setAudioContext=function(e){var t=this;null!==this._audioContext?this._destroyAudioContext().then((function(){t._setAudioContext(e)})):this._setAudioContext(e)},e.prototype._setAudioContext=function(e){this._audioContext=e},e.prototype._destroyAudioContext=function(){return t(this,void 0,void 0,(function(){return o(this,(function(e){switch(e.label){case 0:return[4,this._audioContext.close()];case 1:return e.sent(),this._audioContext=null,[2]}}))}))},e.prototype._unfreezeAudioContext=function(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.resume()},e.prototype._freezeAudioContext=function(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.suspend()},e.prototype.setAudioGraph=function(e){var t=this;null!==this._audioGraph&&this._destroyAudioGraph(),null===e||"gainNode"in e&&null!==e.gainNode&&void 0!==e.gainNode?this._audioGraph=e:this.getAudioContext().then((function(o){e.gainNode=o.createGain(),t._audioGraph=e}))},e.prototype.getAudioGraph=function(){var e=this;return new Promise((function(t,o){null!==e._audioGraph?t(e._audioGraph):e._createAudioGraph().then((function(o){e._audioGraph=o,t(o)})).catch(o)}))},e.prototype._createAudioGraph=function(){var e=this;return new Promise((function(t,o){e.getAudioContext().then((function(o){e._audioGraph||(e._audioGraph={gainNode:o.createGain()}),e._audioGraph.gainNode.connect(o.destination);var n=e._volume/100;e._changeGainValue(n),t(e._audioGraph)})).catch(o)}))},e.prototype._destroyAudioGraph=function(){null!==this._audioGraph&&this._audioGraph.gainNode.disconnect(),this._audioGraph=null},e.prototype.createAudioBufferSourceNode=function(e,n){return t(this,void 0,void 0,(function(){var t,i,u=this;return o(this,(function(o){switch(o.label){case 0:return[4,this.getAudioContext()];case 1:return t=o.sent(),i=t.createBufferSource(),n.audioBufferSourceNode=i,i.loop=e.loop,i.onended=function(t){e.onEnded(t),u.destroySourceNode(n)},[2]}}))}))},e.prototype.createMediaElementSourceNode=function(e,n){return t(this,void 0,void 0,(function(){var t,u,r=this;return o(this,(function(o){switch(o.label){case 0:return[4,this.getAudioContext()];case 1:t=o.sent();try{u=t.createMediaElementSource(e.mediaElement)}catch(e){throw new i(e)}return n.mediaElementAudioSourceNode=u,u.mediaElement.loop=e.loop,u.mediaElement.onended=function(){e.onEnded(),r.destroySourceNode(n)},[2]}}))}))},e.prototype.connectSourceNodeToGraphNodes=function(e){this.getAudioGraph().then((function(t){e.connect(t.gainNode),"analyserNode"in t&&null!==t.analyserNode&&void 0!==t.analyserNode&&e.connect(t.analyserNode),"delayNode"in t&&null!==t.delayNode&&void 0!==t.delayNode&&e.connect(t.delayNode),"pannerNode"in t&&null!==t.pannerNode&&void 0!==t.pannerNode&&e.connect(t.pannerNode)}))},e.prototype.destroySourceNode=function(e){if(null!==e.audioBufferSourceNode)e.audioBufferSourceNode.disconnect();else{if(null===e.mediaElementAudioSourceNode)throw new i("can't destroy as no source node in sound");e.mediaElementAudioSourceNode.disconnect()}e.audioBufferSourceNode=null},e.prototype.changeVolume=function(e){var t=e.volume,o=e.sound,n=void 0===o?null:o,i=e.forceUpdateUserVolume,u=void 0===i||i;if(this._persistVolume){var r=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume"));isNaN(r)||u?u&&localStorage.setItem("WebAudioAPIPlayerVolume",t.toString()):t=r}var s=t/100;return null!==n?n.audioElement.volume=s:this._changeGainValue(s),this._volume=t,t},e.prototype._changeGainValue=function(e){this.getAudioGraph().then((function(t){t.gainNode.gain.value=e}))},e.prototype._setAutoCreateContextOnFirstTouch=function(e){this._createAudioContextOnFirstUserInteraction=e},e.prototype.setPersistVolume=function(e){this._persistVolume=e},e.prototype.getPersistVolume=function(){return this._persistVolume},e.prototype.setLoadPlayerMode=function(e){this._loadPlayerMode=e},e.prototype.getLoadPlayerMode=function(){return this._loadPlayerMode},e}(),r=function(){function e(){}return e.prototype.getArrayBuffer=function(e){return new Promise((function(t,o){var n=new XMLHttpRequest;n.open("GET",e.url,!0),n.responseType="arraybuffer",n.onload=function(){200===n.status?t(n.response):o(new i(n.statusText,n.status))},n.onprogress=function(t){var o=100/(t.total/t.loaded);e.loadingProgress=o,null!==e.onLoading&&e.onLoading(o,t.total,t.loaded)},n.onerror=function(){o(new i("xhr network error"))},n.send()}))},e}(),s=function(){function e(e){void 0===e&&(e={});var t=this;this._playingProgressRequestId=null,this._playingProgressPreviousTimestamp=0,this._customAudioGraph=null,this._customAudioContext=null,this._postMuteVolume=null,this._isMuted=!1,this._progressTrigger=function(e,o){o-t._playingProgressPreviousTimestamp>=t._playingProgressIntervalTime&&(t._playingProgress(e),t._playingProgressPreviousTimestamp=o),t._playingProgressRequestId=window.requestAnimationFrame((function(o){t._progressTrigger(e,o)}))};var o={volume:80,loopQueue:!1,loopSong:!1,soundsBaseUrl:"",playingProgressIntervalTime:200,playNextOnEnded:!0,audioGraph:null,audioContext:null,stopOnReset:!0,visibilityAutoMute:!1,createAudioContextOnFirstUserInteraction:!0,persistVolume:!0,loadPlayerMode:"player_mode_audio"},n=Object.assign({},o,e);this._volume=n.volume,this._soundsBaseUrl=n.soundsBaseUrl,this._queue=[],this._currentIndex=0,this._playingProgressIntervalTime=n.playingProgressIntervalTime,this._playNextOnEnded=n.playNextOnEnded,this._loopQueue=n.loopQueue,this._loopSong=n.loopSong,this._stopOnReset=n.stopOnReset,this._visibilityAutoMute=n.visibilityAutoMute,this._createAudioContextOnFirstUserInteraction=n.createAudioContextOnFirstUserInteraction,this._persistVolume=n.persistVolume,this._loadPlayerMode=n.loadPlayerMode,void 0!==n.audioContext&&(this._customAudioContext=n.audioContext),void 0!==n.audioGraph&&(this._customAudioGraph=n.audioGraph),this._initialize()}return e.prototype._initialize=function(){var t;switch(this._loadPlayerMode){case e.PLAYER_MODE_AUDIO:if(!this._detectAudioContextSupport())throw new i("audio context is not supported by this device");t=this._webAudioApiOptions();break;case e.PLAYER_MODE_AJAX:if(!this._detectAudioElementSupport())throw new i("audio context is not supported by this device");t=this._webAudioElementOptions()}this._playerAudio=new u(t)},e.prototype._webAudioApiOptions=function(){return{customAudioContext:this._customAudioContext,customAudioGraph:this._customAudioGraph,createAudioContextOnFirstUserInteraction:this._createAudioContextOnFirstUserInteraction,persistVolume:this._persistVolume,loadPlayerMode:this._loadPlayerMode}},e.prototype._webAudioElementOptions=function(){return{customAudioContext:null,customAudioGraph:null,createAudioContextOnFirstUserInteraction:!1,persistVolume:this._persistVolume,loadPlayerMode:this._loadPlayerMode}},e.prototype._detectAudioContextSupport=function(){var e=!1;return(void 0!==window.webkitAudioContext||"undefined"!=typeof AudioContext)&&(e=!0),e},e.prototype._detectAudioElementSupport=function(){return!!document.createElement("audio").canPlayType},e.prototype.addSoundToQueue=function(t){var o=t.soundAttributes,i=t.whereInQueue,u=void 0===i?e.WHERE_IN_QUEUE_AT_END:i,r=new n(o);switch(u){case e.WHERE_IN_QUEUE_AT_END:this._appendSoundToQueue(r);break;case e.WHERE_IN_QUEUE_AT_START:case e.WHERE_IN_QUEUE_AFTER_CURRENT:this._prependSoundToQueue(r)}return r},e.prototype._appendSoundToQueue=function(e){this._queue.push(e)},e.prototype._prependSoundToQueue=function(e){this._queue.unshift(e)},e.prototype._addSoundToQueueAfterCurrent=function(e){if(null===this._currentIndex)this._appendSoundToQueue(e);else{var t=this._currentIndex+1;this._queue.splice(t,0,e)}},e.prototype.resetQueue=function(){this._stopOnReset&&this.stop(),this._queue=[]},e.prototype.reset=function(){this.resetQueue()},e.prototype.getQueue=function(){return this._queue},e.prototype.setVolume=function(e){this._volume=e,this._isMuted=!1;var t=this._getSoundFromQueue();null!==t&&t.state===n.SOUND_STATE_PLAYING&&this._playerAudio.changeVolume({volume:e,sound:t,forceUpdateUserVolume:!0})},e.prototype.getVolume=function(){return this._volume},e.prototype.setLoopQueue=function(e){this._loopQueue=e},e.prototype.getLoopQueue=function(){return this._loopQueue},e.prototype.mute=function(){var e=this.getVolume();this._postMuteVolume=e;var t=this._getSoundFromQueue();null!==t&&t.state===n.SOUND_STATE_PLAYING&&this._playerAudio.changeVolume({volume:0,sound:t,forceUpdateUserVolume:!1}),this._isMuted=!0},e.prototype.unMute=function(){var e=this._getSoundFromQueue();null!==e&&e.state===n.SOUND_STATE_PLAYING&&this._playerAudio.changeVolume({volume:this._postMuteVolume,sound:e,forceUpdateUserVolume:!1}),this._isMuted=!1},e.prototype.isMuted=function(){return this._isMuted},e.prototype.setPosition=function(e){var t=this,o=this._getSoundFromQueue();if(null===o)throw new i("position change called, but no current sound found");if(null===o.duration||isNaN(o.duration))this._loadSound(o).then((function(o){var n=o.duration/100*e;t.setPositionInSeconds(n)})).catch((function(e){throw e}));else{var n=o.duration/100*e;this.setPositionInSeconds(n)}},e.prototype.setPositionInSeconds=function(e){var t=this._getSoundFromQueue();if(null===t)throw new i("position change called, but no current sound found");t.state===n.SOUND_STATE_PLAYING?(this.pause(),this.play({whichSound:t.id,playTimeOffset:e})):t.playTimeOffset=e},e.prototype._loadSound=function(t){var o,n;switch(this._loadPlayerMode){case e.PLAYER_MODE_AUDIO:o=this._loadSoundUsingAudioElement(t);break;case e.PLAYER_MODE_AJAX:o=this._loadSoundUsingRequest(t);break;case e.PLAYER_MODE_FETCH:n=new i(e.PLAYER_MODE_FETCH+" is not implemented yet",1),o=Promise.reject(n)}return o},e.prototype._loadSoundUsingAudioElement=function(e){var t=this;return new Promise((function(o,n){var u,r,s=(u=t._findBestSource(e.source)).url,a=void 0===(r=u.codec)?null:r;if(e.url=s,e.codec=a,e.arrayBuffer=null,null!==e.url){var d=new Audio;d.crossOrigin="anonymous",d.src=e.url,d.controls=!1,d.autoplay=!1,document.body.appendChild(d),e.audioElement=d,e.duration=d.duration,e.isReadyToPLay=!0,t._initializeAudioElementListeners(e),e.audioElement.addEventListener("canplaythrough",(function(){o(e)})),e.audioElement.addEventListener("error",(function(){var e=new i("loading sound failed");n(e)}))}else{var l=new i("sound has no url",1);n(l)}}))},e.prototype._loadSoundUsingRequest=function(e){var t=this;return new Promise((function(o,n){var u,s;if(null!==e.audioBuffer&&o(e),null!==e.arrayBuffer&&null===e.audioBuffer&&t._decodeSound({sound:e}).then((function(e){o(e)})).catch(n),null===e.arrayBuffer&&null===e.audioBuffer){var a=(u=t._findBestSource(e.source)).url,d=void 0===(s=u.codec)?null:s;if(e.url=a,e.codec=d,null!==e.url){var l=new r;e.isBuffering=!0,l.getArrayBuffer(e).then((function(i){e.arrayBuffer=i,t._decodeSound({sound:e}).then((function(e){o(e)})).catch(n)})).catch((function(e){n(e)}))}else{var c=new i("sound has no url",1);n(c)}}}))},e.prototype._initializeAudioElementListeners=function(e){e.audioElement.addEventListener("progress",(function(){e.loadingProgress=e.audioElement.duration})),e.audioElement.addEventListener("timeupdate",(function(){e.duration=e.audioElement.duration}))},e.prototype._decodeSound=function(e){var t=e.sound,o=t.arrayBuffer;return this._playerAudio.decodeAudio(o).then((function(e){return t.audioBuffer=e,t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date,t.duration=t.audioBuffer.duration,t.isReadyToPLay=!0,t})).catch((function(e){throw e}))},e.prototype.play=function(e){var t=this,o=void 0===e?{}:e,i=o.whichSound,u=o.playTimeOffset;return new Promise((function(e,o){var r=t._getSoundFromQueue();null!==r&&r.state===n.SOUND_STATE_PLAYING&&t.stop();var s=t._getSoundFromQueue({whichSound:i});if(null===s)throw new Error("no more sounds in array");void 0!==u&&(s.playTimeOffset=u),s.isReadyToPLay?t._play(s).then(e).catch(o):t._loadSound(s).then((function(){t._play(s).then(e).catch(o)})).catch(o)}))},e.prototype._play=function(e){return t(this,void 0,void 0,(function(){var t;return o(this,(function(o){switch(o.label){case 0:return t=this._volume,this._isMuted&&(t=0),this._volume=this._playerAudio.changeVolume({volume:t,sound:e,forceUpdateUserVolume:!1}),null===e.audioBuffer?[3,2]:[4,this._playAudioBuffer(e)];case 1:return o.sent(),[3,4];case 2:return[4,this._playMediaElementAudio(e)];case 3:o.sent(),o.label=4;case 4:return e.state=n.SOUND_STATE_PLAYING,e.startTime=e.getCurrentTime(),e=this._setupSoundEvents(e),[2]}}))}))},e.prototype._playAudioBuffer=function(e){return t(this,void 0,void 0,(function(){var t,n,u,r=this;return o(this,(function(o){switch(o.label){case 0:if(null!==e.audioBufferSourceNode)return[3,4];t={loop:e.loop,onEnded:function(){r._onEnded()}},o.label=1;case 1:return o.trys.push([1,3,,4]),[4,this._playerAudio.createAudioBufferSourceNode(t,e)];case 2:return o.sent(),[3,4];case 3:throw n=o.sent(),new i(n);case 4:(u=e.audioBufferSourceNode).buffer=e.audioBuffer,this._playerAudio.connectSourceNodeToGraphNodes(u);try{void 0!==e.playTimeOffset?u.start(0,e.playTimeOffset):u.start()}catch(e){throw new i(e)}return[2]}}))}))},e.prototype._playMediaElementAudio=function(e){return t(this,void 0,void 0,(function(){var t,n,u,r=this;return o(this,(function(o){switch(o.label){case 0:if(null!==e.mediaElementAudioSourceNode)return[3,4];t={loop:e.loop,onEnded:function(){r._onEnded()},mediaElement:e.audioElement},o.label=1;case 1:return o.trys.push([1,3,,4]),[4,this._playerAudio.createMediaElementSourceNode(t,e)];case 2:return o.sent(),[3,4];case 3:throw n=o.sent(),new i(n);case 4:u=e.mediaElementAudioSourceNode,this._playerAudio.connectSourceNodeToGraphNodes(u),void 0===e.playTimeOffset||isNaN(e.playTimeOffset)||(e.audioElement.currentTime=e.playTimeOffset);try{u.mediaElement.play()}catch(e){throw new i(e)}return[2]}}))}))},e.prototype._setupSoundEvents=function(e){var t=this;return null===e.onResumed||e.firstTimePlayed||e.onResumed(e.playTimeOffset),null!==e.onStarted&&e.firstTimePlayed&&(e.onStarted(e.playTimeOffset),e.firstTimePlayed=!1),null!==e.onPlaying?this._playingProgressRequestId=window.requestAnimationFrame((function(o){t._progressTrigger(e,o)})):this._playingProgressRequestId=null,e},e.prototype._onEnded=function(){var e=this._getSoundFromQueue();if(null!==e&&e.state===n.SOUND_STATE_PLAYING){var t=this._getSoundFromQueue({whichSound:"next",updateIndex:!1});if(null!==e.onEnded){var o=!1;null!==t&&this._playNextOnEnded&&(o=!0),this._loopQueue&&(o=!0),e.onEnded(o)}e.firstTimePlayed=!0,e.playTimeOffset=0,this._stop(e,n.SOUND_STATE_STOPPED),null!==t?this._playNextOnEnded&&this.play({whichSound:"next"}):(this._currentIndex=0,this._loopQueue&&this.play())}},e.prototype._getSoundFromQueue=function(t){var o=void 0===t?{}:t,n=o.whichSound,i=o.updateIndex,u=void 0===i||i,r=null;if(0===this._queue.length)return r;if(void 0===n&&void 0!==this._queue[this._currentIndex])r=this._queue[this._currentIndex];else if("number"==typeof n)r=this._findSoundById({soundId:n,updateIndex:u});else{var s=null;switch(n){case e.PLAY_SOUND_NEXT:void 0!==this._queue[this._currentIndex+1]?(s=this._currentIndex+1,r=this._queue[s]):this._loopQueue&&(s=0,r=this._queue[s]);break;case e.PLAY_SOUND_PREVIOUS:void 0!==this._queue[this._currentIndex-1]&&(s=this._currentIndex-1,r=this._queue[s]);break;case e.PLAY_SOUND_FIRST:this._queue.length>0&&(s=0,r=this._queue[s]);break;case e.PLAY_SOUND_LAST:this._queue.length>0&&(s=this._queue.length-2,r=this._queue[s]);break;default:r=this._findSoundById({soundId:n,updateIndex:u})}null!==s&&u&&(this._currentIndex=s)}return r},e.prototype._findSoundById=function(e){var t=this,o=e.soundId,n=e.updateIndex,i=null;return this._queue.some((function(e,u){if(e.id===o)return i=e,n&&(t._currentIndex=u),!0})),i},e.prototype._findBestSource=function(e){var t=this,o={url:null,codec:null};return(Array.isArray(e)?e:[e]).forEach((function(e){var n="";""!==t._soundsBaseUrl&&(n=t._soundsBaseUrl),n+=e.url;var i=!0;null!==e.codec&&(i=t._checkCodecSupport(e.codec)),i&&(null!==o.url&&e.isPreferred,o.url=n,o.codec=e.codec)})),o},e.prototype._checkCodecSupport=function(e){var t,o="";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:o="unrecognised codec"}if(o)throw new i(o);return this._checkMimeTypesSupport(t)},e.prototype._checkMimeTypesSupport=function(e){var t=new Audio,o=!1;return e.forEach((function(e){t.canPlayType(e).replace(/^no$/,"")&&(o=!0)})),o},e.prototype.pause=function(){var e=this._getSoundFromQueue();if(null!==e&&e.state!==n.SOUND_STATE_PAUSED){var t=e.getCurrentTime();e.playTimeOffset+=t-e.startTime,null!==e.onPaused&&e.onPaused(e.playTimeOffset),this._stop(e,n.SOUND_STATE_PAUSED)}},e.prototype.stop=function(){var e=this._getSoundFromQueue();null!==e&&e.state!==n.SOUND_STATE_STOPPED&&(e.firstTimePlayed=!0,null!==e.onStopped&&e.onStopped(e.playTimeOffset),e.playTimeOffset=0,this._stop(e,n.SOUND_STATE_STOPPED))},e.prototype._stop=function(e,t){if(null!==e.audioBufferSourceNode)e.audioBufferSourceNode.stop(0);else{if(null===e.mediaElementAudioSourceNode)throw new i("can't stop as no source node in sound");e.mediaElementAudioSourceNode.mediaElement.pause()}this._playerAudio.destroySourceNode(e),e.state=t,null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressPreviousTimestamp=0)},e.prototype.next=function(){this.play({whichSound:"next"})},e.prototype.previous=function(){this.play({whichSound:"previous"})},e.prototype.first=function(){this.play({whichSound:"first"})},e.prototype.last=function(){this.play({whichSound:"last"})},e.prototype._playingProgress=function(e){var t=e.getCurrentTime();e.playTime=t-e.startTime+e.playTimeOffset;var o=e.getDuration(),n=e.playTime/o*100;e.playedTimePercentage=n,e.onPlaying(n,o,e.playTime)},e.prototype.setAudioGraph=function(e){this._playerAudio.setAudioGraph(e),this._customAudioGraph=e},e.prototype.getAudioGraph=function(){var e=this;return new Promise((function(t,o){e._playerAudio.getAudioGraph().then((function(o){e._customAudioGraph=o,t(o)})).catch(o)}))},e.prototype.setAudioContext=function(e){this._playerAudio.setAudioContext(e),this._customAudioContext=e},e.prototype.getAudioContext=function(){var e=this;return new Promise((function(t,o){e._playerAudio.getAudioContext().then((function(o){e._customAudioContext=o,t(o)})).catch(o)}))},e.prototype.setVisibilityAutoMute=function(e){this._visibilityAutoMute=e,e?document.addEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1):document.removeEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1)},e.prototype.getVisibilityAutoMute=function(){return this._visibilityAutoMute},e.prototype._handleVisibilityChange=function(){var 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()},e.WHERE_IN_QUEUE_AT_END="append",e.WHERE_IN_QUEUE_AT_START="prepend",e.WHERE_IN_QUEUE_AFTER_CURRENT="afterCurrent",e.PLAY_SOUND_NEXT="next",e.PLAY_SOUND_PREVIOUS="previous",e.PLAY_SOUND_FIRST="first",e.PLAY_SOUND_LAST="last",e.PLAYER_MODE_AUDIO="player_mode_audio",e.PLAYER_MODE_AJAX="player_mode_ajax",e.PLAYER_MODE_FETCH="player_mode_fetch",e}();export{s as PlayerCore,n as PlayerSound}; | ||
var e=function(t,o){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])},e(t,o)};function t(e,t,o,n){return new(o||(o=Promise))((function(i,u){function r(e){try{a(n.next(e))}catch(e){u(e)}}function s(e){try{a(n.throw(e))}catch(e){u(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(r,s)}a((n=n.apply(e,t||[])).next())}))}function o(e,t){var o,n,i,u,r={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return u={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function s(s){return function(a){return function(s){if(o)throw new TypeError("Generator is already executing.");for(;u&&(u=0,s[0]&&(r=0)),r;)try{if(o=1,n&&(i=2&s[0]?n.return:s[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,s[1])).done)return i;switch(n=0,i&&(s=[2&s[0],i.value]),s[0]){case 0:case 1:i=s;break;case 4:return r.label++,{value:s[1],done:!1};case 5:r.label++,n=s[1],s=[0];continue;case 7:s=r.ops.pop(),r.trys.pop();continue;default:if(!(i=r.trys,(i=i.length>0&&i[i.length-1])||6!==s[0]&&2!==s[0])){r=0;continue}if(3===s[0]&&(!i||s[1]>i[0]&&s[1]<i[3])){r.label=s[1];break}if(6===s[0]&&r.label<i[1]){r.label=i[1],i=s;break}if(i&&r.label<i[2]){r.label=i[2],r.ops.push(s);break}i[2]&&r.ops.pop(),r.trys.pop();continue}s=t.call(e,r)}catch(e){s=[6,e],n=0}finally{o=i=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,a])}}}var n=function(){function e(e){this.url=null,this.codec=null,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.playTime=0,this.playedTimePercentage=0,this.state="sound_state_stopped",this.loadingProgress=0,this.duration=null,this.firstTimePlayed=!0,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,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())}return e.prototype.getCurrentTime=function(){var e;return null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.sourceNode.context.currentTime:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.currentTime)),e},e.prototype.getDuration=function(){var e;return null!==this.sourceNode&&(this.sourceNode instanceof AudioBufferSourceNode?e=this.sourceNode.buffer.duration:this.sourceNode instanceof MediaElementAudioSourceNode&&(e=this.audioElement.duration)),e},e.prototype._generateSoundId=function(){return Date.now().toString(36)+Math.random().toString(36).substring(2)},e.SOUND_STATE_STOPPED="sound_state_stopped",e.SOUND_STATE_PAUSED="sound_state_paused",e.SOUND_STATE_PLAYING="sound_state_playing",e}(),i=function(t){function o(e,n){var i=t.call(this,e)||this;return i.code=n||null,Object.setPrototypeOf(i,o.prototype),i}return function(t,o){if("function"!=typeof o&&null!==o)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");function n(){this.constructor=t}e(t,o),t.prototype=null===o?Object.create(o):(n.prototype=o.prototype,new n)}(o,t),o}(Error),u=function(){function e(e){this._audioContext=null,this._volume=null,this._audioNodes={gainNode:null},this._options=e,this._initialize()}return e.prototype._initialize=function(){this._options.createAudioContextOnFirstUserInteraction&&this._addAutoCreateAudioContextOnFirstUserInteractionEventListeners()},e.prototype.decodeAudio=function(e){return t(this,void 0,void 0,(function(){var t;return o(this,(function(o){switch(o.label){case 0:return[4,this.getAudioContext()];case 1:return[4,o.sent().decodeAudioData(e)];case 2:return t=o.sent(),[2,Promise.resolve(t)]}}))}))},e.prototype._createAudioContext=function(){var e=this;return new Promise((function(t,o){e._audioContext instanceof AudioContext&&t();var n=window.AudioContext||window.webkitAudioContext;try{null!==e._options.audioContext?e._audioContext=e._options.audioContext:e._audioContext=new n,t()}catch(e){o(e)}}))},e.prototype._addAutoCreateAudioContextOnFirstUserInteractionEventListeners=function(){this._options.createAudioContextOnFirstUserInteraction&&(document.addEventListener("touchstart",this.getAudioContext.bind(this)),document.addEventListener("touchend",this.getAudioContext.bind(this)),document.addEventListener("mousedown",this.getAudioContext.bind(this)))},e.prototype._removeAutoCreateAudioContextOnFirstUserInteractionEventListeners=function(){this._options.createAudioContextOnFirstUserInteraction&&(document.removeEventListener("touchstart",this.getAudioContext.bind(this)),document.removeEventListener("touchend",this.getAudioContext.bind(this)),document.removeEventListener("mousedown",this.getAudioContext.bind(this)))},e.prototype.getAudioContext=function(){return t(this,void 0,void 0,(function(){return o(this,(function(e){switch(e.label){case 0:return null!==this._audioContext?[3,2]:[4,this._createAudioContext()];case 1:return e.sent(),[3,4];case 2:return"suspended"!==this._audioContext.state?[3,4]:[4,this._unfreezeAudioContext()];case 3:e.sent(),e.label=4;case 4:return[2,this._audioContext]}}))}))},e.prototype._unfreezeAudioContext=function(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.resume()},e.prototype.freezeAudioContext=function(){return void 0===this._audioContext.suspend?Promise.resolve():this._audioContext.suspend()},e.prototype.detectAudioContextSupport=function(){var e=!1;return(void 0!==window.webkitAudioContext||"undefined"!=typeof AudioContext)&&(e=!0),e},e.prototype.detectAudioElementSupport=function(){return!!document.createElement("audio").canPlayType},e.prototype.shutDown=function(e){return t(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return this._removeAutoCreateAudioContextOnFirstUserInteractionEventListeners(),e.forEach((function(e){e.sourceNode instanceof MediaElementAudioSourceNode?void 0!==e.sourceNode.mediaElement&&e.sourceNode.mediaElement.remove():(e.sourceNode,AudioBufferSourceNode)})),this._disconnectPlayerGainNode(),[4,this._destroyAudioContext()];case 1:return t.sent(),[2]}}))}))},e.prototype._destroyAudioContext=function(){return t(this,void 0,void 0,(function(){return o(this,(function(e){switch(e.label){case 0:return null===this._audioContext?[3,2]:[4,this._audioContext.close()];case 1:e.sent(),this._audioContext=null,e.label=2;case 2:return[2]}}))}))},e.prototype.createAudioBufferSourceNode=function(e,n){return t(this,void 0,void 0,(function(){var t,i;return o(this,(function(o){switch(o.label){case 0:return[4,this.getAudioContext()];case 1:return t=o.sent(),i=t.createBufferSource(),n.sourceNode=i,i.loop=e.loop,n.gainNode=i.context.createGain(),n.gainNode.gain.value=1,i.connect(n.gainNode),i.onended=function(t){e.onSourceNodeEnded(t)},[2]}}))}))},e.prototype.createMediaElementSourceNode=function(e,n){return t(this,void 0,void 0,(function(){var u,r,s=this;return o(this,(function(a){switch(a.label){case 0:return null!==n.sourceNode?[3,2]:[4,this.getAudioContext()];case 1:r=a.sent();try{u=r.createMediaElementSource(e.mediaElement)}catch(e){throw new i(e)}u.mediaElement.loop=e.loop,n.gainNode=u.context.createGain(),n.gainNode.gain.value=1,u.connect(n.gainNode),u.mediaElement.onended=function(){return t(s,void 0,void 0,(function(){return o(this,(function(t){return e.onSourceNodeEnded(),[2]}))}))},n.sourceNode=u,a.label=2;case 2:return[2]}}))}))},e.prototype._getPlayerGainNode=function(){return t(this,void 0,void 0,(function(){var e,t;return o(this,(function(o){switch(o.label){case 0:return this._audioNodes.gainNode instanceof GainNode?(e=this._audioNodes.gainNode,[3,3]):[3,1];case 1:return[4,this.getAudioContext()];case 2:t=o.sent(),(e=t.createGain()).connect(t.destination),this._audioNodes.gainNode=e,o.label=3;case 3:return this._initializeVolume(),[2,e]}}))}))},e.prototype._disconnectPlayerGainNode=function(){this._audioNodes.gainNode.disconnect(),this._audioNodes.gainNode=null},e.prototype.connectSound=function(e){return t(this,void 0,void 0,(function(){var t,n;return o(this,(function(o){switch(o.label){case 0:return[4,this._getPlayerGainNode()];case 1:return t=o.sent(),null!==(n=e.gainNode)&&n.connect(t),[2]}}))}))},e.prototype.disconnectSound=function(e){return t(this,void 0,void 0,(function(){return o(this,(function(t){if(null===e.gainNode)throw new i("can't destroy as no source node in sound");return e.sourceNode instanceof AudioBufferSourceNode&&(e.sourceNode=null),[2]}))}))},e.prototype._changePlayerGainValue=function(e){this._audioNodes.gainNode instanceof GainNode&&(this._audioNodes.gainNode.gain.value=e)},e.prototype._roundGainTwoDecimals=function(e){return Math.round(100*(e+Number.EPSILON))/100},e.prototype.setVolume=function(e,t){void 0===t&&(t=!0),this._options.persistVolume&&t&&localStorage.setItem("WebAudioAPIPlayerVolume",e.toString());var o=e/100;this._audioNodes.gainNode instanceof GainNode&&(this._roundGainTwoDecimals(this._audioNodes.gainNode.gain.value)!==this._volume&&this._changePlayerGainValue(o));this._volume=e},e.prototype.getVolume=function(){var e;if(null!==this._volume)e=this._volume;else{if(this._options.persistVolume){var t=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume"));isNaN(t)||(e=t)}void 0===e&&(e=this._options.volume)}return e},e.prototype._initializeVolume=function(){if(this._options.persistVolume){var e=parseInt(localStorage.getItem("WebAudioAPIPlayerVolume"));isNaN(e)||this.setVolume(e,!1)}null===this._volume&&this.setVolume(this._options.volume,!1)},e}(),r=function(){function e(){}return e.prototype.getArrayBuffer=function(e){return new Promise((function(t,o){var n=new XMLHttpRequest;n.open("GET",e.url,!0),n.responseType="arraybuffer",n.onload=function(){200===n.status?t(n.response):o(new i(n.statusText,n.status))},n.onprogress=function(t){var o=100/(t.total/t.loaded);e.loadingProgress=o,null!==e.onLoading&&e.onLoading(o,t.total,t.loaded)},n.onerror=function(){o(new i("xhr network error"))},n.send()}))},e}(),s=function(){function e(e){var t=this;void 0===e&&(e={}),this._playingProgressRequestId=null,this._playingProgressPreviousTimestamp=0,this._progressTrigger=function(e,o){o-t._playingProgressPreviousTimestamp>=t._options.playingProgressIntervalTime&&(t._playingProgress(e),t._playingProgressPreviousTimestamp=o),t._playingProgressRequestId=window.requestAnimationFrame((function(o){t._progressTrigger(e,o)}))};var o={volume:80,loopQueue:!1,loopSong:!1,soundsBaseUrl:"",playingProgressIntervalTime:200,playNextOnEnded:!0,stopOnReset:!0,visibilityAutoMute:!1,createAudioContextOnFirstUserInteraction:!0,persistVolume:!0,loadPlayerMode:"player_mode_audio",audioContext:null},n=Object.assign({},o,e);this._queue=[],this._currentIndex=null,this._options=n,this._initialize()}return e.prototype._initialize=function(){var t=this._audioOptions();switch(this._playerAudio=new u(t),this._options.loadPlayerMode){case e.PLAYER_MODE_AUDIO:if(!this._playerAudio.detectAudioContextSupport())throw new i("audio context is not supported by this device");if(!this._playerAudio.detectAudioElementSupport())throw new i("audio element is not supported by this device");break;case e.PLAYER_MODE_AJAX:if(!this._playerAudio.detectAudioContextSupport())throw new i("audio context is not supported by this device")}},e.prototype._audioOptions=function(){return{audioContext:this._options.audioContext,createAudioContextOnFirstUserInteraction:this._options.createAudioContextOnFirstUserInteraction,volume:this._options.volume,persistVolume:this._options.persistVolume}},e.prototype.addSoundToQueue=function(t){var o=t.soundAttributes,i=t.whereInQueue,u=void 0===i?"append":i,r=new n(o);switch(u){case e.WHERE_IN_QUEUE_AT_END:this._appendSoundToQueue(r);break;case e.WHERE_IN_QUEUE_AT_START:this._prependSoundToQueue(r)}return r},e.prototype._appendSoundToQueue=function(e){this._queue.push(e)},e.prototype._prependSoundToQueue=function(e){this._queue.unshift(e)},e.prototype.resetQueue=function(){this._options.stopOnReset&&this.stop(),this._queue=[]},e.prototype.reset=function(){this.resetQueue()},e.prototype.getQueue=function(){return this._queue},e.prototype.setVolume=function(e){this._playerAudio.setVolume(e)},e.prototype.getVolume=function(){return this._playerAudio.getVolume()},e.prototype.setLoopQueue=function(e){this._options.loopQueue=e},e.prototype.getLoopQueue=function(){return this._options.loopQueue},e.prototype.mute=function(){var e=this.getVolume();this._postMuteVolume=e,this._playerAudio.setVolume(0,!1)},e.prototype.unMute=function(){this._playerAudio.setVolume(this._postMuteVolume,!1),this._postMuteVolume=null},e.prototype.isMuted=function(){return null===this._postMuteVolume},e.prototype.setPosition=function(t){var o=this,n=this._getSoundFromQueue({whichSound:e.CURRENT_SOUND});if(null!==n)if(null===n.duration||isNaN(n.duration))this._loadSound(n).then((function(e){var n=e.duration/100*t;o.setPositionInSeconds(n)})).catch((function(e){throw e}));else{var i=n.duration/100*t;this.setPositionInSeconds(i)}},e.prototype.setPositionInSeconds=function(t){var o=this._getSoundFromQueue({whichSound:e.CURRENT_SOUND});if(null===o)throw new i("position change called, but no current sound found");o.state===n.SOUND_STATE_PLAYING?this.play({whichSound:o.id,playTimeOffset:t}):o.playTimeOffset=t},e.prototype._loadSound=function(t){var o,n;switch(this._options.loadPlayerMode){case e.PLAYER_MODE_AUDIO:o=this._loadSoundUsingAudioElement(t);break;case e.PLAYER_MODE_AJAX:o=this._loadSoundUsingRequest(t);break;case e.PLAYER_MODE_FETCH:n=new i(e.PLAYER_MODE_FETCH+" is not implemented yet",1),o=Promise.reject(n)}return o},e.prototype._loadSoundUsingAudioElement=function(e){var t=this;return new Promise((function(o,n){var u=t._findBestSource(e.source),r=u.url,s=u.codec,a=void 0===s?null:s;if(e.url=r,e.codec=a,e.arrayBuffer=null,null!==e.url){var d=new Audio;d.crossOrigin="anonymous",d.src=e.url,d.controls=!1,d.autoplay=!1,d.id="web_audio_api_player_sound_"+e.id.toString(),document.body.appendChild(d),e.audioElement=d,e.isReadyToPLay=!0,t._initializeAudioElementListeners(e);var c=function(){e.audioElement.removeEventListener("canplaythrough",c),isNaN(d.duration)||(e.duration=d.duration),o(e)};e.audioElement.addEventListener("canplaythrough",c);var l=function(){e.audioElement.removeEventListener("error",l);var t=new i("loading sound failed");n(t)};e.audioElement.addEventListener("error",l)}else{var p=new i("sound has no url",1);n(p)}}))},e.prototype._loadSoundUsingRequest=function(e){var t=this;return new Promise((function(o,n){var u=t._findBestSource(e.source),s=u.url,a=u.codec,d=void 0===a?null:a;if(e.url=s,e.codec=d,null!==e.url){var c=new r;e.isBuffering=!0,c.getArrayBuffer(e).then((function(i){e.arrayBuffer=i,t._decodeSound({sound:e}).then((function(e){o(e)})).catch(n)})).catch((function(e){n(e)}))}else{var l=new i("sound has no url",1);n(l)}}))},e.prototype._initializeAudioElementListeners=function(e){e.audioElement.addEventListener("progress",(function(){e.loadingProgress=e.audioElement.duration})),e.audioElement.addEventListener("timeupdate",(function(){e.duration=e.audioElement.duration}))},e.prototype._decodeSound=function(e){var t=e.sound;return this._playerAudio.decodeAudio(t.arrayBuffer).then((function(e){return t.audioBuffer=e,t.isBuffering=!1,t.isBuffered=!0,t.audioBufferDate=new Date,t.duration=e.duration,t.isReadyToPLay=!0,t})).catch((function(e){throw e}))},e.prototype._cloneAudioBuffer=function(e){for(var t=new AudioBuffer({length:e.length,numberOfChannels:e.numberOfChannels,sampleRate:e.sampleRate}),o=0;o<t.numberOfChannels;++o){var n=e.getChannelData(o);t.copyToChannel(n,o)}return t},e.prototype.play=function(t){var o=this,i=void 0===t?{}:t,u=i.whichSound,r=i.playTimeOffset;return new Promise((function(t,i){var s=o._getSoundFromQueue({whichSound:e.CURRENT_SOUND}),a=o._getSoundFromQueue({whichSound:u,updateIndex:!0});if(null===a)throw new Error("no more sounds in array");null===s||s.state!==n.SOUND_STATE_PLAYING&&s.state!==n.SOUND_STATE_PAUSED||s.id===a.id||o._stop(s,n.SOUND_STATE_STOPPED),null!==s&&s.state===n.SOUND_STATE_PLAYING&&s.id===a.id&&o._stop(s,n.SOUND_STATE_PAUSED),null===s||null!==s&&s.id!==a.id?a.firstTimePlayed=!0:a.firstTimePlayed=!1,void 0!==r&&(a.playTimeOffset=r),a.isReadyToPLay?(null!==a.audioBuffer&&(a.audioBuffer=o._cloneAudioBuffer(a.audioBuffer)),o._play(a).then(t).catch(i)):o._loadSound(a).then((function(){o._play(a).then(t).catch(i)})).catch(i)}))},e.prototype._play=function(e){return t(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return null===e.audioBuffer?[3,2]:[4,this._playAudioBuffer(e)];case 1:return t.sent(),[3,4];case 2:return[4,this._playMediaElementAudio(e)];case 3:t.sent(),t.label=4;case 4:return e.state=n.SOUND_STATE_PLAYING,e.startTime=e.getCurrentTime(),e=this._triggerSoundCallbacks(e),[2]}}))}))},e.prototype._playAudioBuffer=function(e){return t(this,void 0,void 0,(function(){var t,n,u=this;return o(this,(function(o){switch(o.label){case 0:if(null!==e.sourceNode)return[3,4];t={loop:e.loop,onSourceNodeEnded:function(){u._onEnded()}},o.label=1;case 1:return o.trys.push([1,3,,4]),[4,this._playerAudio.createAudioBufferSourceNode(t,e)];case 2:return o.sent(),[3,4];case 3:throw n=o.sent(),new i(n);case 4:return e.sourceNode instanceof AudioBufferSourceNode?(e.sourceNode.buffer=e.audioBuffer,[4,this._playerAudio.connectSound(e)]):[3,6];case 5:o.sent();try{void 0!==e.playTimeOffset?e.sourceNode.start(0,e.playTimeOffset):e.sourceNode.start()}catch(e){throw new i(e)}o.label=6;case 6:return[2]}}))}))},e.prototype._playMediaElementAudio=function(e){return t(this,void 0,void 0,(function(){var t,n,u=this;return o(this,(function(o){switch(o.label){case 0:if(null!==e.sourceNode)return[3,4];t={loop:e.loop,onSourceNodeEnded:function(){u._onEnded()},mediaElement:e.audioElement},o.label=1;case 1:return o.trys.push([1,3,,4]),[4,this._playerAudio.createMediaElementSourceNode(t,e)];case 2:return o.sent(),[3,4];case 3:throw n=o.sent(),new i(n);case 4:return e.sourceNode instanceof MediaElementAudioSourceNode?[4,this._playerAudio.connectSound(e)]:[3,6];case 5:o.sent(),void 0===e.playTimeOffset||isNaN(e.playTimeOffset)||(e.audioElement.currentTime=e.playTimeOffset);try{e.sourceNode.mediaElement.play()}catch(e){throw new i(e)}o.label=6;case 6:return[2]}}))}))},e.prototype._triggerSoundCallbacks=function(e){var t=this;return null===e.onResumed||e.firstTimePlayed||e.onResumed(e.playTimeOffset),null!==e.onStarted&&e.firstTimePlayed&&e.onStarted(e.playTimeOffset),null!==e.onPlaying?this._playingProgressRequestId=window.requestAnimationFrame((function(o){t._progressTrigger(e,o)})):this._playingProgressRequestId=null,e},e.prototype._onEnded=function(){var t=this._getSoundFromQueue({whichSound:e.CURRENT_SOUND});if(null!==t&&t.state===n.SOUND_STATE_PLAYING){var o=this._getSoundFromQueue({whichSound:e.PLAY_SOUND_NEXT,updateIndex:!0});if(null!==t.onEnded){var i=!1;null!==o&&this._options.playNextOnEnded&&(i=!0),this._options.loopQueue&&(i=!0),i||this._playerAudio.freezeAudioContext(),t.onEnded(i)}t.firstTimePlayed=!0,t.playTimeOffset=0,this._stop(t,n.SOUND_STATE_STOPPED),null!==o?this._options.playNextOnEnded&&this.play({whichSound:e.PLAY_SOUND_NEXT}):(this._currentIndex=0,this._options.loopQueue&&this.play())}},e.prototype._getSoundFromQueue=function(t){var o,n=void 0===t?{}:t,i=n.whichSound,u=n.updateIndex,r=void 0!==u&&u,s=null,a=null;if(0===this._queue.length)return s;if(void 0===i)a=0,null!==this._currentIndex&&(a=this._currentIndex),s=this._queue[a];else switch(i){case e.CURRENT_SOUND:null!==this._currentIndex&&(s=this._queue[this._currentIndex]);break;case e.PLAY_SOUND_NEXT:void 0!==this._queue[this._currentIndex+1]?(a=this._currentIndex+1,s=this._queue[a]):this._options.loopQueue&&(a=0,s=this._queue[a]);break;case e.PLAY_SOUND_PREVIOUS:void 0!==this._queue[this._currentIndex-1]?(a=this._currentIndex-1,s=this._queue[a]):this._options.loopQueue&&(a=this._queue.length-1,s=this._queue[a]);break;case e.PLAY_SOUND_FIRST:this._queue.length>0&&(a=0,s=this._queue[a]);break;case e.PLAY_SOUND_LAST:this._queue.length>0&&(a=this._queue.length-1,s=this._queue[a]);break;default:s=(o=this._findSoundById({soundId:i}))[0],a=o[1]}return null!==a&&r&&(this._currentIndex=a),s},e.prototype._findSoundById=function(e){var t=e.soundId,o=null,n=0;return this._queue.some((function(e,i){if(e.id===t)return o=e,n=i,!0})),[o,n]},e.prototype._findBestSource=function(e){var t=this,o={url:null,codec:null};return(Array.isArray(e)?e:[e]).forEach((function(e){var n="";""!==t._options.soundsBaseUrl&&(n=t._options.soundsBaseUrl),n+=e.url;var i=!0;null!==e.codec&&(i=t._checkCodecSupport(e.codec)),i&&(null!==o.url&&e.isPreferred,o.url=n,o.codec=e.codec)})),o},e.prototype._checkCodecSupport=function(e){var t,o="";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:o="unrecognised codec"}if(o)throw new i(o);return this._checkMimeTypesSupport(t)},e.prototype._checkMimeTypesSupport=function(e){var t=new Audio,o=!1;return e.forEach((function(e){t.canPlayType(e).replace(/^no$/,"")&&(o=!0)})),o},e.prototype.pause=function(){var t=this._getSoundFromQueue({whichSound:e.CURRENT_SOUND});if(null!==t&&t.state!==n.SOUND_STATE_PAUSED){var o=t.getCurrentTime();t.playTimeOffset+=o-t.startTime,null!==t.onPaused&&t.onPaused(t.playTimeOffset),this._stop(t,n.SOUND_STATE_PAUSED)}},e.prototype.stop=function(){var t=this._getSoundFromQueue({whichSound:e.CURRENT_SOUND});if(null!==t&&t.state!==n.SOUND_STATE_STOPPED){this._playerAudio.freezeAudioContext();var o=t.getCurrentTime();t.playTimeOffset+=o-t.startTime,null!==t.onStopped&&t.onStopped(t.playTimeOffset),this._stop(t,n.SOUND_STATE_STOPPED)}},e.prototype._stop=function(e,t){t===n.SOUND_STATE_STOPPED&&(e.playTimeOffset=0,e.firstTimePlayed=!0),null!==e.sourceNode&&(e.sourceNode instanceof AudioBufferSourceNode?e.sourceNode.stop(0):e.sourceNode instanceof MediaElementAudioSourceNode&&e.sourceNode.mediaElement.pause(),this._playerAudio.disconnectSound(e),e.state=t,null!==this._playingProgressRequestId&&(cancelAnimationFrame(this._playingProgressRequestId),this._playingProgressPreviousTimestamp=0))},e.prototype.next=function(){this.play({whichSound:e.PLAY_SOUND_NEXT})},e.prototype.previous=function(){this.play({whichSound:e.PLAY_SOUND_PREVIOUS})},e.prototype.first=function(){this.play({whichSound:e.PLAY_SOUND_FIRST})},e.prototype.last=function(){this.play({whichSound:e.PLAY_SOUND_LAST})},e.prototype._playingProgress=function(e){var t=e.getCurrentTime();e.playTime=t-e.startTime+e.playTimeOffset;var o=e.getDuration(),n=e.playTime/o*100;e.playedTimePercentage=n,e.onPlaying(n,o,e.playTime)},e.prototype.setVisibilityAutoMute=function(e){this._options.visibilityAutoMute=e,e?document.addEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1):document.removeEventListener("visibilitychange",this._handleVisibilityChange.bind(this),!1)},e.prototype.getVisibilityAutoMute=function(){return this._options.visibilityAutoMute},e.prototype._handleVisibilityChange=function(){var 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()},e.prototype.disconnect=function(){return t(this,void 0,void 0,(function(){return o(this,(function(e){switch(e.label){case 0:return[4,this._playerAudio.shutDown(this._queue)];case 1:return e.sent(),[2]}}))}))},e.prototype.getAudioContext=function(){return t(this,void 0,void 0,(function(){return o(this,(function(e){switch(e.label){case 0:return[4,this._playerAudio.getAudioContext()];case 1:return[2,e.sent()]}}))}))},e.WHERE_IN_QUEUE_AT_END="append",e.WHERE_IN_QUEUE_AT_START="prepend",e.PLAY_SOUND_NEXT="next",e.PLAY_SOUND_PREVIOUS="previous",e.PLAY_SOUND_FIRST="first",e.PLAY_SOUND_LAST="last",e.CURRENT_SOUND="current",e.PLAYER_MODE_AUDIO="player_mode_audio",e.PLAYER_MODE_AJAX="player_mode_ajax",e.PLAYER_MODE_FETCH="player_mode_fetch",e}();export{s as PlayerCore,n as PlayerSound}; | ||
//# sourceMappingURL=index.min.js.map |
@@ -1,4 +0,9 @@ | ||
import { typePlayerModes } from './core'; | ||
import { ISound } from './sound'; | ||
interface IAudioGraph { | ||
export interface IAudioOptions { | ||
audioContext: AudioContext; | ||
createAudioContextOnFirstUserInteraction: boolean; | ||
volume: number; | ||
persistVolume: boolean; | ||
} | ||
export interface IAudioNodes { | ||
gainNode: GainNode; | ||
@@ -18,58 +23,42 @@ pannerNode?: PannerNode; | ||
} | ||
interface IOnEnded { | ||
interface IOnSourceNodeEnded { | ||
(event?: Event): void; | ||
} | ||
interface IAudioOptions { | ||
customAudioContext?: AudioContext; | ||
customAudioGraph?: IAudioGraph; | ||
createAudioContextOnFirstUserInteraction?: boolean; | ||
persistVolume: boolean; | ||
loadPlayerMode: typePlayerModes; | ||
export interface IAudioBufferSourceOptions extends AudioBufferSourceOptions { | ||
onSourceNodeEnded: IOnSourceNodeEnded; | ||
} | ||
interface IAudioBufferSourceOptions extends AudioBufferSourceOptions { | ||
onEnded: IOnEnded; | ||
} | ||
interface IMediaElementAudioSourceOptions extends MediaElementAudioSourceOptions { | ||
onEnded: IOnEnded; | ||
export interface IMediaElementAudioSourceOptions extends MediaElementAudioSourceOptions { | ||
onSourceNodeEnded: IOnSourceNodeEnded; | ||
loop: boolean; | ||
} | ||
export interface IChangeVolumeOptions { | ||
volume: number; | ||
sound?: ISound; | ||
forceUpdateUserVolume?: boolean; | ||
} | ||
declare class PlayerAudio { | ||
export declare class PlayerAudio { | ||
protected _options: IAudioOptions; | ||
protected _audioContext: AudioContext; | ||
protected _volume: number; | ||
protected _audioContext: AudioContext | null; | ||
protected _audioGraph: IAudioGraph | null; | ||
protected _createAudioContextOnFirstUserInteraction: boolean; | ||
protected _persistVolume: boolean; | ||
protected _loadPlayerMode: typePlayerModes; | ||
protected _audioNodes: IAudioNodes; | ||
constructor(options: IAudioOptions); | ||
protected _initialize(): void; | ||
decodeAudio(arrayBuffer: ArrayBuffer): Promise<AudioBuffer>; | ||
protected _createAudioContext(): Promise<void>; | ||
protected _autoCreateAudioContextRemoveListener(): void; | ||
protected _autoCreateAudioContextOnFirstUserInteraction(): void; | ||
protected _addAutoCreateAudioContextOnFirstUserInteractionEventListeners(): void; | ||
protected _removeAutoCreateAudioContextOnFirstUserInteractionEventListeners(): void; | ||
getAudioContext(): Promise<AudioContext>; | ||
setAudioContext(audioContext: AudioContext): void; | ||
protected _setAudioContext(audioContext: AudioContext): void; | ||
protected _unfreezeAudioContext(): Promise<void>; | ||
freezeAudioContext(): Promise<void>; | ||
detectAudioContextSupport(): boolean; | ||
detectAudioElementSupport(): boolean; | ||
shutDown(songsQueue: ISound[]): Promise<void>; | ||
protected _destroyAudioContext(): Promise<void>; | ||
_unfreezeAudioContext(): Promise<void>; | ||
_freezeAudioContext(): Promise<void>; | ||
setAudioGraph(audioGraph: IAudioGraph): void; | ||
getAudioGraph(): Promise<IAudioGraph>; | ||
protected _createAudioGraph(): Promise<IAudioGraph>; | ||
protected _destroyAudioGraph(): void; | ||
createAudioBufferSourceNode(audioBufferSourceOptions: IAudioBufferSourceOptions, sound: ISound): Promise<void>; | ||
createMediaElementSourceNode(sourceNodeOptions: IMediaElementAudioSourceOptions, sound: ISound): Promise<void>; | ||
connectSourceNodeToGraphNodes(sourceNode: AudioBufferSourceNode | MediaElementAudioSourceNode): void; | ||
destroySourceNode(sound: ISound): void; | ||
changeVolume({ volume, sound, forceUpdateUserVolume }: IChangeVolumeOptions): number; | ||
protected _changeGainValue(gainValue: number): void; | ||
protected _setAutoCreateContextOnFirstTouch(autoCreate: boolean): void; | ||
setPersistVolume(persistVolume: boolean): void; | ||
getPersistVolume(): boolean; | ||
setLoadPlayerMode(loadPlayerMode: typePlayerModes): void; | ||
getLoadPlayerMode(): typePlayerModes; | ||
protected _getPlayerGainNode(): Promise<GainNode>; | ||
protected _disconnectPlayerGainNode(): void; | ||
connectSound(sound: ISound): Promise<void>; | ||
disconnectSound(sound: ISound): Promise<void>; | ||
protected _changePlayerGainValue(gainValue: number): void; | ||
protected _roundGainTwoDecimals(rawGainValue: number): number; | ||
setVolume(volume: number, forceUpdateUserVolume?: boolean): void; | ||
getVolume(): number; | ||
protected _initializeVolume(): void; | ||
} | ||
export { PlayerAudio, IAudioGraph, IAudioOptions, IAudioBufferSourceOptions, IMediaElementAudioSourceOptions }; | ||
export {}; |
import { ISound, ISoundAttributes, ISoundSource, typeSoundStates } from './sound'; | ||
import { PlayerAudio, IAudioGraph, IAudioOptions } from './audio'; | ||
import { PlayerAudio, IAudioOptions } from './audio'; | ||
import { PlayerError } from './error'; | ||
@@ -7,3 +7,6 @@ declare const PLAYER_MODE_AUDIO = "player_mode_audio"; | ||
declare const PLAYER_MODE_FETCH = "player_mode_fetch"; | ||
export type typePlayerModes = typeof PLAYER_MODE_AUDIO | typeof PLAYER_MODE_AJAX | typeof PLAYER_MODE_FETCH; | ||
declare const WHERE_IN_QUEUE_AT_START = "prepend"; | ||
declare const WHERE_IN_QUEUE_AT_END = "append"; | ||
type typePlayerMode = typeof PLAYER_MODE_AUDIO | typeof PLAYER_MODE_AJAX | typeof PLAYER_MODE_FETCH; | ||
type typeWhereInQueue = typeof WHERE_IN_QUEUE_AT_START | typeof WHERE_IN_QUEUE_AT_END; | ||
export interface ICoreOptions { | ||
@@ -16,4 +19,2 @@ volume?: number; | ||
playNextOnEnded?: boolean; | ||
audioGraph?: IAudioGraph; | ||
audioContext?: AudioContext; | ||
stopOnReset?: boolean; | ||
@@ -23,7 +24,8 @@ visibilityAutoMute?: boolean; | ||
persistVolume?: boolean; | ||
loadPlayerMode?: typePlayerModes; | ||
loadPlayerMode?: typePlayerMode; | ||
audioContext?: AudioContext; | ||
} | ||
interface ISoundsQueueOptions { | ||
export interface ISoundsQueueOptions { | ||
soundAttributes: ISoundAttributes; | ||
whereInQueue?: string; | ||
whereInQueue?: typeWhereInQueue; | ||
} | ||
@@ -33,3 +35,3 @@ interface IDecodeSoundOptions { | ||
} | ||
interface IPlayOptions { | ||
export interface IPlayOptions { | ||
whichSound?: number | string | undefined; | ||
@@ -40,7 +42,6 @@ playTimeOffset?: number; | ||
soundId: string | number; | ||
updateIndex: boolean; | ||
} | ||
interface IFindBestSourceResponse { | ||
url: string | null; | ||
codec?: string | null; | ||
url: string; | ||
codec?: string; | ||
} | ||
@@ -53,24 +54,10 @@ interface IGetSoundFromQueue { | ||
protected _queue: ISound[]; | ||
protected _volume: number; | ||
protected _soundsBaseUrl: string; | ||
protected _currentIndex: number; | ||
protected _playerAudio: PlayerAudio; | ||
protected _playingProgressIntervalTime: number; | ||
protected _playingProgressRequestId: number | null; | ||
protected _playingProgressRequestId: number; | ||
protected _playingProgressPreviousTimestamp: DOMHighResTimeStamp; | ||
protected _playNextOnEnded: boolean; | ||
protected _loopQueue: boolean; | ||
protected _loopSong: boolean; | ||
protected _customAudioGraph: IAudioGraph | null; | ||
protected _customAudioContext: AudioContext | null; | ||
protected _stopOnReset: boolean; | ||
protected _postMuteVolume: number; | ||
protected _isMuted: boolean; | ||
protected _visibilityAutoMute: boolean; | ||
protected _createAudioContextOnFirstUserInteraction: boolean; | ||
protected _persistVolume: boolean; | ||
protected _loadPlayerMode: typePlayerModes; | ||
static readonly WHERE_IN_QUEUE_AT_END: string; | ||
static readonly WHERE_IN_QUEUE_AT_START: string; | ||
static readonly WHERE_IN_QUEUE_AFTER_CURRENT: string; | ||
protected _options: ICoreOptions; | ||
static readonly WHERE_IN_QUEUE_AT_END = "append"; | ||
static readonly WHERE_IN_QUEUE_AT_START = "prepend"; | ||
static readonly PLAY_SOUND_NEXT = "next"; | ||
@@ -80,2 +67,3 @@ static readonly PLAY_SOUND_PREVIOUS = "previous"; | ||
static readonly PLAY_SOUND_LAST = "last"; | ||
static readonly CURRENT_SOUND = "current"; | ||
static readonly PLAYER_MODE_AUDIO = "player_mode_audio"; | ||
@@ -86,10 +74,6 @@ static readonly PLAYER_MODE_AJAX = "player_mode_ajax"; | ||
protected _initialize(): void; | ||
protected _webAudioApiOptions(): IAudioOptions; | ||
protected _webAudioElementOptions(): IAudioOptions; | ||
protected _detectAudioContextSupport(): boolean; | ||
protected _detectAudioElementSupport(): boolean; | ||
protected _audioOptions(): IAudioOptions; | ||
addSoundToQueue({ soundAttributes, whereInQueue }: ISoundsQueueOptions): ISound; | ||
_appendSoundToQueue(sound: ISound): void; | ||
_prependSoundToQueue(sound: ISound): void; | ||
_addSoundToQueueAfterCurrent(sound: ISound): void; | ||
resetQueue(): void; | ||
@@ -112,2 +96,3 @@ reset(): void; | ||
protected _decodeSound({ sound }: IDecodeSoundOptions): Promise<ISound>; | ||
protected _cloneAudioBuffer(fromAudioBuffer: AudioBuffer): AudioBuffer; | ||
play({ whichSound, playTimeOffset }?: IPlayOptions): Promise<void>; | ||
@@ -117,11 +102,7 @@ protected _play(sound: ISound): Promise<void>; | ||
protected _playMediaElementAudio(sound: ISound): Promise<void>; | ||
protected _setupSoundEvents(sound: ISound): ISound; | ||
protected _triggerSoundCallbacks(sound: ISound): ISound; | ||
protected _progressTrigger: (sound: ISound, timestamp: DOMHighResTimeStamp) => void; | ||
protected _onEnded(): void; | ||
/** | ||
* whichSound is optional, if set it can be the sound id or if it's | ||
* a string it can be next / previous / first / last | ||
*/ | ||
protected _getSoundFromQueue({ whichSound, updateIndex }?: IGetSoundFromQueue): ISound | null; | ||
protected _findSoundById({ soundId, updateIndex }: IFindSoundById): ISound | null; | ||
protected _getSoundFromQueue({ whichSound, updateIndex }?: IGetSoundFromQueue): ISound; | ||
protected _findSoundById({ soundId }: IFindSoundById): [ISound, number]; | ||
protected _findBestSource(soundSource: (ISoundSource)[] | ISoundSource): IFindBestSourceResponse; | ||
@@ -138,10 +119,8 @@ protected _checkCodecSupport(codec: string): boolean; | ||
protected _playingProgress(sound: ISound): void; | ||
setAudioGraph(customAudioGraph: IAudioGraph): void; | ||
getAudioGraph(): Promise<IAudioGraph>; | ||
setAudioContext(customAudioContext: AudioContext): void; | ||
getAudioContext(): Promise<AudioContext>; | ||
setVisibilityAutoMute(visibilityAutoMute: boolean): void; | ||
getVisibilityAutoMute(): boolean; | ||
protected _handleVisibilityChange(): void; | ||
disconnect(): Promise<void>; | ||
getAudioContext(): Promise<AudioContext>; | ||
} | ||
export {}; |
@@ -1,2 +0,1 @@ | ||
import { IPlayerError } from './error'; | ||
import { IOnProgress } from './sound'; | ||
@@ -9,3 +8,3 @@ export interface IRequested { | ||
export declare class PlayerRequest { | ||
getArrayBuffer(requested: IRequested): Promise<ArrayBuffer | IPlayerError>; | ||
getArrayBuffer(requested: IRequested): Promise<ArrayBuffer>; | ||
} |
@@ -5,7 +5,2 @@ declare const SOUND_STATE_STOPPED = "sound_state_stopped"; | ||
export type typeSoundStates = typeof SOUND_STATE_STOPPED | typeof SOUND_STATE_PAUSED | typeof SOUND_STATE_PLAYING; | ||
export interface ISoundSource { | ||
url: string; | ||
codec?: string; | ||
isPreferred?: boolean; | ||
} | ||
export interface IOnProgress { | ||
@@ -20,9 +15,14 @@ (progress: number, maximumValue: number, currentValue: number): void; | ||
} | ||
export interface ISoundSource { | ||
url: string; | ||
codec?: string; | ||
isPreferred?: boolean; | ||
} | ||
export interface ISoundAttributes { | ||
source?: (ISoundSource)[] | ISoundSource; | ||
id: number; | ||
id?: number | string; | ||
loop?: boolean; | ||
audioBuffer?: AudioBuffer | null; | ||
arrayBuffer?: ArrayBuffer | null; | ||
duration?: number | null; | ||
audioBuffer?: AudioBuffer; | ||
arrayBuffer?: ArrayBuffer; | ||
duration?: number; | ||
onLoading?: IOnProgress; | ||
@@ -37,11 +37,9 @@ onPlaying?: IOnProgress; | ||
export interface ISound extends ISoundAttributes, ISoundSource { | ||
audioBufferSourceNode: AudioBufferSourceNode | null; | ||
mediaElementAudioSourceNode: MediaElementAudioSourceNode | null; | ||
sourceNode: AudioBufferSourceNode | MediaElementAudioSourceNode; | ||
gainNode: GainNode; | ||
isReadyToPLay: boolean; | ||
isBuffered: boolean; | ||
isBuffering: boolean; | ||
audioBuffer: AudioBuffer | null; | ||
arrayBuffer: ArrayBuffer | null; | ||
audioBufferDate: Date | null; | ||
loadingProgress: number; | ||
audioElement: HTMLAudioElement; | ||
audioBufferDate: Date; | ||
playTimeOffset: number; | ||
@@ -52,8 +50,4 @@ startTime: number; | ||
state: typeSoundStates; | ||
source: (ISoundSource)[] | ISoundSource; | ||
url: string | null; | ||
codec: string | null; | ||
duration: number | null; | ||
loadingProgress: number; | ||
firstTimePlayed: boolean; | ||
audioElement: HTMLAudioElement | null; | ||
getCurrentTime(): number; | ||
@@ -67,15 +61,15 @@ getDuration(): number; | ||
source: (ISoundSource)[] | ISoundSource; | ||
url: string | null; | ||
codec: string | null; | ||
id: number; | ||
url: string; | ||
codec: string; | ||
id: number | string; | ||
loop: boolean; | ||
audioBufferSourceNode: AudioBufferSourceNode | null; | ||
mediaElementAudioSourceNode: MediaElementAudioSourceNode | null; | ||
sourceNode: AudioBufferSourceNode | MediaElementAudioSourceNode; | ||
gainNode: GainNode; | ||
isReadyToPLay: boolean; | ||
isBuffered: boolean; | ||
isBuffering: boolean; | ||
audioElement: HTMLAudioElement | null; | ||
audioBuffer: AudioBuffer | null; | ||
arrayBuffer: ArrayBuffer | null; | ||
audioBufferDate: Date | null; | ||
audioElement: HTMLAudioElement; | ||
audioBuffer: AudioBuffer; | ||
arrayBuffer: ArrayBuffer; | ||
audioBufferDate: Date; | ||
playTimeOffset: number; | ||
@@ -87,3 +81,3 @@ startTime: number; | ||
loadingProgress: number; | ||
duration: number | null; | ||
duration: number; | ||
firstTimePlayed: boolean; | ||
@@ -100,3 +94,4 @@ onLoading: IOnProgress; | ||
getDuration(): number; | ||
protected _generateSoundId(): string; | ||
} | ||
export {}; |
{ | ||
"name": "web-audio-api-player", | ||
"version": "4.3.1", | ||
"version": "5.0.0", | ||
"description": "web audio api player", | ||
@@ -43,11 +43,11 @@ "keywords": [ | ||
"@rollup/plugin-terser": "0.4.3", | ||
"@typescript-eslint/eslint-plugin": "6.2.0", | ||
"@typescript-eslint/parser": "6.2.0", | ||
"eslint": "8.46.0", | ||
"eslint-plugin-import": "2.28.0", | ||
"rollup": "3.27.0", | ||
"@typescript-eslint/eslint-plugin": "6.5.0", | ||
"@typescript-eslint/parser": "6.5.0", | ||
"eslint": "8.48.0", | ||
"eslint-plugin-import": "2.28.1", | ||
"rollup": "3.28.1", | ||
"rollup-plugin-typescript2": "0.35.0", | ||
"typescript": "5.1.6" | ||
"typescript": "5.2.2" | ||
}, | ||
"type": "module" | ||
} |
113
README.md
@@ -40,29 +40,28 @@ [![npm version](https://img.shields.io/npm/v/web-audio-api-player.svg?style=flat)](https://www.npmjs.com/package/web-audio-api-player) | ||
* volume: [number] (default: 80) the current playback volume | ||
* loopQueue: [boolean] (default: false) after the last song in the queue has finished to play should the player do a loop and continue to play by playing the first song or stop playing | ||
* soundsBaseUrl: [string] (default: '') the base url for the location of the songs | ||
* playingProgressIntervalTime: [number] (default: 200) the interval in milliseconds at which the player should trigger a songs **onPlaying** callback which will tell you the playing progress in percent, this value is a minimum value because the player uses the [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) internally, meaning that if the browser is very busy it might take a bit longer than the defined interval time before the progress value is being reported, this helps to prevent that your UI uses resources that are needed more urgently somewhere else | ||
* playNextOnEnded: [boolean] (default: true) when a sound or song finishes playing should the player play the next song that is in the queue or just stop playing | ||
* audioGraph: [IAudioGraph] (default: null) a custom audiograph you inject to replace the default audiograph of the player | ||
* audioContext: [AudioContext] (default: null) a custom audiocontext you inject to replace the default audiocontext of the player | ||
* stopOnReset: [boolean] (default: true) when the queue gets reset and a song is currently being played, should the player stop or continue playing that song | ||
* visibilityAutoMute: [boolean] (default: false) tells the player if a song is playing and the visibility API triggers a visibility change event, if the currently playing song should get muted or not, uses the [Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API) internally | ||
* createAudioContextOnFirstUserInteraction: [boolean] (default: true) for a song to be played the player needs to have an audiocontext, on mobile you can play sounds / songs until the user has interacted in some way with your UI, this means autoplay with no user interaction will not work, when this option is set to true the player will try to catch the very first user interaction and initialize and audiocontext so that when a song needs to be played the context will be available | ||
* loopQueue: [boolean] (default: false) after the last sound in the queue has finished to play should the player do a loop and continue to play by playing the first sound or stop playing | ||
* soundsBaseUrl: [string] (default: '') the base url for the location of the sounds | ||
* playingProgressIntervalTime: [number] (default: 200) the interval in milliseconds at which the player should trigger a sounds **onPlaying** callback which will tell you the playing progress in percent, this value is a minimum value because the player uses the [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) internally, meaning that if the browser is very busy it might take a bit longer than the defined interval time before the progress value is being reported, this helps to prevent that your UI uses resources that are needed more urgently somewhere else | ||
* playNextOnEnded: [boolean] (default: true) when a sound or song finishes playing should the player play the next sound that is in the queue or just stop playing | ||
* stopOnReset: [boolean] (default: true) when the queue gets reset and a sound is currently being played, should the player stop or continue playing that sound | ||
* visibilityAutoMute: [boolean] (default: false) tells the player if a sound is playing and the visibility API triggers a visibility change event, if the currently playing sound should get muted or not, uses the [Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API) internally | ||
* createAudioContextOnFirstUserInteraction: [boolean] (default: true) for a sound to be played the player needs to have an audiocontext, on mobile you can play sounds / songs until the user has interacted in some way with your UI, this means autoplay with no user interaction will not work, when this option is set to true the player will try to catch the very first user interaction and initialize and audiocontext so that when a sound needs to be played the context will be available | ||
* persistVolume: [boolean] (default: true) if this value is set to true the player will use the localstorage of the browser and save the value of the volume (localstorage entry key is **WebAudioAPIPlayerVolume**), if the page gets reloaded or the user comes back later the player will check if there is a value in the localstorage and automatically set the player volume to that value | ||
* loadPlayerMode: [typePlayerModes] (default: PLAYER_MODE_AUDIO) this is a constant you can import from player, currently you can chose between two modes, [PLAYER_MODE_AUDIO](#player_mode_audio) which uses the audio element to load sounds via the audio element and [PLAYER_MODE_AJAX](#player_mode_ajax) to load sounds via the web audio API | ||
* loadPlayerMode: [typePlayerModes] (default: PLAYER_MODE_AUDIO) this is a constant you can import from player, currently you can chose between two modes, [PLAYER_MODE_AUDIO](#player_mode_audio) which uses the audio element to load sounds via the audio element and [PLAYER_MODE_AJAX](#player_mode_ajax) to load sounds via the web audio API, for more info about the modes read the [modes extended knowledge](#modes-extended-knowledge) chapter | ||
* audioContext: [AudioContext] (default: null) a custom [audiocontext](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext) you inject to replace the default audiocontext of the player | ||
### sound attributes | ||
Note: if you use typescript, import the **ISoundAttributes** interface along with the playerCore, this makes it a lot easier to see what song attributes are available and what the type of each value is | ||
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] 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 song when needed | ||
* **codec** [string] the codec that got used to encode the song, 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 | ||
* 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] a unique and numeric id for the song, used as a reference to link content to that sound which is not part of the sound object itself | ||
* loop: [boolean] (optional, default false) if the song playback should loop when it reaches the end of sound | ||
* 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, the player depending on the play mode will need to wait for the song to be fully loaded until it can determine the duration | ||
* 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 | ||
@@ -73,3 +72,3 @@ **sound callbacks:** | ||
* onPlaying: [function] (optional) a callback funtion that will get triggered at intervals while the sound is playing | ||
* onEnded: [function] (optional) a callback funtion that will get triggered when the end of the sound playback is reached | ||
* onEnded: [function] (optional) a callback funtion that will get triggered when the end of the sound is reached | ||
* onStarted: [function] (optional) a callback funtion that will get triggered when the sound playback starts | ||
@@ -246,26 +245,16 @@ * onStopped: [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) | ||
#### PLAYER_MODE_AUDIO | ||
#### differencies clarification | ||
sounds / songs get loaded via a hidden HTML `<audio>` element | ||
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. | ||
this is the default mode | ||
If you use this library, the difference is only how the sound (song) gets retrieved: | ||
* Support for streaming | ||
* Files get loaded using the audio element, the loading progress is not just a single value, it can be split into multiple parts (time ranges), so for example the start of a song from 0 to 10 percent got loaded, then there is a blank of not yet loaded data and then also the part from 35 to 60 percent has been loaded | ||
* A song can be played as soon as a big enough portion of the sound has been loaded (what "big enough" means, is that the browser calculates how much of the sounds needs to get loaded to be able to start playing it and continue loading (streaming) what is left without having to pause the sound at some time during the play process until the end of the playback) | ||
##### PLAYER_MODE_AJAX | ||
#### PLAYER_MODE_AJAX | ||
will use an [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) the source will be an [AudioBufferSourceNode](https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode) | ||
songs / sounds get fetched using an `XMLHttpRequest`, this happens in the [request](src/library/request.ts) file, check it out if you want to know exactly how it works | ||
##### PLAYER_MODE_AUDIO | ||
* No support for streaming | ||
* Files get loaded using XMLHttpRequest, the loading progress is in percent and it is a single value between 0 and 100 percent loaded | ||
* A song has to be fully fetched before it can be turned into a buffer and hence before the playback can start | ||
will use the HTML [audio element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio), then the player will use [createMediaElementSource](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaElementSource) method of the [AudioContext](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext) internally to create an [MediaElementAudioSourceNode](https://developer.mozilla.org/en-US/docs/Web/API/MediaElementAudioSourceNode) | ||
#### features / differencies clarification | ||
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. | ||
If you use this library, the difference is only how the sound (song) gets loaded (see list of differences above). If using fetch the source is a Buffer and if using the "HTML audio element" well the source is a media element. Everything that happens after is the same. This is why you can change in the player options the PLAYER_MODE, to either load the sound using [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) if you set the mode to **PLAYER_MODE_AJAX** or load / stream it using the [audio element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio) by setting the mode to **PLAYER_MODE_AUDIO** (this is the default). But this influences only how the sound get loaded (fetched), if loaded via audio element, we use the web audio API [createMediaElementSource method](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaElementSource) of the audiocontext to pass it to the audiocontext of the web audio API. After feeding the web audio API with the input from the web audio element, the playback and what you do with it is being handled by the web audio API. | ||
#### so which PLAYER_MODE should I use | ||
@@ -275,5 +264,5 @@ | ||
If you build a game where you have a lot (of small sounds) that get (pre-)loaded and maybe cached but played later at some time after they finished loading, use PLAYER_MODE_AJAX. Its progress is easier to understand, because when the loading progress of the sound has reached 100% you know it can be played. To display the loading progress a simple [HTML progress element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress) is enough. | ||
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, because in 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 get the rest of it from the server in the background while playing). To display the time range(s) that have been loaded you could for example use a [2D canvas element](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D). | ||
If you build a music player, 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 yet as long as the part that has been loaded is enough to play the song until the end (while the rest of it is being streamed from the server in the background). To display the time range(s) that have been loaded you could for example use a [2D canvas element](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D). | ||
If you build something that has a lot (of small sounds) that get (pre-)loaded and maybe cached, but played later at some time after they finished loading, use PLAYER_MODE_AJAX. Its progress is easier to understand, because when the loading progress of the sound has reached 100% you know it can be played. To display the loading progress a simple [HTML progress element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress) is enough. | ||
@@ -385,19 +374,11 @@ ### advanced usage | ||
* create a react example | ||
* create a vue.js example | ||
* create an example using the (browser) fileReader, something like: | ||
```javascript | ||
var fileInput = document.querySelector('input[type="file"]'); | ||
fileInput.addEventListener('change', function(event) { | ||
var reader = new FileReader(); | ||
reader.onload = function(event) { | ||
playerCore._decodeSound(this.result); | ||
}; | ||
reader.readAsArrayBuffer(this.files[0]); | ||
}, false); | ||
``` | ||
* add a shuffle songs feature | ||
* add a loop song (<https://webaudio.github.io/web-audio-api/#looping-AudioBufferSourceNode>) feature (actually maybe this already works today, need to verify) | ||
* we have sound events, but would player event be useful, like onVolumeChange? | ||
* add (stereo) panning | ||
* allow to add an array of sounds to queue all at once | ||
* allow to add sound to queue after a sound by id (not just at beginning or end, as it is as of now) | ||
* for position and volume, allow to use a percentage or a value, for volume (gain) allow values beyond 0 to 1 to amplify wave or invert it? | ||
* add improve UI style of the "simple" example(s) (or any new example) and then add a screenshot of it to the readme to show what can be achieved | ||
* completely rewrite the sources system, where you can define multiple variants of a sound but with different codecs, app needs to check which codecs are supported by the device and choose one, use should be able to define which codec is preferred if playback support for multiple codecs is available | ||
* destroy the audiocontext at some point, to release memory? | ||
@@ -407,23 +388,33 @@ * feature to use the browser notification system to alert which song is being played | ||
* 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) | ||
* some methods return a promise others don't, use promises for all to make it more consistent | ||
* some methods return a promise others don't, use promises for all to make it more consistent? | ||
* write more documentation | ||
* make a list of all possible errors (set a distinct code for each error), handle all error cases that are still unhandled | ||
* [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 new mode 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 | ||
* 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>) | ||
* add feature to crossfade two songs "on end" (if there is a the next song in a playlist) or just fade out (current song) / fade in (next song) | ||
* 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 | ||
* currently the "find song in queue" can't retrieve songs by queue index, is this useful anyway? | ||
* use suspend and resume if for some time no sound was played? ... 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 | ||
* use suspend and resume if for some time no sound was played? ... 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 web workers, especially for the decoding of the ArrayBuffer into an AudioBuffer, to not block the main thread while decoding? | ||
* add a shuffle songs mode | ||
* add a loop song (<https://webaudio.github.io/web-audio-api/#looping-AudioBufferSourceNode>) feature (actually maybe this already works today, need to verify) | ||
* 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 | ||
* write code tests!!! (goal ofc 100% coverage), add [tests coverage badge](https://coveralls.io) | ||
* add saucelabs (or similar) browser testing (and their badge [browser compatibility table badge](https://saucelabs.com/blog/new-open-sauce-ui-and-refreshed-build-status-badges) in readme) to add a test suite for all player features | ||
* add [travis](https://travis-ci.org) continuous integration and badge | ||
* use github actions for a CI/CD workflow | ||
* add live demo (via github pages?) for people to see how the player works | ||
* for position and volume, allow to use a percentage or a value | ||
* feature that let's the dev set a volume (via a modifier value / coefficient) per song, 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 hooks to the sound object for all the native source node events [AudioBufferSourceNode](https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode) | ||
* add (stereo) panning | ||
* create a react example | ||
* create a vue.js example | ||
* create an example using the (browser) fileReader, something like: | ||
```javascript | ||
var fileInput = document.querySelector('input[type="file"]'); | ||
fileInput.addEventListener('change', function(event) { | ||
var reader = new FileReader(); | ||
reader.onload = function(event) { | ||
playerCore._decodeSound(this.result); | ||
}; | ||
reader.readAsArrayBuffer(this.files[0]); | ||
}, false); | ||
``` | ||
## note to self: publish package on npmjs.com | ||
@@ -430,0 +421,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
324717
1714
433