winlin

support fluency and stream empty count

@@ -30,6 +30,32 @@ function SrsPlayer(container, width, height, private_object) { @@ -30,6 +30,32 @@ function SrsPlayer(container, width, height, private_object) {
30 this.meatadata = {}; // for on_player_metadata 30 this.meatadata = {}; // for on_player_metadata
31 this.time = 0; // current stream time. 31 this.time = 0; // current stream time.
32 this.buffer_length = 0; // current stream buffer length. 32 this.buffer_length = 0; // current stream buffer length.
  33 + this.kbps = 0; // current stream bitrate(video+audio) in kbps.
  34 + this.fps = 0; // current stream video fps.
  35 + this.rtime = 0; // flash relative time in ms.
  36 +
  37 + this.__fluency = {
  38 + total_empty_count: 0,
  39 + total_empty_time: 0,
  40 + current_empty_time: 0
  41 + };
  42 + this.__fluency.on_stream_empty = function(time) {
  43 + this.total_empty_count++;
  44 + this.current_empty_time = time;
  45 + };
  46 + this.__fluency.on_stream_full = function(time) {
  47 + if (this.current_empty_time > 0) {
  48 + this.total_empty_time += time - this.current_empty_time;
  49 + this.current_empty_time = 0;
  50 + }
  51 + };
  52 + this.__fluency.calc = function(time) {
  53 + var den = this.total_empty_count * 4 + this.total_empty_time * 2 + time;
  54 + if (den > 0) {
  55 + return time * 100 / den;
  56 + }
  57 + return 0;
  58 + };
33 } 59 }
34 /** 60 /**
35 * user can set some callback, then start the player. 61 * user can set some callback, then start the player.
@@ -49,6 +75,8 @@ SrsPlayer.prototype.start = function(url) { @@ -49,6 +75,8 @@ SrsPlayer.prototype.start = function(url) {
49 flashvars.on_player_ready = "__srs_on_player_ready"; 75 flashvars.on_player_ready = "__srs_on_player_ready";
50 flashvars.on_player_metadata = "__srs_on_player_metadata"; 76 flashvars.on_player_metadata = "__srs_on_player_metadata";
51 flashvars.on_player_timer = "__srs_on_player_timer"; 77 flashvars.on_player_timer = "__srs_on_player_timer";
  78 + flashvars.on_player_empty = "__srs_on_player_empty";
  79 + flashvars.on_player_full = "__srs_on_player_full";
52 80
53 var params = {}; 81 var params = {};
54 params.wmode = "opaque"; 82 params.wmode = "opaque";
@@ -113,6 +141,18 @@ SrsPlayer.prototype.resume = function() { @@ -113,6 +141,18 @@ SrsPlayer.prototype.resume = function() {
113 this.callbackObj.ref.__resume(); 141 this.callbackObj.ref.__resume();
114 } 142 }
115 /** 143 /**
  144 + * get the stream fluency, where 100 is 100%.
  145 + */
  146 +SrsPlayer.prototype.fluency = function() {
  147 + return this.__fluency.calc(this.rtime);
  148 +}
  149 +/**
  150 + * get the stream empty count.
  151 + */
  152 +SrsPlayer.prototype.empty_count = function() {
  153 + return this.__fluency.total_empty_count;
  154 +}
  155 +/**
116 * to set the DAR, for example, DAR=16:9 where num=16,den=9. 156 * to set the DAR, for example, DAR=16:9 where num=16,den=9.
117 * @param num, for example, 16. 157 * @param num, for example, 16.
118 * use metadata width if 0. 158 * use metadata width if 0.
@@ -148,7 +188,13 @@ SrsPlayer.prototype.on_player_ready = function() { @@ -148,7 +188,13 @@ SrsPlayer.prototype.on_player_ready = function() {
148 SrsPlayer.prototype.on_player_metadata = function(metadata) { 188 SrsPlayer.prototype.on_player_metadata = function(metadata) {
149 // ignore. 189 // ignore.
150 } 190 }
151 -SrsPlayer.prototype.on_player_timer = function(time, buffer_length) { 191 +SrsPlayer.prototype.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
  192 + // ignore.
  193 +}
  194 +SrsPlayer.prototype.on_player_empty = function(time) {
  195 + // ignore.
  196 +}
  197 +SrsPlayer.prototype.on_player_full = function(time) {
152 // ignore. 198 // ignore.
153 } 199 }
154 function __srs_find_player(id) { 200 function __srs_find_player(id) {
@@ -177,7 +223,7 @@ function __srs_on_player_metadata(id, metadata) { @@ -177,7 +223,7 @@ function __srs_on_player_metadata(id, metadata) {
177 223
178 player.on_player_metadata(metadata); 224 player.on_player_metadata(metadata);
179 } 225 }
180 -function __srs_on_player_timer(id, time, buffer_length) { 226 +function __srs_on_player_timer(id, time, buffer_length, kbps, fps, rtime) {
181 var player = __srs_find_player(id); 227 var player = __srs_find_player(id);
182 228
183 buffer_length = Math.max(0, buffer_length); 229 buffer_length = Math.max(0, buffer_length);
@@ -189,6 +235,19 @@ function __srs_on_player_timer(id, time, buffer_length) { @@ -189,6 +235,19 @@ function __srs_on_player_timer(id, time, buffer_length) {
189 // so set the data before invoke it. 235 // so set the data before invoke it.
190 player.time = time; 236 player.time = time;
191 player.buffer_length = buffer_length; 237 player.buffer_length = buffer_length;
192 -  
193 - player.on_player_timer(time, buffer_length); 238 + player.kbps = kbps;
  239 + player.fps = fps;
  240 + player.rtime = rtime;
  241 +
  242 + player.on_player_timer(time, buffer_length, kbps, fps, rtime);
  243 +}
  244 +function __srs_on_player_empty(id, time) {
  245 + var player = __srs_find_player(id);
  246 + player.__fluency.on_stream_empty(time);
  247 + player.on_player_empty(time);
  248 +}
  249 +function __srs_on_player_full(id, time) {
  250 + var player = __srs_find_player(id);
  251 + player.__fluency.on_stream_full(time);
  252 + player.on_player_full(time);
194 } 253 }
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * depends: jquery1.10 5 * depends: jquery1.10
6 * https://code.csdn.net/snippets/147103 6 * https://code.csdn.net/snippets/147103
7 * @see: http://blog.csdn.net/win_lin/article/details/17994347 7 * @see: http://blog.csdn.net/win_lin/article/details/17994347
8 - * v 1.0.10 8 + * v 1.0.11
9 */ 9 */
10 10
11 /** 11 /**
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 margin-top: -20px; 12 margin-top: -20px;
13 padding-top: 3px; 13 padding-top: 3px;
14 } 14 }
15 - #div_play_time { 15 + .div_play_time {
16 margin-top: 10px; 16 margin-top: 10px;
17 } 17 }
18 #pb_buffer_bg { 18 #pb_buffer_bg {
@@ -47,7 +47,7 @@ @@ -47,7 +47,7 @@
47 </div> 47 </div>
48 <div class="form-inline"> 48 <div class="form-inline">
49 URL: 49 URL:
50 - <input type="text" id="txt_url" class="input-xxlarge" value=""></input> 50 + <input type="text" id="txt_url" class="input-xxlarge" value="">
51 <button class="btn btn-primary" id="btn_play">播放视频</button> 51 <button class="btn btn-primary" id="btn_play">播放视频</button>
52 <button class="btn" id="btn_generate_link">生成链接</button> 52 <button class="btn" id="btn_generate_link">生成链接</button>
53 </div> 53 </div>
@@ -281,57 +281,82 @@ @@ -281,57 +281,82 @@
281 </div> 281 </div>
282 </div> 282 </div>
283 <div class="modal-footer" id="my_modal_footer"> 283 <div class="modal-footer" id="my_modal_footer">
284 - <div class="input-prepend" id="div_play_time">  
285 - <span class="add-on" title="播放时长">@T</span>  
286 - <input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">  
287 - </div>  
288 - <div class="btn-group dropup">  
289 - <button class="btn dropdown-toggle" data-toggle="dropdown">  
290 - <a id="fs_tips" href="#" data-toggle="tooltip" data-placement="top" title="">  
291 - <img src="img/tooltip.png"/>  
292 - </a>  
293 - 全屏大小<span class="caret"></span>  
294 - </button>  
295 - <ul class="dropdown-menu">  
296 - <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>  
297 - <li><a id="btn_fs_size_screen_75" href="#">屏幕大小(75%)</a></li>  
298 - <li><a id="btn_fs_size_screen_50" href="#">屏幕大小(50%)</a></li>  
299 - <li><a id="btn_fs_size_video_100" href="#">视频大小(100%)</a></li>  
300 - <li><a id="btn_fs_size_video_75" href="#">视频大小(75%)</a></li>  
301 - <li><a id="btn_fs_size_video_50" href="#">视频大小(50%)</a></li>  
302 - </ul>  
303 - </div>  
304 - <div class="btn-group dropup">  
305 - <button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button>  
306 - <ul class="dropdown-menu">  
307 - <li><a id="btn_dar_original" href="#">视频原始比例</a></li>  
308 - <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>  
309 - <li><a id="btn_dar_16_9" href="#">宽屏电视(16:9)</a></li>  
310 - <li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li>  
311 - <li><a id="btn_dar_fill" href="#">填充(容器比例)</a></li>  
312 - </ul>  
313 - </div>  
314 - <div class="btn-group dropup">  
315 - <button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button>  
316 - <ul class="dropdown-menu">  
317 - <li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li>  
318 - <li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li>  
319 - <li><a id="btn_bt_0_3" href="#">0.3秒(实时)</a></li>  
320 - <li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>  
321 - <li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>  
322 - <li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li>  
323 - <li><a id="btn_bt_2" href="#">2秒(较低延时)</a></li>  
324 - <li><a id="btn_bt_3" href="#">3秒(流畅播放)</a></li>  
325 - <li><a id="btn_bt_5" href="#">5秒(网速较低)</a></li>  
326 - <li><a id="btn_bt_10" href="#">10秒(无所谓延迟)</a></li>  
327 - <li><a id="btn_bt_30" href="#">30秒(流畅第一)</a></li>  
328 - </ul> 284 + <div>
  285 + <div class="btn-group dropup">
  286 + <button class="btn dropdown-toggle" data-toggle="dropdown">
  287 + 设置全屏比例大小<span class="caret"></span>
  288 + </button>
  289 + <ul class="dropdown-menu">
  290 + <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
  291 + <li><a id="btn_fs_size_screen_75" href="#">屏幕大小(75%)</a></li>
  292 + <li><a id="btn_fs_size_screen_50" href="#">屏幕大小(50%)</a></li>
  293 + <li><a id="btn_fs_size_video_100" href="#">视频大小(100%)</a></li>
  294 + <li><a id="btn_fs_size_video_75" href="#">视频大小(75%)</a></li>
  295 + <li><a id="btn_fs_size_video_50" href="#">视频大小(50%)</a></li>
  296 + </ul>
  297 + </div>
  298 + <div class="btn-group dropup">
  299 + <button class="btn dropdown-toggle" data-toggle="dropdown">设置显示比例<span class="caret"></span></button>
  300 + <ul class="dropdown-menu">
  301 + <li><a id="btn_dar_original" href="#">视频原始比例</a></li>
  302 + <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
  303 + <li><a id="btn_dar_16_9" href="#">宽屏电视(16:9)</a></li>
  304 + <li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li>
  305 + <li><a id="btn_dar_fill" href="#">填充(容器比例)</a></li>
  306 + </ul>
  307 + </div>
  308 + <div class="btn-group dropup">
  309 + <button class="btn dropdown-toggle" data-toggle="dropdown">设置缓冲区大小<span class="caret"></span></button>
  310 + <ul class="dropdown-menu">
  311 + <li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li>
  312 + <li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li>
  313 + <li><a id="btn_bt_0_3" href="#">0.3秒(实时)</a></li>
  314 + <li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>
  315 + <li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>
  316 + <li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li>
  317 + <li><a id="btn_bt_2" href="#">2秒(较低延时)</a></li>
  318 + <li><a id="btn_bt_3" href="#">3秒(流畅播放)</a></li>
  319 + <li><a id="btn_bt_5" href="#">5秒(网速较低)</a></li>
  320 + <li><a id="btn_bt_10" href="#">10秒(无所谓延迟)</a></li>
  321 + <li><a id="btn_bt_30" href="#">30秒(流畅第一)</a></li>
  322 + </ul>
  323 + </div>
  324 + <div class="btn-group dropup">
  325 + <a id="btn_fullscreen" class="btn">进入全屏</a>
  326 + </div>
  327 + <div class="btn-group dropup">
  328 + <button id="btn_pause" class="btn">暂停播放</button>
  329 + <button id="btn_resume" class="btn hide">继续播放</button>
  330 + </div>
  331 + <div class="btn-group dropup">
  332 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭播放器</button>
  333 + </div>
329 </div> 334 </div>
330 - <div class="btn-group dropup">  
331 - <button id="btn_pause" class="btn">暂停</button> 335 + <div class="hide" id="fullscreen_tips">
  336 +<font color="red">点击视频</font>进入全屏模式~<br/>
  337 + 由于安全原因,Flash全屏无法使用JS触发
332 </div> 338 </div>
333 - <div class="btn-group dropup">  
334 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button> 339 + <div>
  340 + <div class="input-prepend div_play_time" title="视频的播放流畅度">
  341 + <span class="add-on">@F</span>
  342 + <input class="span2" style="width:57px" id="txt_fluency" type="text" placeholder="100%">
  343 + </div>
  344 + <div class="input-prepend div_play_time" title="视频总共卡顿次数">
  345 + <span class="add-on">@E</span>
  346 + <input class="span2" style="width:85px" id="txt_empty_count" type="text" placeholder="0">
  347 + </div>
  348 + <div class="input-prepend div_play_time" title="视频当前的帧率FPS">
  349 + <span class="add-on">@F</span>
  350 + <input class="span2" style="width:85px" id="txt_fps" type="text" placeholder="fps">
  351 + </div>
  352 + <div class="input-prepend div_play_time" title="视频当前的码率(视频+音频),单位:Kbps">
  353 + <span class="add-on">@B</span>
  354 + <input class="span2" style="width:85px" id="txt_bitrate" type="text" placeholder="kbps">
  355 + </div>
  356 + <div class="input-prepend div_play_time" title="播放时长,格式:天 时:分:秒">
  357 + <span class="add-on">@T</span>
  358 + <input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">
  359 + </div>
335 </div> 360 </div>
336 </div> 361 </div>
337 </div> 362 </div>
@@ -398,10 +423,6 @@ @@ -398,10 +423,6 @@
398 // url set to: rtmp://demo:1935/live/livestream 423 // url set to: rtmp://demo:1935/live/livestream
399 srs_init_rtmp("#txt_url", "#main_modal"); 424 srs_init_rtmp("#txt_url", "#main_modal");
400 425
401 - $("#fs_tips").tooltip({  
402 - title: "点击视频进入或退出全屏"  
403 - });  
404 -  
405 $("#main_modal").on("show", function(){ 426 $("#main_modal").on("show", function(){
406 if (srs_player) { 427 if (srs_player) {
407 return; 428 return;
@@ -427,7 +448,7 @@ @@ -427,7 +448,7 @@
427 select_dar("#btn_dar_original", 0, 0); 448 select_dar("#btn_dar_original", 0, 0);
428 select_fs_size("#btn_fs_size_screen_100", "screen", 100); 449 select_fs_size("#btn_fs_size_screen_100", "screen", 100);
429 }; 450 };
430 - srs_player.on_player_timer = function(time, buffer_length) { 451 + srs_player.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
431 var buffer = buffer_length / this.buffer_time * 100; 452 var buffer = buffer_length / this.buffer_time * 100;
432 $("#pb_buffer").width(Number(buffer).toFixed(1) + "%"); 453 $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
433 454
@@ -435,6 +456,11 @@ @@ -435,6 +456,11 @@
435 "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒(" 456 "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("
436 + Number(buffer).toFixed(1) + "%)"); 457 + Number(buffer).toFixed(1) + "%)");
437 458
  459 + $("#txt_bitrate").val(kbps.toFixed(1) + "kbps");
  460 + $("#txt_fps").val(fps.toFixed(1) + "fps");
  461 + $("#txt_empty_count").val(srs_player.empty_count() + "次卡顿");
  462 + $("#txt_fluency").val(srs_player.fluency().toFixed(2) + "%");
  463 +
438 var time_str = ""; 464 var time_str = "";
439 // day 465 // day
440 time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " "; 466 time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
@@ -454,10 +480,6 @@ @@ -454,10 +480,6 @@
454 }); 480 });
455 481
456 $("#main_modal").on("hide", function(){ 482 $("#main_modal").on("hide", function(){
457 - if ($("#main_modal").is(":visible")) {  
458 - return;  
459 - }  
460 -  
461 if (srs_player) { 483 if (srs_player) {
462 srs_player.stop(); 484 srs_player.stop();
463 srs_player = null; 485 srs_player = null;
@@ -477,22 +499,27 @@ @@ -477,22 +499,27 @@
477 $("#link_stream").text(rtmp.stream); 499 $("#link_stream").text(rtmp.stream);
478 $("#link_rtmp").text($("#txt_url").val()); 500 $("#link_rtmp").text($("#txt_url").val());
479 $("#link_url").attr("href", url); 501 $("#link_url").attr("href", url);
480 - $("#link_modal").modal({show:true, keyboard:false}); 502 + $("#link_modal").modal({show:true, keyboard:true});
481 }); 503 });
482 504
483 $("#btn_play").click(function(){ 505 $("#btn_play").click(function(){
484 url = $("#txt_url").val(); 506 url = $("#txt_url").val();
485 - $("#main_modal").modal({show:true, keyboard:false}); 507 + $("#main_modal").modal({show:true, keyboard:true});
486 }); 508 });
487 509
488 - $("#btn_pause").click(function(){  
489 - if ($("#btn_pause").text() == "暂停") {  
490 - $("#btn_pause").text("继续");  
491 - srs_player.pause();  
492 - } else {  
493 - $("#btn_pause").text("暂停");  
494 - srs_player.resume();  
495 - } 510 + $("#btn_fullscreen").click(function(){
  511 + $("#fullscreen_tips").toggle();
  512 + });
  513 +
  514 + $("#btn_pause").click(function() {
  515 + $("#btn_resume").toggle();
  516 + $("#btn_pause").toggle();
  517 + srs_player.pause();
  518 + });
  519 + $("#btn_resume").click(function(){
  520 + $("#btn_resume").toggle();
  521 + $("#btn_pause").toggle();
  522 + srs_player.resume();
496 }); 523 });
497 524
498 if (true) { 525 if (true) {
@@ -18,6 +18,7 @@ package @@ -18,6 +18,7 @@ package
18 import flash.ui.ContextMenu; 18 import flash.ui.ContextMenu;
19 import flash.ui.ContextMenuItem; 19 import flash.ui.ContextMenuItem;
20 import flash.utils.Timer; 20 import flash.utils.Timer;
  21 + import flash.utils.getTimer;
21 import flash.utils.setTimeout; 22 import flash.utils.setTimeout;
22 23
23 import flashx.textLayout.formats.Float; 24 import flashx.textLayout.formats.Float;
@@ -30,7 +31,9 @@ package @@ -30,7 +31,9 @@ package
30 private var js_on_player_ready:String = null; 31 private var js_on_player_ready:String = null;
31 private var js_on_player_metadata:String = null; 32 private var js_on_player_metadata:String = null;
32 private var js_on_player_timer:String = null; 33 private var js_on_player_timer:String = null;
33 - 34 + private var js_on_player_empty:String = null;
  35 + private var js_on_player_full:String = null;
  36 +
34 // play param url. 37 // play param url.
35 private var user_url:String = null; 38 private var user_url:String = null;
36 // play param, user set width and height 39 // play param, user set width and height
@@ -93,6 +96,8 @@ package @@ -93,6 +96,8 @@ package
93 this.js_on_player_ready = flashvars.on_player_ready; 96 this.js_on_player_ready = flashvars.on_player_ready;
94 this.js_on_player_metadata = flashvars.on_player_metadata; 97 this.js_on_player_metadata = flashvars.on_player_metadata;
95 this.js_on_player_timer = flashvars.on_player_timer; 98 this.js_on_player_timer = flashvars.on_player_timer;
  99 + this.js_on_player_empty = flashvars.on_player_empty;
  100 + this.js_on_player_full = flashvars.on_player_full;
96 101
97 this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer); 102 this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer);
98 this.media_timer.start(); 103 this.media_timer.start();
@@ -106,7 +111,7 @@ package @@ -106,7 +111,7 @@ package
106 */ 111 */
107 private function system_on_js_ready():void { 112 private function system_on_js_ready():void {
108 if (!flash.external.ExternalInterface.available) { 113 if (!flash.external.ExternalInterface.available) {
109 - trace("js not ready, try later."); 114 + log("js not ready, try later.");
110 flash.utils.setTimeout(this.system_on_js_ready, 100); 115 flash.utils.setTimeout(this.system_on_js_ready, 100);
111 return; 116 return;
112 } 117 }
@@ -114,7 +119,7 @@ package @@ -114,7 +119,7 @@ package
114 flash.external.ExternalInterface.addCallback("__play", this.js_call_play); 119 flash.external.ExternalInterface.addCallback("__play", this.js_call_play);
115 flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop); 120 flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
116 flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause); 121 flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause);
117 - flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume); 122 + flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume);
118 flash.external.ExternalInterface.addCallback("__set_dar", this.js_call_set_dar); 123 flash.external.ExternalInterface.addCallback("__set_dar", this.js_call_set_dar);
119 flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size); 124 flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size);
120 flash.external.ExternalInterface.addCallback("__set_bt", this.js_call_set_bt); 125 flash.external.ExternalInterface.addCallback("__set_bt", this.js_call_set_bt);
@@ -126,15 +131,39 @@ package @@ -126,15 +131,39 @@ package
126 * system callack event, timer to do some regular tasks. 131 * system callack event, timer to do some regular tasks.
127 */ 132 */
128 private function system_on_timer(evt:TimerEvent):void { 133 private function system_on_timer(evt:TimerEvent):void {
129 - if (!this.media_stream) {  
130 - trace("stream is null, ignore timer event."); 134 + var ms:NetStream = this.media_stream;
  135 +
  136 + if (!ms) {
  137 + log("stream is null, ignore timer event.");
131 return; 138 return;
132 } 139 }
133 -  
134 - trace("notify js the timer event."); 140 +
  141 + var rtime:Number = flash.utils.getTimer();
  142 + var bitrate:Number = Number((ms.info.videoBytesPerSecond + ms.info.audioBytesPerSecond) * 8 / 1000);
  143 + log("on timer, time=" + ms.time.toFixed(2) + "s, buffer=" + ms.bufferLength.toFixed(2) + "s"
  144 + + ", bitrate=" + bitrate.toFixed(1) + "kbps"
  145 + + ", fps=" + ms.currentFPS.toFixed(1)
  146 + + ", rtime=" + rtime.toFixed(0)
  147 + );
135 flash.external.ExternalInterface.call( 148 flash.external.ExternalInterface.call(
136 - this.js_on_player_timer, this.js_id, this.media_stream.time, this.media_stream.bufferLength); 149 + this.js_on_player_timer, this.js_id, ms.time, ms.bufferLength,
  150 + bitrate, ms.currentFPS, rtime
  151 + );
137 } 152 }
  153 +
  154 + /**
  155 + * system callback event, when stream is empty.
  156 + */
  157 + private function system_on_buffer_empty():void {
  158 + var time:Number = flash.utils.getTimer();
  159 + log("stream is empty at " + time + "ms");
  160 + flash.external.ExternalInterface.call(this.js_on_player_empty, this.js_id, time);
  161 + }
  162 + private function system_on_buffer_full():void {
  163 + var time:Number = flash.utils.getTimer();
  164 + log("stream is full at " + time + "ms");
  165 + flash.external.ExternalInterface.call(this.js_on_player_full, this.js_id, time);
  166 + }
138 167
139 /** 168 /**
140 * system callack event, when got metadata from stream. 169 * system callack event, when got metadata from stream.
@@ -181,7 +210,7 @@ package @@ -181,7 +210,7 @@ package
181 */ 210 */
182 private function user_on_click_video(evt:MouseEvent):void { 211 private function user_on_click_video(evt:MouseEvent):void {
183 if (!this.stage.allowsFullScreen) { 212 if (!this.stage.allowsFullScreen) {
184 - trace("donot allow fullscreen."); 213 + log("donot allow fullscreen.");
185 return; 214 return;
186 } 215 }
187 216
@@ -266,6 +295,7 @@ package @@ -266,6 +295,7 @@ package
266 this.media_conn.close(); 295 this.media_conn.close();
267 this.media_conn = null; 296 this.media_conn = null;
268 } 297 }
  298 + log("player stopped");
269 } 299 }
270 300
271 // srs infos 301 // srs infos
@@ -311,7 +341,7 @@ package @@ -311,7 +341,7 @@ package
311 this.user_url = url; 341 this.user_url = url;
312 this.user_w = _width; 342 this.user_w = _width;
313 this.user_h = _height; 343 this.user_h = _height;
314 - trace("start to play url: " + this.user_url + ", w=" + this.user_w + ", h=" + this.user_h); 344 + log("start to play url: " + this.user_url + ", w=" + this.user_w + ", h=" + this.user_h);
315 345
316 js_call_stop(); 346 js_call_stop();
317 347
@@ -358,7 +388,11 @@ package @@ -358,7 +388,11 @@ package
358 388
359 if (evt.info.code == "NetStream.Video.DimensionChange") { 389 if (evt.info.code == "NetStream.Video.DimensionChange") {
360 system_on_metadata(media_metadata); 390 system_on_metadata(media_metadata);
361 - } 391 + } else if (evt.info.code == "NetStream.Buffer.Empty") {
  392 + system_on_buffer_empty();
  393 + } else if (evt.info.code == "NetStream.Buffer.Full") {
  394 + system_on_buffer_full();
  395 + }
362 396
363 // TODO: FIXME: failed event. 397 // TODO: FIXME: failed event.
364 }); 398 });
@@ -460,7 +494,11 @@ package @@ -460,7 +494,11 @@ package
460 } 494 }
461 495
462 // rescale to fs 496 // rescale to fs
463 - __update_video_size(num, den, obj.width * user_fs_percent / 100, obj.height * user_fs_percent / 100, this.stage.fullScreenWidth, this.stage.fullScreenHeight); 497 + __update_video_size(num, den,
  498 + obj.width * user_fs_percent / 100,
  499 + obj.height * user_fs_percent / 100,
  500 + this.stage.fullScreenWidth, this.stage.fullScreenHeight
  501 + );
464 } 502 }
465 503
466 /** 504 /**
@@ -539,5 +577,18 @@ package @@ -539,5 +577,18 @@ package
539 this.control_fs_mask.graphics.drawRect(0, 0, _width, _height); 577 this.control_fs_mask.graphics.drawRect(0, 0, _width, _height);
540 this.control_fs_mask.graphics.endFill(); 578 this.control_fs_mask.graphics.endFill();
541 } 579 }
  580 +
  581 + private function log(msg:String):void {
  582 + msg = "[" + new Date() +"][srs-player][" + js_id + "] " + msg;
  583 +
  584 + trace(msg);
  585 +
  586 + if (!flash.external.ExternalInterface.available) {
  587 + flash.utils.setTimeout(log, 300, msg);
  588 + return;
  589 + }
  590 +
  591 + ExternalInterface.call("console.log", msg);
  592 + }
542 } 593 }
543 } 594 }