diff --git a/trunk/research/players/js/srs.player.js b/trunk/research/players/js/srs.player.js index 0c82d4457..356b61abd 100755 --- a/trunk/research/players/js/srs.player.js +++ b/trunk/research/players/js/srs.player.js @@ -99,6 +99,7 @@ SrsPlayer.prototype.start = function(url) { flashvars.on_player_timer = "__srs_on_player_timer"; flashvars.on_player_empty = "__srs_on_player_empty"; flashvars.on_player_full = "__srs_on_player_full"; + flashvars.on_player_status = "__srs_on_player_status"; var params = {}; params.wmode = "opaque"; @@ -146,17 +147,6 @@ SrsPlayer.prototype.play = function(url, volume) { * stop play stream. */ SrsPlayer.prototype.stop = function() { - for (var i = 0; i < SrsPlayer.__players.length; i++) { - var player = SrsPlayer.__players[i]; - - if (player.id != this.id) { - continue; - } - - SrsPlayer.__players.splice(i, 1); - break; - } - this.callbackObj.ref.__stop(); } /** @@ -301,6 +291,16 @@ SrsPlayer.prototype.on_player_empty = function(time) { SrsPlayer.prototype.on_player_full = function(time) { // ignore. } +/** + * the callback when player status change. + * @param code the status code, "init", "connected", "play", "closed", "rejected", "failed". + * init => connected/rejected/failed + * connected => play/rejected => closed + * @param desc the description for the status. + */ +SrsPlayer.prototype.on_player_status = function(code, desc) { + // ignore. +} /** * helpers. @@ -359,3 +359,21 @@ function __srs_on_player_full(id, time) { player.__fluency.on_stream_full(time); player.on_player_full(time); } +function __srs_on_player_status(id, code, desc) { + var player = __srs_find_player(id); + player.on_player_status(code, desc); + + if (code != "closed") { + return; + } + for (var i = 0; i < SrsPlayer.__players.length; i++) { + var player = SrsPlayer.__players[i]; + + if (player.id != this.id) { + continue; + } + + SrsPlayer.__players.splice(i, 1); + break; + } +} diff --git a/trunk/research/players/srs_player.html b/trunk/research/players/srs_player.html index b2225eca1..839830335 100755 --- a/trunk/research/players/srs_player.html +++ b/trunk/research/players/srs_player.html @@ -514,6 +514,9 @@ select_buffer(0.5); this.play(url); }; + srs_player.on_player_status = function(code, desc) { + //console.log("[播放器状态] code=" + code + ", desc=" + desc); + }; srs_player.on_player_metadata = function(metadata) { $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")"); if (metadata.ip && metadata.pid && metadata.cid) { diff --git a/trunk/research/players/srs_player/release/srs_player.swf b/trunk/research/players/srs_player/release/srs_player.swf index 359f5677d..085cb9495 100644 Binary files a/trunk/research/players/srs_player/release/srs_player.swf and b/trunk/research/players/srs_player/release/srs_player.swf differ diff --git a/trunk/research/players/srs_player/src/HlsNetStream.as b/trunk/research/players/srs_player/src/HlsNetStream.as index bae7cef55..da5339d00 100755 --- a/trunk/research/players/srs_player/src/HlsNetStream.as +++ b/trunk/research/players/srs_player/src/HlsNetStream.as @@ -1,7 +1,10 @@ package { import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.NetStatusEvent; import flash.events.ProgressEvent; + import flash.events.SecurityErrorEvent; import flash.external.ExternalInterface; import flash.net.NetConnection; import flash.net.NetStream; @@ -27,6 +30,8 @@ package // play param url. private var user_url:String = null; + + private var conn:NetConnection = null; /** * create stream to play hls. @@ -40,6 +45,7 @@ package this.m3u8_refresh_ratio = m3u8_refresh_ratio; this.ts_parse_async_interval = ts_parse_async_interval; hls = new HlsCodec(this); + this.conn = conn; } /** @@ -94,6 +100,8 @@ package refresh_ts(); }) } + + private var metadata:Object = null; private function refresh_ts():void { // all ts parsed. if (parsed_ts_seq_no >= hls.seq_no + hls.tsCount) { @@ -125,9 +133,14 @@ package //log("uv[" + k + "]=" + v); } - if (client && client.hasOwnProperty("onMetaData")) { - client.onMetaData(obj); + // ignore when not changed. + if (!metadata || metadata.srs_server_ip != obj.srs_server_ip || metadata.srs_id != obj.srs_id || metadata.srs_pid != obj.srs_pid) { + if (client && client.hasOwnProperty("onMetaData")) { + log("got metadata for url " + uri); + client.onMetaData(obj); + } } + metadata = obj; } download(uri, function(stream:ByteArray):void{ @@ -177,6 +190,14 @@ package completed(stream); }); + url.addEventListener(IOErrorEvent.IO_ERROR, function(evt:IOErrorEvent):void{ + onPlayFailed(evt); + }); + + url.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(evt:SecurityErrorEvent):void{ + onPlayRejected(evt); + }); + // we set to the query. uri += ((uri.indexOf("?") == -1)? "?":"&") + "shp_xpsid=" + XPlaybackSessionId; var r:URLRequest = new URLRequest(uri); @@ -219,7 +240,35 @@ package log("FLV: sps/pps " + flvHeader.length + " bytes"); writeFlv(flvHeader); + onPlayStart(); } + + private function onPlayStart():void { + log("dispatch NetStream.Play.Start."); + dispatchEvent(new NetStatusEvent(NetStatusEvent.NET_STATUS, false, false, { + code: "NetStream.Play.Start", + stream: user_url, + descrption: "play start" + })); + } + + private function onPlayFailed(evt:IOErrorEvent):void { + log("dispatch NetConnection.Connect.Failed."); + this.conn.dispatchEvent(new NetStatusEvent(NetStatusEvent.NET_STATUS, false, false, { + code: "NetConnection.Connect.Failed", + stream: user_url, + descrption: evt.text + })); + } + + private function onPlayRejected(evt:SecurityErrorEvent):void { + log("dispatch NetConnection.Connect.Rejected."); + this.conn.dispatchEvent(new NetStatusEvent(NetStatusEvent.NET_STATUS, false, false, { + code: "NetConnection.Connect.Rejected", + stream: user_url, + descrption: evt.text + })); + } private function onFlvBody(uri:String, flv:ByteArray):void { if (!flvHeader) { diff --git a/trunk/research/players/srs_player/src/Player.as b/trunk/research/players/srs_player/src/Player.as index 15350363c..b5e918702 100644 --- a/trunk/research/players/srs_player/src/Player.as +++ b/trunk/research/players/srs_player/src/Player.as @@ -57,8 +57,19 @@ package 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; @@ -66,7 +77,8 @@ package this.media_conn.client = {}; this.media_conn.client.onBWDone = function():void {}; this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void { - log("NetConnection: code=" + evt.info.code); + 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); @@ -87,7 +99,21 @@ package 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") { @@ -100,7 +126,16 @@ package media_stream = new NetStream(media_conn); } media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void { - log("NetStream: code=" + evt.info.code); + 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(); @@ -149,14 +184,23 @@ package } 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 { diff --git a/trunk/research/players/srs_player/src/srs_player.as b/trunk/research/players/srs_player/src/srs_player.as index 691eb4600..9f0e424b8 100755 --- a/trunk/research/players/srs_player/src/srs_player.as +++ b/trunk/research/players/srs_player/src/srs_player.as @@ -33,6 +33,7 @@ package private var js_on_player_timer:String = null; private var js_on_player_empty:String = null; private var js_on_player_full:String = null; + private var js_on_player_status:String = null; // play param, user set width and height private var user_w:int = 0; @@ -105,6 +106,7 @@ package this.js_on_player_timer = flashvars.on_player_timer; this.js_on_player_empty = flashvars.on_player_empty; this.js_on_player_full = flashvars.on_player_full; + this.js_on_player_status = flashvars.on_player_status; this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer); this.media_timer.start(); @@ -497,6 +499,11 @@ package public function on_player_buffer_full():void { system_on_buffer_full(); } + + public function on_player_status(code:String, desc:String):void { + log("[STATUS] code=" + code + ", desc=" + desc); + flash.external.ExternalInterface.call(this.js_on_player_status, this.js_id, code, desc); + } /** * get the "right" size of video,