package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageDisplayState; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.FullScreenEvent; import flash.events.MouseEvent; import flash.events.NetStatusEvent; import flash.events.TimerEvent; import flash.external.ExternalInterface; import flash.media.SoundTransform; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.URLVariables; import flash.system.Security; import flash.ui.ContextMenu; import flash.ui.ContextMenuItem; import flash.utils.Timer; import flash.utils.getTimer; import flash.utils.setTimeout; import flashx.textLayout.formats.Float; /** * common player to play rtmp/flv stream, * use system NetStream. */ public class Player { // refresh every ts_fragment_seconds*M3u8RefreshRatio public static var M3u8RefreshRatio:Number = 0.3; // parse ts every this ms. public static var TsParseAsyncInterval:Number = 80; private var js_id:String = null; // play param url. private var user_url:String = null; private var media_stream:NetStream = null; private var media_conn:NetConnection = null; private var owner:srs_player = null; public function Player(o:srs_player) { owner = o; } public function init(flashvars:Object):void { this.js_id = flashvars.id; } public function stream():NetStream { return this.media_stream; } private function dumps_object(obj:Object):String { var smr:String = ""; for (var k:String in obj) { smr += k + "=" + obj[k] + ", "; } return smr; } public function play(url:String):void { owner.on_player_status("init", "Ready to play"); var streamName:String; this.user_url = url; this.media_conn = new NetConnection(); this.media_conn.client = {}; this.media_conn.client.onBWDone = function():void {}; this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void { log("NetConnection: type=" + evt.type + ", bub=" + evt.bubbles + ", can=" + evt.cancelable + ", info is " + dumps_object(evt.info)); if (evt.info.hasOwnProperty("data") && evt.info.data) { owner.on_player_metadata(evt.info.data); } // reject by server, maybe redirect. if (evt.info.code == "NetConnection.Connect.Rejected") { // RTMP 302 redirect. if (evt.info.hasOwnProperty("ex") && evt.info.ex.code == 302) { streamName = url.substr(url.lastIndexOf("/") + 1); url = evt.info.ex.redirect + "/" + streamName; log("Async RTMP 302 Redirect to: " + url); // notify server. media_conn.call("Redirected", null, evt.info.ex.redirect); // do 302. owner.on_player_302(url); return; } owner.on_player_status("rejected", "Server reject play"); close(); } if (evt.info.code == "NetConnection.Connect.Success") { owner.on_player_status("connected", "Connected at server"); } if (evt.info.code == "NetConnection.Connect.Closed") { close(); } if (evt.info.code == "NetConnection.Connect.Failed") { owner.on_player_status("failed", "Connect to server failed."); close(); } // TODO: FIXME: failed event. if (evt.info.code != "NetConnection.Connect.Success") { return; } if (url.indexOf(".m3u8") > 0) { media_stream = new HlsNetStream(M3u8RefreshRatio, TsParseAsyncInterval, media_conn); } else { media_stream = new NetStream(media_conn); } media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void { log("NetStream: type=" + evt.type + ", bub=" + evt.bubbles + ", can=" + evt.cancelable + ", info is " + dumps_object(evt.info)); if (evt.info.code == "NetStream.Play.Start") { owner.on_player_status("play", "Start to play stream"); } if (evt.info.code == "NetStream.Play.StreamNotFound") { owner.on_player_status("rejected", "Stream not found"); close(); } if (evt.info.code == "NetStream.Video.DimensionChange") { owner.on_player_dimension_change(); } else if (evt.info.code == "NetStream.Buffer.Empty") { owner.on_player_buffer_empty(); } else if (evt.info.code == "NetStream.Buffer.Full") { owner.on_player_buffer_full(); } // TODO: FIXME: failed event. }); // setup stream before play. owner.on_player_before_play(); if (url.indexOf("http") == 0) { media_stream.play(url); } else { streamName = url.substr(url.lastIndexOf("/") + 1); media_stream.play(streamName); } owner.on_player_play(); }); if (url.indexOf("http") == 0) { this.media_conn.connect(null); } else { var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/")); streamName = url.substr(url.lastIndexOf("/") + 1); // parse vhost from stream query. if (streamName.indexOf("?") >= 0) { var uv:URLVariables = new URLVariables(user_url.substr(user_url.indexOf("?") + 1)); var domain:String = uv["domain"]; if (!domain) { domain = uv["vhost"]; } if (domain) { tcUrl += "?vhost=" + domain; } } this.media_conn.connect(tcUrl); } } public function close():void { var notify:Boolean = false; if (this.media_stream) { this.media_stream.close(); this.media_stream = null; notify = true; } if (this.media_conn) { this.media_conn.close(); this.media_conn = null; notify = true; } if (notify) { owner.on_player_status("closed", "Server closed."); } } private function log(msg:String):void { Utility.log(js_id, msg); } } }