/*****************************************************
*
* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved.
*
*****************************************************
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
*
* The Initial Developer of the Original Code is Adobe Systems Incorporated.
* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems
* Incorporated. All Rights Reserved.
*
*****************************************************/
package org.osmf.media.pluginClasses
{
import __AS3__.vec.Vector;
import flash.events.EventDispatcher;
import flash.utils.Dictionary;
import org.osmf.events.LoadEvent;
import org.osmf.events.MediaErrorEvent;
import org.osmf.events.MediaFactoryEvent;
import org.osmf.events.PluginManagerEvent;
import org.osmf.media.MediaElement;
import org.osmf.media.MediaFactory;
import org.osmf.media.MediaFactoryItem;
import org.osmf.media.MediaResourceBase;
import org.osmf.media.PluginInfoResource;
import org.osmf.media.URLResource;
import org.osmf.traits.LoadState;
import org.osmf.traits.LoadTrait;
import org.osmf.traits.MediaTraitType;
import org.osmf.utils.OSMFStrings;
import org.osmf.utils.Version;
[ExcludeClass]
/**
* Dispatched when the PluginManager has successfully loaded a plugin.
*
* @eventType org.osmf.events.PluginManagerEvent.PLUGIN_LOAD
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
[Event(name="pluginLoad", type="org.osmf.events.PluginManagerEvent")]
/**
* Dispatched when the PluginManager has failed to load a plugin due to an error.
*
* @eventType org.osmf.events.PluginManagerEvent.PLUGIN_LOAD_ERROR
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
[Event(name="pluginLoadError", type="org.osmf.events.PluginManagerEvent")]
/**
* @private
*
* This class is a manager that provide access to plugin related
* features.
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
public class PluginManager extends EventDispatcher
{
/**
* Constructor.
*
* @param mediaFactory MediaFactory within which the PluginManager will place the
* information from loaded plugins.
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
public function PluginManager(mediaFactory:MediaFactory)
{
super();
_mediaFactory = mediaFactory;
_mediaFactory.addEventListener(MediaFactoryEvent.MEDIA_ELEMENT_CREATE, onMediaElementCreate);
minimumSupportedFrameworkVersion = Version.lastAPICompatibleVersion;
initPluginFactory();
_pluginMap = new Dictionary();
_pluginList = new Vector.<PluginEntry>();
}
/**
* Load a plugin identified by resource. The PluginManager will not reload the plugin
* if it has been loaded. Upon successful loading, a PluginManagerEvent.PLUGIN_LOAD
* event will be dispatched. Otherwise, a PluginManagerEvent.PLUGIN_LOAD_ERROR
* event will be dispatched.
*
* @param resource MediaResourceBase at which the plugin (SWF file or class) is hosted. It is assumed that
* it is sufficient to identify a plugin using the MediaResourceBase.
*
* @throws ArgumentError If resource is null or resource is not URLResource or PluginInfoResource
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
public function loadPlugin(resource:MediaResourceBase):void
{
if (resource == null)
{
throw new ArgumentError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM));
}
var identifier:Object = getPluginIdentifier(resource);
var pluginEntry:PluginEntry = _pluginMap[identifier] as PluginEntry;
if (pluginEntry != null)
{
dispatchEvent
( new PluginManagerEvent
( PluginManagerEvent.PLUGIN_LOAD
, false
, false
, resource
)
);
}
else
{
var pluginElement:MediaElement = _pluginFactory.createMediaElement(resource);
if (pluginElement != null)
{
pluginEntry = new PluginEntry(pluginElement, PluginLoadingState.LOADING);
_pluginMap[identifier] = pluginEntry;
var loadTrait:LoadTrait = pluginElement.getTrait(MediaTraitType.LOAD) as LoadTrait;
if (loadTrait != null)
{
loadTrait.addEventListener(
LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange);
loadTrait.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError);
loadTrait.load();
}
else
{
dispatchEvent(new PluginManagerEvent(PluginManagerEvent.PLUGIN_LOAD_ERROR, false, false, resource));
}
}
else
{
dispatchEvent(new PluginManagerEvent(PluginManagerEvent.PLUGIN_LOAD_ERROR, false, false, resource));
}
}
function onLoadStateChange(event:LoadEvent):void
{
if (event.loadState == LoadState.READY)
{
pluginEntry.state = PluginLoadingState.LOADED;
_pluginList.push(pluginEntry);
var pluginLoadTrait:PluginLoadTrait = pluginElement.getTrait(MediaTraitType.LOAD) as PluginLoadTrait;
if (pluginLoadTrait.pluginInfo.mediaElementCreationNotificationFunction != null)
{
// Inform the newly added plugin about all previously created
// MediaElements.
invokeMediaElementCreationNotificationForCreatedMediaElements(pluginLoadTrait.pluginInfo.mediaElementCreationNotificationFunction);
// Add our notification function to the list of functions to
// call for future-created MediaElements.
if (notificationFunctions == null)
{
notificationFunctions = new Vector.<Function>();
}
notificationFunctions.push(pluginLoadTrait.pluginInfo.mediaElementCreationNotificationFunction);
}
dispatchEvent
( new PluginManagerEvent
( PluginManagerEvent.PLUGIN_LOAD
, false
, false
, resource
)
);
}
else if (event.loadState == LoadState.LOAD_ERROR)
{
// Remove from the pluginMap when the load failed!!!!
delete _pluginMap[identifier];
dispatchEvent(new PluginManagerEvent(PluginManagerEvent.PLUGIN_LOAD_ERROR, false, false, resource));
}
}
function onMediaError(event:MediaErrorEvent):void
{
dispatchEvent(event.clone());
}
}
/**
* Get access to the media factory that is used for plugin loading and
* MediaInfo registering. Plugins can use this MediaFactory to create
* other types of MediaElement.
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
public function get mediaFactory():MediaFactory
{
return _mediaFactory;
}
// Internals
//
private function getPluginIdentifier(resource:MediaResourceBase):Object
{
var identifier:Object = null;
if (resource is URLResource)
{
identifier = (resource as URLResource).url;
}
else if (resource is PluginInfoResource)
{
identifier = (resource as PluginInfoResource).pluginInfo;
}
return identifier;
}
private function initPluginFactory():void
{
_pluginFactory = new MediaFactory();
staticPluginLoader = new StaticPluginLoader(mediaFactory, minimumSupportedFrameworkVersion);
dynamicPluginLoader = new DynamicPluginLoader(mediaFactory, minimumSupportedFrameworkVersion);
// Add MediaInfo objects for the static and dynamic plugin loaders.
//
var staticPluginItem:MediaFactoryItem = new MediaFactoryItem
( STATIC_PLUGIN_MEDIA_INFO_ID
, staticPluginLoader.canHandleResource
, createStaticPluginElement
);
_pluginFactory.addItem(staticPluginItem);
var dynamicPluginItem:MediaFactoryItem = new MediaFactoryItem
( DYNAMIC_PLUGIN_MEDIA_INFO_ID
, dynamicPluginLoader.canHandleResource
, createDynamicPluginElement
);
_pluginFactory.addItem(dynamicPluginItem);
}
private function createStaticPluginElement():MediaElement
{
return new PluginElement(staticPluginLoader);
}
private function createDynamicPluginElement():MediaElement
{
return new PluginElement(dynamicPluginLoader);
}
private function onMediaElementCreate(event:MediaFactoryEvent):void
{
// Inform any plugins that need to know about newly-created
// MediaElements about this one.
invokeMediaElementCreationNotifications(event.mediaElement);
// Add the newly created MediaElement to our list of created
// elements, so that it can be passed to the creation notification
// function for any subsequently added plugins. (Note that we
// store it as the key only, so that it will be GC'd if this is
// the only object that holds a reference to it. We set the
// value to an arbitrary Boolean.)
if (createdElements == null)
{
createdElements = new Dictionary(true);
}
createdElements[event.mediaElement] = true;
}
/**
* Invokes the callback for all stored notification functions, for the given
* MediaElement.
**/
private function invokeMediaElementCreationNotifications(mediaElement:MediaElement):void
{
for each (var func:Function in notificationFunctions)
{
invokeMediaElementCreationNotificationFunction(func, mediaElement);
}
}
private function invokeMediaElementCreationNotificationFunction(func:Function, mediaElement:MediaElement):void
{
try
{
func.call(null, mediaElement);
}
catch (error:Error)
{
// Swallow, the notification function is wrongly
// specified. We'll continue as-is.
}
}
/**
* Invokes the creation callback on the given MediaFactoryItem, for
* all created MediaElements.
**/
private function invokeMediaElementCreationNotificationForCreatedMediaElements(func:Function):void
{
// Remember, the MediaElements are stored as the keys (so
// that they can be GC'd if the Dictionary holds the only
// reference), hence we need to do a for..in.
for (var elem:Object in createdElements)
{
invokeMediaElementCreationNotificationFunction(func, elem as MediaElement);
}
}
private var _mediaFactory:MediaFactory;
private var _pluginFactory:MediaFactory;
private var _pluginMap:Dictionary;
private var _pluginList:Vector.<PluginEntry>;
private var notificationFunctions:Vector.<Function>;
private var createdElements:Dictionary;
// Keys are: MediaElement
// Values are: Boolean (just a placeholder, the important part is the key)
private var minimumSupportedFrameworkVersion:String;
private var staticPluginLoader:StaticPluginLoader;
private var dynamicPluginLoader:DynamicPluginLoader;
private static const STATIC_PLUGIN_MEDIA_INFO_ID:String = "org.osmf.plugins.StaticPluginLoader";
private static const DYNAMIC_PLUGIN_MEDIA_INFO_ID:String = "org.osmf.plugins.DynamicPluginLoader";
}
}