/**
* The FORGE.PlaylistManager is an object that manages playlists of the project.
*
* @constructor FORGE.PlaylistManager
* @param {FORGE.Viewer} viewer - {@link FORGE.Viewer} reference.
* @extends {FORGE.BaseObject}
*
* @todo previous/next playlist
* @todo real keepAudio to resume a "lost sound"
* @todo preload of all sounds
*/
FORGE.PlaylistManager = function(viewer)
{
/**
* The viewer reference.
* @name FORGE.PlaylistManager#_viewer
* @type {FORGE.Viewer}
* @private
*/
this._viewer = viewer;
/**
* The general config backup.
* @name FORGE.PalylistManager#_config
* @type {?AudioPlaylistsConfig}
* @private
*/
this._config = null;
/**
* Array of {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#_playlists
* @type {?Array<FORGE.Playlist>}
* @private
*/
this._playlists = null;
/**
* The tracks list object.
* @name FORGE.PlaylistManager#_tracks
* @type {?Array<FORGE.PlaylistTrack>}
* @private
*/
this._tracks = null;
/**
* Uid of the current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#_playlistUID
* @type {string}
* @private
*/
this._playlistUID = "";
/**
* The default playlist uid.
* @name FORGE.PlaylistManager#_defaultList
* @type {string}
* @private
*/
this._defaultList = "";
/**
* The maximum volume for all playlists.
* @name FORGE.PlaylistManager#_maxVolume
* @type {number}
* @private
*/
this._maxVolume = 1;
/**
* The current volume for all the playlists.
* @name FORGE.PlaylistManager#_volume
* @type {number}
* @private
*/
this._volume = 1;
/**
* Is the playlist manager enabled?
* @name FORGE.PlaylistManager#_enabled
* @type {boolean}
* @private
*/
this._enabled = true;
/**
* Tracks must be preloaded?
* @name FORGE.PlaylistManager#_preload
* @type {boolean}
* @private
*/
this._preload = false;
/**
* Is the playlistManager paused?
* @name FORGE.PlaylistManager#_paused
* @type {boolean}
* @private
*/
this._paused = false;
/**
* On playlist manager ready event dispatcher.
* @name FORGE.Sound#_onReady
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onReady = null;
/**
* On playlist manager play event dispatcher.
* @name FORGE.PlaylistManager#_onPlay
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onPlay = null;
/**
* On playlist manager stop event dispatcher.
* @name FORGE.PlaylistManager#_onStop
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onStop = null;
/**
* On playlist manager pause event dispatcher.
* @name FORGE.PlaylistManager#_onPause
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onPause = null;
/**
* On playlist manager resume event dispatcher.
* @name FORGE.PlaylistManager#_onResume
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onResume = null;
/**
* On playlist manager ended event dispatcher.
* @name FORGE.PlaylistManager#_onEnded
* @type {?FORGE.EventDispatcher}
* @private
*/
this._onEnded = null;
FORGE.BaseObject.call(this, "PlaylistManager");
};
FORGE.PlaylistManager.prototype = Object.create(FORGE.BaseObject.prototype);
FORGE.PlaylistManager.prototype.constructor = FORGE.PlaylistManager;
/**
* Boot sequence.
* @method FORGE.PlaylistManager#boot
*/
FORGE.PlaylistManager.prototype.boot = function()
{
this._playlists = [];
this._tracks = [];
this._viewer.audio.onEnable.add(this._enableSoundHandler, this);
this._viewer.story.onSceneLoadStart.add(this._sceneLoadStartHandler, this);
};
/**
* Enable handler the sound manager.
* @method FORGE.PlaylistManager#_enableSoundHandler
* @private
*/
FORGE.PlaylistManager.prototype._enableSoundHandler = function()
{
if(this._enabled === true && this._playlists.length > 0 && this.ready === true && this.decoded === true && this._paused === false)
{
if(this.paused === true)
{
this.resume();
}
else if(this.playing === false)
{
this.play();
}
}
};
/**
* Event handler for scene start.
* @method FORGE.PlaylistManager#_sceneLoadStartHandler
* @private
*/
FORGE.PlaylistManager.prototype._sceneLoadStartHandler = function()
{
if(typeof this._viewer.story.scene.config.playlists !== "undefined")
{
this._parseSceneConfig(this._viewer.story.scene.config.playlists);
}
else
{
//restore global playlists config
this._applyConfig(this._config);
if(this._paused === false && this._defaultList !== this._playlistUID)
{
if(this._enabled === false || this.ready === false || this.decoded === false || this.playing === true)
{
this._stopScenePlaylist();
}
//load the default playlist of the global audio if exists
this._startScenePlaylist(this._defaultList);
}
}
};
/**
* Parse the scene configuration part related to playlist.
* @method FORGE.PlaylistManager#_parseSceneConfig
* @private
* @param {AudioPlaylistsConfig} config - The scene configuration part related to playlist.
*/
FORGE.PlaylistManager.prototype._parseSceneConfig = function(config)
{
var extendedConfig = /** @type {AudioPlaylistsConfig} */ FORGE.Utils.extendMultipleObjects(this._config, config);
this._applyConfig(extendedConfig);
if(this._paused === false)
{
if(this._enabled === false)
{
this._stopScenePlaylist();
}
else
{
if(!this._startScenePlaylist(this._defaultList))
{
if(this.playing === true)
{
this._stopScenePlaylist();
}
}
}
}
};
/**
* Set values from configuration file.
* @method FORGE.PlaylistManager#_applyConfig
* @param {?AudioPlaylistsConfig} config - The config file.
* @private
*/
FORGE.PlaylistManager.prototype._applyConfig = function(config)
{
if(config !== null)
{
this._enabled = typeof config.enabled !== "undefined" ? Boolean(config.enabled) : true;
if (typeof config.default !== "undefined")
{
if (typeof config.default === "string" && config.default !== "")
{
this._defaultList = config.default;
}
else if (typeof config.default === "number" && config.default >= 0 && config.default < this._playlists.length)
{
this._defaultList = this._playlists[config.default].uid;
}
}
this._maxVolume = (typeof config.volume !== "undefined" && typeof config.volume.max === "number") ? FORGE.Math.clamp(config.volume.max, 0, 1) : 1;
this._volume = (typeof config.volume !== "undefined" && typeof config.volume.default === "number") ? FORGE.Math.clamp(config.volume.default, 0, this._maxVolume) : FORGE.Math.clamp(1, 0, this._maxVolume);
}
};
/**
* Add a playlist config to the manager.
* @method FORGE.PlaylistManager#addConfig
* @param {AudioPlaylistsConfig} config - The config you want to add.
*/
FORGE.PlaylistManager.prototype.addConfig = function(config)
{
this._parseConfig(config);
this._initPlaylist();
};
/**
* Parse a playlist config object.
* @method FORGE.PlaylistManager#_parseConfig
* @private
* @param {AudioPlaylistsConfig} config - The config you want to parse.
*/
FORGE.PlaylistManager.prototype._parseConfig = function(config)
{
var playlist, track;
this._config = config;
if(typeof config.lists !== "undefined")
{
for(var i = 0, ii = config.lists.length; i<ii; i++)
{
playlist = new FORGE.Playlist(this._viewer, config.lists[i]);
this.add(playlist);
}
}
if(typeof config.tracks !== "undefined")
{
for(var j = 0, jj = config.tracks.length; j<jj; j++)
{
track = new FORGE.PlaylistTrack(this._viewer, config.tracks[j]);
this.addTrack(track);
if(this._preload === true)
{
// @todo manage preload queue
this.warn("Preload is not supported yet.");
}
}
}
this._applyConfig(config);
if(typeof config.lists !== "undefined" && config.lists.length > 0)
{
if (this._defaultList === "")
{
this.warn("The playlist manager has a default playlist that is not in its playlists array!");
}
this._playlistUID = this._defaultList;
}
};
/**
* Initialize the default playlist.
* @method FORGE.PlaylistManager#_initPlaylist
* @private
*/
FORGE.PlaylistManager.prototype._initPlaylist = function()
{
// If the page is not visible at init, report it later
if (document[FORGE.Device.visibilityState] !== "visible")
{
this._viewer.onResume.addOnce(this._initPlaylist, this);
return;
}
if(this._playlists.length <= 0)
{
return;
}
var uid;
if(typeof this._defaultList === "string" && this._defaultList !== "")
{
uid = this._defaultList;
}
else
{
uid = this._playlists[0].uid;
}
if(FORGE.UID.get(uid) === undefined)
{
this.warn("PlaylistManager : uid \""+uid+"\" is not into playlists");
}
if(FORGE.UID.isTypeOf(uid, "Playlist") === true)
{
this.play(uid, true);
}
else
{
this.warn("Impossible to play the playlist with uid "+uid+", it doesn't seem to be a playlist!");
}
};
/**
* Start or resume a playlist for a specific scene.
* @method FORGE.PlaylistManager#_startScenePlaylist
* @param {string} playlistUID - The default playlist uid.
* @return {boolean} Returns true if the playlist is found.
* @private
*/
FORGE.PlaylistManager.prototype._startScenePlaylist = function(playlistUID)
{
if(playlistUID !== null && FORGE.UID.isTypeOf(playlistUID, "Playlist") === true)
{
//Maybe the new scene shares the same playlist so we do not reset the playback
if(this.playlist !== null && this.playlist.uid === playlistUID)
{
if(this.playlist.track !== null && (typeof this.playlist.track.uid !== "undefined" && this.playlist.track.uid !== ""))
{
if(this.paused === true)
{
this.resume();
}
else if(this.playing === false)
{
this.play(playlistUID, true);
}
}
else
{
this.stop();
this.play(playlistUID, true);
}
}
else
{
this.stop();
this.play(playlistUID, true);
}
return true;
}
return false;
};
/**
* Stop or pause a playlist.
* @method FORGE.PlaylistManager#_stopScenePlaylist
* @private
*/
FORGE.PlaylistManager.prototype._stopScenePlaylist = function()
{
if(this.playing === true)
{
this.pause();
}
else
{
this.stop();
}
};
/**
* Dispatch play event and notify it to the playlist
* @method FORGE.PlaylistManager#_notifyPlay
* @private
*/
FORGE.PlaylistManager.prototype._notifyPlay = function()
{
if(this._onPlay !== null)
{
this._onPlay.dispatch();
}
if(this.playlist !== null)
{
FORGE.Playlist.prototype._notifyPlay.call(this.playlist);
}
};
/**
* Dispatch stop event and notify it to the playlist
* @method FORGE.PlaylistManager#_notifyStop
* @private
*/
FORGE.PlaylistManager.prototype._notifyStop = function()
{
if(this._onStop !== null)
{
this._onStop.dispatch();
}
if(this.playlist !== null)
{
FORGE.Playlist.prototype._notifyStop.call(this.playlist);
}
};
/**
* Dispatch pause event and notify it to the playlist
* @method FORGE.PlaylistManager#_notifyPause
* @private
*/
FORGE.PlaylistManager.prototype._notifyPause = function()
{
if(this._onPause !== null)
{
this._onPause.dispatch();
}
if(this.playlist !== null)
{
FORGE.Playlist.prototype._notifyPause.call(this.playlist);
}
};
/**
* Dispatch resume event and notify it to the playlist
* @method FORGE.PlaylistManager#_notifyResume
* @private
*/
FORGE.PlaylistManager.prototype._notifyResume = function()
{
if(this._onResume !== null)
{
this._onResume.dispatch();
}
if(this.playlist !== null)
{
FORGE.Playlist.prototype._notifyResume.call(this.playlist);
}
};
/**
* Dispatch ended event and notify it to the playlist
* @method FORGE.PlaylistManager#_notifyEnded
* @private
*/
FORGE.PlaylistManager.prototype._notifyEnded = function()
{
if(this._onEnded !== null)
{
this._onEnded.dispatch();
}
if(this.playlist !== null)
{
FORGE.Playlist.prototype._notifyEnded.call(this.playlist);
}
};
/**
* Add a {@link FORGE.Playlist} to the playlist manager.
* @method FORGE.PlaylistManager#add
* @param {FORGE.Playlist} playlist - The {@link FORGE.Playlist} you want to add.
*/
FORGE.PlaylistManager.prototype.add = function(playlist)
{
this._playlists.push(playlist);
};
/**
* Add a {@link FORGE.PlaylistTrack} to the playlist manager.
* @method FORGE.PlaylistManager#addTrack
* @param {FORGE.PlaylistTrack} track - The {@link FORGE.PlaylistTrack} you want to add.
*/
FORGE.PlaylistManager.prototype.addTrack = function(track)
{
this._tracks.push(track);
};
/**
* Know if the project have any {@link FORGE.Playlist}.
* @method FORGE.PlaylistManager#hasPlaylists
* @return {boolean} Returns true if the project has at least a {@link FORGE.Playlist}, false if not.
*/
FORGE.PlaylistManager.prototype.hasPlaylists = function()
{
return this._playlists.length !== 0;
};
/**
* Know if the project have any {@link FORGE.PlaylistTrack}.
* @method FORGE.PlaylistManager#hasTracks
* @return {boolean} Returns true if the project has at least a {@link FORGE.PlaylistTrack}, false if not.
*/
FORGE.PlaylistManager.prototype.hasTracks = function()
{
return this._tracks.length !== 0;
};
/**
* Play the current playlist or a specific one at a specific track.
* @method FORGE.PlaylistManager#play
* @param {FORGE.Playlist|string|number=} playlist - The {@link FORGE.Playlist} you want to play or its uid or its index.
* @param {boolean=} checkAutoPlay - Set to true if the autoPlay status of the playlist must be checked.
*/
FORGE.PlaylistManager.prototype.play = function(playlist, checkAutoPlay)
{
var uid;
if(typeof playlist === "string" && FORGE.UID.isTypeOf(playlist, "Playlist"))
{
uid = playlist;
}
else if(FORGE.Utils.isTypeOf(playlist, "Playlist"))
{
uid = playlist.uid;
}
else if (typeof playlist === "number" && playlist >= 0 && playlist < this._playlists.length)
{
uid = this._playlists[playlist].uid;
}
else if(this._playlistUID !== "")
{
uid = this._playlistUID;
}
else if(typeof playlist === "undefined" || playlist === "")
{
uid = this._playlists[0].uid;
}
if(typeof uid !== "undefined")
{
if(this.playing === true)
{
this.stop();
}
this._playlistUID = uid;
if(this._enabled === true)
{
this._paused = false;
this.playlist.play(null, checkAutoPlay);
this.log("FORGE.PlaylistManager.play(); [uid: "+this._playlistUID+"]");
}
}
};
/**
* Stop the current {@link FORGE.Playlist}.
* @method FORGE.PlaylistManager#play
*/
FORGE.PlaylistManager.prototype.stop = function()
{
if(this.playlist !== null)
{
this.playlist.stop();
}
};
/**
* Pause the current {@link FORGE.Playlist}.
* @method FORGE.PlaylistManager#pause
*/
FORGE.PlaylistManager.prototype.pause = function()
{
if(this.playlist !== null && this.playlist.playing === true)
{
this._paused = true;
this.playlist.pause();
}
};
/**
* Resume the current {@link FORGE.Playlist}.
* @method FORGE.PlaylistManager#resume
*/
FORGE.PlaylistManager.prototype.resume = function()
{
if(this.playlist !== null && this._enabled === true && this.playlist.paused === true)
{
var isPaused = this._paused;
this._paused = false;
if (isPaused === true && this._defaultList !== this._playlistUID)
{
this._startScenePlaylist(this._defaultList);
}
else
{
this.playlist.resume();
}
}
};
/**
* Set the next {@link FORGE.PlaylistTrack} of the current {@link FORGE.Playlist} to be the current track.<br>
* If the playlist is paused, keep the pause status of the playlist.
* @method FORGE.PlaylistManager#nextTrack
*/
FORGE.PlaylistManager.prototype.nextTrack = function()
{
if(this.playlist !== null && this._enabled === true)
{
this.playlist.nextTrack();
}
};
/**
* Set the previous {@link FORGE.PlaylistTrack} of the current {@link FORGE.Playlist} to be the current track.<br>
* If the playlist is paused, keep the pause status of the playlist.
* @method FORGE.PlaylistManager#previousTrack
*/
FORGE.PlaylistManager.prototype.previousTrack = function()
{
if(this.playlist !== null && this._enabled === true)
{
this.playlist.previousTrack();
}
};
/**
* Destroy sequence
* @method FORGE.PlaylistManager#destroy
*/
FORGE.PlaylistManager.prototype.destroy = function()
{
this.stop();
this._viewer.audio.onEnable.remove(this._enableSoundHandler, this);
this._viewer.story.onSceneLoadStart.remove(this._sceneLoadStartHandler, this);
this._viewer = null;
this._config = null;
var i = this._playlists.length;
while(i--)
{
this._playlists[i].destroy();
}
this._playlists = null;
var j = this._tracks.length;
while(j--)
{
this._tracks[j].destroy();
}
this._tracks = null;
FORGE.BaseObject.prototype.destroy.call(this);
};
/**
* Get the playlists Array.
* @name FORGE.PlaylistManager#playlists
* @readonly
* @type {Array<FORGE.Playlist>}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "playlists",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
return this._playlists;
}
});
/**
* Get the tracks Array.
* @name FORGE.PlaylistManager#tracks
* @readonly
* @type {Array<FORGE.Playlist>}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "tracks",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
return this._tracks;
}
});
/**
* Get the current playlist.
* @name FORGE.PlaylistManager#playlist
* @readonly
* @type {?FORGE.Playlist}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "playlist",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(FORGE.UID.isTypeOf(this._playlistUID, "Playlist") === true)
{
return FORGE.UID.get(this._playlistUID, "Playlist");
}
return null;
}
});
/**
* Get the loop status of the current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#loop
* @type {boolean}
* @readonly
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "loop",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.loop;
}
return true; // default state is true
}
});
/**
* Get the auto play status of the current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#autoPlay
* @type {boolean}
* @readonly
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "autoPlay",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.autoPlay;
}
return true; // default state is true
}
});
/**
* Preload status of audio files.
* @name FORGE.PlaylistManager#preload
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "preload",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
return this._preload;
},
/** @this {FORGE.PlaylistManager} */
set: function(value)
{
this._preload = Boolean(value);
}
});
/**
* Get the enabled status of the playlists manager.
* @name FORGE.PlaylistManager#enabled
* @readonly
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "enabled",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
return this._enabled;
}
});
/**
* Get the ready status of current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#ready
* @readonly
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "ready",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.ready;
}
return false;
}
});
/**
* Get the decoded status of current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#decoded
* @readonly
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "decoded",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.decoded;
}
return false;
}
});
/**
* Get the playing status of current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#playing
* @readonly
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "playing",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.playing;
}
return false;
}
});
/**
* Get the pause status of current {@link FORGE.Playlist}.
* @name FORGE.PlaylistManager#paused
* @readonly
* @type {boolean}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "paused",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this.playlist !== null)
{
return this.playlist.paused;
}
return false;
}
});
/**
* Get the playlist manager main volume.
* @name FORGE.PlaylistManager#volume
* @type {number}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "volume",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
return this._volume;
},
/** @this {FORGE.PlaylistManager} */
set: function(value)
{
if(typeof value !== "number")
{
return;
}
value = FORGE.Math.clamp(value, 0, 1);
if(this._maxVolume < value)
{
this._volume = this._maxVolume;
}
else
{
this._volume = value;
}
if(FORGE.UID.isTypeOf(this._playlistUID, "Playlist") === true)
{
var playlist = FORGE.UID.get(this._playlistUID, "Playlist");
if(playlist !== null)
{
var track = playlist.track;
if(track !== null)
{
track.volume = playlist.volume * this._volume;
}
}
}
}
});
/**
* Get the "onReady" event {@link FORGE.EventDispatcher} of the playlist.
* @name FORGE.PlaylistManager#onReady
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onReady",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onReady === null)
{
this._onReady = new FORGE.EventDispatcher(this);
}
return this._onReady;
}
});
/**
* Get the "onPlay" event {@link FORGE.EventDispatcher} of the track.
* @name FORGE.PlaylistManager#onPlay
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onPlay",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onPlay === null)
{
this._onPlay = new FORGE.EventDispatcher(this);
}
return this._onPlay;
}
});
/**
* Get the "onStop" event {@link FORGE.EventDispatcher} of the track.
* @name FORGE.PlaylistManager#onStop
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onStop",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onStop === null)
{
this._onStop = new FORGE.EventDispatcher(this);
}
return this._onStop;
}
});
/**
* Get the "onPause" event {@link FORGE.EventDispatcher} of the track.
* @name FORGE.PlaylistManager#onPause
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onPause",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onPause === null)
{
this._onPause = new FORGE.EventDispatcher(this);
}
return this._onPause;
}
});
/**
* Get the "onResume" event {@link FORGE.EventDispatcher} of the track.
* @name FORGE.PlaylistManager#onResume
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onResume",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onResume === null)
{
this._onResume = new FORGE.EventDispatcher(this);
}
return this._onResume;
}
});
/**
* Get the "onEnded" event {@link FORGE.EventDispatcher} of the track.
* @name FORGE.PlaylistManager#onEndedd
* @readonly
* @type {FORGE.EventDispatcher}
*/
Object.defineProperty(FORGE.PlaylistManager.prototype, "onEnded",
{
/** @this {FORGE.PlaylistManager} */
get: function()
{
if(this._onEnded === null)
{
this._onEnded = new FORGE.EventDispatcher(this);
}
return this._onEnded;
}
});