API Documentation for: 1.0.0
Show:

File:FlashAudioPlugin.js

/*
 * FlashAudioPlugin
 * Visit http://createjs.com/ for documentation, updates and examples.
 *
 *
 * Copyright (c) 2012 gskinner.com, inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @module SoundJS
 */

// namespace:
this.createjs = this.createjs || {};

(function () {

	"use strict";

	/**
	 * Play sounds using a Flash instance. This plugin is not used by default, and must be registered manually in
	 * {{#crossLink "Sound"}}{{/crossLink}} using the {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} method. This
	 * plugin is recommended to be included if sound support is required in older browsers such as IE8.
	 *
	 * This plugin requires FlashAudioPlugin.swf and swfObject.js, which is compiled
	 * into the minified FlashAudioPlugin-X.X.X.min.js file. You must ensure that {{#crossLink "FlashAudioPlugin/swfPath:property"}}{{/crossLink}}
	 * is set when using this plugin, so that the script can find the swf.
	 *
	 * <h4>Example</h4>
	 *
	 *      createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio";
	 *      createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]);
	 *      // Adds FlashAudioPlugin as a fallback if WebAudio and HTMLAudio do not work.
	 *
	 * Note that the SWF is embedded into a container DIV (with an id and classname of "SoundJSFlashContainer"), and
	 * will have an id of "flashAudioContainer". The container DIV is positioned 1 pixel off-screen to the left to avoid
	 * showing the 1x1 pixel white square.
	 *
	 * <h4>Known Browser and OS issues for Flash Audio</h4>
	 * <b>All browsers</b><br />
	 * <ul><li> There can be a delay in flash player starting playback of audio.  This has been most noticeable in Firefox.
	 * Unfortunely this is an issue with the flash player and the browser and therefore cannot be addressed by SoundJS.</li></ul>
	 *
	 * @class FlashAudioPlugin
	 * @extends AbstractPlugin
	 * @constructor
	 */
	function FlashAudioPlugin() {
		this.AbstractPlugin_constructor();


// Public Properties
		/**
		 * A developer flag to output all flash events to the console (if it exists).  Used for debugging.
		 *
		 *      createjs.Sound.activePlugin.showOutput = true;
		 *
		 * @property showOutput
		 * @type {Boolean}
		 * @default false
		 */
		this.showOutput = false;


//Private Properties
		/**
		 * The id name of the DIV that gets created for Flash content.
		 * @property _CONTAINER_ID
		 * @type {String}
		 * @default flashAudioContainer
		 * @protected
		 */
		this._CONTAINER_ID = "flashAudioContainer";

		/**
		 * The id name of the DIV wrapper that contains the Flash content.
		 * @property _WRAPPER_ID
		 * @type {String}
		 * @default SoundJSFlashContainer
		 * @protected
		 * @since 0.4.1
		 */
		this._WRAPPER_ID = "SoundJSFlashContainer";

		/**
		 * A reference to the DIV container that gets created to hold the Flash instance.
		 * @property _container
		 * @type {HTMLDivElement}
		 * @protected
		 */
		this._container = null,

		/**
		 * A reference to the Flash instance that gets created.
		 * @property flash
		 * @type {Object | Embed}
		 * @protected
		 */
		this._flash = null;

		/**
		 * Determines if the Flash object has been created and initialized. This is required to make <code>ExternalInterface</code>
		 * calls from JavaScript to Flash.
		 * @property flashReady
		 * @type {Boolean}
		 * @default false
		 */
		this.flashReady = false;

		/**
		 * A hash of SoundInstances indexed by the related ID in Flash. This lookup is required to connect sounds in
		 * JavaScript to their respective instances in Flash.
		 * @property _flashInstances
		 * @type {Object}
		 * @protected
		 */
		this._flashInstances = {};

		/**
		 * A hash of Sound Preload instances indexed by the related ID in Flash. This lookup is required to connect
		 * a preloading sound in Flash with its respective instance in JavaScript.
		 * @property _flashPreloadInstances
		 * @type {Object}
		 * @protected
		 */
		this._flashPreloadInstances = {};
		//TODO consider combining _flashInstances and _flashPreloadInstances into a single hash

		this._capabilities = s._capabilities;

		this._loaderClass = createjs.FlashAudioLoader;
		this._soundInstanceClass = createjs.FlashAudioSoundInstance;

		// Create DIV
		var w = this.wrapper = document.createElement("div");
		w.id = this._WRAPPER_ID;
		w.style.position = "absolute";
		w.style.marginLeft = "-1px";
		w.className = this._WRAPPER_ID;
		document.body.appendChild(w);

		// Create Placeholder
		var c = this._container = document.createElement("div");
		c.id = this._CONTAINER_ID;
		c.appendChild(document.createTextNode("SoundJS Flash Container"));
		w.appendChild(c);

		var path = s.swfPath;
		var val = swfobject.embedSWF(path + "FlashAudioPlugin.swf", this._CONTAINER_ID, "1", "1",
				"9.0.0", null, null, {"AllowScriptAccess" : "always"}, null,
				createjs.proxy(this._handleSWFReady, this)
		);
	};

	var p = createjs.extend(FlashAudioPlugin, createjs.AbstractPlugin);
	var s = FlashAudioPlugin;

// Static properties
	/**
	 * Event constant for the "registerFlashID" event for cleaner code.
	 * @property _REG_FLASHID
	 * @type {String}
	 * @default registerflashid
	 * @static
	 * @private
	 */
	s._REG_FLASHID = "registerflashid";

	/**
	 * Event constant for the "unregisterFlashID" event for cleaner code.
	 * @property _UNREG_FLASHID
	 * @type {String}
	 * @default unregisterflashid
	 * @static
	 * @private
	 */
	s._UNREG_FLASHID = "unregisterflashid";

	/**
	 * The capabilities of the plugin. This is generated via the {{#crossLink "WebAudioPlugin/_generateCapabilities"}}{{/crossLink}}
	 * method. Please see the Sound {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} method for a list of available
	 * capabilities.
	 * @property _capabilities
	 * @type {Object}
	 * @private
	 * @static
	 */
	s._capabilities = null;

	/**
	 * The path relative to the HTML page that the FlashAudioPlugin.swf resides. Note if this is not correct, this
	 * plugin will not work.
	 * @property swfPath
	 * @type {String}
	 * @default src/SoundJS
	 * @static
	 * @since 0.5.2
	 */
	s.swfPath = "src/soundjs/flashaudio/";


// Static Methods
	/**
	 * Determine if the plugin can be used in the current browser/OS.
	 * @method isSupported
	 * @return {Boolean} If the plugin can be initialized.
	 * @static
	 */
	s.isSupported = function () {
		// there is no flash player on mobile devices
		if (createjs.BrowserDetect.isIOS || createjs.BrowserDetect.isAndroid || createjs.BrowserDetect.isBlackberry || createjs.BrowserDetect.isWindowsPhone) {return false;}
		s._generateCapabilities();
		if (swfobject == null) {return false;}
		return swfobject.hasFlashPlayerVersion("9.0.0");
	};

	/**
	 * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/capabilities:property"}}{{/crossLink}}
	 * method for an overview of plugin capabilities.
	 * @method _generateCapabilities
	 * @static
	 * @private
	 */
	s._generateCapabilities = function () {
		if (s._capabilities != null) {return;}
		var c = s._capabilities = {
			panning:true,
			volume:true,
			tracks:-1,
			mp3:true,
			ogg:false,
			mpeg:true,
			wav:true,
			// our current implementation cannot support mp4 http://forums.adobe.com/thread/825408
			m4a:false,
			mp4:false,
			aiff:false, // not listed in player but is Supported by Flash so this may be true
			wma:false,
			mid:false
		};
	};


//public methods
	p.register = function (src, instances) {
		var loader = this.AbstractPlugin_register(src, instances);
		loader.addEventListener(s._REG_FLASHID, createjs.proxy(this.registerPreloadInstance, this));
		loader.addEventListener(s._UNREG_FLASHID, createjs.proxy(this.unregisterPreloadInstance, this));
		return loader;
	};

	p.removeAllSounds = function () {
		this._flashInstances = {};
		this._flashPreloadInstances = {};
		// NOTE sound cannot be removed from a swf

		this.AbstractPlugin_removeAllSounds();
	};

	p.create = function (src, startTime, duration) {
		var si = this.AbstractPlugin_create(src, startTime, duration);
		si.on(s._REG_FLASHID, this.registerSoundInstance, this);
		si.on(s._UNREG_FLASHID, this.unregisterSoundInstance, this);
		return si;
	};

	p.toString = function () {
		return "[FlashAudioPlugin]";
	};


// private methods
	/**
	 * The SWF used for sound preloading and playback has been initialized.
	 * @method _handleSWFReady
	 * @param {Object} event Contains a reference to the swf.
	 * @protected
	 */
	p._handleSWFReady = function (event) {
		this._flash = event.ref;
	};

	/**
	 * The Flash application that handles preloading and playback is ready. We wait for a callback from Flash to
	 * ensure that everything is in place before playback begins.
	 * @method _handleFlashReady
	 * @protected
	 */
	p._handleFlashReady = function () {
		this.flashReady = true;

		this._loaderClass.setFlash(this._flash);
		this._soundInstanceClass.setFlash(this._flash);
	};

	/**
	 * Internal function used to set the gain value for master audio.  Should not be called externally.
	 * @method _updateVolume
	 * @return {Boolean}
	 * @protected
	 * @since 0.4.0
	 */
	p._updateVolume = function () {
		var newVolume = createjs.Sound._masterMute ? 0 : this._volume;
		return this._flash.setMasterVolume(newVolume);
	};


// Flash Communication
// Note we have decided not to include these in the docs
	/*
	 * Used to couple a Flash loader instance with a <code>Loader</code> instance
	 * @method registerPreloadInstance
	 * @param {String} flashId Used to identify the Loader.
	 * @param {Loader} instance The actual instance.
	 */
	p.registerPreloadInstance = function (event) {
		this._flashPreloadInstances[event.target.flashId] = event.target;
	};

	/*
	 * Used to decouple a <code>Loader</code> instance from Flash.
	 * @method unregisterPreloadInstance
	 * @param {String} flashId Used to identify the Loader.
	 */
	p.unregisterPreloadInstance = function (event) {
		delete this._flashPreloadInstances[event.target.flashId];
	};

	/*
	 * Used to couple a Flash sound instance with a {{#crossLink "FlashAudioSoundInstance"}}{{/crossLink}}.
	 * @method registerSoundInstance
	 * @param {String} flashId Used to identify the FlashAudioSoundInstance.
	 * @param {Loader} instance The actual instance.
	 */
	p.registerSoundInstance = function (event) {
		this._flashInstances[event.target.flashId] = event.target;
	};

	/*
	 * Used to decouple a {{#crossLink "FlashAudioSoundInstance"}}{{/crossLink}} from Flash.
	 * instance.
	 * @method unregisterSoundInstance
	 * @param {String} flashId Used to identify the FlashAudioSoundInstance.
	 * @param {Loader} instance The actual instance.
	 */
	p.unregisterSoundInstance = function (event) {
		delete this._flashInstances[event.target.flashId];
	};

	/*
	 * Used to output traces from Flash to the console, if {{#crossLink "FlashAudioPlugin/showOutput"}}{{/crossLink}} is
	 * <code>true</code>.
	 * @method flashLog
	 * @param {String} data The information to be output.
	 */
	p.flashLog = function (data) {
		try {
			this.showOutput && console.log(data);
		} catch (error) {
			// older IE will cause error if console is not open
		}
	};

	/*
	 * Handles events from Flash, and routes communication to a {{#crossLink "FlashAudioSoundInstance"}}{{/crossLink}} via
	 * the Flash ID. The method and arguments from Flash are run directly on the loader or sound instance.
	 * @method handleSoundEvent
	 * @param {String} flashId Used to identify the FlashAudioSoundInstance.
	 * @param {String} method Indicates the method to run.
	 */
	p.handleSoundEvent = function (flashId, method) {
		var instance = this._flashInstances[flashId];
		if (instance == null) {return;}
		var args = [];
		for (var i = 2, l = arguments.length; i < l; i++) {
			args.push(arguments[i]);
		}
		try {
			if (args.length == 0) {
				instance[method]();
			} else {
				instance[method].apply(instance, args);
			}
		} catch (error) {
		}
	};

	/*
	 * Handles events from Flash and routes communication to a <code>Loader</code> via the Flash ID. The method
	 * and arguments from Flash are run directly on the sound loader.
	 * @method handlePreloadEvent
	 * @param {String} flashId Used to identify the loader instance.
	 * @param {String} method Indicates the method to run.
	 */
	p.handlePreloadEvent = function (flashId, method) {
		var instance = this._flashPreloadInstances[flashId];
		if (instance == null) {
			return;
		}
		var args = [];
		for (var i = 2, l = arguments.length; i < l; i++) {
			args.push(arguments[i]);
		}
		try {
			if (args.length == 0) {
				instance[method]();
			} else {
				instance[method].apply(instance, args);
			}
		} catch (error) {
		}
	};

	/*
	 * Handles events from Flash intended for the FlashAudioPlugin class. Currently only a "ready" event is processed.
	 * @method handleEvent
	 * @param {String} method Indicates the method to run.
	 */
	p.handleEvent = function (method) {
		switch (method) {
			case "ready":
				this._handleFlashReady();
				break;
		}
	};

	/*
	 * Handles error events from Flash. Note this function currently does not process any events.
	 * @method handleErrorEvent
	 * @param {String} error Indicates the error.
	 */
	p.handleErrorEvent = function (error) {

	};

	createjs.FlashAudioPlugin = createjs.promote(FlashAudioPlugin, "AbstractPlugin");
}());