/*jslint laxbreak:true */ /*jslint laxcomma:true */ /*jslint loopfunc:true */ /*jslint strict:true */ /*jslint browser:true */ /*jslint devel:true */ define([ "underscore" , "jquery" , "backbone" , "modules/webaudio" , "libs/mimes" , "text!../../templates/player/layout.html" , "text!../../templates/player/player-status.html" ] , function ( _ , $ , Backbone , WebAudio , MIMES , tmplPlayerLayout , tmplPlayerStatus ) { "use strict"; if (!_.isFunction(Array.prototype.shuffle)) { Array.prototype.shuffle = function() { var len = this.length , i = len ; if ( len === 0 ) { return false; } while (i--) { var p = parseInt(Math.random()*len, 10); var t = this[i]; this[i] = this[p]; this[p] = t; } }; } var Player = Backbone.View.extend({ elViewport: null , $elViewport: null , $elVolumeInput: null , playIndex: [] , playCursor: -1 , webAudio: null , _stateRandom: null , _stateRepeat: null , _statesRepeat: { none: null , one: false , all: true } , _stateMute: null , _stateVolume: null , _stateAudio: null , _state: null , _states: { stopped: 0 , loading: 1 , playing: 2 , paused: 3 } , debouncers: {} , events: { //"click #add-friend": "showPrompt", "click div:first-child > a.buttonPrev:not(.disabled)": "__buttonPrevious" , "click div:first-child > a.buttonNext:not(.disabled)": "__buttonNext" , "click div:first-child > a.buttonPlay:not(.disabled)": "__buttonPlayPause" // Volume Down , "click div:first-child > .playerVolumeWrapper > a:first-child:not(.disabled)": "__buttonVolumeDown" // Volume Up , "click div:first-child > .playerVolumeWrapper > a:last-child:not(.disabled)": "__buttonVolumeUp" // Volume click , "click div:first-child > .playerVolumeWrapper > input:not(disabled)": "__buttonVolumeClick" // Seek input , "click div:last-child > .playerProgressWrapper > progress": "__buttonSeek" } , initialize: function (options) { var that = this ; _.bindAll(this // Public , "init" , "setPlayIndex" , "sortPlayIndex" , "setRandomState" , "setRepeatState" , "playItem" , "playAtIndex" // Events , "__buttonPlayPause" , "__buttonNext" , "__buttonPrevious" , "__buttonVolumeUp" , "__buttonVolumeDown" , "__buttonVolumeClick" , "__buttonSeek" // Private , "_waCreate" , "_waBindEvents" , "__waStateChanged" , "__waEnded" , "__waTimeUpdate" , "_playerPlay" , "_playerLoading" , "_playNext" , "_playPrevious" , "_playerPause" , "_playerUnpause" , "_playerStop" , "_playerStart" , "_getVolume" , "_setVolume" , "_seek" , "_playBtnSetState" , "_disableControls" , "_enableControls" , "_getItemData" , "_getItemMediaUrl" , "_setViewport" , "_progressSetLoadding" , "_updateViewportProgress" ); Player.__super__.initialize.apply(that); that.$el.html(tmplPlayerLayout); that.elViewport = document.createElement("div"); that.$elViewport = $(that.elViewport); that._setViewport(); that.$elVolumeInput = that.$el.find(".playerVolumeWrapper > input"); that.$el.append(that.elViewport); that._waCreate(); return that; } /** * PUBLIC **/ , init: function () { var that = this ; that._enableControls(); that.$elVolumeInput.val(that.webAudio.obj.volume); } , setPlayIndex: function (index, cursor) { var that = this ; if (that.webAudio._state === that.webAudio._states.paused) { that.webAudio._state = that.webAudio._states.stopped; that._playerStop(); } if (that.webAudio._state < that.webAudio._states.loading) { console.debug("Setting Play Index"); that._playIndex = index; that._playCursor = cursor || 0; if (that._stateRandom) { that.setRandomState(that._stateRandom); } return that._playIndex; } else { return undefined; } } , sortPlayIndex: function (index) { var that = this ; // TODO } , setRandomState: function (random) { var that = this ; if (random === true) { //var previousItem = that._playIndex[that._playCursor]; that._playIndexOrdered = _.clone(that._playIndex); that._playIndex.shuffle(); // TODO: Set cursor back to the item that was playing //if (that._playCursor !== -1 && that.webAudio._state >= that.webAudio._states.loading) { // var newCursor = //} that._playCursor = -1; } else { that._playIndex = _.clone(that._playIndexOrdered); delete that._playIndexOrdered; } return that._stateRandom = random; } , setRepeatState: function (repeat) { var that = this ; return that._stateRepeat = repeat; } , playItem: function (item) { var that = this ; return that._playerPlay(item); } , playAtIndex: function (index) { var that = this ; that._playCursor = index; that.playItem(that._playIndex[that._playCursor]); } /** * EVENTS **/ , __buttonPlayPause: function (event) { var that = this , $target = $(event.target) ; switch (that.webAudio._state) { case that.webAudio._states.stopped: that._playNext(); break; case that.webAudio._states.playing: that._playerPause(); break; case that.webAudio._states.paused: that._playerUnpause(); break; default: break; } } , __buttonNext: function (event) { var that = this ; that._playNext(); } , __buttonPrevious: function (event) { var that = this ; that._playPrevious(); } , __buttonVolumeUp: function (event) { var that = this , volume = that._getVolume() ; if (volume < 1) { if ((volume+0.1) > 1) { volume = 1; } else { volume+= 0.1; } } that._setVolume(volume); } , __buttonVolumeDown: function (event) { var that = this , volume = that._getVolume() ; if (volume > 0) { if ((volume-0.1) < 0) { volume = 0; } else{ volume-= 0.1; } } that._setVolume(volume); } , __buttonVolumeClick: function (event) { var that = this , clientX = event.clientX , left = event.target.offsetLeft , clickoffset = clientX - left , fraction = clickoffset/event.target.offsetWidth ; that._setVolume(fraction); } , __buttonSeek: function (event) { var that = this ; if (_.isUndefined(that.debouncers["__buttonSeek"])) { var clientX = event.clientX , left = event.target.offsetLeft , clickoffset = clientX - left , percent = clickoffset/event.target.offsetWidth , seekTime = percent * that.webAudio.obj.duration ; that._seek(seekTime); that.debouncers["__buttonSeek"] = setTimeout(function __fnPlayerViewButtonSeekDebounce () { clearTimeout(that.debouncers["__buttonSeek"]); delete that.debouncers["__buttonSeek"]; }, 800); } } /** * PRIVATE **/ // Audio Player , _waCreate: function () { var that = this ; that.webAudio = new WebAudio(); that._waBindEvents(); return that.webAudio; } , _waBindEvents: function () { var that = this ; that.webAudio.on("state", function __fnPlayerEventWebAudioState (state) { that.__waStateChanged.apply(that, arguments); }); that.webAudio.on("ended", function __fnPlayerEventWebAudioState (state) { that.__waEnded.apply(that, arguments); }); that.webAudio.on("timeupdate", function __fnPlayerEventWebAudioState () { that.__waTimeUpdate.apply(that, arguments); }); } , __waStateChanged: function (state) { var that = this ; that._playBtnSetState(state); switch (state) { case that.webAudio._states.stopped: console.debug("Player State Stopped"); //that._setViewport(); that._enableControls(); break; case that.webAudio._states.error: console.debug("Player State error"); that._disableControls(); break; case that.webAudio._states.loading: console.debug("Player State loading"); that._progressSetLoadding(); that._disableControls(); break; case that.webAudio._states.playing: console.debug("Player State playing"); that._enableControls(); break; case that.webAudio._states.paused: console.debug("Player State paused"); that._enableControls(); break; } } , __waEnded: function () { var that = this ; that._playNext(); } , __waTimeUpdate: function (event) { var that = this ; that._updateViewportProgress(event.target.currentTime, event.target.duration); } // Player Controls , _playerPlay: function (item) { var that = this ; that.webAudio.loadMedia(that._getItemMediaUrl(item), MIMES.get(item.type), function __fnPlayerViewCbLoaded () { that._setViewport(item); }); } , _playerLoading: function () { var that = this ; } , _playNext: function () { var that = this ; switch (that._stateRepeat) { case that._statesRepeat.all: case that._statesRepeat.none: if (that._stateRepeat === that._statesRepeat.all && that._playIndex.length === (that._playCursor + 1)) { that._playCursor = -1; } if (that._playIndex.length > (that._playCursor + 1)) { that._playerPlay(that._playIndex[++that._playCursor]); } else { that._playerStop(); } break; case that._statesRepeat.one: that._playerPlay(that._playIndex[that._playCursor]); break; } } , _playPrevious: function () { var that = this ; switch (that._stateRepeat) { case that._statesRepeat.all: case that._statesRepeat.none: if (that._stateRepeat === that._statesRepeat.all && that._playCursor === 0) { that._playCursor = that._playIndex.length; } if (that._playCursor > 0) { that._playerPlay(that._playIndex[--that._playCursor]); } else { that._playerStop(); } break; case that._statesRepeat.one: that._playerPlay(that._playIndex[that._playCursor]); break; } } , _playerPause: function () { var that = this ; that.webAudio.obj.pause(); } , _playerUnpause: function () { var that = this ; that.webAudio.obj.play(); } , _playerStop: function () { var that = this ; that.webAudio.obj.pause(); that.webAudio.obj.src = ""; that.webAudio.obj.innetHTML = ""; that._playCursor = -1; that._setViewport(); } , _playerStart: function () { var that = this ; } , _getVolume: function () { var that = this ; return that.webAudio.obj.volume; } , _setVolume: function (volume) { var that = this ; that.$elVolumeInput.val(volume); return that.webAudio.obj.volume = volume; } , _seek: function (seek) { var that = this ; if (that.webAudio._state === that.webAudio._states.playing) { console.debug("Seeking player to " + seek); that.webAudio.obj.currentTime = seek; } } // Viewport methods , _playBtnSetState: function (state) { var that = this , $btn = that.$el.find("a.buttonPlay"); $btn.removeClass("paused"); $btn.removeClass("playing"); $btn.removeClass("stopped"); switch (state) { case that.webAudio._states.stopped: case that.webAudio._states.paused: $btn.addClass("paused"); break; case that.webAudio._states.loading: case that.webAudio._states.ready: case that.webAudio._states.playing: $btn.addClass("playing"); break; case -1: $btn.addClass("stopped"); break; } } , _disableControls: function () { var that = this ; that.$el.find(".enabled").addClass("disabled"); that.$el.find(".enabled").removeClass("enabled"); that.$el.find("[enabled]").attr("disabled", true); that.$el.find("[enabled]").removeAttr("enabled"); //that.$el.find("progress").attr("disabled", true); } , _enableControls: function () { var that = this ; that.$el.find(".disabled").addClass("enabled"); that.$el.find(".disabled").removeClass("disabled"); that.$el.find("[disabled]").attr("enabled", true); that.$el.find("[disabled]").removeAttr("disabled"); //that.$el.find("progress").removeAttr("disabled"); } /*, _getItemData: function (item) { var that = this ; console.log(that.options.servers.get(item.hostname).client.collections); return that.options.servers.get(item.hostname).client.collections.databases[item.id].get("dmap_listing").get(item.dbId); } */ , _getItemMediaUrl: function (item) { var that = this ; return that.options.servers.get(item.hostname).client.urlMedia(item.id, item.type, item.dbId); } , _setViewport: function (item) { var that = this ; item = item || {}; that.$elViewport.html(_.template(tmplPlayerStatus)(item)); } , _progressSetLoadding: function () { var that = this , $progress = that.$el.find(".playerProgressWrapper > progress") ; $progress.removeAttr("value"); $progress.attr("disabled", true); } , _updateViewportProgress: function (progress, time) { var that = this ; progress = progress || 0; time = time || 1; if (that.$el.find("> .playerProgressWrapper")) { var left = (time - progress) , frac = progress / time , precent = frac * 100 , elapsed = Math.floor(progress / 60).toFixed().pad(2, "0") + ":" + (progress % 60).toFixed().pad(2, "0") , remain = "-" + Math.floor(left / 60).toFixed().pad(2, "0") + ":" + (left % 60).toFixed().pad(2, "0") , $progress = that.$el.find(".playerProgressWrapper > progress") ; that.$el.find(".playerProgressWrapper > span:first-child").text(elapsed); that.$el.find(".playerProgressWrapper > span:last-child").text(remain); $progress.removeAttr("disabled"); $progress.val(frac); } } }); return Player; });