/* * 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"); }());