API Documentation for: 2.1.0
Show:

File:VOPlayer.js

/**
*  @module cloudkid
*/
(function() {

	"use strict";
	
	// Class Imports, we'll actually include them in the constructor
	// in case these classes were included after in the load-order
	var Captions,
		Audio,
		OS;

	/**
	*	A class for managing audio by only playing one at a time, playing a list, and even
	*	managing captions (CloudKidCaptions library) at the same time.
	*	@class VOPlayer
	*	@constructor
	*	@param {bool|cloudkid.Captions} [useCaptions=false] If a cloudkid.Captions object should be created for use 
	*			or the captions object to use
	*/
	var VOPlayer = function(useCaptions)
	{
		// Import classes
		Captions = cloudkid.Captions;
		Audio = cloudkid.Audio;
		OS = cloudkid.OS;

		this._audioListener = this._onAudioFinished.bind(this);
		this._update = this._update.bind(this);
		this._updateCaptionPos = this._updateCaptionPos.bind(this);

		if (useCaptions)
		{
			this.captions = useCaptions instanceof Captions ? useCaptions : new Captions();
			this.captions.isSlave = true;
		}
		this._listHelper = [];
	};
	
	// Reference to the prototype
	var p = VOPlayer.prototype = {};
	
	/**
	*  The OS update callback alias for the VOPlayer
	*  @property {String} ALIAS
	*  @static
	*  @final
	*  @private
	*/
	var ALIAS = "VOPlayer";

	/**
	*	The current list of audio/silence times/functions. Generally you will not need to modify this.
	*	@property {Array} audioList
	*	@public
	*/
	p.audioList = null;

	/**
	*	The current position in audioList.
	*	@property {int} _listCounter
	*	@private
	*/
	p._listCounter = 0;

	/**
	*	The current audio alias being played.
	*	@property {String} _currentAudio
	*	@private
	*/
	p._currentAudio = null;

	/**
	*	The current audio instance being played.
	*	@property {SoundInst} _audioInst
	*	@private
	*/
	p._audioInst = null;

	/**
	*	The callback for when the list is finished.
	*	@property {function} _callback
	*	@private
	*/
	p._callback = null;

	/**
	*	The callback for when the list is interrupted for any reason.
	*	@property {function} _cancelledCallback
	*	@private
	*/
	p._cancelledCallback = null;

	/**
	*	The bound _onAudioFinished call.
	*	@property {function} _audioListener
	*	@private
	*/
	p._audioListener = null;

	/**
	*	A timer for silence entries in the list, in milliseconds.
	*	@property {int} _timer
	*	@private
	*/
	p._timer = 0;

	/**
	*	The cloudkid.Captions object used for captions. The developer is responsible for initializing this with a captions
	*	dictionary config file and a reference to a text field.
	*	@property {cloudkid.Captions} captions
	*	@public
	*/
	p.captions = null;

	/**
	*	An Array used when play() is called to avoid creating lots of Array objects.
	*	@property {Array} _listHelper
	*	@private
	*/
	p._listHelper = null;

	/**
	*	If VOPlayer is currently playing (audio or silence).
	*	@property {bool} playing
	*	@public
	*	@readOnly
	*/
	Object.defineProperty(p, "playing",
	{
		get: function() { return this._currentAudio !== null || this._timer > 0; }
	});
	
	/**
	*	Plays a single audio alias, interrupting any current playback.
	*	@method play
	*	@public
	*	@param {String} id The alias of the audio file to play.
	*	@param {function} callback The function to call when playback is complete.
	*	@param {function} cancelledCallback The function to call when playback is interrupted with a stop(), play() or playList() call.
	*/
	p.play = function(id, callback, cancelledCallback)
	{
		this.stop();
		this._listCounter = -1;
		this._listHelper[0] = id;
		this.audioList = this._listHelper;
		this._callback = callback;
		this._cancelledCallback = cancelledCallback;
		this._onAudioFinished();
	};
	
	/**
	*	Plays a list of audio files, timers, and/or functions, interrupting any current playback.
	*	Audio in the list will be preloaded to minimize pauses for loading.
	*	@method playList
	*	@public
	*	@param {Array} list The array of items to play/call in order.
	*	@param {function} callback The function to call when playback is complete.
	*	@param {function} cancelledCallback The function to call when playback is interrupted with a stop(), play() or playList() call.
	*/
	p.playList = function(list, callback, cancelledCallback)
	{
		this.stop();
		this._listCounter = -1;
		this.audioList = list;
		this._callback = callback;
		this._cancelledCallback = cancelledCallback;
		this._onAudioFinished();
	};
	
	/**
	*	Callback for when audio/timer is finished to advance to the next item in the list.
	*	@method _onAudioFinished
	*	@private
	*/
	p._onAudioFinished = function()
	{
		//remove any update callback
		OS.instance.removeUpdateCallback(ALIAS);

		//if we have captions and an audio instance, set the caption time to the length of the audio
		if (this.captions && this._audioInst)
		{
			this.captions.seek(this._audioInst.length);
		}
		//clear the audio instance
		this._audioInst = null;

		//advance list
		this._listCounter++;

		//if the list is complete
		if (this._listCounter >= this.audioList.length)
		{
			if (this.captions)
			{
				this.captions.stop();
			}
			this._currentAudio = null;
			this._cancelledCallback = null;
			var c = this._callback;
			this._callback = null;
			if (c) c();
		}
		else
		{
			this._currentAudio = this.audioList[this._listCounter];

			if (typeof this._currentAudio == "string")
			{
				//If the sound doesn't exist, then we play it and let it fail, 
				// an error should be shown and playback will continue
				this._playAudio();
			}
			else if (typeof this._currentAudio == "function")
			{
				//call function
				this._currentAudio();

				//immediately continue
				this._onAudioFinished();
			}
			else
			{
				//set up a timer to wait
				this._timer = this._currentAudio;
				this._currentAudio = null;
				OS.instance.addUpdateCallback(ALIAS, this._update);
			}
		}
	};

	/**
	*	The update callback used for silence timers and updating captions without active audio.
	*	This method is bound to the VOPlayer instance.
	*	@method _update
	*	@private
	*	@param {int} elapsed The time elapsed since the previous frame, in milliseconds.
	*/
	p._update = function(elapsed)
	{
		if (this.captions)
		{
			this.captions.updateTime(elapsed);
		}
		this._timer -= elapsed;
		if (this._timer <= 0)
		{
			this._onAudioFinished();
		}
	};

	/**
	*	The update callback used for updating captions with active audio.
	*	This method is bound to the VOPlayer instance.
	*	@method _updateCaptionPos
	*	@private
	*	@param {int} elapsed The time elapsed since the previous frame, in milliseconds.
	*/
	p._updateCaptionPos = function(elapsed)
	{
		if (!this._audioInst) return;
		this.captions.seek(this._audioInst.position);
	};

	/** 
	*	Plays the current audio item and begins preloading the next item.
	*	@method _playAudio
	*	@private
	*/
	p._playAudio = function()
	{
		var s = Audio.instance;
		if (!s.hasAlias(this._currentAudio) && this.captions && this.captions.hasCaption(this._currentAudio))
		{
			this.captions.play(this._currentAudio);
			this._timer = this.captions.currentDuration;
			this._currentAudio = null;
			OS.instance.addUpdateCallback(ALIAS, this._update);
		}
		else
		{
			this._audioInst = s.play(this._currentAudio, this._audioListener);
			if (this.captions)
			{
				this.captions.play(this._currentAudio);
				OS.instance.addUpdateCallback(ALIAS, this._updateCaptionPos);
			}
		}
	};
	
	/**
	*	Stops playback of any audio/timer.
	*	@method stop
	*	@public
	*/
	p.stop = function()
	{
		if (this._currentAudio)
		{
			Audio.instance.stop();
			this._currentAudio = null;
		}
		if (this.captions)
		{
			this.captions.stop();
		}
		OS.instance.removeUpdateCallback(ALIAS);
		this.audioList = null;
		this._timer = 0;
		this._callback = null;
		var c = this._cancelledCallback;
		this._cancelledCallback = null;
		if (c) c();
	};

	/**
	*	Cleans up this VOPlayer.
	*	@method destroy
	*	@public
	*/
	p.destroy = function()
	{
		this.stop();
		this.audioList = null;
		this._listHelper = null;
		this._currentAudio = null;
		this._audioInst = null;
		this._callback = null;
		this._cancelledCallback = null;
		this._audioListener = null;

		if (this.captions)
		{
			this.captions.destroy();
			this.captions = null;
		}
	};
	
	// Assign to the global namespace
	namespace('cloudkid').VOPlayer = VOPlayer;

}());