/*
 * FLINT PARTICLE SYSTEM
 * .....................
 *
 * Author: Richard Lord
 * Copyright (c) Richard Lord 2008-2011
 * http://flintparticles.org
 *
 *
 * Licence Agreement
 *
 * 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.
 */

package org.flintparticles.common.counters
{
	import org.flintparticles.common.emitters.Emitter;

	/**
	 * The Random counter causes the emitter to emit particles continuously
	 * at a variable random rate between two limits.
	 */
	public class Random implements Counter
	{
		private var _timeToNext:Number;
		private var _minRate:Number;
		private var _maxRate:Number;
		private var _running:Boolean;

		/**
		 * The constructor creates a Random counter for use by an emitter. To
		 * add a Random counter to an emitter use the emitter's counter property.
		 *
		 * @param minRate The minimum number of particles to emit per second.
		 * @param maxRate The maximum number of particles to emit per second.
		 *
		 * @see org.flintparticles.common.emitter.Emitter.counter
		 */
		public function Random( minRate:Number = 0, maxRate:Number = 0 )
		{
			_running = false;
			_minRate = minRate;
			_maxRate = maxRate;
		}

		/**
		 * Stops the emitter from emitting particles
		 */
		public function stop():void
		{
			_running = false;
		}

		/**
		 * Resumes the emitter emitting particles after a stop
		 */
		public function resume():void
		{
			_running = true;
		}

		/**
		 * The minimum number of particles to emit per second.
		 */
		public function get minRate():Number
		{
			return _minRate;
		}
		public function set minRate( value:Number ):void
		{
			_minRate = value;
		}

		/**
		 * The maximum number of particles to emit per second.
		 */
		public function get maxRate():Number
		{
			return _maxRate;
		}
		public function set maxRate( value:Number ):void
		{
			_maxRate = value;
		}

		/**
		 * Initilizes the counter. Returns 0 to indicate that the emitter should
		 * emit no particles when it starts.
		 *
		 *
This method is called within the emitter's start method
		 * and need not be called by the user.

		 *
		 * @param emitter The emitter.
		 * @return 0
		 *
		 * @see org.flintparticles.common.counters.Counter#startEmitter()
		 */
		public function startEmitter( emitter:Emitter ):uint
		{
			_timeToNext = newTimeToNext();
			return 0;
		}

		private function newTimeToNext():Number
		{
			var rate:Number = Math.random() * ( _maxRate - _minRate ) + _maxRate;
			return 1 / rate;
		}

		/**
		 * Uses the time, rateMin and rateMax to calculate how many
		 * particles the emitter should emit now.
		 *
		 *
This method is called within the emitter's update loop and need not
		 * be called by the user.

		 *
		 * @param emitter The emitter.
		 * @param time The time, in seconds, since the previous call to this method.
		 * @return the number of particles the emitter should create.
		 *
		 * @see org.flintparticles.common.counters.Counter#updateEmitter()
		 */
		public function updateEmitter( emitter:Emitter, time:Number ):uint
		{
			if( !_running )
			{
				return 0;
			}
			var count:uint = 0;
			_timeToNext -= time;
			while( _timeToNext <= 0 )
			{
				++count;
				_timeToNext += newTimeToNext();
			}
			return count;
		}

		/**
		 * Indicates if the counter has emitted all its particles. For this counter
		 * this will always be false.
		 */
		public function get complete():Boolean
		{
			return false;
		}

		/**
		 * Indicates if the counter is currently emitting particles
		 */
		public function get running():Boolean
		{
			return _running;
		}
	}
}

/*
 * FLINT PARTICLE SYSTEM
 * .....................
 *
 * Author: Richard Lord
 * Copyright (c) Richard Lord 2008-2011
 * http://flintparticles.org
 *
 *
 * Licence Agreement
 *
 * 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.
 */

package org.flintparticles.common.counters
{
	import org.flintparticles.common.emitters.Emitter;

	/**
	 * The Random counter causes the emitter to emit particles continuously
	 * at a variable random rate between two limits.
	 */
	public class Random implements Counter
	{
		private var _timeToNext:Number;
		private var _minRate:Number;
		private var _maxRate:Number;
		private var _running:Boolean;

		/**
		 * The constructor creates a Random counter for use by an emitter. To
		 * add a Random counter to an emitter use the emitter's counter property.
		 *
		 * @param minRate The minimum number of particles to emit per second.
		 * @param maxRate The maximum number of particles to emit per second.
		 *
		 * @see org.flintparticles.common.emitter.Emitter.counter
		 */
		public function Random( minRate:Number = 0, maxRate:Number = 0 )
		{
			_running = false;
			_minRate = minRate;
			_maxRate = maxRate;
		}

		/**
		 * Stops the emitter from emitting particles
		 */
		public function stop():void
		{
			_running = false;
		}

		/**
		 * Resumes the emitter emitting particles after a stop
		 */
		public function resume():void
		{
			_running = true;
		}

		/**
		 * The minimum number of particles to emit per second.
		 */
		public function get minRate():Number
		{
			return _minRate;
		}
		public function set minRate( value:Number ):void
		{
			_minRate = value;
		}

		/**
		 * The maximum number of particles to emit per second.
		 */
		public function get maxRate():Number
		{
			return _maxRate;
		}
		public function set maxRate( value:Number ):void
		{
			_maxRate = value;
		}

		/**
		 * Initilizes the counter. Returns 0 to indicate that the emitter should
		 * emit no particles when it starts.
		 *
		 *
This method is called within the emitter's start method
		 * and need not be called by the user.

		 *
		 * @param emitter The emitter.
		 * @return 0
		 *
		 * @see org.flintparticles.common.counters.Counter#startEmitter()
		 */
		public function startEmitter( emitter:Emitter ):uint
		{
			_running = true;
			_timeToNext = newTimeToNext();
			return 0;
		}

		private function newTimeToNext():Number
		{
			var rate:Number = Math.random() * ( _maxRate - _minRate ) + _maxRate;
			return 1 / rate;
		}

		/**
		 * Uses the time, rateMin and rateMax to calculate how many
		 * particles the emitter should emit now.
		 *
		 *
This method is called within the emitter's update loop and need not
		 * be called by the user.

		 *
		 * @param emitter The emitter.
		 * @param time The time, in seconds, since the previous call to this method.
		 * @return the number of particles the emitter should create.
		 *
		 * @see org.flintparticles.common.counters.Counter#updateEmitter()
		 */
		public function updateEmitter( emitter:Emitter, time:Number ):uint
		{
			if( !_running )
			{
				return 0;
			}
			var count:uint = 0;
			_timeToNext -= time;
			while( _timeToNext <= 0 )
			{
				++count;
				_timeToNext += newTimeToNext();
			}
			return count;
		}

		/**
		 * Indicates if the counter has emitted all its particles. For this counter
		 * this will always be false.
		 */
		public function get complete():Boolean
		{
			return false;
		}

		/**
		 * Indicates if the counter is currently emitting particles
		 */
		public function get running():Boolean
		{
			return _running;
		}
	}
}

Fix bug with Random counter not running

Fix bug with Random counter not running


/**
  * LFCApplication.as
  *
  * @copyright Copyright 2007, 2008, 2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  * @author Henry Minsky <hminsky@laszlosystems.com>
  */

public class LFCApplication {

    // This serves as the superclass of DefaultApplication, currently that is where
    // the compiler puts top level code to run.

    #passthrough (toplevel:true) {
    import flash.display.*;
    import flash.events.*;
    import flash.utils.*;
    import flash.text.*;
    import flash.system.*;
    import flash.net.*;
    import flash.ui.*;
    import flash.text.Font;
    }#

    // The application sprite
    static public var _sprite:Sprite;

    public static function addChild(child:DisplayObject):DisplayObject {
       return _sprite.addChild(child);
    }

    public static function removeChild(child:DisplayObject):DisplayObject {
       return _sprite.removeChild(child);
    }

    public static function setChildIndex(child:DisplayObject, index:int):void {
        _sprite.setChildIndex(child, index);
    }

    // Allow anyone access to the stage object (see ctor below)
    public static var stage:Stage = null;

    // Allow anyone access to write to the debugger
    public static var write:Function;

    // global tabEnabled flag for TextField
    public static var textfieldTabEnabled:Boolean = false;

    public function LFCApplication (sprite:Sprite) {
        LFCApplication._sprite = sprite;
        // wait for the ADDED_TO_STAGE event before continuing to init
        LFCApplication._sprite.addEventListener(Event.ADDED_TO_STAGE, initLFC);
    }

    private function initLFC(event:Event = null) {
        LFCApplication._sprite.removeEventListener(Event.ADDED_TO_STAGE, initLFC);
        // Allow anyone to access the stage object
        LFCApplication.stage = LFCApplication._sprite.stage;
        runToplevelDefinitions()

        var idleTimerPeriod = 14; // msecs

        //trace('idle timer period = ', idleTimerPeriod , 'msecs');
        LzIdleKernel.startTimer( idleTimerPeriod );

        stage.addEventListener(KeyboardEvent.KEY_DOWN,reportKeyDown);
        stage.addEventListener(KeyboardEvent.KEY_UP,reportKeyUp);
        if (Capabilities.playerType == "ActiveX") {
            // workaround for flash player bug FP-1355
            LFCApplication.textfieldTabEnabled = true;
            stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventFocusChange);
        }

        // necessary for consistent behavior - in netscape browsers HTML is ignored
        stage.align = StageAlign.TOP_LEFT;
        stage.scaleMode = StageScaleMode.NO_SCALE;
        //Stage.align = ('canvassalign' in global && global.canvassalign != null) ? global.canvassalign : "LT";
        //Stage.scaleMode = ('canvasscale' in global && global.canvasscale != null) ? global.canvasscale : "noScale";

        stage.addEventListener(Event.RESIZE, resizeHandler);

        // Register for callbacks from the kernel
        LzMouseKernel.setCallback(lz.ModeManager, 'rawMouseEvent');
        LzMouseKernel.initCursor();

        /* TODO [hqm 2008-01] Do we want to do anything with other
         * events, like click, or mousewheel ?

           stage.addEventListener(MouseEvent.CLICK, reportClick);
           stage.addEventListener(MouseEvent.MOUSE_WHEEL, reportWheel);
        */

        LzKeyboardKernel.setCallback(lz.Keys, '__keyEvent');

        // LPP-7597: This is the fix for LPP-7499 canvas size not intialized to browser size
        LzScreenKernel.handleResizeEvent();

    }

    function reportWheel(event:MouseEvent):void {
        /*
        Debug.write(event.currentTarget.toString() +
              " dispatches MouseWheelEvent. delta = " + event.delta); */
        lz.Keys.__mousewheelEvent(event.delta);
    }

    function resizeHandler(event:Event):void {
        //trace('LFCApplication.resizeHandler stage width/height = ', stage.stageWidth, stage.stageHeight);
        LzScreenKernel.handleResizeEvent();
    }

    function reportKeyUp(event:KeyboardEvent):void {
        /*
          trace("Key Released: " + String.fromCharCode(event.charCode) +
              " (key code: " + event.keyCode + " character code: " +
              event.charCode + ")");
        */
        LzKeyboardKernel.__keyboardEvent(event, 'onkeyup');
    }

    function reportKeyDown(event:KeyboardEvent):void {
        /*
          trace("Key Pressed: " + String.fromCharCode(event.charCode) +
              " (key code: " + event.keyCode + " character code: "
              + event.charCode + ")");
        */
        LzKeyboardKernel.__keyboardEvent(event, 'onkeydown');
    }

    function preventFocusChange(event:FocusEvent):void {
        if (event.keyCode == 9) {
            event.preventDefault();
        }
    }

    public function runToplevelDefinitions() {
        // overridden by swf9 script compiler
    }

}

// Resource library
// contains {ptype, class, frames, width, height}
// ptype is one of "ar" (app relative) or "sr" (system relative)
var LzResourceLibrary = {};

/**
  * LFCApplication.as
  *
  * @copyright Copyright 2007, 2008, 2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  * @author Henry Minsky <hminsky@laszlosystems.com>
  */

public class LFCApplication {

    // This serves as the superclass of DefaultApplication, currently that is where
    // the compiler puts top level code to run.

    #passthrough (toplevel:true) {
    import flash.display.*;
    import flash.events.*;
    import flash.utils.*;
    import flash.text.*;
    import flash.system.*;
    import flash.net.*;
    import flash.ui.*;
    import flash.text.Font;
    }#

    // The application sprite
    static public var _sprite:Sprite;

    public static function addChild(child:DisplayObject):DisplayObject {
       return _sprite.addChild(child);
    }

    public static function removeChild(child:DisplayObject):DisplayObject {
       return _sprite.removeChild(child);
    }

    public static function setChildIndex(child:DisplayObject, index:int):void {
        _sprite.setChildIndex(child, index);
    }

    // Allow anyone access to the stage object (see ctor below)
    public static var stage:Stage = null;

    // Allow anyone access to write to the debugger
    public static var write:Function;

    // global tabEnabled flag for TextField
    public static var textfieldTabEnabled:Boolean = false;

    public function LFCApplication (sprite:Sprite) {
        LFCApplication._sprite = sprite;
        // wait for the ADDED_TO_STAGE event before continuing to init
        LFCApplication._sprite.addEventListener(Event.ADDED_TO_STAGE, initLFC);
    }

    private function initLFC(event:Event = null) {
        LFCApplication._sprite.removeEventListener(Event.ADDED_TO_STAGE, initLFC);
        // Allow anyone to access the stage object
        LFCApplication.stage = LFCApplication._sprite.stage;
        runToplevelDefinitions()

        var idleTimerPeriod = 14; // msecs

        //trace('idle timer period = ', idleTimerPeriod , 'msecs');
        LzIdleKernel.startTimer( idleTimerPeriod );

        stage.addEventListener(KeyboardEvent.KEY_DOWN,reportKeyDown);
        stage.addEventListener(KeyboardEvent.KEY_UP,reportKeyUp);
        if (Capabilities.playerType == "ActiveX") {
            // workaround for flash player bug FP-1355
            LFCApplication.textfieldTabEnabled = true;
            stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventFocusChange);
        }

        // necessary for consistent behavior - in netscape browsers HTML is ignored
        stage.align = StageAlign.TOP_LEFT;
        stage.scaleMode = StageScaleMode.NO_SCALE;
        //Stage.align = ('canvassalign' in global && global.canvassalign != null) ? global.canvassalign : "LT";
        //Stage.scaleMode = ('canvasscale' in global && global.canvasscale != null) ? global.canvasscale : "noScale";

        stage.addEventListener(Event.RESIZE, resizeHandler);

        // Register for callbacks from the kernel
        LzMouseKernel.setCallback(lz.ModeManager, 'rawMouseEvent');
        LzMouseKernel.initCursor();

        /* TODO [hqm 2008-01] Do we want to do anything with other
         * events, like click?

           stage.addEventListener(MouseEvent.CLICK, reportClick);
        */
        stage.addEventListener(MouseEvent.MOUSE_WHEEL, reportWheel);

        LzKeyboardKernel.setCallback(lz.Keys, '__keyEvent');

        // LPP-7597: This is the fix for LPP-7499 canvas size not intialized to browser size
        LzScreenKernel.handleResizeEvent();

    }

    function reportWheel(event:MouseEvent):void {
        /*
        Debug.write(event.currentTarget.toString() +
              " dispatches MouseWheelEvent. delta = " + event.delta); */
        lz.Keys.__mousewheelEvent(event.delta);
    }

    function resizeHandler(event:Event):void {
        //trace('LFCApplication.resizeHandler stage width/height = ', stage.stageWidth, stage.stageHeight);
        LzScreenKernel.handleResizeEvent();
    }

    function reportKeyUp(event:KeyboardEvent):void {
        /*
          trace("Key Released: " + String.fromCharCode(event.charCode) +
              " (key code: " + event.keyCode + " character code: " +
              event.charCode + ")");
        */
        LzKeyboardKernel.__keyboardEvent(event, 'onkeyup');
    }

    function reportKeyDown(event:KeyboardEvent):void {
        /*
          trace("Key Pressed: " + String.fromCharCode(event.charCode) +
              " (key code: " + event.keyCode + " character code: "
              + event.charCode + ")");
        */
        LzKeyboardKernel.__keyboardEvent(event, 'onkeydown');
    }

    function preventFocusChange(event:FocusEvent):void {
        if (event.keyCode == 9) {
            event.preventDefault();
        }
    }

    public function runToplevelDefinitions() {
        // overridden by swf9 script compiler
    }

}

// Resource library
// contains {ptype, class, frames, width, height}
// ptype is one of "ar" (app relative) or "sr" (system relative)
var LzResourceLibrary = {};

Change 20090207-maxcarlson-I by maxcarlson@Bank.lan on 2009-02-07 06:56:52 PST
    in /Users/maxcarlson/openlaszlo/trunk-clean
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Fix mousewheel events in swf9 windows

Bugs Fixed: LPP-7731 - swf9: mousewheel events not working in swf9 on windows

Technical Reviewer: hminsky
QA Reviewer: promanik

Details: Uncomment the event registration for MOUSE_WHEEL - the method was already set up...  braino!

Tests: See LPP-7731

git-svn-id: d62bde4b5aa582fdf07c8d403e53e0399a7ed285@12792 fa20e4f9-1d0a-0410-b5f3-dc9c16b8b17c


/*
 *  ISteamWorks.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by Ventero <http://github.com/Ventero> on 2013-08-28
 *  Copyright (c) 2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam {
	import flash.display.DisplayObjectContainer;
	import flash.events.IEventDispatcher;
	import flash.utils.ByteArray;

	public interface ISteamWorks extends IEventDispatcher {
		[Event(name="steamResponse", type="com.amanitadesign.steam.SteamEvent")]
		function ISteamWorks(target:IEventDispatcher = null);

		function init():Boolean;
		function dispose():void;

		function addOverlayWorkaround(container:DisplayObjectContainer,
			alwaysVisible:Boolean = false, color:uint = 0x000000):void;

		function runCallbacks():Boolean
		function getUserID():String
		function getAppID():uint
		function getPersonaName():String
		function useCrashHandler(appID:uint, version:String, date:String, time:String):Boolean
		/* stats/achievements */
		function requestStats():Boolean
		function setAchievement(name:String):Boolean
		function clearAchievement(name:String):Boolean
		function isAchievement(name:String):Boolean
		function getStatInt(name:String):int
		function getStatFloat(name:String):Number
		function setStatInt(name:String, value:int):Boolean
		function setStatFloat(name:String, value:Number):Boolean
		function storeStats():Boolean
		function resetAllStats(achievementsToo:Boolean):Boolean
		/* cloud */
		function getFileCount():int
		function getFileSize(name:String):int
		function fileExists(name:String):Boolean
		function fileWrite(name:String, data:ByteArray):Boolean
		function fileRead(name:String, data:ByteArray):Boolean
		function fileDelete(name:String):Boolean
		function fileShare(name:String):Boolean
		function fileShareResult():String
		function isCloudEnabledForApp():Boolean
		function setCloudEnabledForApp(enabled:Boolean):Boolean
		function getQuota():Array
		/* ugc/workshop */
		function UGCDownload(handle:String, priority:int):Boolean
		function UGCRead(handle:String, size:int, offset:uint, data:ByteArray):Boolean
		function getUGCDownloadProgress(handle:String):Array
		function getUGCDownloadResult(handle:String):DownloadUGCResult
		function publishWorkshopFile(name:String, preview:String, appId:uint, title:String, description:String, visibility:uint, tags:Array, fileType:uint):Boolean
		function publishWorkshopFileResult():String
		function deletePublishedFile(file:String):Boolean
		function getPublishedFileDetails(file:String, maxAge:int = 0):Boolean
		function getPublishedFileDetailsResult(file:String):FileDetailsResult
		function enumerateUserPublishedFiles(startIndex:uint):Boolean
		function enumerateUserPublishedFilesResult():UserFilesResult
		function enumeratePublishedWorkshopFiles(type:uint, start:uint, count:uint, days:uint, tags:Array, userTags:Array):Boolean
		function enumeratePublishedWorkshopFilesResult():WorkshopFilesResult
		function enumerateUserSubscribedFiles(startIndex:uint):Boolean
		function enumerateUserSubscribedFilesResult():SubscribedFilesResult
		function enumerateUserSharedWorkshopFiles(steamID:String, start:uint, required:Array, excluded:Array):Boolean
		function enumerateUserSharedWorkshopFilesResult():UserFilesResult
		function enumeratePublishedFilesByUserAction(action:uint, startIndex:uint):Boolean
		function enumeratePublishedFilesByUserActionResult():FilesByUserActionResult
		function subscribePublishedFile(file:String):Boolean
		function unsubscribePublishedFile(file:String):Boolean
		function createPublishedFileUpdateRequest(file:String):String
		function updatePublishedFileFile(handle:String, file:String):Boolean
		function updatePublishedFilePreviewFile(handle:String, preview:String):Boolean
		function updatePublishedFileTitle(handle:String, title:String):Boolean
		function updatePublishedFileDescription(handle:String, description:String):Boolean
		function updatePublishedFileSetChangeDescription(handle:String, changeDesc:String):Boolean
		function updatePublishedFileVisibility(handle:String, visibility:uint):Boolean
		function updatePublishedFileTags(handle:String, tags:Array):Boolean
		function commitPublishedFileUpdate(handle:String):Boolean
		function getPublishedItemVoteDetails(file:String):Boolean
		function getPublishedItemVoteDetailsResult():ItemVoteDetailsResult
		function getUserPublishedItemVoteDetails(file:String):Boolean
		function getUserPublishedItemVoteDetailsResult():UserVoteDetails
		function updateUserPublishedItemVote(file:String, upvote:Boolean):Boolean
		function setUserPublishedFileAction(file:String, action:uint):Boolean
		/* overlay */
		function activateGameOverlay(dialog:String):Boolean
		function activateGameOverlayToUser(dialog:String, steamId:String):Boolean
		function activateGameOverlayToWebPage(url:String):Boolean
		function activateGameOverlayToStore(appId:uint, flag:uint):Boolean
		function activateGameOverlayInviteDialog(steamIdLobby:String):Boolean
		function isOverlayEnabled():Boolean
		/* DLC / subscriptions */
		function isSubscribedApp(appId:uint):Boolean
		function isDLCInstalled(appId:uint):Boolean
		function getDLCCount():int
		function installDLC(appId:uint):Boolean
		function uninstallDLC(appId:uint):Boolean
		function DLCInstalledResult():uint
	}
}

/*
 *  ISteamWorks.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by Ventero <http://github.com/Ventero> on 2013-08-28
 *  Copyright (c) 2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam {
	import flash.display.DisplayObjectContainer;
	import flash.events.IEventDispatcher;
	import flash.utils.ByteArray;

	public interface ISteamWorks extends IEventDispatcher {
		[Event(name="steamResponse", type="com.amanitadesign.steam.SteamEvent")]
		function init():Boolean;
		function dispose():void;

		function addOverlayWorkaround(container:DisplayObjectContainer,
			alwaysVisible:Boolean = false, color:uint = 0x000000):void;

		function runCallbacks():Boolean
		function getUserID():String
		function getAppID():uint
		function getPersonaName():String
		function useCrashHandler(appID:uint, version:String, date:String, time:String):Boolean
		/* stats/achievements */
		function requestStats():Boolean
		function setAchievement(name:String):Boolean
		function clearAchievement(name:String):Boolean
		function isAchievement(name:String):Boolean
		function getStatInt(name:String):int
		function getStatFloat(name:String):Number
		function setStatInt(name:String, value:int):Boolean
		function setStatFloat(name:String, value:Number):Boolean
		function storeStats():Boolean
		function resetAllStats(achievementsToo:Boolean):Boolean
		/* cloud */
		function getFileCount():int
		function getFileSize(name:String):int
		function fileExists(name:String):Boolean
		function fileWrite(name:String, data:ByteArray):Boolean
		function fileRead(name:String, data:ByteArray):Boolean
		function fileDelete(name:String):Boolean
		function fileShare(name:String):Boolean
		function fileShareResult():String
		function isCloudEnabledForApp():Boolean
		function setCloudEnabledForApp(enabled:Boolean):Boolean
		function getQuota():Array
		/* ugc/workshop */
		function UGCDownload(handle:String, priority:int):Boolean
		function UGCRead(handle:String, size:int, offset:uint, data:ByteArray):Boolean
		function getUGCDownloadProgress(handle:String):Array
		function getUGCDownloadResult(handle:String):DownloadUGCResult
		function publishWorkshopFile(name:String, preview:String, appId:uint, title:String, description:String, visibility:uint, tags:Array, fileType:uint):Boolean
		function publishWorkshopFileResult():String
		function deletePublishedFile(file:String):Boolean
		function getPublishedFileDetails(file:String, maxAge:int = 0):Boolean
		function getPublishedFileDetailsResult(file:String):FileDetailsResult
		function enumerateUserPublishedFiles(startIndex:uint):Boolean
		function enumerateUserPublishedFilesResult():UserFilesResult
		function enumeratePublishedWorkshopFiles(type:uint, start:uint, count:uint, days:uint, tags:Array, userTags:Array):Boolean
		function enumeratePublishedWorkshopFilesResult():WorkshopFilesResult
		function enumerateUserSubscribedFiles(startIndex:uint):Boolean
		function enumerateUserSubscribedFilesResult():SubscribedFilesResult
		function enumerateUserSharedWorkshopFiles(steamID:String, start:uint, required:Array, excluded:Array):Boolean
		function enumerateUserSharedWorkshopFilesResult():UserFilesResult
		function enumeratePublishedFilesByUserAction(action:uint, startIndex:uint):Boolean
		function enumeratePublishedFilesByUserActionResult():FilesByUserActionResult
		function subscribePublishedFile(file:String):Boolean
		function unsubscribePublishedFile(file:String):Boolean
		function createPublishedFileUpdateRequest(file:String):String
		function updatePublishedFileFile(handle:String, file:String):Boolean
		function updatePublishedFilePreviewFile(handle:String, preview:String):Boolean
		function updatePublishedFileTitle(handle:String, title:String):Boolean
		function updatePublishedFileDescription(handle:String, description:String):Boolean
		function updatePublishedFileSetChangeDescription(handle:String, changeDesc:String):Boolean
		function updatePublishedFileVisibility(handle:String, visibility:uint):Boolean
		function updatePublishedFileTags(handle:String, tags:Array):Boolean
		function commitPublishedFileUpdate(handle:String):Boolean
		function getPublishedItemVoteDetails(file:String):Boolean
		function getPublishedItemVoteDetailsResult():ItemVoteDetailsResult
		function getUserPublishedItemVoteDetails(file:String):Boolean
		function getUserPublishedItemVoteDetailsResult():UserVoteDetails
		function updateUserPublishedItemVote(file:String, upvote:Boolean):Boolean
		function setUserPublishedFileAction(file:String, action:uint):Boolean
		/* overlay */
		function activateGameOverlay(dialog:String):Boolean
		function activateGameOverlayToUser(dialog:String, steamId:String):Boolean
		function activateGameOverlayToWebPage(url:String):Boolean
		function activateGameOverlayToStore(appId:uint, flag:uint):Boolean
		function activateGameOverlayInviteDialog(steamIdLobby:String):Boolean
		function isOverlayEnabled():Boolean
		/* DLC / subscriptions */
		function isSubscribedApp(appId:uint):Boolean
		function isDLCInstalled(appId:uint):Boolean
		function getDLCCount():int
		function installDLC(appId:uint):Boolean
		function uninstallDLC(appId:uint):Boolean
		function DLCInstalledResult():uint
	}
}

Remove ctor from interface.

Remove ctor from interface.


package {
  import com.axis.ClientEvent;
  import com.axis.IClient;
  import com.axis.audioclient.AxisTransmit;
  import com.axis.http.url;
  import com.axis.httpclient.HTTPClient;
  import com.axis.rtmpclient.RTMPClient;
  import com.axis.rtspclient.IRTSPHandle;
  import com.axis.rtspclient.RTSPClient;
  import com.axis.rtspclient.RTSPoverHTTPHandle;
  import com.axis.rtspclient.RTSPoverTCPHandle;

  import flash.display.Sprite;
  import flash.display.Stage;
  import flash.display.StageAlign;
  import flash.display.StageDisplayState;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.external.ExternalInterface;
  import flash.media.Microphone;
  import flash.media.SoundMixer;
  import flash.media.SoundTransform;
  import flash.media.Video;
  import flash.net.NetStream;
  import flash.system.Security;

  [SWF(frameRate="60")]
  [SWF(backgroundColor="#efefef")]

  public class Player extends Sprite {
    private var config:Object = {
      'buffer': 1,
      'scaleUp': false
    };
    private var video:Video;
    private var audioTransmit:AxisTransmit = new AxisTransmit();
    private var meta:Object = {};
    private var client:IClient;
    private var ns:NetStream;
    private var urlParsed:Object;
    private var savedSpeakerVolume:Number;
    private var fullscreenAllowed:Boolean = true;
    private var currentState:String = "Stopped";
    private var streamHasAudio:Boolean = false;
    private var streamHasVideo:Boolean = false;

    public function Player() {
      var self:Player = this;

      Security.allowDomain("*");
      Security.allowInsecureDomain("*");

      ExternalInterface.marshallExceptions = true;

      /* Media player API */
      ExternalInterface.addCallback("play", play);
      ExternalInterface.addCallback("pause", pause);
      ExternalInterface.addCallback("resume", resume);
      ExternalInterface.addCallback("stop", stop);
      ExternalInterface.addCallback("seek", seek);
      ExternalInterface.addCallback("playbackSpeed", playbackSpeed);
      ExternalInterface.addCallback("streamStatus", streamStatus);
      ExternalInterface.addCallback("playerStatus", playerStatus);
      ExternalInterface.addCallback("speakerVolume", speakerVolume);
      ExternalInterface.addCallback("muteSpeaker", muteSpeaker);
      ExternalInterface.addCallback("unmuteSpeaker", unmuteSpeaker);
      ExternalInterface.addCallback("microphoneVolume", microphoneVolume);
      ExternalInterface.addCallback("muteMicrophone", muteMicrophone);
      ExternalInterface.addCallback("unmuteMicrophone", unmuteMicrophone);
      ExternalInterface.addCallback("allowFullscreen", allowFullscreen);

      /* Audio Transmission API */
      ExternalInterface.addCallback("startAudioTransmit", startAudioTransmit);
      ExternalInterface.addCallback("stopAudioTransmit", stopAudioTransmit);

      /* Set default speaker volume */
      this.speakerVolume(50);

      /* Stage setup */
      this.stage.align = StageAlign.TOP_LEFT;
      this.stage.scaleMode = StageScaleMode.NO_SCALE;
      addEventListener(Event.ADDED_TO_STAGE, onStageAdded);

      /* Video object setup */
      video = new Video(stage.stageWidth, stage.stageHeight);
      addChild(video);

      /* Fullscreen support setup */
      this.stage.doubleClickEnabled = true;
      this.stage.addEventListener(MouseEvent.DOUBLE_CLICK, fullscreen);
      this.stage.addEventListener(Event.FULLSCREEN, function(event:Event):void {
        videoResize();
      });
    }

    public function fullscreen(event:MouseEvent):void {
      if (this.fullscreenAllowed)
        this.stage.displayState = (StageDisplayState.NORMAL === stage.displayState) ?
          StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL;
    }

    public function videoResize():void {
      var stagewidth:uint = (StageDisplayState.NORMAL === stage.displayState) ?
        stage.stageWidth : stage.fullScreenWidth;
      var stageheight:uint = (StageDisplayState.NORMAL === stage.displayState) ?
        stage.stageHeight : stage.fullScreenHeight;

      var scale:Number = ((stagewidth / meta.width) > (stageheight / meta.height)) ?
        (stageheight / meta.height) : (stagewidth / meta.width);

      video.width = meta.width;
      video.height = meta.height;
      if ((scale < 1.0) || (scale > 1.0 && true === config.scaleUp)) {
        trace('scaling video, scale:', scale.toFixed(2), ' (aspect ratio: ' +  (video.width / video.height).toFixed(2) + ')');
        video.width = meta.width * scale;
        video.height = meta.height * scale;
      }

      video.x = (stagewidth - video.width) / 2;
      video.y = (stageheight - video.height) / 2;
    }

    public function play(iurl:String = null):void {
      if (client) {
        urlParsed = url.parse(iurl);
        /* Stop the client, and 'onStopped' will start the new stream. */
        client.stop();
        return;
      }

      urlParsed = url.parse(iurl);
      start();
    }

    private function start():void {
      switch (urlParsed.protocol) {
      case 'rtsph':
        /* RTSP over HTTP */
        client = new RTSPClient(this.video, urlParsed, new RTSPoverHTTPHandle(urlParsed));
        break;

      case 'rtsp':
        /* RTSP over TCP */
        client = new RTSPClient(this.video, urlParsed, new RTSPoverTCPHandle(urlParsed));
        this.callAPI('streamStarted');
        break;

      case 'http':
        /* Progressive download over HTTP */
        client = new HTTPClient(this.video, urlParsed);
        break;

      case 'rtmp':
        /* RTMP */
        client = new RTMPClient(this.video, urlParsed);
        break;

      default:
        trace('Unknown streaming protocol:', urlParsed.protocol)
        return;
      }

      client.addEventListener(ClientEvent.NETSTREAM_CREATED, onNetStreamCreated);
      client.addEventListener(ClientEvent.STOPPED, onStopped);
      client.addEventListener(ClientEvent.START_PLAY, onStartPlay);
      client.start();
    }

    public function pause():void {
      client.pause();
      this.callAPI('streamPaused');
      this.currentState = "Paused";
    }

    public function resume():void {
      client.resume();
      this.callAPI('streamResumed');
    }

    public function stop():void {
      urlParsed = null;
      ns = null;
      client.stop();
      this.callAPI('streamStopped');
      this.currentState = "Stopped";
      this.streamHasAudio = false;
      this.streamHasVideo = false;
    }

    public function seek(timestamp:String):void {
      trace('seek, timestamp->' + timestamp);
    }

    public function playbackSpeed(speed:Number):void {
      trace('playbackSpeed, speed->' + speed);
    }

    public function streamStatus():Object {
      if (this.currentState === 'Playing') {
        this.streamHasAudio = (this.streamHasAudio || this.ns.info.audioBufferByteLength);
        this.streamHasVideo = (this.streamHasVideo || this.ns.info.videoBufferByteLength);
      }
      var status:Object = {
        'fps': (this.ns) ? Math.floor(this.ns.currentFPS + 0.5) : null,
        'resolution': (this.ns) ? (meta.width + 'x' + meta.height) : null,
        'playbackSpeed': (this.ns) ? 1.0 : null,
        'protocol': (this.urlParsed) ? this.urlParsed.protocol: null,
        'audio': (this.ns) ? this.streamHasAudio : null,
        'video': (this.ns) ? this.streamHasVideo : null,
        'state': this.currentState,
        'isSeekable': false,
        'isPlaybackSpeedChangeable': false,
        'streamURL': (this.urlParsed) ? this.urlParsed.full : null
      };

      return status;
    }

    public function playerStatus():Object {
      var mic:Microphone = Microphone.getMicrophone();

      var status:Object = {
        'microphoneVolume': audioTransmit.microphoneVolume,
        'speakerVolume': this.savedSpeakerVolume,
        'microphoneMuted': (mic.gain === 0),
        'speakerMuted': (flash.media.SoundMixer.soundTransform.volume === 0),
        'fullscreen': (StageDisplayState.FULL_SCREEN === stage.displayState)
      };

      return status;
    }

    public function speakerVolume(volume:Number):void {
      this.savedSpeakerVolume = volume;
      var transform:SoundTransform = new SoundTransform(volume / 100.0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function muteSpeaker():void {
      var transform:SoundTransform = new SoundTransform(0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function unmuteSpeaker():void {
      if (flash.media.SoundMixer.soundTransform.volume !== 0)
        return;

      var transform:SoundTransform = new SoundTransform(this.savedSpeakerVolume / 100.0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function microphoneVolume(volume:Number):void {
      audioTransmit.microphoneVolume = volume;
    }

    public function muteMicrophone():void {
      audioTransmit.muteMicrophone();
    }

    public function unmuteMicrophone():void {
      audioTransmit.unmuteMicrophone();
    }

    public function startAudioTransmit(url:String = null, type:String = 'axis'):void {
      if (type === 'axis') {
        audioTransmit.start(url);
      } else {
        trace("unsupported type");
      }
    }

    public function stopAudioTransmit():void {
      audioTransmit.stop();
    }

    public function allowFullscreen(state:Boolean):void {
      this.fullscreenAllowed = state;

      if (!state)
        this.stage.displayState = StageDisplayState.NORMAL;
    }

    private function onStageAdded(e:Event):void {
      trace('stage added');
    }

    public function onMetaData(item:Object):void {
      this.meta = item;
      this.videoResize();
    }

    public function onNetStreamCreated(ev:ClientEvent):void {
      this.ns = ev.data.ns;
      ev.data.ns.bufferTime = config.buffer;
      ev.data.ns.client = this;
    }

    private function onStopped(ev:ClientEvent):void {
      video.clear();
      client = null;
      if (urlParsed) {
        start();
      }
    }

    private function onStartPlay(ev:ClientEvent):void {
      this.currentState = "Playing";
    }

    public function onPlayStatus(ev:Object):void {
      this.currentState = "Stopped";
    }

    private function callAPI(eventName:String, data:Object = null):void {
      if (!ExternalInterface.available) {
        trace("ExternalInterface is not available!");
        return;
      }

      var functionName:String = "Locomote('" + ExternalInterface.objectID + "').__playerEvent";
      if (data) {
        ExternalInterface.call(functionName, eventName, data);
      } else {
        ExternalInterface.call(functionName, eventName);
      }
    }
  }
}

package {
  import com.axis.ClientEvent;
  import com.axis.IClient;
  import com.axis.audioclient.AxisTransmit;
  import com.axis.http.url;
  import com.axis.httpclient.HTTPClient;
  import com.axis.rtmpclient.RTMPClient;
  import com.axis.rtspclient.IRTSPHandle;
  import com.axis.rtspclient.RTSPClient;
  import com.axis.rtspclient.RTSPoverHTTPHandle;
  import com.axis.rtspclient.RTSPoverTCPHandle;

  import flash.display.Sprite;
  import flash.display.Stage;
  import flash.display.StageAlign;
  import flash.display.StageDisplayState;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.external.ExternalInterface;
  import flash.media.Microphone;
  import flash.media.SoundMixer;
  import flash.media.SoundTransform;
  import flash.media.Video;
  import flash.net.NetStream;
  import flash.system.Security;

  [SWF(frameRate="60")]
  [SWF(backgroundColor="#efefef")]

  public class Player extends Sprite {
    private var config:Object = {
      'buffer': 1,
      'scaleUp': false
    };
    private var video:Video;
    private var audioTransmit:AxisTransmit = new AxisTransmit();
    private var meta:Object = {};
    private var client:IClient;
    private var ns:NetStream;
    private var urlParsed:Object;
    private var savedSpeakerVolume:Number;
    private var fullscreenAllowed:Boolean = true;
    private var currentState:String = "Stopped";
    private var streamHasAudio:Boolean = false;
    private var streamHasVideo:Boolean = false;

    public function Player() {
      var self:Player = this;

      Security.allowDomain("*");
      Security.allowInsecureDomain("*");

      ExternalInterface.marshallExceptions = true;

      /* Media player API */
      ExternalInterface.addCallback("play", play);
      ExternalInterface.addCallback("pause", pause);
      ExternalInterface.addCallback("resume", resume);
      ExternalInterface.addCallback("stop", stop);
      ExternalInterface.addCallback("seek", seek);
      ExternalInterface.addCallback("playbackSpeed", playbackSpeed);
      ExternalInterface.addCallback("streamStatus", streamStatus);
      ExternalInterface.addCallback("playerStatus", playerStatus);
      ExternalInterface.addCallback("speakerVolume", speakerVolume);
      ExternalInterface.addCallback("muteSpeaker", muteSpeaker);
      ExternalInterface.addCallback("unmuteSpeaker", unmuteSpeaker);
      ExternalInterface.addCallback("microphoneVolume", microphoneVolume);
      ExternalInterface.addCallback("muteMicrophone", muteMicrophone);
      ExternalInterface.addCallback("unmuteMicrophone", unmuteMicrophone);
      ExternalInterface.addCallback("allowFullscreen", allowFullscreen);

      /* Audio Transmission API */
      ExternalInterface.addCallback("startAudioTransmit", startAudioTransmit);
      ExternalInterface.addCallback("stopAudioTransmit", stopAudioTransmit);

      /* Set default speaker volume */
      this.speakerVolume(50);

      /* Stage setup */
      this.stage.align = StageAlign.TOP_LEFT;
      this.stage.scaleMode = StageScaleMode.NO_SCALE;
      addEventListener(Event.ADDED_TO_STAGE, onStageAdded);

      /* Video object setup */
      video = new Video(stage.stageWidth, stage.stageHeight);
      addChild(video);

      /* Fullscreen support setup */
      this.stage.doubleClickEnabled = true;
      this.stage.addEventListener(MouseEvent.DOUBLE_CLICK, fullscreen);
      this.stage.addEventListener(Event.FULLSCREEN, function(event:Event):void {
        videoResize();
      });
    }

    public function fullscreen(event:MouseEvent):void {
      if (this.fullscreenAllowed)
        this.stage.displayState = (StageDisplayState.NORMAL === stage.displayState) ?
          StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL;
    }

    public function videoResize():void {
      var stagewidth:uint = (StageDisplayState.NORMAL === stage.displayState) ?
        stage.stageWidth : stage.fullScreenWidth;
      var stageheight:uint = (StageDisplayState.NORMAL === stage.displayState) ?
        stage.stageHeight : stage.fullScreenHeight;

      var scale:Number = ((stagewidth / meta.width) > (stageheight / meta.height)) ?
        (stageheight / meta.height) : (stagewidth / meta.width);

      video.width = meta.width;
      video.height = meta.height;
      if ((scale < 1.0) || (scale > 1.0 && true === config.scaleUp)) {
        trace('scaling video, scale:', scale.toFixed(2), ' (aspect ratio: ' +  (video.width / video.height).toFixed(2) + ')');
        video.width = meta.width * scale;
        video.height = meta.height * scale;
      }

      video.x = (stagewidth - video.width) / 2;
      video.y = (stageheight - video.height) / 2;
    }

    public function play(iurl:String = null):void {
      if (client) {
        urlParsed = url.parse(iurl);
        /* Stop the client, and 'onStopped' will start the new stream. */
        client.stop();
        return;
      }

      this.streamHasAudio = false;
      this.streamHasVideo = false;
      urlParsed = url.parse(iurl);
      start();
    }

    private function start():void {
      switch (urlParsed.protocol) {
      case 'rtsph':
        /* RTSP over HTTP */
        client = new RTSPClient(this.video, urlParsed, new RTSPoverHTTPHandle(urlParsed));
        break;

      case 'rtsp':
        /* RTSP over TCP */
        client = new RTSPClient(this.video, urlParsed, new RTSPoverTCPHandle(urlParsed));
        this.callAPI('streamStarted');
        break;

      case 'http':
        /* Progressive download over HTTP */
        client = new HTTPClient(this.video, urlParsed);
        break;

      case 'rtmp':
        /* RTMP */
        client = new RTMPClient(this.video, urlParsed);
        break;

      default:
        trace('Unknown streaming protocol:', urlParsed.protocol)
        return;
      }

      client.addEventListener(ClientEvent.NETSTREAM_CREATED, onNetStreamCreated);
      client.addEventListener(ClientEvent.STOPPED, onStopped);
      client.addEventListener(ClientEvent.START_PLAY, onStartPlay);
      client.start();
    }

    public function pause():void {
      client.pause();
      this.callAPI('streamPaused');
      this.currentState = "Paused";
    }

    public function resume():void {
      client.resume();
      this.callAPI('streamResumed');
    }

    public function stop():void {
      urlParsed = null;
      ns = null;
      client.stop();
      this.callAPI('streamStopped');
      this.currentState = "Stopped";
      this.streamHasAudio = false;
      this.streamHasVideo = false;
    }

    public function seek(timestamp:String):void {
      trace('seek, timestamp->' + timestamp);
    }

    public function playbackSpeed(speed:Number):void {
      trace('playbackSpeed, speed->' + speed);
    }

    public function streamStatus():Object {
      if (this.currentState === 'Playing') {
        this.streamHasAudio = (this.streamHasAudio || this.ns.info.audioBufferByteLength);
        this.streamHasVideo = (this.streamHasVideo || this.ns.info.videoBufferByteLength);
      }
      var status:Object = {
        'fps': (this.ns) ? Math.floor(this.ns.currentFPS + 0.5) : null,
        'resolution': (this.ns) ? (meta.width + 'x' + meta.height) : null,
        'playbackSpeed': (this.ns) ? 1.0 : null,
        'protocol': (this.urlParsed) ? this.urlParsed.protocol: null,
        'audio': (this.ns) ? this.streamHasAudio : null,
        'video': (this.ns) ? this.streamHasVideo : null,
        'state': this.currentState,
        'isSeekable': false,
        'isPlaybackSpeedChangeable': false,
        'streamURL': (this.urlParsed) ? this.urlParsed.full : null
      };

      return status;
    }

    public function playerStatus():Object {
      var mic:Microphone = Microphone.getMicrophone();

      var status:Object = {
        'microphoneVolume': audioTransmit.microphoneVolume,
        'speakerVolume': this.savedSpeakerVolume,
        'microphoneMuted': (mic.gain === 0),
        'speakerMuted': (flash.media.SoundMixer.soundTransform.volume === 0),
        'fullscreen': (StageDisplayState.FULL_SCREEN === stage.displayState)
      };

      return status;
    }

    public function speakerVolume(volume:Number):void {
      this.savedSpeakerVolume = volume;
      var transform:SoundTransform = new SoundTransform(volume / 100.0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function muteSpeaker():void {
      var transform:SoundTransform = new SoundTransform(0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function unmuteSpeaker():void {
      if (flash.media.SoundMixer.soundTransform.volume !== 0)
        return;

      var transform:SoundTransform = new SoundTransform(this.savedSpeakerVolume / 100.0);
      flash.media.SoundMixer.soundTransform = transform;
    }

    public function microphoneVolume(volume:Number):void {
      audioTransmit.microphoneVolume = volume;
    }

    public function muteMicrophone():void {
      audioTransmit.muteMicrophone();
    }

    public function unmuteMicrophone():void {
      audioTransmit.unmuteMicrophone();
    }

    public function startAudioTransmit(url:String = null, type:String = 'axis'):void {
      if (type === 'axis') {
        audioTransmit.start(url);
      } else {
        trace("unsupported type");
      }
    }

    public function stopAudioTransmit():void {
      audioTransmit.stop();
    }

    public function allowFullscreen(state:Boolean):void {
      this.fullscreenAllowed = state;

      if (!state)
        this.stage.displayState = StageDisplayState.NORMAL;
    }

    private function onStageAdded(e:Event):void {
      trace('stage added');
    }

    public function onMetaData(item:Object):void {
      this.meta = item;
      this.videoResize();
    }

    public function onNetStreamCreated(ev:ClientEvent):void {
      this.ns = ev.data.ns;
      ev.data.ns.bufferTime = config.buffer;
      ev.data.ns.client = this;
    }

    private function onStopped(ev:ClientEvent):void {
      video.clear();
      client = null;
      if (urlParsed) {
        start();
      }
    }

    private function onStartPlay(ev:ClientEvent):void {
      this.currentState = "Playing";
    }

    public function onPlayStatus(ev:Object):void {
      this.currentState = "Stopped";
    }

    private function callAPI(eventName:String, data:Object = null):void {
      if (!ExternalInterface.available) {
        trace("ExternalInterface is not available!");
        return;
      }

      var functionName:String = "Locomote('" + ExternalInterface.objectID + "').__playerEvent";
      if (data) {
        ExternalInterface.call(functionName, eventName, data);
      } else {
        ExternalInterface.call(functionName, eventName);
      }
    }
  }
}

Reset audio and video status

Reset audio and video status

Added reset of stream audio and video status in case play is run without
stopping a previously running stream first.


package fairygui {
	import fairygui.display.MovieClip;
	import fairygui.utils.ByteBuffer;

	import laya.maths.Rectangle;
	import laya.utils.Handler;
	import fairygui.gears.IAnimationGear;
	import fairygui.gears.IColorGear;

	public class GMovieClip extends GObject implements IAnimationGear, IColorGear {
		private var _movieClip: MovieClip;

		public function GMovieClip() {
			super();
			this._sizeImplType = 1;
		}

		public function get color(): String {
			return "#FFFFFF";
		}

		public function set color(value: String):void {
		}

		override protected function createDisplayObject(): void {
			this._displayObject = _movieClip = new MovieClip();
			_movieClip.mouseEnabled = false;
			this._displayObject["$owner"] = this;
		}

		public function get playing(): Boolean {
			return _movieClip.playing;
		}

		public function set playing(value: Boolean):void {
			if (_movieClip.playing != value) {
				_movieClip.playing = value;
				this.updateGear(5);
			}
		}

		public function get frame(): Number {
			return _movieClip.frame;
		}

		public function set frame(value: Number):void {
			if (_movieClip.frame != value) {
				_movieClip.frame = value;
				this.updateGear(5);
			}
		}

		final public function get timeScale():Number
		{
			return _movieClip.timeScale;
		}

		public function set timeScale(value:Number):void
		{
			_movieClip.timeScale = value;
		}

		public function rewind():void
		{
			_movieClip.rewind();
		}

		public function syncStatus(anotherMc:GMovieClip):void
		{
			_movieClip.syncStatus(anotherMc._movieClip);
		}

		public function advance(timeInMiniseconds:int):void
		{
			_movieClip.advance(timeInMiniseconds);
		}

		//从start帧开始，播放到end帧（-1表示结尾），重复times次（0表示无限循环），循环结束后，停止在endAt帧（-1表示参数end）
		public function setPlaySettings(start: Number = 0,end: Number = -1,
										times: Number = 0,endAt: Number = -1,
										endHandler: Handler = null): void {
			_movieClip.setPlaySettings(start, end, times, endAt, endHandler);
		}

		override public function constructFromResource(): void {
			this.sourceWidth = this.packageItem.width;
			this.sourceHeight = this.packageItem.height;
			this.initWidth = this.sourceWidth;
			this.initHeight = this.sourceHeight;

			this.setSize(this.sourceWidth, this.sourceHeight);

			this.packageItem.load();

			_movieClip.interval = this.packageItem.interval;
			_movieClip.swing = this.packageItem.swing;
			_movieClip.repeatDelay = this.packageItem.repeatDelay;
			_movieClip.frames = this.packageItem.frames;
			_movieClip.boundsRect = new Rectangle(0, 0, this.sourceWidth, this.sourceHeight);
		}

		override public function setup_beforeAdd(buffer:ByteBuffer, beginPos:int): void {
			super.setup_beforeAdd(buffer, beginPos);

			buffer.seek(beginPos, 5);

			if (buffer.readBool())
				this.color = buffer.readColorS();
			buffer.readByte(); //flip
			_movieClip.frame = buffer.getInt32();
			_movieClip.playing = buffer.readBool();
		}
	}
}

package fairygui {
	import fairygui.display.MovieClip;
	import fairygui.utils.ByteBuffer;

	import laya.maths.Rectangle;
	import laya.utils.Handler;
	import fairygui.gears.IAnimationGear;
	import fairygui.gears.IColorGear;

	public class GMovieClip extends GObject implements IAnimationGear, IColorGear {
		private var _movieClip: MovieClip;

		public function GMovieClip() {
			super();
		}

		public function get color(): String {
			return "#FFFFFF";
		}

		public function set color(value: String):void {
		}

		override protected function createDisplayObject(): void {
			this._displayObject = _movieClip = new MovieClip();
			_movieClip.mouseEnabled = false;
			this._displayObject["$owner"] = this;
		}

		public function get playing(): Boolean {
			return _movieClip.playing;
		}

		public function set playing(value: Boolean):void {
			if (_movieClip.playing != value) {
				_movieClip.playing = value;
				this.updateGear(5);
			}
		}

		public function get frame(): Number {
			return _movieClip.frame;
		}

		public function set frame(value: Number):void {
			if (_movieClip.frame != value) {
				_movieClip.frame = value;
				this.updateGear(5);
			}
		}

		final public function get timeScale():Number
		{
			return _movieClip.timeScale;
		}

		public function set timeScale(value:Number):void
		{
			_movieClip.timeScale = value;
		}

		public function rewind():void
		{
			_movieClip.rewind();
		}

		public function syncStatus(anotherMc:GMovieClip):void
		{
			_movieClip.syncStatus(anotherMc._movieClip);
		}

		public function advance(timeInMiniseconds:int):void
		{
			_movieClip.advance(timeInMiniseconds);
		}

		//从start帧开始，播放到end帧（-1表示结尾），重复times次（0表示无限循环），循环结束后，停止在endAt帧（-1表示参数end）
		public function setPlaySettings(start: Number = 0,end: Number = -1,
										times: Number = 0,endAt: Number = -1,
										endHandler: Handler = null): void {
			_movieClip.setPlaySettings(start, end, times, endAt, endHandler);
		}

		override public function constructFromResource(): void {
			this.sourceWidth = this.packageItem.width;
			this.sourceHeight = this.packageItem.height;
			this.initWidth = this.sourceWidth;
			this.initHeight = this.sourceHeight;

			this.setSize(this.sourceWidth, this.sourceHeight);

			this.packageItem.load();

			_movieClip.interval = this.packageItem.interval;
			_movieClip.swing = this.packageItem.swing;
			_movieClip.repeatDelay = this.packageItem.repeatDelay;
			_movieClip.frames = this.packageItem.frames;
		}

		override public function setup_beforeAdd(buffer:ByteBuffer, beginPos:int): void {
			super.setup_beforeAdd(buffer, beginPos);

			buffer.seek(beginPos, 5);

			if (buffer.readBool())
				this.color = buffer.readColorS();
			buffer.readByte(); //flip
			_movieClip.frame = buffer.getInt32();
			_movieClip.playing = buffer.readBool();
		}
	}
}

remove unused code.

remove unused code.


package goplayer
{
  import flash.utils.getTimer

  public class Player implements
    FlashNetConnectionListener,
    FlashNetStreamListener
  {
    private const DEFAULT_VOLUME : Number = .8

    private const START_BUFFER : Duration = Duration.seconds(3)
    private const SMALL_BUFFER : Duration = Duration.seconds(5)
    private const LARGE_BUFFER : Duration = Duration.seconds(60)
    private const SEEK_GRACE_TIME : Duration = Duration.seconds(2)

    private const finishingListeners : Array = []

    private var connection : FlashNetConnection
    private var _movie : Movie
    private var bitratePolicy : BitratePolicy
    private var enableRTMP : Boolean
    private var reporter : MovieEventReporter
    private var sharedVolumeVariable : SharedVariable

    private var _started : Boolean = false
    private var _finished : Boolean = false
    private var triedStandardRTMP : Boolean = false
    private var _usingRTMP : Boolean = false

    private var measuredBandwidth : Bitrate = null
    private var measuredLatency : Duration = null

    private var stream : FlashNetStream = null
    private var metadata : Object = null

    private var _volume : Number = NaN
    private var savedVolume : Number = 0
    private var _paused : Boolean = false
    private var _buffering : Boolean = false
    private var seekStopwatch : Stopwatch = new Stopwatch

    public function Player
      (connection : FlashNetConnection,
       movie : Movie,
       bitratePolicy : BitratePolicy,
       enableRTMP : Boolean,
       reporter : MovieEventReporter,
       sharedVolumeVariable : SharedVariable)
    {
      this.connection = connection
      _movie = movie
      this.bitratePolicy = bitratePolicy
      this.enableRTMP = enableRTMP
      this.reporter = reporter
      this.sharedVolumeVariable = sharedVolumeVariable

      connection.listener = this

      reporter.reportMovieViewed(movie.id)

      if (sharedVolumeVariable.hasValue)
        volume = sharedVolumeVariable.value
      else
        volume = DEFAULT_VOLUME
    }

    public function get movie() : Movie
    { return _movie }

    public function addFinishingListener
      (value : PlayerFinishingListener) : void
    { finishingListeners.push(value) }

    public function get started() : Boolean
    { return _started }

    public function get running() : Boolean
    { return started && !finished }

    public function get finished() : Boolean
    { return _finished }

    // -----------------------------------------------------

    public function destroy() : void
    {
      if (stream != null)
        stream.destroy()
    }

    public function start() : void
    {
      _started = true

      if (enableRTMP && movie.rtmpURL != null)
        connectUsingRTMP()
      else
        connectUsingHTTP()

      reporter.reportMoviePlayed(movie.id)
    }

    public function handleConnectionFailed() : void
    {
      if (movie.rtmpURL.hasPort && !triedStandardRTMP)
        handleCustomRTMPUnavailable()
      else
        handleRTMPUnavailable()
    }

    private function handleCustomRTMPUnavailable() : void
    {
      debug("Trying to connect using default RTMP ports.")
      connectUsingStandardRTMP()
    }

    private function handleRTMPUnavailable() : void
    {
      debug("Could not connect using RTMP; trying plain HTTP.")
      connectUsingHTTP()
    }

    public function get usingRTMP() : Boolean
    { return _usingRTMP }

    private function connectUsingRTMP() : void
    { connection.connect(movie.rtmpURL) }

    private function connectUsingStandardRTMP() : void
    {
      triedStandardRTMP = true
      connection.connect(movie.rtmpURL.withoutPort)
    }

    private function connectUsingHTTP() : void
    {
      _usingRTMP = false
      connection.dontConnect()
      startPlaying()
    }

    public function handleConnectionClosed() : void
    {}

    // -----------------------------------------------------

    public function handleConnectionEstablished() : void
    {
      _usingRTMP = true

      if (bandwidthDeterminationNeeded)
        connection.determineBandwidth()
      else
        startPlaying()
    }

    private function get bandwidthDeterminationNeeded() : Boolean
    { return bitratePolicy == BitratePolicy.BEST }

    public function handleBandwidthDetermined
      (bandwidth : Bitrate, latency : Duration) : void
    {
      measuredBandwidth = bandwidth
      measuredLatency = latency

      startPlaying()
    }

    private function get bandwidthDetermined() : Boolean
    { return measuredBandwidth != null }

    private function startPlaying() : void
    {
      stream = connection.getNetStream()
      stream.listener = this
      stream.volume = volume

      useStartBuffer()

      if (usingRTMP)
        playRTMPStream()
      else
        playHTTPStream()

      if (paused)
        stream.paused = true
    }

    private function playRTMPStream() : void
    { stream.playRTMP(streamPicker.first, streamPicker.all) }

    private function playHTTPStream() : void
    { stream.playHTTP(movie.httpURL) }

    private function get streamPicker() : RTMPStreamPicker
    {
      return new RTMPStreamPicker
        (movie.rtmpStreams, bitratePolicy, measuredBandwidth)
    }

    // -----------------------------------------------------

    public function handleNetStreamMetadata(data : Object) : void
    {
      metadata = data

      if (!usingRTMP)
        debug("Video file size: " + stream.httpFileSize)
    }

    public function handleStreamingStarted() : void
    {
      useStartBuffer()
      _buffering = true
      _finished = false
    }

    public function handleBufferFilled() : void
    { handleBufferingFinished() }

    private function handleBufferingFinished() : void
    {
      _buffering = false

      // Give the backend a chance to resume playback before we go
      // ahead and raise the buffer size further.
      later($handleBufferingFinished)
    }

    private function $handleBufferingFinished() : void
    {
      // Make sure playback was not interrupted.
      if (!buffering && !finished)
        useLargeBuffer()
    }

    public function handleBufferEmptied() : void
    {
      if (finishedPlaying)
        handleFinishedPlaying()
      else
        handleBufferingStarted()
    }

    private function handleBufferingStarted() : void
    {
      useSmallBuffer()
      _buffering = true
      _finished = false
    }

    private function useStartBuffer() : void
    { stream.bufferTime = START_BUFFER }

    private function useSmallBuffer() : void
    { stream.bufferTime = SMALL_BUFFER }

    private function useLargeBuffer() : void
    { stream.bufferTime = LARGE_BUFFER }

    public function get buffering() : Boolean
    { return _buffering }

    public function get bufferingUnexpectedly() : Boolean
    { return buffering && !justSeeked }

    private function get justSeeked() : Boolean
    { return seekStopwatch.within(SEEK_GRACE_TIME) }

    public function handleStreamingStopped() : void
    {
      _buffering = false

      if (finishedPlaying)
        handleFinishedPlaying()
    }

    private function handleFinishedPlaying() : void
    {
      debug("Finished playing.")
      _finished = true

      for each (var listener : PlayerFinishingListener in finishingListeners)
        listener.handleMovieFinishedPlaying()
    }

    public function stop() : void
    {
      debug("Stopping.")
      stream.close()
      _started = false
      stream = null
      metadata = null
    }

    private function get finishedPlaying() : Boolean
    { return timeRemaining.seconds < 1 }

    private function get timeRemaining() : Duration
    { return duration.minus(currentTime) }

    // -----------------------------------------------------

    public function get paused() : Boolean
    { return _paused }

    public function set paused(value : Boolean) : void
    {
      if (stream != null)
        _paused = value, stream.paused = value
    }

    public function togglePaused() : void
    {
      if (stream != null)
        paused = !paused
    }

    // -----------------------------------------------------

    public function get currentTime() : Duration
    {
      return stream != null && stream.currentTime != null
        ? stream.currentTime : Duration.ZERO
    }

    public function get playheadRatio() : Number
    { return getRatio(currentTime.seconds, duration.seconds) }

    public function get bufferRatio() : Number
    { return getRatio(bufferPosition.seconds, duration.seconds) }

    private function getRatio
      (numerator : Number, denominator : Number) : Number
    { return Math.min(1, numerator / denominator) }

    private function get bufferPosition() : Duration
    { return currentTime.plus(bufferLength) }

    public function set currentTime(value : Duration) : void
    {
      if (stream != null)
        $currentTime = value
    }

    private function set $currentTime(value : Duration) : void
    {
      _finished = false
      seekStopwatch.start()
      useStartBuffer()
      stream.currentTime = value
    }

    public function set playheadRatio(value : Number) : void
    { currentTime = duration.scaledBy(value) }

    public function seekBy(delta : Duration) : void
    { currentTime = currentTime.plus(delta) }

    public function rewind() : void
    { currentTime = Duration.ZERO }

    public function get playing() : Boolean
    { return started && stream != null && !paused && !finished }

    // -----------------------------------------------------

    public function get volume() : Number
    { return _volume }

    public function set volume(value : Number) : void
    {
      _volume = Math.round(clamp(value, 0, 1) * 100) / 100

      if (sharedVolumeVariable.available)
        sharedVolumeVariable.value = volume

      if (stream)
        stream.volume = volume
    }

    public function changeVolumeBy(delta : Number) : void
    { volume = volume + delta }

    public function mute() : void
    {
      savedVolume = volume
      volume = 0
    }

    public function unmute() : void
    { volume = savedVolume == 0 ? DEFAULT_VOLUME : savedVolume }

    public function get muted() : Boolean
    { return volume == 0 }

    // -----------------------------------------------------

    public function get aspectRatio() : Number
    { return movie.aspectRatio }

    public function get bufferTime() : Duration
    {
      return stream != null && stream.bufferTime != null
        ? stream.bufferTime : START_BUFFER
    }

    public function get bufferLength() : Duration
    {
      return stream != null && stream.bufferLength != null
        ? stream.bufferLength : Duration.ZERO
    }

    public function get bufferFillRatio() : Number
    { return getRatio(bufferLength.seconds, bufferTime.seconds) }

    public function get duration() : Duration
    {
      return metadata != null
        ? Duration.seconds(metadata.duration)
        : movie.duration
    }

    public function get currentBitrate() : Bitrate
    {
      return stream != null && stream.bitrate != null
        ? stream.bitrate : Bitrate.ZERO
    }

    public function get currentBandwidth() : Bitrate
    {
      return stream != null && stream.bandwidth != null
        ? stream.bandwidth : Bitrate.ZERO
    }

    public function get highQualityDimensions() : Dimensions
    {
      var result : Dimensions = Dimensions.ZERO

      for each (var stream : RTMPStream in movie.rtmpStreams)
        if (stream.dimensions.isGreaterThan(result))
          result = stream.dimensions

      return result
    }
  }
}

package goplayer
{
  import flash.utils.getTimer

  public class Player implements
    FlashNetConnectionListener,
    FlashNetStreamListener
  {
    private const DEFAULT_VOLUME : Number = .8

    private const START_BUFFER : Duration = Duration.seconds(3)
    private const SMALL_BUFFER : Duration = Duration.seconds(5)
    private const LARGE_BUFFER : Duration = Duration.seconds(60)
    private const SEEK_GRACE_TIME : Duration = Duration.seconds(2)

    private const finishingListeners : Array = []

    private var connection : FlashNetConnection
    private var _movie : Movie
    private var bitratePolicy : BitratePolicy
    private var enableRTMP : Boolean
    private var reporter : MovieEventReporter
    private var sharedVolumeVariable : SharedVariable

    private var _started : Boolean = false
    private var _finished : Boolean = false
    private var triedStandardRTMP : Boolean = false
    private var _usingRTMP : Boolean = false

    private var measuredBandwidth : Bitrate = null
    private var measuredLatency : Duration = null

    private var stream : FlashNetStream = null
    private var metadata : Object = null

    private var _volume : Number = NaN
    private var savedVolume : Number = 0
    private var _paused : Boolean = false
    private var _buffering : Boolean = false
    private var seekStopwatch : Stopwatch = new Stopwatch

    public function Player
      (connection : FlashNetConnection,
       movie : Movie,
       bitratePolicy : BitratePolicy,
       enableRTMP : Boolean,
       reporter : MovieEventReporter,
       sharedVolumeVariable : SharedVariable)
    {
      this.connection = connection
      _movie = movie
      this.bitratePolicy = bitratePolicy
      this.enableRTMP = enableRTMP
      this.reporter = reporter
      this.sharedVolumeVariable = sharedVolumeVariable

      connection.listener = this

      reporter.reportMovieViewed(movie.id)

      if (sharedVolumeVariable.hasValue)
        volume = sharedVolumeVariable.value
      else
        volume = DEFAULT_VOLUME
    }

    public function get movie() : Movie
    { return _movie }

    public function addFinishingListener
      (value : PlayerFinishingListener) : void
    { finishingListeners.push(value) }

    public function get started() : Boolean
    { return _started }

    public function get running() : Boolean
    { return started && !finished }

    public function get finished() : Boolean
    { return _finished }

    // -----------------------------------------------------

    public function destroy() : void
    {
      if (stream != null)
        stream.destroy()
    }

    public function start() : void
    {
      _started = true

      if (enableRTMP && movie.rtmpURL != null)
        connectUsingRTMP()
      else
        connectUsingHTTP()

      reporter.reportMoviePlayed(movie.id)
    }

    public function handleConnectionFailed() : void
    {
      if (movie.rtmpURL.hasPort && !triedStandardRTMP)
        handleCustomRTMPUnavailable()
      else
        handleRTMPUnavailable()
    }

    private function handleCustomRTMPUnavailable() : void
    {
      debug("Trying to connect using default RTMP ports.")
      connectUsingStandardRTMP()
    }

    private function handleRTMPUnavailable() : void
    {
      debug("Could not connect using RTMP; trying plain HTTP.")
      connectUsingHTTP()
    }

    public function get usingRTMP() : Boolean
    { return _usingRTMP }

    private function connectUsingRTMP() : void
    { connection.connect(movie.rtmpURL) }

    private function connectUsingStandardRTMP() : void
    {
      triedStandardRTMP = true
      connection.connect(movie.rtmpURL.withoutPort)
    }

    private function connectUsingHTTP() : void
    {
      _usingRTMP = false
      connection.dontConnect()
      startPlaying()
    }

    public function handleConnectionClosed() : void
    {}

    // -----------------------------------------------------

    public function handleConnectionEstablished() : void
    {
      _usingRTMP = true

      if (bandwidthDeterminationNeeded)
        connection.determineBandwidth()
      else
        startPlaying()
    }

    private function get bandwidthDeterminationNeeded() : Boolean
    { return bitratePolicy == BitratePolicy.BEST }

    public function handleBandwidthDetermined
      (bandwidth : Bitrate, latency : Duration) : void
    {
      measuredBandwidth = bandwidth
      measuredLatency = latency

      startPlaying()
    }

    private function get bandwidthDetermined() : Boolean
    { return measuredBandwidth != null }

    private function startPlaying() : void
    {
      stream = connection.getNetStream()
      stream.listener = this
      stream.volume = volume

      useStartBuffer()

      if (usingRTMP)
        playRTMPStream()
      else
        playHTTPStream()

      if (paused)
        stream.paused = true
    }

    private function playRTMPStream() : void
    { stream.playRTMP(streamPicker.first, streamPicker.all) }

    private function playHTTPStream() : void
    { stream.playHTTP(movie.httpURL) }

    private function get streamPicker() : RTMPStreamPicker
    {
      return new RTMPStreamPicker
        (movie.rtmpStreams, bitratePolicy, measuredBandwidth)
    }

    // -----------------------------------------------------

    public function handleNetStreamMetadata(data : Object) : void
    {
      metadata = data

      if (!usingRTMP)
        debug("Video file size: " + stream.httpFileSize)
    }

    public function handleStreamingStarted() : void
    {
      useStartBuffer()
      _buffering = true
      _finished = false
    }

    public function handleBufferFilled() : void
    { handleBufferingFinished() }

    private function handleBufferingFinished() : void
    {
      _buffering = false

      // Give the backend a chance to resume playback before we go
      // ahead and raise the buffer size further.
      later($handleBufferingFinished)
    }

    private function $handleBufferingFinished() : void
    {
      // Make sure playback was not interrupted.
      if (!buffering && !finished)
        useLargeBuffer()
    }

    public function handleBufferEmptied() : void
    {
      if (finishedPlaying)
        handleFinishedPlaying()
      else
        handleBufferingStarted()
    }

    private function handleBufferingStarted() : void
    {
      useSmallBuffer()
      _buffering = true
      _finished = false
    }

    private function useStartBuffer() : void
    { stream.bufferTime = START_BUFFER }

    private function useSmallBuffer() : void
    { stream.bufferTime = SMALL_BUFFER }

    private function useLargeBuffer() : void
    { stream.bufferTime = LARGE_BUFFER }

    public function get buffering() : Boolean
    { return _buffering }

    public function get bufferingUnexpectedly() : Boolean
    { return buffering && !justSeeked }

    private function get justSeeked() : Boolean
    { return seekStopwatch.within(SEEK_GRACE_TIME) }

    public function handleStreamingStopped() : void
    {
      _buffering = false

      if (finishedPlaying)
        handleFinishedPlaying()
    }

    private function handleFinishedPlaying() : void
    {
      debug("Finished playing.")
      _finished = true

      for each (var listener : PlayerFinishingListener in finishingListeners)
        listener.handleMovieFinishedPlaying()
    }

    public function stop() : void
    {
      debug("Stopping.")
      stream.close()
      _started = false
      stream = null
      metadata = null
    }

    private function get finishedPlaying() : Boolean
    { return timeRemaining.seconds < 1 }

    private function get timeRemaining() : Duration
    { return duration.minus(currentTime) }

    // -----------------------------------------------------

    public function get paused() : Boolean
    { return _paused }

    public function set paused(value : Boolean) : void
    {
      if (stream != null && _paused != value)
        _paused = value, stream.paused = value
    }

    public function togglePaused() : void
    {
      if (stream != null)
        paused = !paused
    }

    // -----------------------------------------------------

    public function get currentTime() : Duration
    {
      return stream != null && stream.currentTime != null
        ? stream.currentTime : Duration.ZERO
    }

    public function get playheadRatio() : Number
    { return getRatio(currentTime.seconds, duration.seconds) }

    public function get bufferRatio() : Number
    { return getRatio(bufferPosition.seconds, duration.seconds) }

    private function getRatio
      (numerator : Number, denominator : Number) : Number
    { return Math.min(1, numerator / denominator) }

    private function get bufferPosition() : Duration
    { return currentTime.plus(bufferLength) }

    public function set currentTime(value : Duration) : void
    {
      if (stream != null)
        $currentTime = value
    }

    private function set $currentTime(value : Duration) : void
    {
      _finished = false
      seekStopwatch.start()
      useStartBuffer()
      stream.currentTime = value
    }

    public function set playheadRatio(value : Number) : void
    { currentTime = duration.scaledBy(value) }

    public function seekBy(delta : Duration) : void
    { currentTime = currentTime.plus(delta) }

    public function rewind() : void
    { currentTime = Duration.ZERO }

    public function get playing() : Boolean
    { return started && stream != null && !paused && !finished }

    // -----------------------------------------------------

    public function get volume() : Number
    { return _volume }

    public function set volume(value : Number) : void
    {
      _volume = Math.round(clamp(value, 0, 1) * 100) / 100

      if (sharedVolumeVariable.available)
        sharedVolumeVariable.value = volume

      if (stream)
        stream.volume = volume
    }

    public function changeVolumeBy(delta : Number) : void
    { volume = volume + delta }

    public function mute() : void
    {
      savedVolume = volume
      volume = 0
    }

    public function unmute() : void
    { volume = savedVolume == 0 ? DEFAULT_VOLUME : savedVolume }

    public function get muted() : Boolean
    { return volume == 0 }

    // -----------------------------------------------------

    public function get aspectRatio() : Number
    { return movie.aspectRatio }

    public function get bufferTime() : Duration
    {
      return stream != null && stream.bufferTime != null
        ? stream.bufferTime : START_BUFFER
    }

    public function get bufferLength() : Duration
    {
      return stream != null && stream.bufferLength != null
        ? stream.bufferLength : Duration.ZERO
    }

    public function get bufferFillRatio() : Number
    { return getRatio(bufferLength.seconds, bufferTime.seconds) }

    public function get duration() : Duration
    {
      return metadata != null
        ? Duration.seconds(metadata.duration)
        : movie.duration
    }

    public function get currentBitrate() : Bitrate
    {
      return stream != null && stream.bitrate != null
        ? stream.bitrate : Bitrate.ZERO
    }

    public function get currentBandwidth() : Bitrate
    {
      return stream != null && stream.bandwidth != null
        ? stream.bandwidth : Bitrate.ZERO
    }

    public function get highQualityDimensions() : Dimensions
    {
      var result : Dimensions = Dimensions.ZERO

      for each (var stream : RTMPStream in movie.rtmpStreams)
        if (stream.dimensions.isGreaterThan(result))
          result = stream.dimensions

      return result
    }
  }
}

Make setting Player.pause idempotent.

Make setting Player.pause idempotent.