////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.events
{
    import flash.events.MouseEvent;
    import org.apache.flex.core.IDragInitiator;

	/**
	 *  Drag and Drop Events.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
	 */
	public class DragEvent extends MouseEvent
	{
        /**
         *  The DragEvent.DRAG_START constant defines the value of the
         *  event object's type property for a dragStart event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragStart
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_START:String = "dragStart";

        /**
         *  The DragEvent.DRAG_MOVE constant defines the value of the
         *  event object's type property for a dragMove event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragMove
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_MOVE:String = "dragMove";

        /**
         *  The DragEvent.DRAG_END constant defines the value of the
         *  event object's type property for a dragEnd event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragEnd
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_END:String = "dragEnd";

        /**
         *  The DragEvent.DRAG_ENTER constant defines the value of the
         *  event object's type property for a dragEnter event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragEnter
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_ENTER:String = "dragEnter";

        /**
         *  The DragEvent.DRAG_OVER constant defines the value of the
         *  event object's type property for a dragOver event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragOver
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_OVER:String = "dragOver";

        /**
         *  The DragEvent.DRAG_EXIT constant defines the value of the
         *  event object's type property for a dragExit event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragExit
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_EXIT:String = "dragExit";

        /**
         *  The DragEvent.DRAG_DROP constant defines the value of the
         *  event object's type property for a dragDrop event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragDrop
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_DROP:String = "dragDrop";

        /**
         *  Constructor.
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function DragEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}

        /**
         *  The object that wants to know if a drop is accepted
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var dragInitiator:IDragInitiator;

        /**
         *  The data being dragged. Or an instance
         *  of an object describing the data.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var dragSource:Object;

        public function copyMouseEventProperties(event:MouseEvent):void
        {
            localX = event.localX;
            localY = event.localY;
            altKey = event.altKey;
            ctrlKey = event.ctrlKey;
            shiftKey = event.shiftKey;
            buttonDown = event.buttonDown;
            delta = event.delta;
            relatedObject = event.relatedObject;
        }
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.events
{
    import flash.events.MouseEvent;

    import org.apache.flex.core.IDragInitiator;

	/**
	 *  Drag and Drop Events.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
	 */
	public class DragEvent extends flash.events.MouseEvent
	{
        /**
         *  The DragEvent.DRAG_START constant defines the value of the
         *  event object's type property for a dragStart event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragStart
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_START:String = "dragStart";

        /**
         *  The DragEvent.DRAG_MOVE constant defines the value of the
         *  event object's type property for a dragMove event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragMove
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_MOVE:String = "dragMove";

        /**
         *  The DragEvent.DRAG_END constant defines the value of the
         *  event object's type property for a dragEnd event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragEnd
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_END:String = "dragEnd";

        /**
         *  The DragEvent.DRAG_ENTER constant defines the value of the
         *  event object's type property for a dragEnter event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragEnter
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_ENTER:String = "dragEnter";

        /**
         *  The DragEvent.DRAG_OVER constant defines the value of the
         *  event object's type property for a dragOver event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragOver
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_OVER:String = "dragOver";

        /**
         *  The DragEvent.DRAG_EXIT constant defines the value of the
         *  event object's type property for a dragExit event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragExit
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_EXIT:String = "dragExit";

        /**
         *  The DragEvent.DRAG_DROP constant defines the value of the
         *  event object's type property for a dragDrop event.
         *
         *
The properties of the event object have the following values:

         *

         *
Property	Value

         *
bubbles	false

         *
cancelable	false

         *
currentTarget	The Object that defines the
         *       event listener that handles the event. For example, if you use
         *       myButton.addEventListener() to register an event listener,
         *       myButton is the value of the currentTarget.

         *
target	The Object that dispatched the event;
         *       it is not always the Object listening for the event.
         *       Use the currentTarget property to always access the
         *       Object listening for the event.

         *

         *
         *  @eventType dragDrop
         *
         *  @langversion 3.0
         *  @playerversion Flash 9
         *  @playerversion AIR 1.1
         *  @productversion Flex 3
         */
        public static const DRAG_DROP:String = "dragDrop";

        /**
         *  Constructor.
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function DragEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}

        /**
         *  The object that wants to know if a drop is accepted
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var dragInitiator:IDragInitiator;

        /**
         *  The data being dragged. Or an instance
         *  of an object describing the data.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var dragSource:Object;

        public function copyMouseEventProperties(event:flash.events.MouseEvent):void
        {
            localX = event.localX;
            localY = event.localY;
            altKey = event.altKey;
            ctrlKey = event.ctrlKey;
            shiftKey = event.shiftKey;
            buttonDown = event.buttonDown;
            delta = event.delta;
            relatedObject = event.relatedObject;
        }
	}
}

Remove ambiguity of MouseEvent reference.


package org.arisgames.editor.view
{
import flash.events.MouseEvent;
import flash.utils.Dictionary;

import mx.collections.ArrayCollection;
import mx.containers.Panel;
import mx.controls.Alert;
import mx.controls.Button;
import mx.controls.DataGrid;
import mx.controls.TextArea;
import mx.controls.TextInput;
import mx.events.DynamicEvent;
import mx.events.FlexEvent;
import mx.rpc.Responder;
import mx.rpc.events.ResultEvent;

import org.arisgames.editor.data.Game;
import org.arisgames.editor.data.PlaceMark;
import org.arisgames.editor.data.arisserver.Item;
import org.arisgames.editor.data.arisserver.Media;
import org.arisgames.editor.data.arisserver.NPC;
import org.arisgames.editor.data.arisserver.Node;
import org.arisgames.editor.data.arisserver.WebPage;
import org.arisgames.editor.data.businessobjects.ObjectPaletteItemBO;
import org.arisgames.editor.models.GameModel;
import org.arisgames.editor.models.SecurityModel;
import org.arisgames.editor.models.StateModel;
import org.arisgames.editor.services.AppServices;
import org.arisgames.editor.util.AppConstants;
import org.arisgames.editor.util.AppDynamicEventManager;
import org.arisgames.editor.util.AppUtils;

public class CreateOrOpenGameSelectorView extends Panel
{
    [Bindable] public var nameOfGame:TextInput;
    [Bindable] public var gameDescription:TextArea;
    [Bindable] public var createGameButton:Button;
    [Bindable] public var gamesDataGrid:DataGrid;
    [Bindable] public var loadGameButton:Button;
    [Bindable] public var usersGames:ArrayCollection;

    /**
     * Constructor
     */
    public function CreateOrOpenGameSelectorView()
    {
        super();
        usersGames = new ArrayCollection();
        this.addEventListener(FlexEvent.CREATION_COMPLETE, onComplete);
    }

    private function onComplete(event:FlexEvent): void
    {
		doubleClickEnabled = true;
        createGameButton.addEventListener(MouseEvent.CLICK, onCreateButtonClick);
        loadGameButton.addEventListener(MouseEvent.CLICK, onLoadButtonClick);
		gamesDataGrid.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
        AppServices.getInstance().loadGamesByUserId(SecurityModel.getInstance().getUserId(), new Responder(handleLoadUsersGames, handleFault));
		AppDynamicEventManager.getInstance().addEventListener(AppConstants.APPLICATIONDYNAMICEVENT_CURRENTSTATECHANGED, handleCurrentStateChangedEvent);
    }

	private function handleCurrentStateChangedEvent(obj:Object):void
	{
		trace("CreateOrOpenGameSelectorView: handleCurrentStateChangedEvent");

		if (StateModel.getInstance().currentState == StateModel.VIEWCREATEOROPENGAMEWINDOW){
			trace("CreateOrOpenGameSelectorView: handleCurrentStateChangedEvent: Refreshing");
			nameOfGame.text = "";
			gameDescription.text = "";
			usersGames.removeAll();
			AppServices.getInstance().loadGamesByUserId(SecurityModel.getInstance().getUserId(), new Responder(handleLoadUsersGames, handleFault));
		}
	}

    private function handleLoadUsersGames(obj:Object):void
    {
		trace("handleLoadUsersGames");

		usersGames.removeAll();

        if (obj.result.data == null)
        {
            trace("obj.result.data is NULL");
            return;
        }

        for (var j:Number = 0; j < obj.result.data.list.length; j++)
        {
            var g:Game = new Game();
            g.gameId = obj.result.data.list.getItemAt(j).game_id;
            g.name = obj.result.data.list.getItemAt(j).name;
            g.description = obj.result.data.list.getItemAt(j).description;
			g.iconMediaId = obj.result.data.list.getItemAt(j).icon_media_id;
			g.mediaId = obj.result.data.list.getItemAt(j).media_id;
			g.pcMediaId = obj.result.data.list.getItemAt(j).pc_media_id;
			g.introNodeId = obj.result.data.list.getItemAt(j).on_launch_node_id;
			g.completeNodeId = obj.result.data.list.getItemAt(j).game_complete_node_id;
			g.allowsPlayerCreatedLocations = obj.result.data.list.getItemAt(j).allow_player_created_locations;
			g.resetDeletesPlayerCreatedLocations = obj.result.data.list.getItemAt(j).delete_player_locations_on_reset;
			g.isLocational = obj.result.data.list.getItemAt(j).is_locational;
			g.readyForPublic = obj.result.data.list.getItemAt(j).ready_for_public;

			usersGames.addItem(g);

        }
        trace("done loading UsersGames.");
    }

    private function onCreateButtonClick(evt:MouseEvent):void
    {
		trace("create button clicked!");
		var g:Game = new Game();
		GameModel.getInstance().game = g;
		g.name = nameOfGame.text;
		g.description = gameDescription.text;

        AppServices.getInstance().saveGame(g, new Responder(handleCreateGame, handleFault));
    }

    private function onLoadButtonClick(evt:MouseEvent):void
    {
		trace("load button clicked!");
		//make sure something is happening
		if(gamesDataGrid.selectedItem != null){
	        var g:Game = gamesDataGrid.selectedItem as Game;
	        trace("Selected game to load data for has Id = " + g.gameId);

	        // Load the game into the app's models
	        GameModel.getInstance().game = g;
	        GameModel.getInstance().game.placeMarks.removeAll();
	        GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

	        StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;
		}
    }

	private function onDoubleClick(evt:MouseEvent):void
	{
		trace("Double Click");
		//make sure something is happening
		if(gamesDataGrid.selectedItem != null){
			var g:Game = gamesDataGrid.selectedItem as Game;
			trace("Selected game to load data for has Id = " + g.gameId);

			// Load the game into the app's models
			GameModel.getInstance().game = g;
			GameModel.getInstance().game.placeMarks.removeAll();
			GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

			StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;
		}
	}

    public function handleCreateGame(obj:Object):void
    {
        trace("Result called with obj = " + obj + "; Result = " + obj.result);
        if (obj.result.returnCode != 0)
        {
            trace("Bad create game attempt... let's see what happened.");
            var msg:String = obj.result.returnCodeDescription;
            Alert.show("Error Was: " + msg, "Error While Creating Game");
        }
        else
        {
            trace("Game Creation was successfull");
            GameModel.getInstance().game.gameId = obj.result.data;
            GameModel.getInstance().game.name = nameOfGame.text;
            GameModel.getInstance().game.description = gameDescription.text;
            Alert.show("Your game was succesfully created.  Please use the editor to start building it.", "Successfully Created Game");

			//Clear everything from previous loads of other games
			GameModel.getInstance().game.placeMarks.removeAll();
			GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

			StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;
        }
    }

    public function handleFault(obj:Object):void
    {
        trace("Fault called.  The error is: " + obj.fault.faultString);
        Alert.show("Error occurred: " + obj.fault.faultString, "More problems..");
    }
}
}

package org.arisgames.editor.view
{
import flash.events.MouseEvent;
import flash.utils.Dictionary;

import mx.collections.ArrayCollection;
import mx.containers.Panel;
import mx.controls.Alert;
import mx.controls.Button;
import mx.controls.DataGrid;
import mx.controls.TextArea;
import mx.controls.TextInput;
import mx.events.DynamicEvent;
import mx.events.FlexEvent;
import mx.rpc.Responder;
import mx.rpc.events.ResultEvent;

import org.arisgames.editor.data.Game;
import org.arisgames.editor.data.PlaceMark;
import org.arisgames.editor.data.arisserver.Item;
import org.arisgames.editor.data.arisserver.Media;
import org.arisgames.editor.data.arisserver.NPC;
import org.arisgames.editor.data.arisserver.Node;
import org.arisgames.editor.data.arisserver.WebPage;
import org.arisgames.editor.data.businessobjects.ObjectPaletteItemBO;
import org.arisgames.editor.models.GameModel;
import org.arisgames.editor.models.SecurityModel;
import org.arisgames.editor.models.StateModel;
import org.arisgames.editor.services.AppServices;
import org.arisgames.editor.util.AppConstants;
import org.arisgames.editor.util.AppDynamicEventManager;
import org.arisgames.editor.util.AppUtils;

public class CreateOrOpenGameSelectorView extends Panel
{
    [Bindable] public var nameOfGame:TextInput;
    [Bindable] public var gameDescription:TextArea;
    [Bindable] public var createGameButton:Button;
    [Bindable] public var gamesDataGrid:DataGrid;
    [Bindable] public var loadGameButton:Button;
    [Bindable] public var usersGames:ArrayCollection;

    /**
     * Constructor
     */
    public function CreateOrOpenGameSelectorView()
    {
        super();
        usersGames = new ArrayCollection();
        this.addEventListener(FlexEvent.CREATION_COMPLETE, onComplete);
    }

    private function onComplete(event:FlexEvent): void
    {
		doubleClickEnabled = true;
        createGameButton.addEventListener(MouseEvent.CLICK, onCreateButtonClick);
        loadGameButton.addEventListener(MouseEvent.CLICK, onLoadButtonClick);
		gamesDataGrid.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
        AppServices.getInstance().loadGamesByUserId(SecurityModel.getInstance().getUserId(), new Responder(handleLoadUsersGames, handleFault));
		AppDynamicEventManager.getInstance().addEventListener(AppConstants.APPLICATIONDYNAMICEVENT_CURRENTSTATECHANGED, handleCurrentStateChangedEvent);
    }

	private function handleCurrentStateChangedEvent(obj:Object):void
	{
		trace("CreateOrOpenGameSelectorView: handleCurrentStateChangedEvent");

		if (StateModel.getInstance().currentState == StateModel.VIEWCREATEOROPENGAMEWINDOW){
			trace("CreateOrOpenGameSelectorView: handleCurrentStateChangedEvent: Refreshing");
			nameOfGame.text = "";
			gameDescription.text = "";
			usersGames.removeAll();
			AppServices.getInstance().loadGamesByUserId(SecurityModel.getInstance().getUserId(), new Responder(handleLoadUsersGames, handleFault));
		}
	}

    private function handleLoadUsersGames(obj:Object):void
    {
		trace("handleLoadUsersGames");

		usersGames.removeAll();

        if (obj.result.data == null)
        {
            trace("obj.result.data is NULL");
            return;
        }

        for (var j:Number = 0; j < obj.result.data.list.length; j++)
        {
            var g:Game = new Game();
            g.gameId = obj.result.data.list.getItemAt(j).game_id;
            g.name = obj.result.data.list.getItemAt(j).name;
            g.description = obj.result.data.list.getItemAt(j).description;
			g.iconMediaId = obj.result.data.list.getItemAt(j).icon_media_id;
			g.mediaId = obj.result.data.list.getItemAt(j).media_id;
			g.pcMediaId = obj.result.data.list.getItemAt(j).pc_media_id;
			g.introNodeId = obj.result.data.list.getItemAt(j).on_launch_node_id;
			g.completeNodeId = obj.result.data.list.getItemAt(j).game_complete_node_id;
			g.allowsPlayerCreatedLocations = obj.result.data.list.getItemAt(j).allow_player_created_locations;
			g.resetDeletesPlayerCreatedLocations = obj.result.data.list.getItemAt(j).delete_player_locations_on_reset;
			g.isLocational = obj.result.data.list.getItemAt(j).is_locational;
			g.readyForPublic = obj.result.data.list.getItemAt(j).ready_for_public;

			usersGames.addItem(g);

        }
        trace("done loading UsersGames.");
    }

    private function onCreateButtonClick(evt:MouseEvent):void
    {
		trace("create button clicked!");
		var g:Game = new Game();
		GameModel.getInstance().game = g;
		g.name = nameOfGame.text;
		g.description = gameDescription.text;

        AppServices.getInstance().saveGame(g, new Responder(handleCreateGame, handleFault));
    }

    private function onLoadButtonClick(evt:MouseEvent):void
    {
		trace("load button clicked!");
		//make sure something is happening
		if(gamesDataGrid.selectedItem != null){
	        var g:Game = gamesDataGrid.selectedItem as Game;
	        trace("Selected game to load data for has Id = " + g.gameId);

	        // Load the game into the app's models
	        GameModel.getInstance().game = g;
	        GameModel.getInstance().game.placeMarks.removeAll();
	        GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

	        StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;

			var de:DynamicEvent = new DynamicEvent(AppConstants.DYNAMICEVENT_CLOSEOBJECTPALETTEITEMEDITOR);
			AppDynamicEventManager.getInstance().dispatchEvent(de);
		}
    }

	private function onDoubleClick(evt:MouseEvent):void
	{
		trace("Double Click");
		//make sure something is happening
		if(gamesDataGrid.selectedItem != null){
			var g:Game = gamesDataGrid.selectedItem as Game;
			trace("Selected game to load data for has Id = " + g.gameId);

			// Load the game into the app's models
			GameModel.getInstance().game = g;
			GameModel.getInstance().game.placeMarks.removeAll();
			GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

			StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;

			var de:DynamicEvent = new DynamicEvent(AppConstants.DYNAMICEVENT_CLOSEOBJECTPALETTEITEMEDITOR);
			AppDynamicEventManager.getInstance().dispatchEvent(de);
		}
	}

    public function handleCreateGame(obj:Object):void
    {
        trace("Result called with obj = " + obj + "; Result = " + obj.result);
        if (obj.result.returnCode != 0)
        {
            trace("Bad create game attempt... let's see what happened.");
            var msg:String = obj.result.returnCodeDescription;
            Alert.show("Error Was: " + msg, "Error While Creating Game");
        }
        else
        {
            trace("Game Creation was successfull");
            GameModel.getInstance().game.gameId = obj.result.data;
            GameModel.getInstance().game.name = nameOfGame.text;
            GameModel.getInstance().game.description = gameDescription.text;
            Alert.show("Your game was succesfully created.  Please use the editor to start building it.", "Successfully Created Game");

			//Clear everything from previous loads of other games
			GameModel.getInstance().game.placeMarks.removeAll();
			GameModel.getInstance().game.gameObjects.removeAll();
			GameModel.getInstance().loadLocations();

			StateModel.getInstance().currentState = StateModel.VIEWGAMEEDITOR;
        }
    }

    public function handleFault(obj:Object):void
    {
        trace("Fault called.  The error is: " + obj.fault.faultString);
        Alert.show("Error occurred: " + obj.fault.faultString, "More problems..");
    }
}
}

Delete modals on game switch

Delete modals on game switch


package com.kaltura.hls.m2ts
{
    import flash.utils.ByteArray;
    import flash.net.ObjectEncoding;
    import flash.utils.ByteArray;
    import flash.utils.Endian;
    import flash.utils.IDataInput;
    import flash.utils.IDataOutput;
    import com.hurlant.util.Hex;

    CONFIG::LOGGING
    {
        import org.osmf.logging.Logger;
        import org.osmf.logging.Log;
    }

    /**
     * Process packetized elementary streams and extract NALUs and other data.
     */
    public class PESProcessor
    {
        CONFIG::LOGGING
        {
            private static const logger:Logger = Log.getLogger("com.kaltura.hls.m2ts.PESProcessor");
        }

        public var types:Object = {};
        public var streams:Object = {};

        public var lastVideoNALU:NALU = null;

        public var transcoder:FLVTranscoder = new FLVTranscoder();

        public var headerSent:Boolean = false;

        public var pmtStreamId:int = -1;

        protected var pendingBuffers:Vector.<Object> = new Vector.<Object>();
        protected var pendingLastConvertedIndex:int = 0;

        public var lastPTS:Number = 0, lastDTS:Number = 0;

        /**
         * Given a MPEG timestamp we've seen previously, determine if the new timestamp
         * has wrapped and correct it to follow the old timestamp.
         */
        static function handleMpegTimestampWrap(newTime:Number, oldTime:Number):Number
        {
            while (!isNaN(oldTime) && (Math.abs(newTime - oldTime) > 4294967296))
                newTime += (oldTime < newTime) ? -8589934592 : 8589934592;

            return newTime;
        }

        public function logStreams():void
        {
            CONFIG::LOGGING
            {
                logger.debug("----- PES state -----");
                for(var k:* in streams)
                {
                    logger.debug("   " + k + " has " + streams[k].buffer.length + " bytes, type=" + types[k]);
                }
            }
        }

        public function clear(clearAACConfig:Boolean = true):void
        {
            streams = {};
            lastVideoNALU = null;
            transcoder.clear(clearAACConfig);

            // Reset PTS/DTS reference.
            lastPTS = lastDTS = 0;
        }

        private function parseProgramAssociationTable(bytes:ByteArray, cursor:uint):Boolean
        {
            // Get the section length.
            var sectionLen:uint = ((bytes[cursor+2] & 0x03) << 8) | bytes[cursor+3];

            // Check the section length for a single PMT.
            CONFIG::LOGGING
            {
                if (sectionLen > 13)
                {
                    logger.debug("Saw multiple PMT entries in the PAT; blindly choosing first one.");
                }
            }

            // Grab the PMT ID.
            pmtStreamId = ((bytes[cursor+10] << 8) | bytes[cursor+11]) & 0x1FFF;

            CONFIG::LOGGING
            {
                logger.debug("Saw PMT ID of " + pmtStreamId);
            }

            return true;
        }

        private function parseProgramMapTable(bytes:ByteArray, cursor:uint):Boolean
        {
            var sectionLength:uint;
            var sectionLimit:uint;
            var programInfoLength:uint;
            var type:uint;
            var pid:uint;
            var esInfoLength:uint;
            var seenPIDsByClass:Array;
            var mediaClass:int;

            var hasAudio:Boolean = false, hasVideo:Boolean = false;

            // Set up types.
            types = [];
            seenPIDsByClass = [];
            seenPIDsByClass[MediaClass.VIDEO] = Infinity;
            seenPIDsByClass[MediaClass.AUDIO] = Infinity;

            // Process section length and limit.
            cursor++;

            sectionLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
            cursor += 2;

            if(sectionLength + cursor > bytes.length)
            {
                CONFIG::LOGGING
                {
                    logger.error("Not enough data to read. 1");
                }
                return false;
            }

            // Skip a few things we don't care about: program number, RSV, version, CNI, section, last_section, pcr_cid
            sectionLimit = cursor + sectionLength;
            cursor += 7;

            // And get the program info length.
            programInfoLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
            cursor += 2;

            // If not enough data to proceed, bail.
            if(programInfoLength + cursor > bytes.length)
            {
                CONFIG::LOGGING
                {
                    logger.error("Not enough data to read. 2");
                }
                return false;
            }

            cursor += programInfoLength;

            const CRC_SIZE:int = 4;
            while(cursor < sectionLimit - CRC_SIZE)
            {
                type = bytes[cursor++];
                pid = ((bytes[cursor] & 0x1f) << 8) + bytes[cursor + 1];
                cursor += 2;

                mediaClass = MediaClass.calculate(type);

                if(mediaClass == MediaClass.VIDEO)
                    hasVideo = true

                if(mediaClass == MediaClass.AUDIO)
                    hasAudio = true

                // For video & audio, select the lowest PID for each kind.
                if(mediaClass == MediaClass.OTHER
                 || pid < seenPIDsByClass[mediaClass])
                {
                    // Clear a higher PID if present.
                    if(mediaClass != MediaClass.OTHER
                     && seenPIDsByClass[mediaClass] < Infinity)
                        types[seenPIDsByClass[mediaClass]] = -1;

                    types[pid] = type;
                    seenPIDsByClass[mediaClass] = pid;
                }

                // Skip the esInfo data.
                esInfoLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
                cursor += 2;
                cursor += esInfoLength;
            }

            // Cook out header to transcoder.
            //transcoder.writeHeader(hasAudio, hasVideo);
            headerSent = true;

            return true;
        }

        public function append(packet:PESPacket):Boolean
        {
//            logger.debug("saw packet of " + packet.buffer.length);
            var b:ByteArray = packet.buffer;
            b.position = 0;

            if(b.length < 8)
            {
                CONFIG::LOGGING
                {
                    logger.error("Ignoring too short PES packet, length=" + b.length);
                }
                return true;
            }

            // Get the start code.
            var startCode:uint = b.readUnsignedInt();
            if((startCode & 0xFFFFFF00) != 0x00000100)
            {
                // It could be a program association table.
                if((startCode & 0xFFFFFF00) == 0x0000b000)
                {
                    parseProgramAssociationTable(b, 1);
                    return true;
                }

                // It could be the program map table.
                if((startCode & 0xFFFFFC00) == 0x0002b000)
                {
                    parseProgramMapTable(b, 1);
                    return true;
                }

                var tmp:ByteArray = new ByteArray();
                tmp.writeInt(startCode);
                CONFIG::LOGGING
                {
                    logger.error("ES prefix was wrong, expected 00:00:01:xx but got " + Hex.fromArray(tmp, true));
                }
                return true;
            }

            // Get the stream ID.
            var streamID:int = startCode & 0xFF;

            // Get the length.
            var packetLength:uint = b.readUnsignedShort();
            if(packetLength)
            {
                if(b.length < packetLength )
                {
                    CONFIG::LOGGING
                    {
                        logger.warn("WARNING: parsePESPacket - not enough bytes, expecting " + packetLength + ", but have " + b.length);
                    }
                    return false; // not enough bytes in packet
                }
            }

            if(b.length < 9)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - too short to read header!");
                }
                return false;
            }

            // Read the rest of the header.
            var cursor:uint = 6;
            var dataAlignment:Boolean = (b[cursor] & 0x04) != 0;
            cursor++;

            var ptsDts:uint = (b[cursor] & 0xc0) >> 6;
            cursor++;

            var pesHeaderDataLength:uint = b[cursor];
            cursor++;

            //logger.debug(" PES align=" + dataAlignment + " ptsDts=" + ptsDts + " header=" + pesHeaderDataLength);

            var pts:Number = 0, dts:Number = 0;

            if(ptsDts & 0x02)
            {
                // has PTS at least
                if(cursor + 5 > b.length)
                    return true;

                pts  = b[cursor] & 0x0e;
                pts *= 128;
                pts += b[cursor + 1];
                pts *= 256;
                pts += b[cursor + 2] & 0xfe;
                pts *= 128;
                pts += b[cursor + 3];
                pts *= 256;
                pts += b[cursor + 4] & 0xfe;
                pts /= 2;

                if(ptsDts & 0x01)
                {
                    // DTS too!
                    if(cursor + 10 > b.length)
                        return true;

                    dts  = b[cursor + 5] & 0x0e;
                    dts *= 128;
                    dts += b[cursor + 6];
                    dts *= 256;
                    dts += b[cursor + 7] & 0xfe;
                    dts *= 128;
                    dts += b[cursor + 8];
                    dts *= 256;
                    dts += b[cursor + 9] & 0xfe;
                    dts /= 2;
                }
                else
                {
                    //logger.debug("Filling in DTS")
                    dts = pts;
                }
            }

            // Condition PTS and DTS.
            pts = handleMpegTimestampWrap(pts, lastPTS);
            lastPTS = pts;

            dts = handleMpegTimestampWrap(dts, lastDTS);
            lastDTS = dts;

            packet.pts = pts;
            packet.dts = dts;
            //logger.debug("   PTS=" + pts/90000 + " DTS=" + dts/90000);

            cursor += pesHeaderDataLength;

            if(cursor > b.length)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - ran out of bytes");
                }
                return true;
            }

            if(types[packet.packetID] == undefined)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - unknown type");
                }
                return true;
            }

            var pes:PESPacketStream;

            if(streams[packet.packetID] == undefined)
            {
                if(dts < 0.0)
                {
                    CONFIG::LOGGING
                    {
                        logger.warn("WARNING: parsePESPacket - invalid decode timestamp, skipping");
                    }
                    return true;
                }

                pes = new PESPacketStream();
                streams[packet.packetID] = pes;
            }
            else
            {
                pes = streams[packet.packetID];
            }

            if(headerSent == false)
            {
                CONFIG::LOGGING
                {
                    logger.warn("Skipping data that came before PMT");
                }
                return true;
            }

            // Note the type at this moment in time.
            packet.type = types[packet.packetID];
            packet.headerLength = cursor;

            // And process.
            if(MediaClass.calculate(types[packet.packetID]) == MediaClass.VIDEO)
            {
                var start:int = NALU.scan(b, cursor, true);
                if(start == -1 && lastVideoNALU)
                {
                    CONFIG::LOGGING
                    {
                        logger.debug("Stuff entire " + (b.length - cursor) + " bytes into previous NALU.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, b.length - cursor);
                    return true;

                }
                else if((start - cursor) > 0 && lastVideoNALU)
                {
                    // Shove into previous buffer.
                    CONFIG::LOGGING
                    {
                        logger.debug("Stuffing first " + (start - cursor) + " bytes into previous NALU.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, start - cursor);
                    cursor = start;
                }

                // If it's identical timestamps, accumulate it into the current unit and keep going.
                if(lastVideoNALU && pts == lastVideoNALU.pts && dts == lastVideoNALU.dts)
                {
                    CONFIG::LOGGING
                    {
                        logger.debug("Combining " + (start-cursor) + " bytes into previous NALU due to matching DTS/PTS.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, start - cursor);
                    cursor = start;
                }
                else
                {
                    // Submit previous data.
                    if(lastVideoNALU)
                    {
                        pendingBuffers.push(lastVideoNALU.clone());
                    }

                    // Update NALU state.
                    lastVideoNALU = new NALU();
                    lastVideoNALU.buffer = new ByteArray();
                    lastVideoNALU.pts = pts;
                    lastVideoNALU.dts = dts;
                    lastVideoNALU.type = packet.type;
                    lastVideoNALU.buffer.writeBytes(b, cursor);

                }
            }
            else if(types[packet.packetID] == 0x0F)
            {
                // It's an AAC stream.
                pendingBuffers.push(packet.clone());
            }
            else if(types[packet.packetID] == 0x03 || types[packet.packetID] == 0x04)
            {
                // It's an MP3 stream.
                pendingBuffers.push(packet.clone());
            }
            else
            {
                CONFIG::LOGGING
                {
                    logger.warn("Unknown packet ID type " + types[packet.packetID] + ", ignoring (A).");
                }
            }

            bufferPendingNalus();

            return true;
        }

        /**
         * To avoid transcoding all content on flush, we buffer it into FLV
         * tags as we go. However, they remain undelivered until we can gather
         * final SPS/PPS information. This method is responsible for
         * incrementally buffering in the FLV transcoder as we go.
         */
        public function bufferPendingNalus():void
        {
            // Iterate and buffer new NALUs.
            for(var i:int=pendingLastConvertedIndex; i<pendingBuffers.length; i++)
            {
                if(pendingBuffers[i] is NALU)
                {
                    transcoder.convert(pendingBuffers[i] as NALU);
                }
                else if(pendingBuffers[i] is PESPacket)
                {
                    var packet:PESPacket = pendingBuffers[i] as PESPacket;
                    if(packet.type == 0x0F)
                    {
                        // It's an AAC stream.
                        transcoder.convertAAC(packet);
                    }
                    else if(packet.type == 0x03 || packet.type == 0x04)
                    {
                        // It's an MP3 stream. Pass through directly.
                        transcoder.convertMP3(packet);
                    }
                    else
                    {
                        CONFIG::LOGGING
                        {
                            logger.warn("Unknown packet ID type " + packet.type + ", ignoring (B).");
                        }
                    }
                }
            }

            // Note the last item we converted so we can avoid duplicating work.
            pendingLastConvertedIndex = pendingBuffers.length;
        }

        public function processAllNalus():void
        {
            // Consume any unposted video NALUs.
            if(lastVideoNALU)
            {
                pendingBuffers.push(lastVideoNALU.clone());
                lastVideoNALU = null;
            }

            // First walk all the video NALUs and get the correct SPS/PPS
            if(pendingBuffers.length == 0)
                return;

            // Then emit SPS/PPS
            transcoder.emitSPSPPSUnbuffered();

            // Complete buffering and emit it all.
            bufferPendingNalus();
            transcoder.emitBufferedTags();

            // Don't forget to clear the pending list.
            pendingBuffers.length = 0;
            pendingLastConvertedIndex = 0;
        }
    }
}

package com.kaltura.hls.m2ts
{
    import flash.utils.ByteArray;
    import flash.net.ObjectEncoding;
    import flash.utils.ByteArray;
    import flash.utils.Endian;
    import flash.utils.IDataInput;
    import flash.utils.IDataOutput;
    import com.hurlant.util.Hex;

    CONFIG::LOGGING
    {
        import org.osmf.logging.Logger;
        import org.osmf.logging.Log;
    }

    /**
     * Process packetized elementary streams and extract NALUs and other data.
     */
    public class PESProcessor
    {
        CONFIG::LOGGING
        {
            private static const logger:Logger = Log.getLogger("com.kaltura.hls.m2ts.PESProcessor");
        }

        public var types:Object = {};
        public var streams:Object = {};

        public var lastVideoNALU:NALU = null;

        public var transcoder:FLVTranscoder = new FLVTranscoder();

        public var headerSent:Boolean = false;

        public var pmtStreamId:int = -1;

        protected var pendingBuffers:Vector.<Object> = new Vector.<Object>();
        protected var pendingLastConvertedIndex:int = 0;

        public var lastPTS:Number = 0, lastDTS:Number = 0;

        /**
         * Given a MPEG timestamp we've seen previously, determine if the new timestamp
         * has wrapped and correct it to follow the old timestamp.
         */
        static function handleMpegTimestampWrap(newTime:Number, oldTime:Number):Number
        {
            while (!isNaN(oldTime) && (Math.abs(newTime - oldTime) > 4294967296))
                newTime += (oldTime < newTime) ? -8589934592 : 8589934592;

            return newTime;
        }

        public function logStreams():void
        {
            CONFIG::LOGGING
            {
                logger.debug("----- PES state -----");
                for(var k:* in streams)
                {
                    logger.debug("   " + k + " has " + streams[k].buffer.length + " bytes, type=" + types[k]);
                }
            }
        }

        public function clear(clearAACConfig:Boolean = true):void
        {
            streams = {};
            lastVideoNALU = null;
            transcoder.clear(clearAACConfig);

            // Reset PTS/DTS reference.
            lastPTS = lastDTS = 0;
        }

        private function parseProgramAssociationTable(bytes:ByteArray, cursor:uint):Boolean
        {
            // Get the section length.
            var sectionLen:uint = ((bytes[cursor+2] & 0x03) << 8) | bytes[cursor+3];

            // Check the section length for a single PMT.
            CONFIG::LOGGING
            {
                if (sectionLen > 13)
                {
                    logger.debug("Saw multiple PMT entries in the PAT; blindly choosing first one.");
                }
            }

            // Grab the PMT ID.
            pmtStreamId = ((bytes[cursor+10] << 8) | bytes[cursor+11]) & 0x1FFF;

            CONFIG::LOGGING
            {
                logger.debug("Saw PMT ID of " + pmtStreamId);
            }

            return true;
        }

        private function parseProgramMapTable(bytes:ByteArray, cursor:uint):Boolean
        {
            var sectionLength:uint;
            var sectionLimit:uint;
            var programInfoLength:uint;
            var type:uint;
            var pid:uint;
            var esInfoLength:uint;
            var seenPIDsByClass:Array;
            var mediaClass:int;

            var hasAudio:Boolean = false, hasVideo:Boolean = false;

            // Set up types.
            types = [];
            seenPIDsByClass = [];
            seenPIDsByClass[MediaClass.VIDEO] = Infinity;
            seenPIDsByClass[MediaClass.AUDIO] = Infinity;

            // Process section length and limit.
            cursor++;

            sectionLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
            cursor += 2;

            if(sectionLength + cursor > bytes.length)
            {
                CONFIG::LOGGING
                {
                    logger.error("Not enough data to read. 1");
                }
                return false;
            }

            // Skip a few things we don't care about: program number, RSV, version, CNI, section, last_section, pcr_cid
            sectionLimit = cursor + sectionLength;
            cursor += 7;

            // And get the program info length.
            programInfoLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
            cursor += 2;

            // If not enough data to proceed, bail.
            if(programInfoLength + cursor > bytes.length)
            {
                CONFIG::LOGGING
                {
                    logger.error("Not enough data to read. 2");
                }
                return false;
            }

            cursor += programInfoLength;

            const CRC_SIZE:int = 4;
            while(cursor < sectionLimit - CRC_SIZE)
            {
                type = bytes[cursor++];
                pid = ((bytes[cursor] & 0x1f) << 8) + bytes[cursor + 1];
                cursor += 2;

                mediaClass = MediaClass.calculate(type);

                if(mediaClass == MediaClass.VIDEO)
                    hasVideo = true

                if(mediaClass == MediaClass.AUDIO)
                    hasAudio = true

                // For video & audio, select the lowest PID for each kind.
                if(mediaClass == MediaClass.OTHER
                 || pid < seenPIDsByClass[mediaClass])
                {
                    // Clear a higher PID if present.
                    if(mediaClass != MediaClass.OTHER
                     && seenPIDsByClass[mediaClass] < Infinity)
                        types[seenPIDsByClass[mediaClass]] = -1;

                    types[pid] = type;
                    seenPIDsByClass[mediaClass] = pid;
                }

                // Skip the esInfo data.
                esInfoLength = ((bytes[cursor] & 0x0f) << 8) + bytes[cursor + 1];
                cursor += 2;
                cursor += esInfoLength;
            }

            // Cook out header to transcoder.
            //transcoder.writeHeader(hasAudio, hasVideo);
            headerSent = true;

            return true;
        }

        public function append(packet:PESPacket):Boolean
        {
//            logger.debug("saw packet of " + packet.buffer.length);
            var b:ByteArray = packet.buffer;
            b.position = 0;

            if(b.length < 8)
            {
                CONFIG::LOGGING
                {
                    logger.error("Ignoring too short PES packet, length=" + b.length);
                }
                return true;
            }

            // Get the start code.
            var startCode:uint = b.readUnsignedInt();
            if((startCode & 0xFFFFFF00) != 0x00000100)
            {
                // It could be a program association table.
                if((startCode & 0xFFFFFF00) == 0x0000b000)
                {
                    parseProgramAssociationTable(b, 1);
                    return true;
                }

                // It could be the program map table.
                if((startCode & 0xFFFFFC00) == 0x0002b000)
                {
                    parseProgramMapTable(b, 1);
                    return true;
                }

                var tmp:ByteArray = new ByteArray();
                tmp.writeInt(startCode);
                CONFIG::LOGGING
                {
                    logger.error("ES prefix was wrong, expected 00:00:01:xx but got " + Hex.fromArray(tmp, true));
                }
                return true;
            }

            // Get the stream ID.
            var streamID:int = startCode & 0xFF;

            // Get the length.
            var packetLength:uint = b.readUnsignedShort();
            if(packetLength)
            {
                if(b.length < packetLength )
                {
                    CONFIG::LOGGING
                    {
                        logger.warn("WARNING: parsePESPacket - not enough bytes, expecting " + packetLength + ", but have " + b.length);
                    }
                    return false; // not enough bytes in packet
                }
            }

            if(b.length < 9)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - too short to read header!");
                }
                return false;
            }

            // Read the rest of the header.
            var cursor:uint = 6;
            var dataAlignment:Boolean = (b[cursor] & 0x04) != 0;
            cursor++;

            var ptsDts:uint = (b[cursor] & 0xc0) >> 6;
            cursor++;

            var pesHeaderDataLength:uint = b[cursor];
            cursor++;

            //logger.debug(" PES align=" + dataAlignment + " ptsDts=" + ptsDts + " header=" + pesHeaderDataLength);

            var pts:Number = 0, dts:Number = 0;

            if(ptsDts & 0x02)
            {
                // has PTS at least
                if(cursor + 5 > b.length)
                    return true;

                pts  = b[cursor] & 0x0e;
                pts *= 128;
                pts += b[cursor + 1];
                pts *= 256;
                pts += b[cursor + 2] & 0xfe;
                pts *= 128;
                pts += b[cursor + 3];
                pts *= 256;
                pts += b[cursor + 4] & 0xfe;
                pts /= 2;

                if(ptsDts & 0x01)
                {
                    // DTS too!
                    if(cursor + 10 > b.length)
                        return true;

                    dts  = b[cursor + 5] & 0x0e;
                    dts *= 128;
                    dts += b[cursor + 6];
                    dts *= 256;
                    dts += b[cursor + 7] & 0xfe;
                    dts *= 128;
                    dts += b[cursor + 8];
                    dts *= 256;
                    dts += b[cursor + 9] & 0xfe;
                    dts /= 2;
                }
                else
                {
                    //logger.debug("Filling in DTS")
                    dts = pts;
                }
            }

            // Condition PTS and DTS.
            pts = handleMpegTimestampWrap(pts, lastPTS);
            lastPTS = pts;

            dts = handleMpegTimestampWrap(dts, lastDTS);
            lastDTS = dts;

            packet.pts = pts;
            packet.dts = dts;
            //logger.debug("   PTS=" + pts/90000 + " DTS=" + dts/90000);

            cursor += pesHeaderDataLength;

            if(cursor > b.length)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - ran out of bytes");
                }
                return true;
            }

            if(types[packet.packetID] == undefined)
            {
                CONFIG::LOGGING
                {
                    logger.warn("WARNING: parsePESPacket - unknown type");
                }
                return true;
            }

            var pes:PESPacketStream;

            if(streams[packet.packetID] == undefined)
            {
                if(dts < 0.0)
                {
                    CONFIG::LOGGING
                    {
                        logger.warn("WARNING: parsePESPacket - invalid decode timestamp? DTS="  + dts);
                    }
                    //return true;
                }

                pes = new PESPacketStream();
                streams[packet.packetID] = pes;
            }
            else
            {
                pes = streams[packet.packetID];
            }

            if(headerSent == false)
            {
                CONFIG::LOGGING
                {
                    logger.warn("Skipping data that came before PMT");
                }
                return true;
            }

            // Note the type at this moment in time.
            packet.type = types[packet.packetID];
            packet.headerLength = cursor;

            // And process.
            if(MediaClass.calculate(types[packet.packetID]) == MediaClass.VIDEO)
            {
                var start:int = NALU.scan(b, cursor, true);
                if(start == -1 && lastVideoNALU)
                {
                    CONFIG::LOGGING
                    {
                        logger.debug("Stuff entire " + (b.length - cursor) + " bytes into previous NALU.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, b.length - cursor);
                    return true;

                }
                else if((start - cursor) > 0 && lastVideoNALU)
                {
                    // Shove into previous buffer.
                    CONFIG::LOGGING
                    {
                        logger.debug("Stuffing first " + (start - cursor) + " bytes into previous NALU.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, start - cursor);
                    cursor = start;
                }

                // If it's identical timestamps, accumulate it into the current unit and keep going.
                if(lastVideoNALU && pts == lastVideoNALU.pts && dts == lastVideoNALU.dts)
                {
                    CONFIG::LOGGING
                    {
                        logger.debug("Combining " + (start-cursor) + " bytes into previous NALU due to matching DTS/PTS.");
                    }
                    lastVideoNALU.buffer.position = lastVideoNALU.buffer.length;
                    b.position = 0;
                    lastVideoNALU.buffer.writeBytes(b, cursor, start - cursor);
                    cursor = start;
                }
                else
                {
                    // Submit previous data.
                    if(lastVideoNALU)
                    {
                        pendingBuffers.push(lastVideoNALU.clone());
                    }

                    // Update NALU state.
                    lastVideoNALU = new NALU();
                    lastVideoNALU.buffer = new ByteArray();
                    lastVideoNALU.pts = pts;
                    lastVideoNALU.dts = dts;
                    lastVideoNALU.type = packet.type;
                    lastVideoNALU.buffer.writeBytes(b, cursor);

                }
            }
            else if(types[packet.packetID] == 0x0F)
            {
                // It's an AAC stream.
                pendingBuffers.push(packet.clone());
            }
            else if(types[packet.packetID] == 0x03 || types[packet.packetID] == 0x04)
            {
                // It's an MP3 stream.
                pendingBuffers.push(packet.clone());
            }
            else
            {
                CONFIG::LOGGING
                {
                    logger.warn("Unknown packet ID type " + types[packet.packetID] + ", ignoring (A).");
                }
            }

            bufferPendingNalus();

            return true;
        }

        /**
         * To avoid transcoding all content on flush, we buffer it into FLV
         * tags as we go. However, they remain undelivered until we can gather
         * final SPS/PPS information. This method is responsible for
         * incrementally buffering in the FLV transcoder as we go.
         */
        public function bufferPendingNalus():void
        {
            // Iterate and buffer new NALUs.
            for(var i:int=pendingLastConvertedIndex; i<pendingBuffers.length; i++)
            {
                if(pendingBuffers[i] is NALU)
                {
                    transcoder.convert(pendingBuffers[i] as NALU);
                }
                else if(pendingBuffers[i] is PESPacket)
                {
                    var packet:PESPacket = pendingBuffers[i] as PESPacket;
                    if(packet.type == 0x0F)
                    {
                        // It's an AAC stream.
                        transcoder.convertAAC(packet);
                    }
                    else if(packet.type == 0x03 || packet.type == 0x04)
                    {
                        // It's an MP3 stream. Pass through directly.
                        transcoder.convertMP3(packet);
                    }
                    else
                    {
                        CONFIG::LOGGING
                        {
                            logger.warn("Unknown packet ID type " + packet.type + ", ignoring (B).");
                        }
                    }
                }
            }

            // Note the last item we converted so we can avoid duplicating work.
            pendingLastConvertedIndex = pendingBuffers.length;
        }

        public function processAllNalus():void
        {
            // Consume any unposted video NALUs.
            if(lastVideoNALU)
            {
                pendingBuffers.push(lastVideoNALU.clone());
                lastVideoNALU = null;
            }

            // First walk all the video NALUs and get the correct SPS/PPS
            if(pendingBuffers.length == 0)
                return;

            // Then emit SPS/PPS
            transcoder.emitSPSPPSUnbuffered();

            // Complete buffering and emit it all.
            bufferPendingNalus();
            transcoder.emitBufferedTags();

            // Don't forget to clear the pending list.
            pendingBuffers.length = 0;
            pendingLastConvertedIndex = 0;
        }
    }
}

Fix issue with unwrapped negative DTS dropping PES packets.


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.model.AudioTrack;

    import flash.display.Stage;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLStream;
    import flash.events.EventDispatcher;
    import flash.events.Event;

    import org.mangui.hls.model.Level;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.loader.ManifestLoader;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.loader.FragmentLoader;
    import org.mangui.hls.stream.HLSNetStream;
    import org.hola.WorkerUtils;
    import org.hola.HSettings;
    import flash.external.ExternalInterface;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        public var _fragmentLoader : FragmentLoader;
        private var _manifestLoader : ManifestLoader;
        private var _audioTrackController : AudioTrackController;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream **/
        private var _hlsURLStream : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        private var _url:String;
        private static var hola_api_inited:Boolean;
        private static var g_curr_id:Number = 0;
        private static var g_curr_hls:HLS;

        private static function hola_version() : Object
        {
            return {
                flashls_version: '0.3.5',
                patch_version: '1.0.7'
            };
        }
        private static function hola_hls_get_video_url() : String {
            return g_curr_hls._url;
        }

        private static function hola_hls_get_position() : Number {
            return g_curr_hls.position;
        }

        private static function hola_hls_get_duration() : Number {
            return g_curr_hls.duration;
        }

        private static function hola_hls_get_buffer_sec() : Number {
            return g_curr_hls.bufferLength;
        }

        private static function hola_hls_call(method:String, args:Array):Object{
            return g_curr_hls[method].apply(g_curr_hls, args);
        }

        private static function hola_hls_get_state() : String {
            return g_curr_hls.playbackState;
        }

        private static function hola_hls_get_levels() : Object {
            return g_curr_hls.levels
        }

        private static function hola_hls_get_level() : Number {
            return g_curr_hls.level
        }

        /** Create and connect all components. **/
        public function HLS() {
            HSettings.init();
            WorkerUtils.start_worker();
            if (!hola_api_inited && ExternalInterface.available)
            {
                ExternalInterface.call('console.log', 'HLS hola_api_inited');
                hola_api_inited = true;
                ExternalInterface.addCallback("hola_hls_call", HLS.hola_hls_call);
                ExternalInterface.addCallback("hola_version", HLS.hola_version);
                ExternalInterface.addCallback("hola_hls_get_video_url", HLS.hola_hls_get_video_url);
                ExternalInterface.addCallback("hola_hls_get_position", HLS.hola_hls_get_position);
                ExternalInterface.addCallback("hola_hls_get_duration", HLS.hola_hls_get_duration);
                ExternalInterface.addCallback("hola_hls_get_buffer_sec", HLS.hola_hls_get_buffer_sec);
                ExternalInterface.addCallback("hola_hls_get_state", HLS.hola_hls_get_state);
                ExternalInterface.addCallback("hola_hls_get_levels", HLS.hola_hls_get_levels);
                ExternalInterface.addCallback("hola_hls_get_level", HLS.hola_hls_get_level);
            }
            g_curr_id++;
            g_curr_hls = this;
            if (ExternalInterface.available)
            {
                ExternalInterface.call('console.log', 'HLS new ', g_curr_id);
                ExternalInterface.call('window.postMessage',
                    {id: 'flashls.hlsNew', hls_id: g_curr_id}, '*');
            }
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _manifestLoader = new ManifestLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _hlsURLStream = URLStream as Class;
            // default loader
            _fragmentLoader = new FragmentLoader(this, _audioTrackController);
            _hlsNetStream = new HLSNetStream(connection, this, _fragmentLoader);

            add_event(HLSEvent.MANIFEST_LOADING);
            add_event(HLSEvent.MANIFEST_PARSED);
            add_event(HLSEvent.MANIFEST_LOADED);
            add_event(HLSEvent.LEVEL_LOADING);
            add_event(HLSEvent.LEVEL_LOADED);
            add_event(HLSEvent.LEVEL_SWITCH);
            add_event(HLSEvent.LEVEL_ENDLIST);
            add_event(HLSEvent.FRAGMENT_LOADING);
            add_event(HLSEvent.FRAGMENT_LOADED);
            add_event(HLSEvent.FRAGMENT_PLAYING);
            add_event(HLSEvent.AUDIO_TRACKS_LIST_CHANGE);
            add_event(HLSEvent.AUDIO_TRACK_CHANGE);
            add_event(HLSEvent.TAGS_LOADED);
            add_event(HLSEvent.LAST_VOD_FRAGMENT_LOADED);
            add_event(HLSEvent.ERROR);
            add_event(HLSEvent.MEDIA_TIME);
            add_event(HLSEvent.PLAYBACK_STATE);
            add_event(HLSEvent.SEEK_STATE);
            add_event(HLSEvent.PLAYBACK_COMPLETE);
            add_event(HLSEvent.PLAYLIST_DURATION_UPDATED);
            add_event(HLSEvent.ID3_UPDATED);
        };

        private function add_event(name:String):void{
            this.addEventListener(name, event_handler_func('flashls.'+name));
        }
        private function event_handler_func(name:String):Function{
            return function(event:HLSEvent):void{
                if (!ExternalInterface.available)
                    return;
                ExternalInterface.call('window.postMessage',
                    {id: name, hls_id: g_curr_id, url: event.url,
                    level: event.level, duration: event.duration,
                    levels: event.levels, error: event.error,
                    loadMetrics: event.loadMetrics,
                    playMetrics: event.playMetrics, mediatime: event.mediatime,
                    state: event.state, audioTrack: event.audioTrack}, '*');
            }
        }

        /** Forward internal errors. **/
        override public function dispatchEvent(event : Event) : Boolean {
            if (event.type == HLSEvent.ERROR) {
                CONFIG::LOGGING {
                    Log.error((event as HLSEvent).error);
                }
                _hlsNetStream.close();
            }
            return super.dispatchEvent(event);
        };

        public function dispose() : void {
            if (ExternalInterface.available)
            {
                ExternalInterface.call('window.postMessage',
                    {id: 'flashls.hlsDispose', hls_id: g_curr_id}, '*');
            }
            _fragmentLoader.dispose();
            _manifestLoader.dispose();
            _audioTrackController.dispose();
            _hlsNetStream.dispose_();
            _fragmentLoader = null;
            _manifestLoader = null;
            _audioTrackController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return the quality level used when starting a fresh playback **/
        public function get startlevel() : int {
            return _manifestLoader.startlevel;
        };

        /** Return the quality level used after a seek operation **/
        public function get seeklevel() : int {
            return _manifestLoader.seeklevel;
        };

        /** Return the quality level of the currently played fragment **/
        public function get playbacklevel() : int {
            return _hlsNetStream.playbackLevel;
        };

        /** Return the quality level of last loaded fragment **/
        public function get level() : int {
            return _fragmentLoader.level;
        };

        /*  set quality level for next loaded fragment (-1 for automatic level selection) */
        public function set level(level : int) : void {
            _fragmentLoader.level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autolevel() : Boolean {
            return _fragmentLoader.autolevel;
        };

        /** Return a Vector of quality level **/
        public function get levels() : Vector.<Level> {
            return _manifestLoader.levels;
        };

        /** Return the current playback position. **/
        public function get position() : Number {
            return _hlsNetStream.position;
        };

        public function get video_url() : String {
            return _url;
        };

        public function get duration() : Number {
            return _hlsNetStream.duration;
        };

        /** Return the current playback state. **/
        public function get playbackState() : String {
            return _hlsNetStream.playbackState;
        };

        /** Return the current seek state. **/
        public function get seekState() : String {
            return _hlsNetStream.seekState;
        };

        /** Return the type of stream (VOD/LIVE). **/
        public function get type() : String {
            return _manifestLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _hlsNetStream.close();
            _url = url;
            _manifestLoader.load(url);
        };

        /** return HLS NetStream **/
        public function get stream() : NetStream {
            return _hlsNetStream;
        }

        public function get client() : Object {
            return _client;
        }

        public function set client(value : Object) : void {
            _client = value;
        }

        /** get current Buffer Length  **/
        public function get bufferLength() : Number {
            return _hlsNetStream.bufferLength;
        };

        /** get audio tracks list**/
        public function get audioTracks() : Vector.<AudioTrack> {
            return _audioTrackController.audioTracks;
        };

        /** get alternate audio tracks list from playlist **/
        public function get altAudioTracks() : Vector.<AltAudioTrack> {
            return _manifestLoader.altAudioTracks;
        };

        /** get index of the selected audio track (index in audio track lists) **/
        public function get audioTrack() : int {
            return _audioTrackController.audioTrack;
        };

        /** select an audio track, based on its index in audio track lists**/
        public function set audioTrack(val : int) : void {
            _audioTrackController.audioTrack = val;
        }

        /* set stage */
        public function set stage(stage : Stage) : void {
            _stage = stage;
        }

        /* get stage */
        public function get stage() : Stage {
            return _stage;
        }

        /* set URL stream loader */
        public function set URLstream(urlstream : Class) : void {
            _hlsURLStream = urlstream;
        }

        /* retrieve URL stream loader */
        public function get URLstream() : Class {
            return _hlsURLStream;
        }
    };
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.model.AudioTrack;

    import flash.display.Stage;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLStream;
    import flash.events.EventDispatcher;
    import flash.events.Event;

    import org.mangui.hls.model.Level;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.loader.ManifestLoader;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.loader.FragmentLoader;
    import org.mangui.hls.stream.HLSNetStream;
    import org.hola.WorkerUtils;
    import org.hola.HSettings;
    import flash.external.ExternalInterface;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        public var _fragmentLoader : FragmentLoader;
        private var _manifestLoader : ManifestLoader;
        private var _audioTrackController : AudioTrackController;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream **/
        private var _hlsURLStream : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        private var _url:String;
        private static var hola_api_inited:Boolean;
        private static var g_curr_id:Number = 0;
        private static var g_curr_hls:HLS;

        private static function hola_version() : Object
        {
            return {
                flashls_version: '0.3.5',
                patch_version: '1.0.7',
                have_worker: CONFIG::HAVE_WORKER
            };
        }
        private static function hola_hls_get_video_url() : String {
            return g_curr_hls._url;
        }

        private static function hola_hls_get_position() : Number {
            return g_curr_hls.position;
        }

        private static function hola_hls_get_duration() : Number {
            return g_curr_hls.duration;
        }

        private static function hola_hls_get_buffer_sec() : Number {
            return g_curr_hls.bufferLength;
        }

        private static function hola_hls_call(method:String, args:Array):Object{
            return g_curr_hls[method].apply(g_curr_hls, args);
        }

        private static function hola_hls_get_state() : String {
            return g_curr_hls.playbackState;
        }

        private static function hola_hls_get_levels() : Object {
            return g_curr_hls.levels
        }

        private static function hola_hls_get_level() : Number {
            return g_curr_hls.level
        }

        /** Create and connect all components. **/
        public function HLS() {
            HSettings.init();
            WorkerUtils.start_worker();
            if (!hola_api_inited && ExternalInterface.available)
            {
                ExternalInterface.call('console.log', 'HLS hola_api_inited');
                hola_api_inited = true;
                ExternalInterface.addCallback("hola_hls_call", HLS.hola_hls_call);
                ExternalInterface.addCallback("hola_version", HLS.hola_version);
                ExternalInterface.addCallback("hola_hls_get_video_url", HLS.hola_hls_get_video_url);
                ExternalInterface.addCallback("hola_hls_get_position", HLS.hola_hls_get_position);
                ExternalInterface.addCallback("hola_hls_get_duration", HLS.hola_hls_get_duration);
                ExternalInterface.addCallback("hola_hls_get_buffer_sec", HLS.hola_hls_get_buffer_sec);
                ExternalInterface.addCallback("hola_hls_get_state", HLS.hola_hls_get_state);
                ExternalInterface.addCallback("hola_hls_get_levels", HLS.hola_hls_get_levels);
                ExternalInterface.addCallback("hola_hls_get_level", HLS.hola_hls_get_level);
            }
            g_curr_id++;
            g_curr_hls = this;
            if (ExternalInterface.available)
            {
                ExternalInterface.call('console.log', 'HLS new ', g_curr_id);
                ExternalInterface.call('window.postMessage',
                    {id: 'flashls.hlsNew', hls_id: g_curr_id}, '*');
            }
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _manifestLoader = new ManifestLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _hlsURLStream = URLStream as Class;
            // default loader
            _fragmentLoader = new FragmentLoader(this, _audioTrackController);
            _hlsNetStream = new HLSNetStream(connection, this, _fragmentLoader);

            add_event(HLSEvent.MANIFEST_LOADING);
            add_event(HLSEvent.MANIFEST_PARSED);
            add_event(HLSEvent.MANIFEST_LOADED);
            add_event(HLSEvent.LEVEL_LOADING);
            add_event(HLSEvent.LEVEL_LOADED);
            add_event(HLSEvent.LEVEL_SWITCH);
            add_event(HLSEvent.LEVEL_ENDLIST);
            add_event(HLSEvent.FRAGMENT_LOADING);
            add_event(HLSEvent.FRAGMENT_LOADED);
            add_event(HLSEvent.FRAGMENT_PLAYING);
            add_event(HLSEvent.AUDIO_TRACKS_LIST_CHANGE);
            add_event(HLSEvent.AUDIO_TRACK_CHANGE);
            add_event(HLSEvent.TAGS_LOADED);
            add_event(HLSEvent.LAST_VOD_FRAGMENT_LOADED);
            add_event(HLSEvent.ERROR);
            add_event(HLSEvent.MEDIA_TIME);
            add_event(HLSEvent.PLAYBACK_STATE);
            add_event(HLSEvent.SEEK_STATE);
            add_event(HLSEvent.PLAYBACK_COMPLETE);
            add_event(HLSEvent.PLAYLIST_DURATION_UPDATED);
            add_event(HLSEvent.ID3_UPDATED);
        };

        private function add_event(name:String):void{
            this.addEventListener(name, event_handler_func('flashls.'+name));
        }
        private function event_handler_func(name:String):Function{
            return function(event:HLSEvent):void{
                if (!ExternalInterface.available)
                    return;
                ExternalInterface.call('window.postMessage',
                    {id: name, hls_id: g_curr_id, url: event.url,
                    level: event.level, duration: event.duration,
                    levels: event.levels, error: event.error,
                    loadMetrics: event.loadMetrics,
                    playMetrics: event.playMetrics, mediatime: event.mediatime,
                    state: event.state, audioTrack: event.audioTrack}, '*');
            }
        }

        /** Forward internal errors. **/
        override public function dispatchEvent(event : Event) : Boolean {
            if (event.type == HLSEvent.ERROR) {
                CONFIG::LOGGING {
                    Log.error((event as HLSEvent).error);
                }
                _hlsNetStream.close();
            }
            return super.dispatchEvent(event);
        };

        public function dispose() : void {
            if (ExternalInterface.available)
            {
                ExternalInterface.call('window.postMessage',
                    {id: 'flashls.hlsDispose', hls_id: g_curr_id}, '*');
            }
            _fragmentLoader.dispose();
            _manifestLoader.dispose();
            _audioTrackController.dispose();
            _hlsNetStream.dispose_();
            _fragmentLoader = null;
            _manifestLoader = null;
            _audioTrackController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return the quality level used when starting a fresh playback **/
        public function get startlevel() : int {
            return _manifestLoader.startlevel;
        };

        /** Return the quality level used after a seek operation **/
        public function get seeklevel() : int {
            return _manifestLoader.seeklevel;
        };

        /** Return the quality level of the currently played fragment **/
        public function get playbacklevel() : int {
            return _hlsNetStream.playbackLevel;
        };

        /** Return the quality level of last loaded fragment **/
        public function get level() : int {
            return _fragmentLoader.level;
        };

        /*  set quality level for next loaded fragment (-1 for automatic level selection) */
        public function set level(level : int) : void {
            _fragmentLoader.level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autolevel() : Boolean {
            return _fragmentLoader.autolevel;
        };

        /** Return a Vector of quality level **/
        public function get levels() : Vector.<Level> {
            return _manifestLoader.levels;
        };

        /** Return the current playback position. **/
        public function get position() : Number {
            return _hlsNetStream.position;
        };

        public function get video_url() : String {
            return _url;
        };

        public function get duration() : Number {
            return _hlsNetStream.duration;
        };

        /** Return the current playback state. **/
        public function get playbackState() : String {
            return _hlsNetStream.playbackState;
        };

        /** Return the current seek state. **/
        public function get seekState() : String {
            return _hlsNetStream.seekState;
        };

        /** Return the type of stream (VOD/LIVE). **/
        public function get type() : String {
            return _manifestLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _hlsNetStream.close();
            _url = url;
            _manifestLoader.load(url);
        };

        /** return HLS NetStream **/
        public function get stream() : NetStream {
            return _hlsNetStream;
        }

        public function get client() : Object {
            return _client;
        }

        public function set client(value : Object) : void {
            _client = value;
        }

        /** get current Buffer Length  **/
        public function get bufferLength() : Number {
            return _hlsNetStream.bufferLength;
        };

        /** get audio tracks list**/
        public function get audioTracks() : Vector.<AudioTrack> {
            return _audioTrackController.audioTracks;
        };

        /** get alternate audio tracks list from playlist **/
        public function get altAudioTracks() : Vector.<AltAudioTrack> {
            return _manifestLoader.altAudioTracks;
        };

        /** get index of the selected audio track (index in audio track lists) **/
        public function get audioTrack() : int {
            return _audioTrackController.audioTrack;
        };

        /** select an audio track, based on its index in audio track lists**/
        public function set audioTrack(val : int) : void {
            _audioTrackController.audioTrack = val;
        }

        /* set stage */
        public function set stage(stage : Stage) : void {
            _stage = stage;
        }

        /* get stage */
        public function get stage() : Stage {
            return _stage;
        }

        /* set URL stream loader */
        public function set URLstream(urlstream : Class) : void {
            _hlsURLStream = urlstream;
        }

        /* retrieve URL stream loader */
        public function get URLstream() : Class {
            return _hlsURLStream;
        }
    };
}

return CONFIG::HAVE_WORKER in hola_version()


Change 20070323-sallen-0 by sallen@sallen-new on 2007-03-23 13:08:03 PDT
    in /cygdrive/c/laszlo/svn/openlaszlo/trunk
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: missed from last change (sorry about that)

Bugs Fixed: LPP-3753 (goes with change 4468)

Technical Reviewer: ptw@openlaszlo.orG
QA Reviewer: (pending)
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details: sorry, I'm still getting the hang of svn

Tests:

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