//////////////////////////////////////////////////////////////////////////// /* // Player Class // // @class Player // @package com.ask.coaching // @extends MovieClip // // @author Dave Castelnuovo // @version 1.0 // @date 2005-10-20 // // @description Description // // @symbolName com.ask.video.Player // @linkageID com.ask.video.Player // // Copyright (c) 2005 ASK learning. All rights reserved. */ /////////////////////////////////////////////////////////////////////////// import mx.events.EventDispatcher; import com.ask.lib.*; import com.ask.utils.*; import com.ask.video.*; class com.ask.video.Player extends MovieClip { //////////////////////////////////////////////////////////////////////////// // // Properties // //////////////////////////////////////////////////////////////////////////// // @property Used for debugging var className:String = "Player"; // @property symbolName for object. Used to attach. static var symbolName:String = "com.ask.video.Player"; // @property Class used in createClassObject static var symbolOwner = com.ask.video.Player; // @method Method stub to be mixed in by EventDispatcher. // @see mx.events.EventDispatcher var dispatchEvent:Function; // @method Method stub to be mixed in by EventDispatcher // @see mx.events.EventDispatcher var addEventListener:Function; // @method Method stub to be mixed in by EventDispatcher // @see mx.events.EventDispatcher var removeEventListener:Function; var iLoadLoop:MovieClip; var iPlayLoop:MovieClip; var mControlClip:MovieClip; static var mbCaptionOn:Boolean = false; var iCaption:MovieClip; var mPreloadUrl:String; var mPreloadMap:Object; var mbDrag:Boolean = false; var mUrl:String; var mBaseUrl:String; var mDuration:Number = 0; var mDefaultCaptionDuration = 3; var mTime:Number = 0; var mbBufferFlush:Boolean = false; var mbBufferStop:Boolean = false; var mbBufferEmpty:Boolean = false; var mbMovieComplete:Boolean = false; var mCaption:String = ""; var mEventNodeArray:Array; var mVideoEventListener:Object; var mVideo:Video; var mSwfStub:MovieClip; var mPlayingSwf:MovieClip; var mbPlaying:Boolean = false; var mbPlaySwf:Boolean = false; var mToggleProxy:Object; var mScrubberArray:Array; var mSectionIndex:Number; var mRevealPercent:Number; // @property a map of all the event types we encounter var mEventTypeMap:Object; // @property the net connection object we will use for all our video var mNetConnection:NetConnection; // @property the net stream object we will use for all our video var mNetStream:NetStream; // @property global sound object static var mGlobalSound:Sound; // @property used to init our statics static var mbClassConstruct:Boolean = classConstruct(); //////////////////////////////////////////////////////////////////////////// // // Class Constructor // // @method ClassConstruct. // @description Constructor. // //////////////////////////////////////////////////////////////////////////// static function classConstruct():Boolean { mGlobalSound = new Sound(); return true; } //////////////////////////////////////////////////////////////////////////// // // Constructor // // @method Player Constructor. // @description Constructor. // //////////////////////////////////////////////////////////////////////////// function Player() { initPlayer(); } //////////////////////////////////////////////////////////////////////////// // // Initialization // // @method Init. // @description Initilizes Player. // //////////////////////////////////////////////////////////////////////////// private function initPlayer():Void { // add ability to broadcast events. EventDispatcher.initialize( this); // set the event to a local object, so our subclass can overrite it without worrying about screwing this event up mVideoEventListener = {}; mVideoEventListener._parent = this; addEventListener( "onVideoEvent", mVideoEventListener); mVideoEventListener.onVideoEvent = function( inEvent:Object) { switch ( inEvent.mEventType) { case "caption": if ( inEvent.node != false) { _parent.mCaption = inEvent.node.text; } else { _parent.mCaption = ""; } break; } } createEmptyMovieClip( "iLoadLoop", 1000); createEmptyMovieClip( "iPlayLoop", 2000); mPreloadMap = {}; mNetConnection = new NetConnection(); mNetConnection.connect( null); mNetStream = new NetStream( mNetConnection); mNetStream.setBufferTime( 15); mNetStream._parent = this; mNetStream.onStatus = function( inInfo:Object) { this._parent.onStreamStatus( inInfo); }; mNetStream.onMetaData = function( inInfo:Object) { this._parent.onStreamMetaData( inInfo); }; } //////////////////////////////////////////////////////////////////////////// // // Static Methods // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // Public Methods // //////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// /* // @method attachSwfStub // // @description attach our stream to a video // @param inSwfStub the stub we load our swf type movies into // @return Void */ function attachSwfStub( inSwfStub:MovieClip) { mSwfStub = inSwfStub; } ///////////////////////////////////// /* // @method attachVideo // // @description attach our stream to a video // @param inVideo the video object // @return Void */ function attachVideo( inVideo:Video) { mVideo = inVideo; inVideo.attachVideo( mNetStream); } ///////////////////////////////////// /* // @method closeVideo // // @description shut down our video stream // @return Void */ function closeVideo() { mbPlaying = false; mPlayingSwf._visible = false; mPlayingSwf.gotoAndStop( 1); iPlayLoop.onEnterFrame = null; iLoadLoop.onEnterFrame = null; mNetStream.close(); } ///////////////////////////////////// /* // @method playVideo // // @description play a video stream // @param inUrl the url of the stream // @return Void */ function playVideo( inUrl:String) { mbPlaying = true; mNetStream.play( inUrl); } //////////////////////////////////////////////////////////////////////////// // // Private Methods // //////////////////////////////////////////////////////////////////////////// function closeFlv() { mbPlaying = false; onPlayerHideVideoMode(); } function onPlayerShowVideoMode() { this.gotoAndPlay( "video"); } function onPlayerHideVideoMode() { this.gotoAndPlay( "standard"); } function setScrubberArray( inScrubberArray:Array) { mScrubberArray = inScrubberArray; } function setRevealPercent( inRevealPercent:Number) { mRevealPercent = inRevealPercent; } function playSwf( inUrl:String) { mbPlaySwf = true; playContent( inUrl); } function playFlv( inUrl:String) { mbPlaySwf = false; playContent( inUrl); } function playContent( inUrl:String) { mBaseUrl = inUrl; mbPlaying = true; mDuration = 0; mCaption = ""; mbMovieComplete = false; mPlayingSwf._visible = false; mPlayingSwf.gotoAndStop(1); if ( mScrubberArray != undefined) { mSectionIndex = -1; var oIndex = 0; while ( oIndex < mScrubberArray.length) { if ( mScrubberArray[ oIndex] == mBaseUrl) { mSectionIndex = oIndex; break; } oIndex ++; } if ( mSectionIndex == -1) { mScrubberArray = null; } } mControlClip.iPlay.deactivate(); if ( mbPlaySwf == true) { mUrl = inUrl + ".swf"; } else { mUrl = inUrl + ".flv"; } if ( mbPlaySwf == true) { mSwfStub.createEmptyMovieClip( "iSwf", 1); var oMovieClipLoader:MovieClipLoader = new MovieClipLoader(); oMovieClipLoader.loadClip( mUrl, mSwfStub.iSwf); oMovieClipLoader.addListener( this); mPlayingSwf = mSwfStub.iSwf; } else { playVideo( mUrl); } iPlayLoop.onEnterFrame = function() { _parent.onEnterFramePlay(); } iLoadLoop.onEnterFrame = function() { _parent.onEnterFrameLoad(); } onPlayerShowVideoMode(); } function onLoadInit( inMovieClip:MovieClip) { inMovieClip.gotoAndStop( 1); } function onLoadComplete( inMovieClip:MovieClip) { inMovieClip.gotoAndStop( 1); } ///////////////////////////////////// /* // @method onStreamStatus // // @description called when our video stream gets an onStatusEvent // @param inInfo info about the event // @return Void */ function onStreamStatus( inInfo:Object) { switch ( inInfo.code) { case "NetStream.Seek.InvalidTime": mNetStream.seek( inInfo.details); break; case "NetStream.Play.Stop": if ( mbBufferFlush == true) { mbMovieComplete = true; closeFlv(); dispatchEvent( { target: this, type: "onVideoComplete"}); } mbBufferFlush = false; mbBufferStop = true; mbBufferEmpty = false; break; case "NetStream.Buffer.Empty": if ( mbBufferStop == true) { mbMovieComplete = true; closeFlv(); dispatchEvent( { target: this, type: "onVideoComplete"}); } mbBufferFlush = false; mbBufferStop = false; mbBufferEmpty = true; break; case "NetStream.Buffer.Flush": // if we were immediately preceded by a stop of empty, then we are at the end of the movie if (( mbBufferEmpty == true) || ( mbBufferStop == true)) { mbMovieComplete = true; closeFlv(); dispatchEvent( { target: this, type: "onVideoComplete"}); } mbBufferFlush = true; mbBufferStop = false; mbBufferEmpty = false; break; default: mbBufferFlush = false; mbBufferStop = false; mbBufferEmpty = false; mbMovieComplete = false; break; } } ///////////////////////////////////// /* // @method onStreamMetaData // // @description called when our video stream gets an onMetaData event // // the info object contains the following attributes // // canSeekToEnd // videocodecid // framerate // videodatarate // height // width // duration // // @param inInfo info about the event // @return Void */ function onStreamMetaData( inInfo:Object) { mDuration = inInfo.duration; } function refreshVideoUi() { mControlClip.iFF1.mPlayer = this; mControlClip.iFF1.onRelease = function() { this.mPlayer.onFF1(); } mControlClip.iRW1.mPlayer = this; mControlClip.iRW1.onRelease = function() { this.mPlayer.onRW1(); } mControlClip.iFF2.mPlayer = this; mControlClip.iFF2.onRelease = function() { this.mPlayer.onFF2(); } mControlClip.iRW2.mPlayer = this; mControlClip.iRW2.onRelease = function() { this.mPlayer.onRW2(); } if ( mToggleProxy == undefined) { mToggleProxy = {}; mToggleProxy._parent = this; } mToggleProxy.onToggle = function( inEvent:Object) { this._parent.onTogglePlayer( inEvent); } if ( mbPlaying == true) { mControlClip.iPlay.deactivate(); } else { mControlClip.iPlay.activate(); } mControlClip.iPlay.addEventListener( "onToggle", mToggleProxy); if ( mGlobalSound.getVolume() == 100) { mControlClip.iSound.activate(); } else { mControlClip.iSound.deactivate(); } mControlClip.iSound.addEventListener( "onToggle", mToggleProxy); if ( mbCaptionOn == true) { iCaption.gotoAndPlay( "active"); mControlClip.iCaption.activate(); } else { iCaption.gotoAndPlay( "deactive"); mControlClip.iCaption.deactivate(); } mControlClip.iCaption.addEventListener( "onToggle", mToggleProxy); mControlClip.iScrubHandle.mPlayer = this; mControlClip.iBarBackdrop.mPlayer = this; mControlClip.iBarBackdrop.onPress = function() { this.mPlayer.onPressScrubHandle(); } mControlClip.iBarBackdrop.onRelease = function() { this.mPlayer.onReleaseScrubHandle(); } mControlClip.iBarBackdrop.onReleaseOutside = function() { this.mPlayer.onReleaseScrubHandle(); } mControlClip.iScrubHandle._x = mControlClip.iControls.iBarBackdrop._x; mControlClip.iLoadBar.setPercent( 0); if ( mRevealPercent != undefined) { mControlClip.iRevealBar. n( mRevealPercent); } } function onEnterFrameLoad() { var oPercent = 0; if ( mbPlaySwf == true) { var oBytesLoaded = mPlayingSwf.getBytesLoaded(); var oBytesTotal = mPlayingSwf.getBytesTotal(); if (( oBytesLoaded != 4) && ( oBytesLoaded != 0)) { oPercent = oBytesLoaded / oBytesTotal; } } else if ( mNetStream.bytesTotal > 0) { oPercent = mNetStream.bytesLoaded / mNetStream.bytesTotal; } mControlClip.iLoadBar.setPercent( oPercent); } function onFF1() { mNetStream.seek( mTime + 1); } function onRW1() { mNetStream.seek( mTime - 5); } function onFF2() { mNetStream.seek( mTime + 10); } function onRW2() { mNetStream.seek( mTime - 10); } ///////////////////////////////////// /* // @method onTogglePlayer // // @description call by one of our toggles when they get selected // @param inEvent the event that was triggered // @return Void */ function onTogglePlayer( inEvent) { switch ( inEvent.toggle) { case mControlClip.iPlay: if ( mControlClip.iPlay.isActive() == true) { onPlay(); } else { onPause(); } break; case mControlClip.iSound: if ( mControlClip.iSound.isActive() == true) { soundOn(); } else { soundOff(); } break; case mControlClip.iCaption: if ( mControlClip.iCaption.isActive() == true) { captionOn(); } else { captionOff(); } dispatchEvent( { type: "onToggleCaption", mbCaptionOn: mbCaptionOn}); break; } } function onPlay() { if ( mbPlaySwf == true) { mPlayingSwf.stop(); } else { mNetStream.pause( true); } dispatchEvent( { type: "onPauseVideo"}); } function onPause() { if ( mbPlaySwf == true) { if ( mbMovieComplete != true) { mPlayingSwf.play(); } } else { mNetStream.pause( false); } dispatchEvent( { type: "onPlayVideo"}); } function soundOn() { mGlobalSound.setVolume( 100); } function soundOff() { mGlobalSound.setVolume( 0); } function captionOn() { mbCaptionOn = true; iCaption.gotoAndPlay( "active"); } function captionOff() { mbCaptionOn = false; iCaption.gotoAndPlay( "deactive"); } function disableScrub(){ mControlClip.iBarBackdrop.enabled = false; } function enableScrub(){ mControlClip.iBarBackdrop.enabled = true; } function updatePlayBar( inPercent:Number) { if ( mScrubberArray != undefined) { var oSectionWidth = ( mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._x) / mScrubberArray.length; var oStartXPos = mControlClip.iBarBackdrop._x + ( oSectionWidth * mSectionIndex); mControlClip.iScrubHandle._x = oStartXPos + ( oSectionWidth * inPercent); } else { var oStartXPos = mControlClip.iBarBackdrop._x; var oDeltaXPos = mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._width; mControlClip.iScrubHandle._x = oStartXPos + ( oDeltaXPos * inPercent); } if ( mRevealPercent != undefined) { var oRevealPercent = ( mControlClip.iScrubHandle._x - mControlClip.iBarBackdrop._x) / ( mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._x); if ( oRevealPercent > mRevealPercent) { mRevealPercent = oRevealPercent; dispatchEvent( { type: "onVideoRevealPercent", mRevealPercent: mRevealPercent}); } mControlClip.iRevealBar.setPercent( mRevealPercent); } } function onEnterFramePlay() { var oPercent = 0; var oEventTime = 0; if ( mbPlaySwf == true) { oPercent = mPlayingSwf._currentframe / mPlayingSwf._totalframes; oEventTime = mPlayingSwf._currentframe; if (( mPlayingSwf._currentframe == mPlayingSwf._totalframes) && ( mbMovieComplete != true)) { mPlayingSwf.stop(); mbMovieComplete = true; dispatchEvent( { target: this, type: "onVideoComplete"}); } } else { if ( mDuration != 0) { oPercent = mNetStream.time / mDuration; } oEventTime = mNetStream.time; } mTime = oEventTime; var oEventMap = {}; var oIndex = 0; while ( oIndex < mEventNodeArray.length) { var oEvent = mEventNodeArray[ oIndex]; var oMinTime = parseFloat( oEvent.attributes.time); var oDuration = mDefaultCaptionDuration; if ( oEvent.attributes.duration != undefined) { oDuration = parseFloat( oEvent.attributes.duration); } var oMaxTime = oMinTime + oDuration; if (( oMinTime < oEventTime) && ( oMaxTime > oEventTime)) { oEventMap[ oEvent.attributes.type] = oEvent; } oIndex ++; } // process all the video events that we know about for ( var oName in mEventTypeMap) { if ( oEventMap[ oName] == undefined) { oEventMap[ oName] = false; } if ( mEventTypeMap[ oName] != oEventMap[ oName]) { mEventTypeMap[ oName] = oEventMap[ oName]; dispatchEvent( { target: this, type: "onVideoEvent", mEventType: oName, node: oEventMap[ oName]}); } } updatePlayBar( oPercent); } function onPressScrubHandle() { mbDrag = true; if ( mScrubberArray != undefined) { mControlClip.iScrubHandle.onEnterFrame = function() { this.mPlayer.onEnterFrameDragScrubArray(); } } else { mControlClip.iScrubHandle.onEnterFrame = function() { this.mPlayer.onEnterFrameDrag(); } } if ( mbPlaySwf != true) { mNetStream.pause( true); } } function onReleaseScrubHandle() { mbDrag = false; mControlClip.iScrubHandle.onEnterFrame = null; // if ( mControlClip.iPlay.isActive() == false) // { if ( mbPlaySwf != true) { mNetStream.pause( true); } else { mPlayingSwf.stop(); } //} } function onEnterFrameDrag() { mbMovieComplete = false; var oStartXPos = mControlClip.iBarBackdrop._x; var oDeltaXPos = mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._width; if ( mControlClip._xmouse < oStartXPos) { mControlClip.iScrubHandle._x = oStartXPos; } else if ( mControlClip._xmouse > ( oStartXPos + oDeltaXPos)) { mControlClip.iScrubHandle._x = oStartXPos + oDeltaXPos; } else { mControlClip.iScrubHandle._x = mControlClip._xmouse; } var oMouseDelta = mControlClip.iScrubHandle._x - oStartXPos; var oPercent = oMouseDelta / oDeltaXPos; if ( mbPlaySwf == true) { var oFrame = Math.floor( oPercent * ( mPlayingSwf._totalframes - 1)) + 1; mPlayingSwf.gotoAndStop( oFrame); } else { mNetStream.seek( mDuration * oPercent); } } function onEnterFrameDragScrubArray() { mbMovieComplete = false; var oStartXPos = mControlClip.iBarBackdrop._x; var oDeltaXPos = mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._width; if ( mControlClip._xmouse < oStartXPos) { mControlClip.iScrubHandle._x = oStartXPos; } else if ( mControlClip._xmouse > ( oStartXPos + oDeltaXPos)) { mControlClip.iScrubHandle._x = oStartXPos + oDeltaXPos; } else if (( mRevealPercent != undefined) && ( mControlClip._xmouse > ( oStartXPos + ( oDeltaXPos * mRevealPercent)))) { mControlClip.iScrubHandle._x = oStartXPos + ( oDeltaXPos * mRevealPercent); } else { mControlClip.iScrubHandle._x = mControlClip._xmouse; } var oSectionWidth = ( mControlClip.iBarBackdrop._width - mControlClip.iScrubHandle._x) / mScrubberArray.length; var oSectionPercent = ( mControlClip.iScrubHandle._x - oStartXPos) / oSectionWidth; var oSectionIndex = Math.floor( oSectionPercent); var oSectionPercent = oSectionPercent - oSectionIndex; if ( oSectionIndex != mSectionIndex) { // we need to change sections playContent( mScrubberArray[ oSectionIndex]); dispatchEvent( { type: "onVideoChangeSection", mSectionIndex: mSectionIndex, mUrl: mBaseUrl}); } if ( mbPlaySwf == true) { var oFrame = Math.floor( oSectionPercent * ( mPlayingSwf._totalframes - 1)) + 1; mPlayingSwf.gotoAndStop( oFrame); } else { mNetStream.seek( mDuration * oSectionPercent); } } //////////////////////////////////////////////////////////////////////////// // // Accessor Methods // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // Events // //////////////////////////////////////////////////////////////////////////// }