<?xml version="1.0" encoding="utf-8"?>
<!--
/*****************************************************
*
* Copyright 2009 Akamai Technologies, Inc. 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 Akamai Technologies, Inc.
* Portions created by Akamai Technologies, Inc. are Copyright (C) 2009 Akamai
* Technologies, Inc. All Rights Reserved.
*
*****************************************************/
-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:players="com.adobe.strobe.players.*" applicationComplete="initApp()"
backgroundColor="#000000">
<mx:Style source="AkamaiPluginSample.css" />
<mx:Script>
<![CDATA[
import mx.controls.sliderClasses.Slider;
import mx.events.DropdownEvent;
import mx.events.SliderEvent;
import mx.controls.Alert;
import flash.utils.getDefinitionByName;
import flash.net.getClassByAlias;
import org.osmf.plugin.PluginClassResource;
import org.osmf.plugin.PluginManager;
import org.osmf.traits.MediaTraitType;
import org.osmf.traits.LoadState;
import org.osmf.traits.ILoadable;
import org.osmf.traits.MediaTraitType;
import org.osmf.traits.ISpatial;
import org.osmf.events.*;
import org.osmf.media.MediaInfo;
import org.osmf.media.MediaFactory;
import org.osmf.media.MediaElement;
import org.osmf.media.IMediaResource;
import org.osmf.media.URLResource;
import org.osmf.media.IURLResource;
import org.osmf.net.NetLoader;
import org.osmf.utils.*;
import org.osmf.video.VideoElement;
import org.osmf.metadata.*;
// Our plugins (for loading as static plugins)
import com.akamai.osmf.AkamaiBasicStreamingPluginInfo;
import org.osmf.mast.MASTPluginInfo;
private var pluginManager:PluginManager;
private var mediaFactory:MediaFactory;
private var pluginElement:MediaElement;
private var sliderDragging:Boolean;
private var waitForSeek:Boolean;
private static const AKAMAI_BASIC_STREAMING_PLUGIN_URL:String = "http://mediapm.edgesuite.net/osmf/swf/AkamaiBasicStreamingPlugin.swf";
private static const DEFAULT_PROGRESS_DELAY:uint = 100;
private static const AKAMAI_BASIC_STREAMING_PLUGIN_INFOCLASS:String = "com.akamai.osmf.AkamaiBasicStreamingPluginInfo";
private static const MAST_PLUGIN_INFOCLASS:String = "org.osmf.mast.MASTPluginInfo";
// We need these or getDefinitionByName will fail:
private static const loadTestRef:AkamaiBasicStreamingPluginInfo = null;
private static const loadTestRef2:MASTPluginInfo = null;
// ------ TEST CONTENT ------
// FLV
private static const PROGRESSIVE_FLV:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv";
private static const PROGRESSIVE_FLV_2:String = "http://mediapm.edgesuite.net/osmf/content/test/akamai_10_year_f8_512K.flv";
private static const PROGRESSIVE_FLV_SSL:String = "https://a248.e.akamai.net/7/248/67129/v0001/mediapm.download.akamai.com/67129/osmf/content/test/akamai_10_year_f8_512K.flv";
private static const STREAMING_FLV:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/osmf/content/test/akamai_10_year_f8_512K";
// MP4
private static const PROGRESSIVE_MP4:String = "http://mediapm.edgesuite.net/osmf/content/test/spacealonehd_sounas_640_700.mp4";
private static const PROGRESSIVE_MP4_SSL:String = "https://a248.e.akamai.net/7/248/67129/v0001/mediapm.download.akamai.com/67129/osmf/content/test/spacealonehd_sounas_640_700.mp4";
private static const STREAMING_MP4:String = "rtmp://cp67126.edgefcs.net/ondemand/mp4:mediapm/osmf/content/test/spacealonehd_sounas_640_700.mp4";
// F4V
private static const PROGRESSIVE_F4V:String = "http://mediapm.edgesuite.net/osmf/content/test/sample1_700kbps.f4v";
private static const PROGRESSIVE_F4V_SSL:String = "https://a248.e.akamai.net/7/248/67129/v0001/mediapm.download.akamai.com/67129/osmf/content/test/sample1_700kbps.f4v";
private static const STREAMING_F4V:String = "rtmp://cp67126.edgefcs.net/ondemand/mp4:mediapm/osmf/content/test/sample1_700kbps.f4v";
// STREAM WITH AUTH
private static const REMOTE_STREAM_WITH_AUTH:String = "rtmp://cp78634.edgefcs.net/ondemand/mp4:mediapmsec/osmf/content/test/SpaceAloneHD_sounas_640_700.mp4?auth=daEc2a9a5byaMa.avcxbiaoa8dBcibqbAa8-bkxDGK-b4toa-znnrqzzBvl&aifp=v0001";
// LIVE
private static const REMOTE_LIVE:String = "rtmp://cp34973.live.edgefcs.net/live/Flash_Live_Benchmark@632";
// MISC
private static const REMOTE_STREAM:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short";
// MOV
private static const PROGRESSIVE_MOV:String = "http://mediapm.edgesuite.net/osmf/content/test/akamai_10_year_500.mov";
private static const PROGRESSIVE_MOV_SSL:String = "https://a248.e.akamai.net/7/248/67129/v0001/mediapm.download.akamai.com/67129/osmf/content/test/akamai_10_year_500.mov";
private static const STREAMING_MOV:String = "rtmp://cp67126.edgefcs.net/ondemand/mp4:mediapm/osmf/content/test/akamai_10_year_500.mov";
// AUDIO
private static const STREAMING_AUDIO:String = "rtmp://cp67126.edgefcs.net/ondemand/mp3:mediapm/osmf/content/test/train_1500";
// MAST documents
private static const MAST_URL_POSTROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemend.xml";
private static const MAST_URL_PREROLL:String = "http://mediapm.edgesuite.net/osmf/content/mast/mast_sample_onitemstart.xml";
[Bindable]
private var plugins:Array = [ {label:"Akamai Basic Streaming Plugin (Dynamic)", url:AKAMAI_BASIC_STREAMING_PLUGIN_URL},
{label:"Akamai Basic Streaming Plugin (Static)", url:AKAMAI_BASIC_STREAMING_PLUGIN_INFOCLASS},
{label:"MAST plugin (Static)", url:MAST_PLUGIN_INFOCLASS}
];
[Bindable]
private var streams:Array = [ {label:"Progressive FLV", url:PROGRESSIVE_FLV},
{label:"Progressive FLV (another)", url:PROGRESSIVE_FLV_2},
{label:"Progressive FLV (https)", url:PROGRESSIVE_FLV_SSL},
{label:"Streaming FLV", url:STREAMING_FLV},
{label:"Progressive MP4", url:PROGRESSIVE_MP4},
{label:"Progressive MP4 (https)", url:PROGRESSIVE_MP4_SSL},
{label:"Streaming MP4", url:STREAMING_MP4},
{label:"Progressive F4V", url:PROGRESSIVE_F4V},
{label:"Progressive F4V (https)", url:PROGRESSIVE_F4V_SSL},
{label:"Streaming F4V", url:STREAMING_F4V},
{label:"Stream with Auth", url:REMOTE_STREAM_WITH_AUTH},
{label:"Live", url:REMOTE_LIVE},
{label:"Remote Stream", url:REMOTE_STREAM},
{label:"Progressive MOV", url:PROGRESSIVE_MOV},
{label:"Progressive MOV (https)", url:PROGRESSIVE_MOV_SSL},
{label:"Streaming MOV", url:STREAMING_MOV},
{label:"Streaming Audio", url:STREAMING_AUDIO}
];
private var _currentInfoLineNum:int;
private function initApp():void
{
mediaFactory = new MediaFactory();
pluginManager = new PluginManager(mediaFactory);
urlInput.text = plugins[0].url;
mediaInput.text = streams[0].url;
mediaPlayerWrapper.mediaPlayer.addEventListener(DimensionChangeEvent.DIMENSION_CHANGE, onDimensionChange);
mediaPlayerWrapper.mediaPlayer.addEventListener(DurationChangeEvent.DURATION_CHANGE, onDurationChange);
mediaPlayerWrapper.mediaPlayer.addEventListener(PlayheadChangeEvent.PLAYHEAD_CHANGE, onPlayheadChange);
mediaPlayerWrapper.mediaPlayer.addEventListener(SeekingChangeEvent.SEEKING_CHANGE, onSeekingChange);
mediaPlayerWrapper.mediaPlayer.addEventListener(PlayingChangeEvent.PLAYING_CHANGE, onPlayingChange );
mediaPlayerWrapper.mediaPlayer.playheadUpdateInterval = DEFAULT_PROGRESS_DELAY;
sliderDragging = false;
waitForSeek = false;
clearInfoText();
}
private function loadMedia(url:String):void
{
var resource:IURLResource = new URLResource(new FMSURL(url));
// Assign to the resource the metadata that indicates that it should have a MAST
// document applied (and include the URL of that MAST document).
var kvFacet:KeyValueFacet = new KeyValueFacet(new URL("http://www.akamai.com/mast"));
kvFacet.addValue(new ObjectIdentifier("url"), MAST_URL_PREROLL);
resource.metadata.addFacet(kvFacet);
var mediaElement:MediaElement = mediaFactory.createMediaElement(resource);
if (mediaElement == null)
{
var netLoader:NetLoader = new NetLoader();
// Add a default VideoElement
mediaFactory.addMediaInfo(new MediaInfo("org.osmf.video", netLoader, VideoElement, [netLoader]));
mediaElement = mediaFactory.createMediaElement(resource);
}
mediaElement.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError, false, 0, true);
//var loadable:ILoadable = mediaElement.getTrait(MediaTraitType.LOADABLE) as ILoadable;
//loadable.addEventListener(LoadableStateChangeEvent.LOADABLE_STATE_CHANGE, onLoadableStateChange);
mediaPlayerWrapper.element = mediaElement;
enablePlayerControls(true);
}
private function unloadMedia():void
{
var mediaElement:MediaElement = mediaPlayerWrapper.element;
if (mediaElement != null && mediaElement.hasTrait(MediaTraitType.LOADABLE))
{
var loadable:ILoadable = mediaElement.getTrait(MediaTraitType.LOADABLE) as ILoadable;
if (loadable.loadState == LoadState.LOADED)
{
loadable.unload();
}
}
enablePlayerControls(false);
}
private function loadPlugin(source:String, load:Boolean=true):void
{
var pluginResource:IMediaResource;
if (source.substr(0, 4) == "http" || source.substr(0, 4) == "file")
{
// This is a URL, create a URLResource
pluginResource = new URLResource(new URL(source));
}
else
{
// Assume this is a class
var pluginInfoRef:Class = flash.utils.getDefinitionByName(source) as Class;
pluginResource = new PluginClassResource(pluginInfoRef);
}
if (load)
{
loadPluginFromResource(pluginResource);
}
else
{
unloadPluginFromResource(pluginResource);
}
}
private function loadPluginFromResource(pluginResource:IMediaResource):void
{
pluginManager.addEventListener(PluginLoadEvent.PLUGIN_LOADED, onPluginLoaded);
pluginManager.addEventListener(PluginLoadEvent.PLUGIN_LOAD_FAILED, onPluginLoadFailed);
pluginManager.loadPlugin(pluginResource);
}
private function unloadPluginFromResource(pluginResource:IMediaResource):void
{
pluginManager.addEventListener(PluginLoadEvent.PLUGIN_UNLOADED, onPluginUnloaded);
pluginManager.unloadPlugin(pluginResource);
}
private function unloadPlugin(source:String):void
{
loadPlugin(source, false);
}
private function onPluginLoaded(event:PluginLoadEvent):void
{
var selection:Object = cbPlugin.selectedItem;
appendInfoText("Plugin LOADED: " + selection.label);
}
private function onPluginLoadFailed(event:PluginLoadEvent):void
{
var selection:Object = cbPlugin.selectedItem;
appendInfoText("Plugin LOAD FAILED: " + selection.label);
}
private function onPluginUnloaded(event:PluginLoadEvent):void
{
var selection:Object = cbPlugin.selectedItem;
appendInfoText("Plugin UNLOADED: " + selection.label);
}
private function pluginComboBoxChanged(event:DropdownEvent):void
{
var cb:ComboBox = event.currentTarget as ComboBox;
var selection:Object = cb.selectedItem;
urlInput.text = selection.url;
}
private function urlComboBoxChanged(event:Event):void
{
var cb:ComboBox = event.currentTarget as ComboBox;
var selection:Object = cb.selectedItem;
mediaInput.text = selection.url;
}
private function onDimensionChange(event:DimensionChangeEvent):void
{
mediaPlayerWrapper.width = event.newWidth;
mediaPlayerWrapper.height = event.newHeight;
}
private function onDurationChange(event:DurationChangeEvent):void
{
seekBar.maximum = event.newDuration;
lblDuration.text = timeCode(event.newDuration);
}
private function onPlayheadChange(event:PlayheadChangeEvent):void
{
if (mediaPlayerWrapper.mediaPlayer.temporal && !sliderDragging && !waitForSeek)
{
seekBar.value = event.newPosition;
lblPlayhead.text = timeCode(event.newPosition);
}
}
private function onSeekingChange(event:SeekingChangeEvent):void
{
if (!event.seeking)
{
waitForSeek = false;
}
}
private function toggleDragging(state:Boolean):void
{
sliderDragging = state;
if (!state)
{
waitForSeek = true;
if (mediaPlayerWrapper.mediaPlayer.seekable)
{
mediaPlayerWrapper.mediaPlayer.seek(seekBar.value);
}
}
}
private function onPlayingChange(event:PlayingChangeEvent):void
{
if (event.playing)
{
seekBar.enabled = seekBar.visible = mediaPlayerWrapper.mediaPlayer.seekable;
}
}
private function appendInfoText(...args):void
{
var lineNum:int = _currentInfoLineNum++;
taInfo.text += lineNum + ":" + args + "\n";
callLater(autoScrollInfoText);
}
private function clearInfoText():void
{
taInfo.text = "";
_currentInfoLineNum = 1;
}
private function autoScrollInfoText():void
{
taInfo.verticalScrollPosition = taInfo.maxVerticalScrollPosition;
}
private function onMediaError(event:MediaErrorEvent):void
{
if (taInfo.text.length)
{
taInfo.text += "\n";
}
taInfo.text += taInfo.text + "error code="+event.error.errorCode+" description="+event.error.description;
}
private function timeCode(sec:Number):String
{
var h:Number = Math.floor(sec/3600);
h = isNaN(h) ? 0 : h;
var m:Number = Math.floor((sec%3600)/60);
m = isNaN(m) ? 0 : m;
var s:Number = Math.floor((sec%3600)%60);
s = isNaN(s) ? 0 : s;
return (h == 0 ? "":(h<10 ? "0"+h.toString()+":" : h.toString()+":"))+(m<10 ? "0"+m.toString() : m.toString())+":"+(s<10 ? "0"+s.toString() : s.toString());
}
private function onClickPlayBtn():void
{
if (mediaPlayerWrapper.mediaPlayer.playing && mediaPlayerWrapper.mediaPlayer.pausable)
{
playBtn.label = "Play";
mediaPlayerWrapper.mediaPlayer.pause();
}
else if (mediaPlayerWrapper.mediaPlayer.paused && mediaPlayerWrapper.mediaPlayer.playable)
{
playBtn.label = "Pause";
mediaPlayerWrapper.mediaPlayer.play();
}
}
private function enablePlayerControls(enable:Boolean=true):void
{
playBtn.enabled = seekBar.enabled = enable;
}
]]>
</mx:Script>
<mx:VBox height="100%" width="100%" paddingLeft="10" paddingTop="10">
<mx:Label text="OSMF Akamai Plugin Sample" styleName="title" width="100%" textAlign="left" paddingLeft="20"/>
<mx:Spacer height="20" />
<mx:HBox height="60">
<mx:Spacer width="10" />
<mx:Label text="Plugin Name:"/>
<mx:ComboBox id="cbPlugin" close="pluginComboBoxChanged(event)" dataProvider="{plugins}" />
<mx:Label text="Plugin URL:" />
<mx:TextInput id="urlInput" width="500"/>
<mx:Button label="Load Plugin" click="{loadPlugin(urlInput.text)}"/>
<mx:Button label="Unload Plugin" click="{unloadPlugin(urlInput.text)}"/>
</mx:HBox>
<mx:HBox height="60">
<mx:Spacer width="10" />
<mx:Label text="Media Type:"/>
<mx:ComboBox id="cbMediaURL" close="urlComboBoxChanged(event)" dataProvider="{this.streams}" />
<mx:Label text="URL:"/>
<mx:TextInput id="mediaInput" width="500"/>
<mx:Button label="Load Media Resource" click="{loadMedia(mediaInput.text)}"/>
<mx:Button label="Unload Media Resource" click="{unloadMedia()}"/>
</mx:HBox>
<mx:Spacer height="5" />
<mx:HBox>
<mx:VBox paddingLeft="20">
<mx:Spacer width="10" />
<players:MediaPlayerWrapper id="mediaPlayerWrapper" width="320" height="240" />
<mx:HSlider id="seekBar" width="100%" thumbPress="toggleDragging(true)" thumbRelease="toggleDragging(false)" enabled="false" />
<mx:HBox horizontalAlign="right" width="100%">
<mx:Label text="Position: " />
<mx:Label id="lblPlayhead" width="100" styleName="timeCode" />
<mx:Label text="Duration: " />
<mx:Label id="lblDuration" width="100" styleName="timeCode" />
<mx:Button id="playBtn" label="Pause" click="onClickPlayBtn()" enabled="false" />
</mx:HBox>
</mx:VBox>
<mx:Spacer width="20" />
<mx:VBox>
<mx:TextArea id="taInfo" wordWrap="true" enabled="false" width="420" height="240"/>
</mx:VBox>
</mx:HBox>
</mx:VBox>
</mx:Application>