package
{
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.net.Socket;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.NetStatusEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.utils.ByteArray;
    import flash.utils.setTimeout;

    import rtmfp.RTMFPSocket;
    import rtmfp.events.RTMFPSocketEvent;
    import Utils;

    public class rtmfpcat extends Sprite {

      /* Nate's facilitator -- also serving a crossdomain policy */
      private const DEFAULT_FAC_ADDR:Object = {
        host: "128.12.179.80",
        port: 9002
      };

      private const DEFAULT_TOR_CLIENT_ADDR:Object = {
        host: "127.0.0.1",
        port: 3333
      };

      /* David's bridge (nickname eRYaZuvY02FpExln) that also serves a
         crossdomain policy. */
      private const DEFAULT_TOR_PROXY_ADDR:Object = {
        host: "69.164.193.231",
        port: 9001
      };

      // Milliseconds.
      private const FACILITATOR_POLL_INTERVAL:int = 10000;

      private var output_text:TextField;

      private var s_f:Socket;
      private var s_r:RTMFPSocket;
      private var s_t:Socket;

      private var fac_addr:Object;
      private var tor_addr:Object;

      private var proxy_mode:Boolean;

      public function rtmfpcat()
      {
        output_text = new TextField();
        output_text.width = 400;
        output_text.height = 300;
        output_text.background = true;
        output_text.backgroundColor = 0x001f0f;
        output_text.textColor = 0x44CC44;
        addChild(output_text);

        puts("Starting.");

        this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
      }

      private function puts(s:String):void
      {
          output_text.appendText(s + "\n");
          output_text.scrollV = output_text.maxScrollV;
      }

      private function onLoaderInfoComplete(e:Event):void
      {
        var fac_spec:String;
        var tor_spec:String;

        puts("Parameters loaded.");

        proxy_mode = (this.loaderInfo.parameters["proxy"] != null);

        fac_spec = this.loaderInfo.parameters["facilitator"];
        if (!fac_spec) {
          puts("No \"facilitator\" specification provided...using default.");
          fac_addr = DEFAULT_FAC_ADDR;
        } else {
          puts("Facilitator spec: \"" + fac_spec + "\"");
          fac_addr = Utils.parseAddrSpec(fac_spec);
        }

        if (!fac_addr) {
            puts("Error: Facilitator spec must be in the form \"host:port\".");
            return;
        }

        tor_spec = this.loaderInfo.parameters["tor"];
        if (!tor_spec) {
          puts("No Tor specification provided...using default.");
          if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
          else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
        } else {
          puts("Tor spec: \"" + tor_spec + "\"")
          tor_addr = Utils.parseAddrSpec(tor_spec);
        }

        if (!tor_addr) {
          puts("Error: Tor spec must be in the form \"host:port\".");
          return;
        }

        establishRTMFPConnection();
      }

      private function establishRTMFPConnection():void
      {
        s_r = new RTMFPSocket();
        s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
          puts("Cirrus: connected with id " + s_r.id + ".");
          establishFacilitatorConnection();
        });
        s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
          puts("Error: failed to connect to Cirrus.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
          puts("Publishing started.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
          puts("Peer connected.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
          puts("Peer disconnected.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
          puts("Peering success.");
          establishTorConnection();
        });
        s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
          puts("Peering fail.");
        });
        s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var bytes:ByteArray = new ByteArray();
          s_r.readBytes(bytes);
          puts("RTMFP: read " + bytes.length + " bytes.");
          s_t.writeBytes(bytes);
        });

        s_r.connect();
      }

      private function establishTorConnection():void
      {
        s_t = new Socket();
        s_t.addEventListener(Event.CONNECT, function (e:Event):void {
          puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
        });
        s_t.addEventListener(Event.CLOSE, function (e:Event):void {
          puts("Tor: closed connection.");
        });
        s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
          puts("Tor: I/O error: " + e.text + ".");
        });
        s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var bytes:ByteArray = new ByteArray();
          s_t.readBytes(bytes, 0, e.bytesLoaded);
          puts("Tor: read " + bytes.length + " bytes.");
          s_r.writeBytes(bytes);
        });
        s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
          puts("Tor: security error: " + e.text + ".");
        });

        s_t.connect(tor_addr.host, tor_addr.port);
      }

      private function establishFacilitatorConnection():void
      {
        s_f = new Socket();
        s_f.addEventListener(Event.CONNECT, function (e:Event):void {
          puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
          if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
          else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
        });
        s_f.addEventListener(Event.CLOSE, function (e:Event):void {
          puts("Facilitator: connection closed.");
          if (proxy_mode) {
            setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
          }
        });
        s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
          puts("Facilitator: I/O error: " + e.text + ".");
        });
        s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
          puts("Facilitator: got \"" + clientID + "\"");
          if (clientID != "Registration list empty") {
            puts("Connecting to " + clientID + ".");
            s_r.peer = clientID;
          }
        });
        s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
          puts("Facilitator: security error: " + e.text + ".");
        });

        s_f.connect(fac_addr.host, fac_addr.port);
      }
  }
}

package
{
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.net.Socket;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.NetStatusEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.utils.ByteArray;
    import flash.utils.setTimeout;

    import rtmfp.RTMFPSocket;
    import rtmfp.events.RTMFPSocketEvent;
    import Utils;

    public class rtmfpcat extends Sprite {

      /* Nate's facilitator -- also serving a crossdomain policy */
      private const DEFAULT_FAC_ADDR:Object = {
        host: "128.12.179.80",
        port: 9002
      };

      private const DEFAULT_TOR_CLIENT_ADDR:Object = {
        host: "127.0.0.1",
        port: 3333
      };

      /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
         crossdomain policy. */
      private const DEFAULT_TOR_PROXY_ADDR:Object = {
        host: "173.255.221.44",
        port: 9001
      };

      // Milliseconds.
      private const FACILITATOR_POLL_INTERVAL:int = 10000;

      private var output_text:TextField;

      private var s_f:Socket;
      private var s_r:RTMFPSocket;
      private var s_t:Socket;

      private var fac_addr:Object;
      private var tor_addr:Object;

      private var proxy_mode:Boolean;

      public function rtmfpcat()
      {
        output_text = new TextField();
        output_text.width = 400;
        output_text.height = 300;
        output_text.background = true;
        output_text.backgroundColor = 0x001f0f;
        output_text.textColor = 0x44CC44;
        addChild(output_text);

        puts("Starting.");

        this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
      }

      private function puts(s:String):void
      {
          output_text.appendText(s + "\n");
          output_text.scrollV = output_text.maxScrollV;
      }

      private function onLoaderInfoComplete(e:Event):void
      {
        var fac_spec:String;
        var tor_spec:String;

        puts("Parameters loaded.");

        proxy_mode = (this.loaderInfo.parameters["proxy"] != null);

        fac_spec = this.loaderInfo.parameters["facilitator"];
        if (!fac_spec) {
          puts("No \"facilitator\" specification provided...using default.");
          fac_addr = DEFAULT_FAC_ADDR;
        } else {
          puts("Facilitator spec: \"" + fac_spec + "\"");
          fac_addr = Utils.parseAddrSpec(fac_spec);
        }

        if (!fac_addr) {
            puts("Error: Facilitator spec must be in the form \"host:port\".");
            return;
        }

        tor_spec = this.loaderInfo.parameters["tor"];
        if (!tor_spec) {
          puts("No Tor specification provided...using default.");
          if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
          else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
        } else {
          puts("Tor spec: \"" + tor_spec + "\"")
          tor_addr = Utils.parseAddrSpec(tor_spec);
        }

        if (!tor_addr) {
          puts("Error: Tor spec must be in the form \"host:port\".");
          return;
        }

        establishRTMFPConnection();
      }

      private function establishRTMFPConnection():void
      {
        s_r = new RTMFPSocket();
        s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
          puts("Cirrus: connected with id " + s_r.id + ".");
          establishFacilitatorConnection();
        });
        s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
          puts("Error: failed to connect to Cirrus.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
          puts("Publishing started.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
          puts("Peer connected.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
          puts("Peer disconnected.");
        });
        s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
          puts("Peering success.");
          establishTorConnection();
        });
        s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
          puts("Peering fail.");
        });
        s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var bytes:ByteArray = new ByteArray();
          s_r.readBytes(bytes);
          puts("RTMFP: read " + bytes.length + " bytes.");
          s_t.writeBytes(bytes);
        });

        s_r.connect();
      }

      private function establishTorConnection():void
      {
        s_t = new Socket();
        s_t.addEventListener(Event.CONNECT, function (e:Event):void {
          puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
        });
        s_t.addEventListener(Event.CLOSE, function (e:Event):void {
          puts("Tor: closed connection.");
        });
        s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
          puts("Tor: I/O error: " + e.text + ".");
        });
        s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var bytes:ByteArray = new ByteArray();
          s_t.readBytes(bytes, 0, e.bytesLoaded);
          puts("Tor: read " + bytes.length + " bytes.");
          s_r.writeBytes(bytes);
        });
        s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
          puts("Tor: security error: " + e.text + ".");
        });

        s_t.connect(tor_addr.host, tor_addr.port);
      }

      private function establishFacilitatorConnection():void
      {
        s_f = new Socket();
        s_f.addEventListener(Event.CONNECT, function (e:Event):void {
          puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
          if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
          else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
        });
        s_f.addEventListener(Event.CLOSE, function (e:Event):void {
          puts("Facilitator: connection closed.");
          if (proxy_mode) {
            setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
          }
        });
        s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
          puts("Facilitator: I/O error: " + e.text + ".");
        });
        s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
          var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
          puts("Facilitator: got \"" + clientID + "\"");
          if (clientID != "Registration list empty") {
            puts("Connecting to " + clientID + ".");
            s_r.peer = clientID;
          }
        });
        s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
          puts("Facilitator: security error: " + e.text + ".");
        });

        s_f.connect(fac_addr.host, fac_addr.port);
      }
  }
}

Switch back to the public relay.

Switch back to the public relay.


/* 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 flash.display.Stage;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLLoader;
    import flash.net.URLStream;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.controller.LevelController;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.handler.StatsHandler;
    import org.mangui.hls.loader.AltAudioLevelLoader;
    import org.mangui.hls.loader.LevelLoader;
    import org.mangui.hls.model.AudioTrack;
    import org.mangui.hls.model.Level;
    import org.mangui.hls.model.Stats;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.stream.HLSNetStream;
    import org.mangui.hls.stream.StreamBuffer;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        private var _levelLoader : LevelLoader;
        private var _altAudioLevelLoader : AltAudioLevelLoader;
        private var _audioTrackController : AudioTrackController;
        private var _levelController : LevelController;
        private var _streamBuffer : StreamBuffer;
        private var _statsHandler : StatsHandler;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream/URLLoader **/
        private var _hlsURLStream : Class;
        private var _hlsURLLoader : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        /* level handling */
        private var _level : int;
        /* overrided quality_manual_level level */
        private var _manual_level : int = -1;

        /** Create and connect all components. **/
        public function HLS() {
            _levelLoader = new LevelLoader(this);
            _altAudioLevelLoader = new AltAudioLevelLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _levelController = new LevelController(this);
            _statsHandler = new StatsHandler(this);
            _streamBuffer = new StreamBuffer(this, _audioTrackController, _levelController);
            _hlsURLStream = URLStream as Class;
            _hlsURLLoader = URLLoader as Class;
            // default loader
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _hlsNetStream = new HLSNetStream(connection, this, _streamBuffer);
            this.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
        };

        /** 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);
        };

        private function _levelSwitchHandler(event : HLSEvent) : void {
            _level = event.level;
        };

        public function dispose() : void {
            this.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            _levelLoader.dispose();
            _altAudioLevelLoader.dispose();
            _audioTrackController.dispose();
            _levelController.dispose();
            _hlsNetStream.dispose_();
            _statsHandler.dispose();
            _streamBuffer.dispose();
            _levelLoader = null;
            _altAudioLevelLoader = null;
            _audioTrackController = null;
            _levelController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return index of first quality level referenced in Manifest  **/
        public function get firstLevel() : int {
            return _levelController.firstLevel;
        };

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

        /*  set the quality level used when starting a fresh playback */
        public function set startLevel(level : int) : void {
            _levelController.startLevel = level;
        };

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

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

        /** Return the quality level of the next played fragment **/
        public function get nextLevel() : int {
            return _streamBuffer.nextLevel;
        };

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

        /*  instant quality level switch (-1 for automatic level selection) */
        public function set currentLevel(level : int) : void {
            _manual_level = level;
            _streamBuffer.flushBuffer();
            _hlsNetStream.seek(position);
        };

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

        /*  set quality level for last loaded fragment (-1 for automatic level selection) */
        public function set loadLevel(level : int) : void {
            _manual_level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autoLevel() : Boolean {
            return (_manual_level == -1);
        };

        /* return manual level */
        public function get manualLevel() : int {
            return _manual_level;
        };

        /** Return the capping/max level value that could be used by automatic level selection algorithm **/
        public function get autoLevelCapping() : int {
            return _levelController.autoLevelCapping;
        }

        /** set the capping/max level value that could be used by automatic level selection algorithm **/
        public function set autoLevelCapping(newLevel : int) : void {
            _levelController.autoLevelCapping = newLevel;
        }

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

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

        /** 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 _levelLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _level = 0;
            _hlsNetStream.close();
            _levelLoader.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 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 _levelLoader.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;
            this.dispatchEvent(new HLSEvent(HLSEvent.STAGE_SET));
        }

        /* 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;
        }

        /* set URL stream loader */
        public function set URLloader(urlloader : Class) : void {
            _hlsURLLoader = urlloader;
        }

        /* retrieve URL stream loader */
        public function get URLloader() : Class {
            return _hlsURLLoader;
        }
        /* retrieve playback session stats */
        public function get stats() : Stats {
            return _statsHandler.stats;
        }

        /* start/restart playlist/fragment loading.
           this is only effective if MANIFEST_PARSED event has been triggered already */
        public function startLoad() : void {
            if(levels && levels.length) {
                this.dispatchEvent(new HLSEvent(HLSEvent.LEVEL_SWITCH, startLevel));
            }
        }
    }
}

/* 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 flash.display.Stage;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLLoader;
    import flash.net.URLStream;
    import org.mangui.hls.constant.HLSSeekStates;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.controller.LevelController;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.handler.StatsHandler;
    import org.mangui.hls.loader.AltAudioLevelLoader;
    import org.mangui.hls.loader.LevelLoader;
    import org.mangui.hls.model.AudioTrack;
    import org.mangui.hls.model.Level;
    import org.mangui.hls.model.Stats;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.stream.HLSNetStream;
    import org.mangui.hls.stream.StreamBuffer;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        private var _levelLoader : LevelLoader;
        private var _altAudioLevelLoader : AltAudioLevelLoader;
        private var _audioTrackController : AudioTrackController;
        private var _levelController : LevelController;
        private var _streamBuffer : StreamBuffer;
        private var _statsHandler : StatsHandler;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream/URLLoader **/
        private var _hlsURLStream : Class;
        private var _hlsURLLoader : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        /* level handling */
        private var _level : int;
        /* overrided quality_manual_level level */
        private var _manual_level : int = -1;

        /** Create and connect all components. **/
        public function HLS() {
            _levelLoader = new LevelLoader(this);
            _altAudioLevelLoader = new AltAudioLevelLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _levelController = new LevelController(this);
            _statsHandler = new StatsHandler(this);
            _streamBuffer = new StreamBuffer(this, _audioTrackController, _levelController);
            _hlsURLStream = URLStream as Class;
            _hlsURLLoader = URLLoader as Class;
            // default loader
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _hlsNetStream = new HLSNetStream(connection, this, _streamBuffer);
            this.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
        };

        /** 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);
        };

        private function _levelSwitchHandler(event : HLSEvent) : void {
            _level = event.level;
        };

        public function dispose() : void {
            this.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            _levelLoader.dispose();
            _altAudioLevelLoader.dispose();
            _audioTrackController.dispose();
            _levelController.dispose();
            _hlsNetStream.dispose_();
            _statsHandler.dispose();
            _streamBuffer.dispose();
            _levelLoader = null;
            _altAudioLevelLoader = null;
            _audioTrackController = null;
            _levelController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return index of first quality level referenced in Manifest  **/
        public function get firstLevel() : int {
            return _levelController.firstLevel;
        };

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

        /*  set the quality level used when starting a fresh playback */
        public function set startLevel(level : int) : void {
            _levelController.startLevel = level;
        };

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

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

        /** Return the quality level of the next played fragment **/
        public function get nextLevel() : int {
            return _streamBuffer.nextLevel;
        };

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

        /*  instant quality level switch (-1 for automatic level selection) */
        public function set currentLevel(level : int) : void {
            _manual_level = level;
            // don't flush and seek if never seeked or if end of stream
            if(seekState != HLSSeekStates.IDLE) {
                _streamBuffer.flushBuffer();
                _hlsNetStream.seek(position);
            }
        };

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

        /*  set quality level for last loaded fragment (-1 for automatic level selection) */
        public function set loadLevel(level : int) : void {
            _manual_level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autoLevel() : Boolean {
            return (_manual_level == -1);
        };

        /* return manual level */
        public function get manualLevel() : int {
            return _manual_level;
        };

        /** Return the capping/max level value that could be used by automatic level selection algorithm **/
        public function get autoLevelCapping() : int {
            return _levelController.autoLevelCapping;
        }

        /** set the capping/max level value that could be used by automatic level selection algorithm **/
        public function set autoLevelCapping(newLevel : int) : void {
            _levelController.autoLevelCapping = newLevel;
        }

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

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

        /** 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 _levelLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _level = 0;
            _hlsNetStream.close();
            _levelLoader.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 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 _levelLoader.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;
            this.dispatchEvent(new HLSEvent(HLSEvent.STAGE_SET));
        }

        /* 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;
        }

        /* set URL stream loader */
        public function set URLloader(urlloader : Class) : void {
            _hlsURLLoader = urlloader;
        }

        /* retrieve URL stream loader */
        public function get URLloader() : Class {
            return _hlsURLLoader;
        }
        /* retrieve playback session stats */
        public function get stats() : Stats {
            return _statsHandler.stats;
        }

        /* start/restart playlist/fragment loading.
           this is only effective if MANIFEST_PARSED event has been triggered already */
        public function startLoad() : void {
            if(levels && levels.length) {
                this.dispatchEvent(new HLSEvent(HLSEvent.LEVEL_SWITCH, startLevel));
            }
        }
    }
}

set currentLevel : don't flush and seek if seeking state is IDLE


package com.axis.rtspclient {

  import flash.events.EventDispatcher;
  import flash.events.Event;
  import flash.utils.ByteArray;
  import flash.net.Socket;
  import flash.net.NetConnection;
  import flash.net.NetStream;
  import flash.media.Video;
  import mx.utils.StringUtil;

  import com.axis.rtspclient.FLVMux;
  import com.axis.rtspclient.RTP;
  import com.axis.rtspclient.SDP;
  import com.axis.http.url;
  import com.axis.http.request;
  import com.axis.http.auth;
  import com.axis.IClient;
  import com.axis.ClientEvent;

  public class RTSPClient extends EventDispatcher implements IClient {
    [Embed(source = "../../../../VERSION", mimeType = "application/octet-stream")] private var Version:Class;
    private var userAgent:String;

    private static var STATE_INITIAL:uint  = 1 << 0;
    private static var STATE_OPTIONS:uint  = 1 << 1;
    private static var STATE_DESCRIBE:uint = 1 << 2;
    private static var STATE_SETUP:uint    = 1 << 3;
    private static var STATE_PLAY:uint     = 1 << 4;
    private static var STATE_PLAYING:uint  = 1 << 5;
    private static var STATE_PAUSE:uint    = 1 << 6;
    private static var STATE_PAUSED:uint   = 1 << 7;
    private static var STATE_TEARDOWN:uint = 1 << 8;

    private var state:int = STATE_INITIAL;
    private var handle:IRTSPHandle;
    private var ns:NetStream;
    private var video:Video;

    private var sdp:SDP = new SDP();
    private var flvmux:FLVMux;

    private var urlParsed:Object;
    private var cSeq:uint = 1;
    private var session:String;
    private var contentBase:String;
    private var interleaveChannelIndex:uint = 0;

    private var methods:Array = [];
    private var data:ByteArray = new ByteArray();
    private var rtpLength:int = -1;
    private var rtpChannel:int = -1;
    private var tracks:Array;

    private var authState:String = "none";
    private var authOpts:Object = {};
    private var digestNC:uint = 1;

    public function RTSPClient(video:Video, urlParsed:Object, handle:IRTSPHandle) {
      this.userAgent = "Slush " + StringUtil.trim(new Version().toString());
      this.state = STATE_INITIAL;
      this.handle = handle;
      this.video = video;
      this.urlParsed = urlParsed;

      handle.addEventListener('data', this.onData);
    }

    public function start():Boolean {
      var self:RTSPClient = this;
      handle.addEventListener('connected', function():void {
        if (state !== STATE_INITIAL) {
          trace('Cannot start unless in initial state.');
          return;
        }

        /* If the handle closes, take care of it */
        handle.addEventListener('closed', self.onClose);

        if (0 === self.methods.length) {
          /* We don't know the options yet. Start with that. */
          sendOptionsReq();
        } else {
          /* Already queried the options (and perhaps got unauthorized on describe) */
          sendDescribeReq();
        }
      });

      var nc:NetConnection = new NetConnection();
      nc.connect(null);
      this.ns = new NetStream(nc);
      dispatchEvent(new ClientEvent(ClientEvent.NETSTREAM_CREATED, { ns : this.ns }));
      video.attachNetStream(this.ns);

      handle.connect();
      return true;
    }

    public function pause():Boolean
    {
      if (state !== STATE_PLAYING) {
        trace('Unable to pause a stream if not playing.');
        return false;
      }

      try {
        sendPauseReq();
      } catch (err:Error) {
        trace("Unable to pause: " + err.message);
        return false;
      }

      return true;
    }

    public function resume():Boolean
    {
      if (state !== STATE_PAUSED) {
        trace('Unable to resume a stream if not paused.');
        return false;
      }

      sendPlayReq();
      return true;
    }

    public function stop():Boolean
    {
      if (state < STATE_PLAY) {
        trace('Unable to stop if we never reached play.');
        return false;
      }
      sendTeardownReq();
      return true;
    }

    private function onClose(event:Event):void
    {
      if (state === STATE_TEARDOWN) {
        this.ns.dispose();
        dispatchEvent(new ClientEvent(ClientEvent.STOPPED));
      } else {
        trace('RTSPClient: Handle unexpectedly closed.');
      }
    }

    private function onData(event:Event):void
    {
      if (0 < data.bytesAvailable) {
        /* Determining byte have already been read. This is a continuation */
      } else {
        /* Read the determining byte */
        handle.readBytes(data, 0, 1);
      }

      switch(data[0]) {
        case 0x52:
          /* ascii 'R', start of RTSP */
          onRTSPCommand();
          break;

        case 0x24:
          /* ascii '$', start of interleaved packet */
          onInterleavedData();
          break;

        default:
          trace('Unknown determining byte:', '0x' + data[0].toString(16), '. Stopping stream.');
          stop();
          break;
      }
    }

    private function requestReset():void
    {
      var copy:ByteArray = new ByteArray();
      data.readBytes(copy);
      data.clear();
      copy.readBytes(data);

      rtpLength  = -1;
      rtpChannel = -1;
    }

    private function readRequest(oBody:ByteArray):*
    {
      var parsed:* = request.readHeaders(handle, data);
      if (false === parsed) {
        return false;
      }

      if (401 === parsed.code) {
        /* Unauthorized, change authState and (possibly) try again */
        authOpts = parsed.headers['www-authenticate'];
        var newAuthState:String = auth.nextMethod(authState, authOpts);
        if (authState === newAuthState) {
          trace('GET: Exhausted all authentication methods.');
          trace('GET: Unable to authorize to ' + urlParsed.host);
          return false;
        }

        trace('RTSPClient: switching http-authorization from ' + authState + ' to ' + newAuthState);
        authState = newAuthState;
        state = STATE_INITIAL;
        data = new ByteArray();
        handle.reconnect();
        return false;
      }

      if (data.bytesAvailable < parsed.headers['content-length']) {
        return false;
      }

      /* RTSP commands contain no heavy body, so it's safe to read everything */
      data.readBytes(oBody, 0, parsed.headers['content-length']);
      requestReset();
      return parsed;
    }

    private function onRTSPCommand():void {
      var parsed:*, body:ByteArray = new ByteArray();
      if (false === (parsed = readRequest(body))) {
        return;
      }

      if (200 !== parsed.code) {
        trace('RTSPClient: Invalid RTSP response - ', parsed.code, parsed.message);
        return;
      }

      switch (state) {
      case STATE_INITIAL:
        trace("RTSPClient: STATE_INITIAL");

      case STATE_OPTIONS:
        trace("RTSPClient: STATE_OPTIONS");
        this.methods = parsed.headers.public.split(/[ ]*,[ ]*/);
        sendDescribeReq();

        break;
      case STATE_DESCRIBE:
        trace("RTSPClient: STATE_DESCRIBE");

        if (!sdp.parse(body)) {
          trace("RTSPClient:Failed to parse SDP file");
          return;
        }

        if (!parsed.headers['content-base']) {
          trace('RTSPClient: no content-base in describe reply');
          return;
        }

        contentBase = parsed.headers['content-base'];
        tracks = sdp.getMediaBlockList();
        trace('SDP contained ' + tracks.length + ' track(s). Calling SETUP for each.');

        if (0 === tracks.length) {
          trace('No tracks in SDP file.');
          return;
        }

        /* Fall through, it's time for setup */
      case STATE_SETUP:
        trace("RTSPClient: STATE_SETUP");

        if (parsed.headers['session']) {
          session = parsed.headers['session'];
        }

        if (0 !== tracks.length) {
          /* More tracks we must setup before playing */
          var block:Object = tracks.shift();
          sendSetupReq(block);
          return;
        }

        /* All tracks setup and ready to go! */
        sendPlayReq();
        break;

      case STATE_PLAY:
        trace("RTSPClient: STATE_PLAY");
        state = STATE_PLAYING;

        if (this.flvmux) {
          /* If the flvmux have been initialized don't do it again.
             this is probably a resume after pause */
          break;
        }

        this.flvmux = new FLVMux(this.ns, this.sdp);
        var analu:ANALU = new ANALU();
        var aaac:AAAC = new AAAC(sdp);

        this.addEventListener("VIDEO_PACKET", analu.onRTPPacket);
        this.addEventListener("AUDIO_PACKET", aaac.onRTPPacket);
        analu.addEventListener(NALU.NEW_NALU, flvmux.onNALU);
        aaac.addEventListener(AACFrame.NEW_FRAME, flvmux.onAACFrame);
        break;

      case STATE_PLAYING:
        trace("RTSPClient: STATE_PLAYING");
        break;

      case STATE_PAUSE:
        trace("RTSPClient: STATE_PAUSE");
        state = STATE_PAUSED;
        break;

      case STATE_TEARDOWN:
        trace('RTSPClient: STATE_TEARDOWN');
        this.handle.disconnect();
        break;
      }

      if (0 < data.bytesAvailable) {
        onData(null);
      }
    }

    private function onInterleavedData():void
    {
      handle.readBytes(data, data.length);

      if (-1 == rtpLength && 0x24 === data[0]) {
        /* This is the beginning of a new RTP package */
        data.readByte();
        rtpChannel = data.readByte();
        rtpLength = data.readShort();
      }

      if (data.bytesAvailable < rtpLength) {
        /* The complete RTP package is not here yet, wait for more data */
        return;
      }

      var pkgData:ByteArray = new ByteArray();

      data.readBytes(pkgData, 0, rtpLength);

      if (rtpChannel === 0 || rtpChannel === 2) {
        /* We're discarding the RTCP counter parts for now */
        var rtppkt:RTP = new RTP(pkgData, sdp);
        dispatchEvent(rtppkt);
      }

      requestReset();

      if (0 < data.bytesAvailable) {
        onData(null);
      }
    }

    private function supportCommand(command:String):Boolean
    {
      return (-1 !== this.methods.indexOf(command));
    }

    private function sendOptionsReq():void {
      state = STATE_OPTIONS;
      var req:String =
        "OPTIONS * RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendDescribeReq():void {
      state = STATE_DESCRIBE;
      var u:String = 'rtsp://' + urlParsed.host + ":" + urlParsed.port + urlParsed.urlpath;
      var req:String =
        "DESCRIBE " + u + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Accept: application/sdp\r\n" +
        auth.authorizationHeader("DESCRIBE", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendSetupReq(block:Object):void {
      state = STATE_SETUP;
      var interleavedChannels:String = interleaveChannelIndex++ + "-" + interleaveChannelIndex++;
      var p:String = url.isAbsolute(block.control) ? block.control : contentBase + block.control;

      trace('Setting up track: ' + p);
      var req:String =
        "SETUP " + p + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        (session ? ("Session: " + session + "\r\n") : "") +
        "Transport: RTP/AVP/TCP;unicast;interleaved=" + interleavedChannels + "\r\n" +
        auth.authorizationHeader("SETUP", authState, authOpts, urlParsed, digestNC++) +
        "Date: " + new Date().toUTCString() + "\r\n" +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendPlayReq():void {
      /* Put the NetStream in 'Data Generation Mode'. Data is generated by FLVMux */
      this.ns.play(null);

      state = STATE_PLAY;

      var req:String =
        "PLAY " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("PLAY", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendPauseReq():void {
      if (-1 === this.supportCommand("PAUSE")) {
        throw new Error('Pause is not supported by server.');
      }

      state = STATE_PAUSE;

      /* NetStream must be closed here, otherwise it will think of this rtsp pause
         as a very bad connection and buffer a lot before playing again. Not
         excellent for live data. */
      this.ns.close();

      var req:String =
        "PAUSE " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("PAUSE", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendTeardownReq():void {
      state = STATE_TEARDOWN;
      var req:String =
        "TEARDOWN " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("TEARDOWN", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }
  }
}

package com.axis.rtspclient {

  import flash.events.EventDispatcher;
  import flash.events.Event;
  import flash.utils.ByteArray;
  import flash.net.Socket;
  import flash.net.NetConnection;
  import flash.net.NetStream;
  import flash.media.Video;
  import mx.utils.StringUtil;

  import com.axis.rtspclient.FLVMux;
  import com.axis.rtspclient.RTP;
  import com.axis.rtspclient.SDP;
  import com.axis.http.url;
  import com.axis.http.request;
  import com.axis.http.auth;
  import com.axis.IClient;
  import com.axis.ClientEvent;

  public class RTSPClient extends EventDispatcher implements IClient {
    [Embed(source = "../../../../VERSION", mimeType = "application/octet-stream")] private var Version:Class;
    private var userAgent:String;

    private static const STATE_INITIAL:uint  = 1 << 0;
    private static const STATE_OPTIONS:uint  = 1 << 1;
    private static const STATE_DESCRIBE:uint = 1 << 2;
    private static const STATE_SETUP:uint    = 1 << 3;
    private static const STATE_PLAY:uint     = 1 << 4;
    private static const STATE_PLAYING:uint  = 1 << 5;
    private static const STATE_PAUSE:uint    = 1 << 6;
    private static const STATE_PAUSED:uint   = 1 << 7;
    private static const STATE_TEARDOWN:uint = 1 << 8;

    private var state:int = STATE_INITIAL;
    private var handle:IRTSPHandle;
    private var ns:NetStream;
    private var video:Video;

    private var sdp:SDP = new SDP();
    private var flvmux:FLVMux;

    private var urlParsed:Object;
    private var cSeq:uint = 1;
    private var session:String;
    private var contentBase:String;
    private var interleaveChannelIndex:uint = 0;

    private var methods:Array = [];
    private var data:ByteArray = new ByteArray();
    private var rtpLength:int = -1;
    private var rtpChannel:int = -1;
    private var tracks:Array;

    private var authState:String = "none";
    private var authOpts:Object = {};
    private var digestNC:uint = 1;

    public function RTSPClient(video:Video, urlParsed:Object, handle:IRTSPHandle) {
      this.userAgent = "Slush " + StringUtil.trim(new Version().toString());
      this.state = STATE_INITIAL;
      this.handle = handle;
      this.video = video;
      this.urlParsed = urlParsed;

      handle.addEventListener('data', this.onData);
    }

    public function start():Boolean {
      var self:RTSPClient = this;
      handle.addEventListener('connected', function():void {
        if (state !== STATE_INITIAL) {
          trace('Cannot start unless in initial state.');
          return;
        }

        /* If the handle closes, take care of it */
        handle.addEventListener('closed', self.onClose);

        if (0 === self.methods.length) {
          /* We don't know the options yet. Start with that. */
          sendOptionsReq();
        } else {
          /* Already queried the options (and perhaps got unauthorized on describe) */
          sendDescribeReq();
        }
      });

      var nc:NetConnection = new NetConnection();
      nc.connect(null);
      this.ns = new NetStream(nc);
      dispatchEvent(new ClientEvent(ClientEvent.NETSTREAM_CREATED, { ns : this.ns }));
      video.attachNetStream(this.ns);

      handle.connect();
      return true;
    }

    public function pause():Boolean
    {
      if (state !== STATE_PLAYING) {
        trace('Unable to pause a stream if not playing.');
        return false;
      }

      try {
        sendPauseReq();
      } catch (err:Error) {
        trace("Unable to pause: " + err.message);
        return false;
      }

      return true;
    }

    public function resume():Boolean
    {
      if (state !== STATE_PAUSED) {
        trace('Unable to resume a stream if not paused.');
        return false;
      }

      sendPlayReq();
      return true;
    }

    public function stop():Boolean
    {
      if (state < STATE_PLAY) {
        trace('Unable to stop if we never reached play.');
        return false;
      }
      sendTeardownReq();
      return true;
    }

    private function onClose(event:Event):void
    {
      if (state === STATE_TEARDOWN) {
        this.ns.dispose();
        dispatchEvent(new ClientEvent(ClientEvent.STOPPED));
      } else {
        trace('RTSPClient: Handle unexpectedly closed.');
      }
    }

    private function onData(event:Event):void
    {
      if (0 < data.bytesAvailable) {
        /* Determining byte have already been read. This is a continuation */
      } else {
        /* Read the determining byte */
        handle.readBytes(data, 0, 1);
      }

      switch(data[0]) {
        case 0x52:
          /* ascii 'R', start of RTSP */
          onRTSPCommand();
          break;

        case 0x24:
          /* ascii '$', start of interleaved packet */
          onInterleavedData();
          break;

        default:
          trace('Unknown determining byte:', '0x' + data[0].toString(16), '. Stopping stream.');
          stop();
          break;
      }
    }

    private function requestReset():void
    {
      var copy:ByteArray = new ByteArray();
      data.readBytes(copy);
      data.clear();
      copy.readBytes(data);

      rtpLength  = -1;
      rtpChannel = -1;
    }

    private function readRequest(oBody:ByteArray):*
    {
      var parsed:* = request.readHeaders(handle, data);
      if (false === parsed) {
        return false;
      }

      if (401 === parsed.code) {
        /* Unauthorized, change authState and (possibly) try again */
        authOpts = parsed.headers['www-authenticate'];
        var newAuthState:String = auth.nextMethod(authState, authOpts);
        if (authState === newAuthState) {
          trace('GET: Exhausted all authentication methods.');
          trace('GET: Unable to authorize to ' + urlParsed.host);
          return false;
        }

        trace('RTSPClient: switching http-authorization from ' + authState + ' to ' + newAuthState);
        authState = newAuthState;
        state = STATE_INITIAL;
        data = new ByteArray();
        handle.reconnect();
        return false;
      }

      if (data.bytesAvailable < parsed.headers['content-length']) {
        return false;
      }

      /* RTSP commands contain no heavy body, so it's safe to read everything */
      data.readBytes(oBody, 0, parsed.headers['content-length']);
      requestReset();
      return parsed;
    }

    private function onRTSPCommand():void {
      var parsed:*, body:ByteArray = new ByteArray();
      if (false === (parsed = readRequest(body))) {
        return;
      }

      if (200 !== parsed.code) {
        trace('RTSPClient: Invalid RTSP response - ', parsed.code, parsed.message);
        return;
      }

      switch (state) {
      case STATE_INITIAL:
        trace("RTSPClient: STATE_INITIAL");

      case STATE_OPTIONS:
        trace("RTSPClient: STATE_OPTIONS");
        this.methods = parsed.headers.public.split(/[ ]*,[ ]*/);
        sendDescribeReq();

        break;
      case STATE_DESCRIBE:
        trace("RTSPClient: STATE_DESCRIBE");

        if (!sdp.parse(body)) {
          trace("RTSPClient:Failed to parse SDP file");
          return;
        }

        if (!parsed.headers['content-base']) {
          trace('RTSPClient: no content-base in describe reply');
          return;
        }

        contentBase = parsed.headers['content-base'];
        tracks = sdp.getMediaBlockList();
        trace('SDP contained ' + tracks.length + ' track(s). Calling SETUP for each.');

        if (0 === tracks.length) {
          trace('No tracks in SDP file.');
          return;
        }

        /* Fall through, it's time for setup */
      case STATE_SETUP:
        trace("RTSPClient: STATE_SETUP");

        if (parsed.headers['session']) {
          session = parsed.headers['session'];
        }

        if (0 !== tracks.length) {
          /* More tracks we must setup before playing */
          var block:Object = tracks.shift();
          sendSetupReq(block);
          return;
        }

        /* All tracks setup and ready to go! */
        sendPlayReq();
        break;

      case STATE_PLAY:
        trace("RTSPClient: STATE_PLAY");
        state = STATE_PLAYING;

        if (this.flvmux) {
          /* If the flvmux have been initialized don't do it again.
             this is probably a resume after pause */
          break;
        }

        this.flvmux = new FLVMux(this.ns, this.sdp);
        var analu:ANALU = new ANALU();
        var aaac:AAAC = new AAAC(sdp);

        this.addEventListener("VIDEO_PACKET", analu.onRTPPacket);
        this.addEventListener("AUDIO_PACKET", aaac.onRTPPacket);
        analu.addEventListener(NALU.NEW_NALU, flvmux.onNALU);
        aaac.addEventListener(AACFrame.NEW_FRAME, flvmux.onAACFrame);
        break;

      case STATE_PLAYING:
        trace("RTSPClient: STATE_PLAYING");
        break;

      case STATE_PAUSE:
        trace("RTSPClient: STATE_PAUSE");
        state = STATE_PAUSED;
        break;

      case STATE_TEARDOWN:
        trace('RTSPClient: STATE_TEARDOWN');
        this.handle.disconnect();
        break;
      }

      if (0 < data.bytesAvailable) {
        onData(null);
      }
    }

    private function onInterleavedData():void
    {
      handle.readBytes(data, data.length);

      if (-1 == rtpLength && 0x24 === data[0]) {
        /* This is the beginning of a new RTP package */
        data.readByte();
        rtpChannel = data.readByte();
        rtpLength = data.readShort();
      }

      if (data.bytesAvailable < rtpLength) {
        /* The complete RTP package is not here yet, wait for more data */
        return;
      }

      var pkgData:ByteArray = new ByteArray();

      data.readBytes(pkgData, 0, rtpLength);

      if (rtpChannel === 0 || rtpChannel === 2) {
        /* We're discarding the RTCP counter parts for now */
        var rtppkt:RTP = new RTP(pkgData, sdp);
        dispatchEvent(rtppkt);
      }

      requestReset();

      if (0 < data.bytesAvailable) {
        onData(null);
      }
    }

    private function supportCommand(command:String):Boolean
    {
      return (-1 !== this.methods.indexOf(command));
    }

    private function sendOptionsReq():void {
      state = STATE_OPTIONS;
      var req:String =
        "OPTIONS * RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendDescribeReq():void {
      state = STATE_DESCRIBE;
      var u:String = 'rtsp://' + urlParsed.host + ":" + urlParsed.port + urlParsed.urlpath;
      var req:String =
        "DESCRIBE " + u + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Accept: application/sdp\r\n" +
        auth.authorizationHeader("DESCRIBE", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendSetupReq(block:Object):void {
      state = STATE_SETUP;
      var interleavedChannels:String = interleaveChannelIndex++ + "-" + interleaveChannelIndex++;
      var p:String = url.isAbsolute(block.control) ? block.control : contentBase + block.control;

      trace('Setting up track: ' + p);
      var req:String =
        "SETUP " + p + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        (session ? ("Session: " + session + "\r\n") : "") +
        "Transport: RTP/AVP/TCP;unicast;interleaved=" + interleavedChannels + "\r\n" +
        auth.authorizationHeader("SETUP", authState, authOpts, urlParsed, digestNC++) +
        "Date: " + new Date().toUTCString() + "\r\n" +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendPlayReq():void {
      /* Put the NetStream in 'Data Generation Mode'. Data is generated by FLVMux */
      this.ns.play(null);

      state = STATE_PLAY;

      var req:String =
        "PLAY " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("PLAY", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendPauseReq():void {
      if (-1 === this.supportCommand("PAUSE")) {
        throw new Error('Pause is not supported by server.');
      }

      state = STATE_PAUSE;

      /* NetStream must be closed here, otherwise it will think of this rtsp pause
         as a very bad connection and buffer a lot before playing again. Not
         excellent for live data. */
      this.ns.close();

      var req:String =
        "PAUSE " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("PAUSE", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }

    private function sendTeardownReq():void {
      state = STATE_TEARDOWN;
      var req:String =
        "TEARDOWN " + contentBase + " RTSP/1.0\r\n" +
        "CSeq: " + (++cSeq) + "\r\n" +
        "User-Agent: " + userAgent + "\r\n" +
        "Session: " + session + "\r\n" +
        auth.authorizationHeader("TEARDOWN", authState, authOpts, urlParsed, digestNC++) +
        "\r\n";
      handle.writeUTFBytes(req);
    }
  }
}

Set state vars as const

RTSPClient: Set state vars as const


package control
{
	import com.adobe.serialization.json.JSON;

	import dragonBones.objects.DataParser;
	import dragonBones.utils.ConstValues;

	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.utils.ByteArray;

	import message.Message;
	import message.MessageDispatcher;

	import model.ImportDataProxy;
	import model.JSFLProxy;
	import model.XMLDataProxy;

	import utils.BitmapDataUtil;
	import utils.GlobalConstValues;
	import utils.PNGEncoder;
	import utils.xmlToObject;

	import zero.zip.Zip;

	public class ExportDataCommand
	{
		public static const instance:ExportDataCommand = new ExportDataCommand();

		private var _fileREF:FileReference;
		private var _isExporting:Boolean;
		private var _scale:Number;
		private var _exportType:uint;
		private var _backgroundColor:uint;

		private var _importDataProxy:ImportDataProxy;

		private var _xmlDataProxy:XMLDataProxy;
		private var _bitmapData:BitmapData;

		public function ExportDataCommand()
		{
			_fileREF = new FileReference();

			_importDataProxy = ImportDataProxy.getInstance();
		}

		public function export(exportType:uint, scale:Number, backgroundColor:uint = 0):void
		{
			if(_isExporting)
			{
				return;
			}
			_isExporting = true;

			_exportType = exportType;
			_scale = scale;

			switch(_exportType)
			{
				case 0:
				case 2:
				case 5:
					_scale = 1;
					break;
			}

			_backgroundColor = backgroundColor;

			exportStart();
		}

		private function exportStart():void
		{
			var dataBytes:ByteArray;
			var zip:Zip;
			var date:Date;

			_xmlDataProxy = _importDataProxy.xmlDataProxy;
			_bitmapData = _importDataProxy.textureAtlas.bitmapData;

			if(_scale != 1)
			{
				_xmlDataProxy = _xmlDataProxy.clone();
				var subBitmapDataDic:Object;
				var movieClip:MovieClip = _importDataProxy.textureAtlas.movieClip;
				if(movieClip && movieClip.totalFrames >= 3)
				{
					subBitmapDataDic = {};
					for each (var displayName:String in _xmlDataProxy.getSubTextureListFromDisplayList())
					{
						movieClip.gotoAndStop(movieClip.totalFrames);
						movieClip.gotoAndStop(displayName);
						subBitmapDataDic[displayName] = movieClip.getChildAt(0);
					}
				}
				else
				{
					subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
						_bitmapData,
						_xmlDataProxy.getSubTextureRectMap()
					);
				}

				_xmlDataProxy.scaleData(_scale);

				_bitmapData = BitmapDataUtil.getMergeBitmapData(
					subBitmapDataDic,
					_xmlDataProxy.getSubTextureRectMap(),
					_xmlDataProxy.textureAtlasWidth,
					_xmlDataProxy.textureAtlasHeight,
					_scale
				);
			}

			var isSWF:Boolean = _exportType == 0 || _exportType == 2 || _exportType == 5;
			var isXML:Boolean = _exportType == 2 || _exportType == 3 || _exportType == 4;

			switch(_exportType)
			{
				case 0:
					try
					{
						dataBytes = getSWFBytes();
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.SWF_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 1:
					try
					{
						dataBytes = getPNGBytes(_backgroundColor);
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.PNG_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 2:
				case 3:
				case 5:
				case 6:
					try
					{
						if(isSWF)
						{
							dataBytes = getSWFBytes();
						}
						else
						{
							dataBytes = getPNGBytes(_backgroundColor);
						}

						if(dataBytes)
						{
							date = new Date();
							zip = new Zip();
							zip.add(
								dataBytes,
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + (isSWF?GlobalConstValues.SWF_SUFFIX:GlobalConstValues.PNG_SUFFIX),
								date
							);
							_xmlDataProxy.setImagePath(GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.PNG_SUFFIX);

							if(isXML)
							{
								zip.add(
									_xmlDataProxy.xml.toXMLString(),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
								zip.add(
									_xmlDataProxy.textureAtlasXML.toXMLString(),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
							}
							else
							{
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
							}
							exportSave(
								zip.encode(),
								_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
							);
							zip.clear();
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 4:
				case 7:
					try
					{
						date = new Date();
						zip = new Zip();

						if(_xmlDataProxy == _importDataProxy.xmlDataProxy)
						{
							_xmlDataProxy = _xmlDataProxy.clone();
						}
						_xmlDataProxy.changePath();

						subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
							_bitmapData,
							_xmlDataProxy.getSubTextureRectMap()
						);
						for(var subTextureName:String in subBitmapDataDic)
						{
							var subBitmapData:BitmapData = subBitmapDataDic[subTextureName];
							zip.add(
								PNGEncoder.encode(subBitmapData),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + "/" + subTextureName + GlobalConstValues.PNG_SUFFIX,
								date
							);
							subBitmapData.dispose();
						}
						if(isXML)
						{
							zip.add(
								_xmlDataProxy.xml.toXMLString(),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
							zip.add(
								_xmlDataProxy.textureAtlasXML.toXMLString(),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
						}
						else
						{
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
						}

						exportSave(
							zip.encode(),
							_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
						);
						zip.clear();
						return;
					}
					catch(_e:Error)
					{
						break;
					}
				default:
					break;
			}
			_isExporting = false;
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
		}

		private function getSWFBytes():ByteArray
		{
			if(_importDataProxy.textureAtlas.movieClip)
			{
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function getPNGBytes(color:uint = 0):ByteArray
		{
			if(color)
			{
				var bitmapData:BitmapData = new BitmapData(_bitmapData.width, _bitmapData.height, true, color);
				bitmapData.draw(_bitmapData);

				var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
				bitmapData.dispose();

				return byteArray;
			}
			else if(_importDataProxy.textureAtlas.movieClip)
			{
				return PNGEncoder.encode(_bitmapData);
			}
			else
			{
				if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
				{
					return PNGEncoder.encode(_bitmapData);
				}
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function exportSave(fileData:ByteArray, fileName:String):void
		{
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT, fileName);
			_fileREF.addEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.addEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.addEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_fileREF.save(fileData, fileName);
		}

		private function onFileSaveHandler(e:Event):void
		{
			_fileREF.removeEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.removeEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.removeEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_isExporting = false;
			switch(e.type)
			{
				case Event.CANCEL:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_CANCEL);
					break;
				case IOErrorEvent.IO_ERROR:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
					break;
				case Event.COMPLETE:
					if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
					{
						_bitmapData.dispose();
						_bitmapData = null;
					}
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_COMPLETE);
					break;
			}
		}
	}
}

package control
{
	import com.adobe.serialization.json.JSON;

	import dragonBones.objects.DataParser;
	import dragonBones.utils.ConstValues;

	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.utils.ByteArray;

	import message.Message;
	import message.MessageDispatcher;

	import model.ImportDataProxy;
	import model.JSFLProxy;
	import model.XMLDataProxy;

	import utils.BitmapDataUtil;
	import utils.GlobalConstValues;
	import utils.PNGEncoder;
	import utils.xmlToObject;

	import zero.zip.Zip;

	public class ExportDataCommand
	{
		public static const instance:ExportDataCommand = new ExportDataCommand();

		private var _fileREF:FileReference;
		private var _isExporting:Boolean;
		private var _scale:Number;
		private var _exportType:uint;
		private var _backgroundColor:uint;

		private var _importDataProxy:ImportDataProxy;

		private var _xmlDataProxy:XMLDataProxy;
		private var _bitmapData:BitmapData;

		public function ExportDataCommand()
		{
			_fileREF = new FileReference();

			_importDataProxy = ImportDataProxy.getInstance();
		}

		public function export(exportType:uint, scale:Number, backgroundColor:uint = 0):void
		{
			if(_isExporting)
			{
				return;
			}
			_isExporting = true;

			_exportType = exportType;
			_scale = scale;

			switch(_exportType)
			{
				case 0:
				case 2:
				case 5:
					_scale = 1;
					break;
			}

			_backgroundColor = backgroundColor;

			exportStart();
		}

		private function exportStart():void
		{
			var dataBytes:ByteArray;
			var zip:Zip;
			var date:Date;

			_xmlDataProxy = _importDataProxy.xmlDataProxy;
			_bitmapData = _importDataProxy.textureAtlas.bitmapData;

			if(_scale != 1)
			{
				_xmlDataProxy = _xmlDataProxy.clone();
				var subBitmapDataDic:Object;
				var movieClip:MovieClip = _importDataProxy.textureAtlas.movieClip;
				if(movieClip && movieClip.totalFrames >= 3)
				{
					subBitmapDataDic = {};
					for each (var displayName:String in _xmlDataProxy.getSubTextureListFromDisplayList())
					{
						movieClip.gotoAndStop(movieClip.totalFrames);
						movieClip.gotoAndStop(displayName);
						subBitmapDataDic[displayName] = movieClip.getChildAt(0);
					}
				}
				else
				{
					subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
						_bitmapData,
						_xmlDataProxy.getSubTextureRectMap()
					);
				}

				_xmlDataProxy.scaleData(_scale);

				_bitmapData = BitmapDataUtil.getMergeBitmapData(
					subBitmapDataDic,
					_xmlDataProxy.getSubTextureRectMap(),
					_xmlDataProxy.textureAtlasWidth,
					_xmlDataProxy.textureAtlasHeight,
					_scale
				);
			}

			var isSWF:Boolean = _exportType == 0 || _exportType == 2 || _exportType == 5;
			var isXML:Boolean = _exportType == 2 || _exportType == 3 || _exportType == 4;

			switch(_exportType)
			{
				case 0:
					try
					{
						dataBytes = getSWFBytes();
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.SWF_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 1:
					try
					{
						dataBytes = getPNGBytes(_backgroundColor);
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.PNG_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 2:
				case 3:
				case 5:
				case 6:
					try
					{
						if(isSWF)
						{
							dataBytes = getSWFBytes();
						}
						else
						{
							dataBytes = getPNGBytes(_backgroundColor);
						}

						if(dataBytes)
						{
							date = new Date();
							zip = new Zip();
							zip.add(
								dataBytes,
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + (isSWF?GlobalConstValues.SWF_SUFFIX:GlobalConstValues.PNG_SUFFIX),
								date
							);
							_xmlDataProxy.setImagePath(GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.PNG_SUFFIX);

							if(isXML)
							{
								zip.add(
									_xmlDataProxy.xml.toXMLString(),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
								zip.add(
									_xmlDataProxy.textureAtlasXML.toXMLString(),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
							}
							else
							{
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
							}
							exportSave(
								zip.encode(),
								_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
							);
							zip.clear();
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 4:
				case 7:
					try
					{
						date = new Date();
						zip = new Zip();

						if(_xmlDataProxy == _importDataProxy.xmlDataProxy)
						{
							_xmlDataProxy = _xmlDataProxy.clone();
						}

						//do not need to change changePath for TexturePacker
						//_xmlDataProxy.changePath();

						subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
							_bitmapData,
							_xmlDataProxy.getSubTextureRectMap()
						);
						for(var subTextureName:String in subBitmapDataDic)
						{
							var subBitmapData:BitmapData = subBitmapDataDic[subTextureName];
							zip.add(
								PNGEncoder.encode(subBitmapData),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + "/" + subTextureName + GlobalConstValues.PNG_SUFFIX,
								date
							);
							subBitmapData.dispose();
						}
						if(isXML)
						{
							zip.add(
								_xmlDataProxy.xml.toXMLString(),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
							zip.add(
								_xmlDataProxy.textureAtlasXML.toXMLString(),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
						}
						else
						{
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
						}

						exportSave(
							zip.encode(),
							_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
						);
						zip.clear();
						return;
					}
					catch(_e:Error)
					{
						break;
					}
				default:
					break;
			}
			_isExporting = false;
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
		}

		private function getSWFBytes():ByteArray
		{
			if(_importDataProxy.textureAtlas.movieClip)
			{
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function getPNGBytes(color:uint = 0):ByteArray
		{
			if(color)
			{
				var bitmapData:BitmapData = new BitmapData(_bitmapData.width, _bitmapData.height, true, color);
				bitmapData.draw(_bitmapData);

				var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
				bitmapData.dispose();

				return byteArray;
			}
			else if(_importDataProxy.textureAtlas.movieClip)
			{
				return PNGEncoder.encode(_bitmapData);
			}
			else
			{
				if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
				{
					return PNGEncoder.encode(_bitmapData);
				}
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function exportSave(fileData:ByteArray, fileName:String):void
		{
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT, fileName);
			_fileREF.addEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.addEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.addEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_fileREF.save(fileData, fileName);
		}

		private function onFileSaveHandler(e:Event):void
		{
			_fileREF.removeEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.removeEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.removeEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_isExporting = false;
			switch(e.type)
			{
				case Event.CANCEL:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_CANCEL);
					break;
				case IOErrorEvent.IO_ERROR:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
					break;
				case Event.COMPLETE:
					if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
					{
						_bitmapData.dispose();
						_bitmapData = null;
					}
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_COMPLETE);
					break;
			}
		}
	}
}

remove _xmlDataProxy.changePath

remove _xmlDataProxy.changePath


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.filesystem.File;
import flash.geom.Rectangle;

import flump.SwfTexture;

import com.threerings.util.Map;
import com.threerings.util.Maps;

public class Atlas
{
    public var name :String;
    public var w :int, h :int, id :int;
    public var bins :Vector.<Rectangle> = new Vector.<Rectangle>();
    public const textures :Vector.<SwfTexture> = new Vector.<SwfTexture>();

    public function Atlas(name :String, w :int, h :int) {
        this.name = name;
        this.w = w;
        this.h = h;
        bins.push(new Rectangle(0, 0, w, h));
    }

    public function place (tex :SwfTexture, target :Rectangle, rotated :Boolean) :void {
        _locs.put(tex, {x: target.x, y: target.y, rotated: rotated});
        textures.push(tex);
        trace("Packer " + tex);
        var used :Rectangle =
            new Rectangle(target.x, target.y, rotated ? tex.h : tex.w, rotated ? tex.w : tex.h);
        const newBins :Vector.<Rectangle> = new Vector.<Rectangle>();
        for each (var bin :Rectangle in bins) {
            for each (var newBin :Rectangle in subtract(bin, used)) {
                newBins.push(newBin);
            }
        }
        bins = newBins;
    }

    public function subtract (space :Rectangle, area :Rectangle) :Vector.<Rectangle> {
        const left :Vector.<Rectangle> = new Vector.<Rectangle>();
        if (space.x < area.x) {
            left.push(new Rectangle(space.x, space.y, area.left - space.x, space.height));
        }
        if (space.right > area.right) {
            left.push(new Rectangle(area.right, space.y, space.right - area.right, space.height));
        }
        if (space.y < area.y) {
            left.push(new Rectangle(space.x, space.y, space.width, area.top - space.y));
        }
        if (space.bottom > area.bottom) {
            left.push(new Rectangle(space.x, area.bottom, space.width, space.bottom - area.bottom));
        }
        return left;
    }

    public function publish (dir :File) :void {
        var constructed :Sprite = new Sprite();
        for each (var tex :SwfTexture in textures) {
            constructed.addChild(tex.holder);
            var loc :Object = _locs.get(tex);
            tex.holder.x = loc.x;
            tex.holder.y = loc.y;
        }
        PngPublisher.publish(dir.resolvePath(name + ".png"), w, h, constructed);
    }

    public function toXml () :String {
        var xml :String = "<atlas name='" + name + "' filename='" + name + ".png'>\n";
        for each (var tex :SwfTexture in textures) {
            var loc :Object = _locs.get(tex);
            xml += "  <texture name='" + tex.name + "' xOffset='" + tex.offset.x +
                "' yOffset='" + tex.offset.y + "' md5='" + tex.md5 +
                "' xAtlas='" + loc.x + "' yAtlas='" + loc.y +
                "' wAtlas='" + tex.w + "' hAtlas='" + tex.h + "'/>\n";
        }
        return xml + "</atlas>\n";
    }

    protected const _locs :Map = Maps.newMapOf(SwfTexture);//{x :int, y :int, rotated :Boolean}
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.filesystem.File;
import flash.geom.Rectangle;

import flump.SwfTexture;

import com.threerings.util.Map;
import com.threerings.util.Maps;

public class Atlas
{
    public var name :String;
    public var w :int, h :int, id :int;
    public var bins :Vector.<Rectangle> = new Vector.<Rectangle>();
    public const textures :Vector.<SwfTexture> = new Vector.<SwfTexture>();

    public function Atlas(name :String, w :int, h :int) {
        this.name = name;
        this.w = w;
        this.h = h;
        bins.push(new Rectangle(0, 0, w, h));
    }

    public function place (tex :SwfTexture, target :Rectangle, rotated :Boolean) :void {
        _locs.put(tex, {x: target.x, y: target.y, rotated: rotated});
        textures.push(tex);
        trace("Packer " + tex);
        var used :Rectangle =
            new Rectangle(target.x, target.y, rotated ? tex.h : tex.w, rotated ? tex.w : tex.h);
        const newBins :Vector.<Rectangle> = new Vector.<Rectangle>();
        for each (var bin :Rectangle in bins) {
            for each (var newBin :Rectangle in subtract(bin, used)) {
                newBins.push(newBin);
            }
        }
        bins = newBins;
    }

    public function subtract (space :Rectangle, area :Rectangle) :Vector.<Rectangle> {
        const left :Vector.<Rectangle> = new Vector.<Rectangle>();
        if (space.x < area.x) {
            left.push(new Rectangle(space.x, space.y, area.left - space.x, space.height));
        }
        if (space.right > area.right) {
            left.push(new Rectangle(area.right, space.y, space.right - area.right, space.height));
        }
        if (space.y < area.y) {
            left.push(new Rectangle(space.x, space.y, space.width, area.top - space.y));
        }
        if (space.bottom > area.bottom) {
            left.push(new Rectangle(space.x, area.bottom, space.width, space.bottom - area.bottom));
        }
        return left;
    }

    public function publish (dir :File) :void {
        var constructed :Sprite = new Sprite();
        for each (var tex :SwfTexture in textures) {
            constructed.addChild(tex.holder);
            var loc :Object = _locs.get(tex);
            tex.holder.x = loc.x;
            tex.holder.y = loc.y;
        }
        PngPublisher.publish(dir.resolvePath(name + ".png"), w, h, constructed);
    }

    public function toXml () :String {
        var xml :String = '<atlas name="' + name + '" filename="' + name + '.png">\n';
        for each (var tex :SwfTexture in textures) {
            var loc :Object = _locs.get(tex);
            xml += '  <texture name="' + tex.name + '" xOffset="' + tex.offset.x +
                '" yOffset="' + tex.offset.y + '" md5="' + tex.md5 +
                '" xAtlas="' + loc.x + '" yAtlas="' + loc.y +
                '" wAtlas="' + tex.w + '" hAtlas="' + tex.h + '"/>\n';
        }
        return xml + '</atlas>\n';
    }

    protected const _locs :Map = Maps.newMapOf(SwfTexture);//{x :int, y :int, rotated :Boolean}
}
}

Use double quotes around XML attributes for consistency.


//////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2012 Freshplanet (http://freshplanet.com | opensource@freshplanet.com)
//
//  Licensed 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 com.freshplanet.ane.AirBackgroundFetch
{
	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

	public class AirBackgroundFetch extends EventDispatcher
	{
		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/** AirBackgroundFetch is supported on iOS and Android devices. */
		public static function get isSupported() : Boolean
		{
			var isIOS:Boolean = (Capabilities.manufacturer.indexOf("iOS") != -1);
			var isAndroid:Boolean = (Capabilities.manufacturer.indexOf("Android") != -1)
			return isIOS || isAndroid;
		}

		public function AirBackgroundFetch()
		{
			if (!_instance)
			{
				_context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
				if (!_context)
				{
					log("ERROR - Extension context is null. Please check if extension.xml is setup correctly.");
					return;
				}
				_context.addEventListener(StatusEvent.STATUS, onStatus);

				_instance = this;
			}
			else
			{
				throw Error("This is a singleton, use getInstance(), do not call the constructor directly.");
			}
		}

		public static function getInstance() : AirBackgroundFetch
		{
			return _instance ? _instance : new AirBackgroundFetch();
		}

		public var logEnabled : Boolean = true;

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	FUNCTIONS										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/**
        * Load a music stream url
        * @param url:String
        */
        public function loadUrl(url:String, data:String):void
        {
            _context.call("loadUrl", url, data);
        }

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		private static const EXTENSION_ID : String = "com.freshplanet.AirBackgroundFetch";

		private static var _instance : AirBackgroundFetch;

		private var _context : ExtensionContext;

		private function onStatus( event : StatusEvent ) : void
		{
			if (event.code == "LOGGING") // Simple log message
			{
				log(event.level);
			}
		}

		private function log( message : String ) : void
		{
			if (logEnabled) trace("[AirBackgroundFetch] " + message);
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2012 Freshplanet (http://freshplanet.com | opensource@freshplanet.com)
//
//  Licensed 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 com.freshplanet.ane.AirBackgroundFetch
{
	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

	public class AirBackgroundFetch extends EventDispatcher
	{
		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/** AirBackgroundFetch is supported on iOS and Android devices. */
		public static function get isSupported() : Boolean
		{
			var isIOS:Boolean = (Capabilities.manufacturer.indexOf("iOS") != -1);
			var isAndroid:Boolean = (Capabilities.manufacturer.indexOf("Android") != -1)
			return isIOS || isAndroid;
		}

		public function AirBackgroundFetch()
		{
			if (!_instance)
			{
				_context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
				if (!_context)
				{
					log("ERROR - Extension context is null. Please check if extension.xml is setup correctly.");
					return;
				}
				_context.addEventListener(StatusEvent.STATUS, onStatus);

				_instance = this;
			}
			else
			{
				throw Error("This is a singleton, use getInstance(), do not call the constructor directly.");
			}
		}

		public static function getInstance() : AirBackgroundFetch
		{
			return _instance ? _instance : new AirBackgroundFetch();
		}

		public var logEnabled : Boolean = true;

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	FUNCTIONS										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/**
        * Load get-create-mega url/data
        * @param url:String
        * @param data:jsonString
        */
        public function loadUrl(url:String, data:String):void
        {
            _context.call("loadUrl", url, data);
        }

        /**
        * Load a music stream url
        */
        public function getUserData():String
        {
            return _context.call("getUserData") as String;
        }

        /**
        * Load a music stream url
        */
        public function flushUserData():void
        {
            _context.call("flushUserData");
        }

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		private static const EXTENSION_ID : String = "com.freshplanet.AirBackgroundFetch";

		private static var _instance : AirBackgroundFetch;

		private var _context : ExtensionContext;

		private function onStatus( event : StatusEvent ) : void
		{
			if (event.code == "LOGGING") // Simple log message
			{
				log(event.level);
			}
		}

		private function log( message : String ) : void
		{
			if (logEnabled) trace("[AirBackgroundFetch] " + message);
		}
	}
}

Add flush user data

Add flush user data