1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-15 04:42:04 +00:00

refine bandwidth test client, provides js and as library

This commit is contained in:
winlin 2014-07-12 20:48:03 +08:00
parent b1dd0218be
commit c319cc6a40
12 changed files with 700 additions and 336 deletions

View file

@ -27,6 +27,8 @@ function SrsBandwidth(container, width, height, private_object) {
// the callback set data.
this.percent = 0;
this.status = "";
this.report = "";
this.server = "";
}
/**
* user can set some callback, then start the bandwidth.
@ -38,7 +40,7 @@ function SrsBandwidth(container, width, height, private_object) {
* on_update_status(status:String):void, when srs bandwidth update the status.
* status:String the human readable status text.
*/
SrsBandwidth.prototype.start = function(url) {
SrsBandwidth.prototype.render = function(url) {
if (url) {
this.stream_url = url;
}
@ -49,6 +51,8 @@ SrsBandwidth.prototype.start = function(url) {
flashvars.on_bandwidth_ready = "__srs_on_bandwidth_ready";
flashvars.on_update_progress = "__srs_on_update_progress";
flashvars.on_update_status = "__srs_on_update_status";
flashvars.on_srs_info = "__srs_on_srs_info";
flashvars.on_complete = "__srs_on_complete";
var params = {};
params.wmode = "opaque";
@ -75,7 +79,6 @@ SrsBandwidth.prototype.start = function(url) {
/**
* play the stream.
* @param stream_url the url of stream, rtmp or http.
* @param volume the volume, 0 is mute, 1 is 100%, 2 is 200%.
*/
SrsBandwidth.prototype.check_bandwidth = function(url) {
this.stop();
@ -107,6 +110,10 @@ SrsBandwidth.prototype.on_update_progress = function(percent) {
}
SrsBandwidth.prototype.on_update_status = function(status) {
}
SrsBandwidth.prototype.on_srs_info = function(srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip) {
}
SrsBandwidth.prototype.on_complete = function(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time) {
}
function __srs_find_bandwidth(id) {
for (var i = 0; i < SrsBandwidth.__bandwidths.length; i++) {
var bandwidth = SrsBandwidth.__bandwidths[i];
@ -129,8 +136,52 @@ function __srs_on_update_progress(id, percent) {
bandwidth.percent = percent;
bandwidth.on_update_progress(percent);
}
function __srs_on_update_status(id, status) {
function __srs_on_update_status(id, code, data) {
var bandwidth = __srs_find_bandwidth(id);
var status = "";
switch(code){
case "NetConnection.Connect.Failed":
status = "连接服务器失败!";
break;
case "NetConnection.Connect.Rejected":
status = "服务器拒绝连接!";
break;
case "NetConnection.Connect.Success":
status = "连接服务器成功!";
break;
case "NetConnection.Connect.Closed":
if (bandwidth.report) {
return;
}
status = "连接已断开!";
break;
case "srs.bwtc.play.start":
status = "开始测试下行带宽";
break;
case "srs.bwtc.play.stop":
status = "下行带宽测试完毕," + data + "kbps开始测试上行带宽。";
break;
default:
return;
}
bandwidth.status = status;
bandwidth.on_update_status(status);
}
function __srs_on_srs_info(id, srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip) {
var bandwidth = __srs_find_bandwidth(id);
bandwidth.status = status;
bandwidth.server = srs_server_ip;
bandwidth.on_srs_info(srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip);
}
function __srs_on_complete(id, start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time) {
var bandwidth = __srs_find_bandwidth(id);
var status = "检测结束: " + bandwidth.server + " 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
+ " 测试时间: " + Number((end_time - start_time) / 1000).toFixed(1) + " 秒";
bandwidth.report = status;
bandwidth.on_update_status(status);
bandwidth.on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
}

View file

@ -35,6 +35,7 @@
function on_click_play() {
$("#check_status").text("");
$("#check_info").text("");
$("#progress_bar").width("0%");
$("#main_modal").modal({show:true, keyboard:false});
}
@ -61,7 +62,13 @@
bandwidth.on_update_status = function(status) {
$("#check_status").text(status);
}
bandwidth.start(url);
bandwidth.on_srs_info = function(srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip) {
$("#check_info").text(
"server:" + srs_server + ", authors:" + srs_primary_authors +
", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip
);
}
bandwidth.render(url);
}
function on_stop_bandwidth_test() {
bandwidth.stop();
@ -112,7 +119,8 @@
</div>
<div class="span1"></div>
</div>
<span id="check_status">status</span>
<div id="check_status">status</div>
<div id="check_info">info</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>

View file

@ -1,24 +0,0 @@
package SrsClass
{
import flash.system.System;
public class SrsElapsedTimer
{
private var beginDate:Date;
public function SrsElapsedTimer()
{
beginDate = new Date;
}
public function elapsed():Number{
var endDate:Date = new Date;
// get deiff by ms
return (endDate.time - beginDate.time);
}
public function restart():void{
beginDate = new Date;
}
}
}

View file

@ -1,27 +0,0 @@
package SrsClass
{
import flash.net.SharedObject;
public class SrsSettings
{
private var settings:SharedObject;
private var key:String = "SrsBandCheck";
public function SrsSettings()
{
settings = SharedObject.getLocal(key);
}
public function addAddressText(val:String):void{
settings.data.address_text = val;
}
public function addressText():String{
return settings.data.address_text;
}
static public function instance():SrsSettings{
return new SrsSettings;
}
}
}

View file

@ -0,0 +1,502 @@
package srs
{
import flash.events.NetStatusEvent;
import flash.external.ExternalInterface;
import flash.net.NetConnection;
import flash.net.ObjectEncoding;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
/**
* SRS bandwidth check/test library,
* user can copy this file and use it directly,
* this library will export as callback functions, and js callback functions.
*
* Usage:
* var bandwidth:SrsBandwidth = new SrsBandwidth();
* bandwidth.initialize(......); // required
* bandwidth.check_bandwidth(......); // required
* bandwidth.stop(); // optional
*
* @remark we donot use event, but use callback functions set by initialize.
*/
public class SrsBandwidth
{
/**
* server notice client to do the downloading/play bandwidth test.
*/
public static const StatusSrsBwtcPlayStart:String = "srs.bwtc.play.start";
/**
* server notice client to complete the downloading/play bandwidth test.
*/
public static const StatusSrsBwtcPlayStop:String = "srs.bwtc.play.stop";
/**
* server notice client to do the uploading/publish bandwidth test.
*/
public static const StatusSrsBwtcPublishStart:String = "srs.bwtc.publish.start";
/**
* server notice client to complete the uploading/publish bandwidth test.
*/
public static const StatusSrsBwtcPublishStop:String = "srs.bwtc.publish.stop";
/**
* constructor, do nothing
*/
public function SrsBandwidth()
{
}
/**
* initialize the bandwidth test tool, the callbacks. null to ignore.
*
* the as callbacks.
* @param as_on_ready, function():void, callback when bandwidth tool is ready to run.
* @param as_on_status_change, function(code:String, data:String):void, where:
* code can be:
* "NetConnection.Connect.Failed", see NetStatusEvent(evt.info.code).
* "NetConnection.Connect.Rejected", see NetStatusEvent(evt.info.code).
* "NetConnection.Connect.Success", see NetStatusEvent(evt.info.code).
* "NetConnection.Connect.Closed", see NetStatusEvent(evt.info.code).
* SrsBandwidth.StatusSrsBwtcPlayStart, "srs.bwtc.play.start", when srs start test play bandwidth.
* SrsBandwidth.StatusSrsBwtcPlayStop, "srs.bwtc.play.stop", when srs complete test play bandwidth.
* SrsBandwidth.StatusSrsBwtcPublishStart, "srs.bwtc.publish.start", when srs start test publish bandwidth.
* SrsBandwidth.StatusSrsBwtcPublishStop, "srs.bwtc.publish.stop", when srs complete test publish bandwidth.
* data is extra parameter:
* kbps, for code is SrsBandwidth.StatusSrsBwtcPlayStop or SrsBandwidth.StatusSrsBwtcPublishStop.
* "", otherwise empty string.
* @param as_on_progress_change, function(percent:Number):void, where:
* percent, the progress percent, 0 means 0%, 100 means 100%.
* @param as_on_srs_info, function(srs_server:String, srs_primary_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void, where:
* srs_server: the srs server info.
* srs_primary_authors: the srs version info.
* srs_id: the tracable log id, to direclty grep the log..
* srs_pid: the srs process id, to direclty grep the log.
* srs_server_ip: the srs server ip, where client connected at.
* @param as_on_complete, function(start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void, where
* start_time, the start timestamp, in ms.
* end_time, the finish timestamp, in ms.
* play_kbps, the play/downloading kbps.
* publish_kbps, the publish/uploading kbps.
* play_bytes, the bytes play/download from server, in bytes.
* publish_bytes, the bytes publish/upload to server, in bytes.
* play_time, the play/download duration time, in ms.
* publish_time, the publish/upload duration time, in ms.
*
* the js callback id.
* @param js_id, specifies the id of swfobject, used to identify the bandwidth object.
* for all js callback, the first param always be the js_id, to identify the callback object.
*
* the js callbacks.
* @param js_on_ready, function(js_id:String):void, callback when bandwidth tool is ready to run.
* @param js_on_status_change, function(js_id:String, code:String, data:String):void
* @param as_on_progress_change, function(js_id:String, percent:Number):void
* @param as_on_srs_info, function(js_id:String, srs_server:String, srs_primary_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void
* @param as_on_complete, function(js_id:String, start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void
*
* the js export functions.
* @param js_export_check_bandwidth, function(url:String):void, for js to start bandwidth check, @see: check_bandwidth(url:String):void
* @param js_export_stop, function():void, for js to stop bandwidth check, @see: stop():void
*
* @remark, all parameters can be null.
* @remark, as and js callback use same parameter, except that the js calblack first parameter is js_id:String.
*/
public function initialize(
as_on_ready:Function, as_on_status_change:Function, as_on_progress_change:Function, as_on_srs_info:Function, as_on_complete:Function,
js_id:String, js_on_ready:String, js_on_status_change:String, js_on_progress_change:String, js_on_srs_info:String, js_on_complete:String,
js_export_check_bandwidth:String, js_export_stop:String
):void {
this.as_on_ready = as_on_ready;
this.as_on_srs_info = as_on_srs_info;
this.as_on_status_change = as_on_status_change;
this.as_on_progress_change = as_on_progress_change;
this.as_on_complete = as_on_complete;
this.js_id = js_id;
this.js_on_srs_info = js_on_srs_info;
this.js_on_ready = js_on_ready;
this.js_on_status_change = js_on_status_change;
this.js_on_progress_change = js_on_progress_change;
this.js_on_complete = js_on_complete;
this.js_export_check_bandwidth = js_export_check_bandwidth;
this.js_export_stop = js_export_stop;
flash.utils.setTimeout(this.system_on_js_ready, 0);
}
/**
* start check bandwidth.
* @param url, a String indicates the url to check bandwidth,
* format as: rtmp://server:port/app?key=xxx&&vhost=xxx
* for example, rtmp://dev:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com
* where the key and vhost must be config in SRS, like:
* vhost bandcheck.srs.com {
* enabled on;
* chunk_size 65000;
* bandcheck {
* enabled on;
* key "35c9b402c12a7246868752e2878f7e0e";
* interval 30;
* limit_kbps 4000;
* }
* }
*
* @remark user must invoke this as method, or js exported method.
*/
public function check_bandwidth(url:String):void {
this.js_call_check_bandwidth(url);
}
/**
* stop check bancwidth.
* @remark it's optional, however, user can abort the bandwidth check.
*/
public function stop():void {
this.js_call_stop();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// Private Section, ignore please. ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
////////////////////////// ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* ***********************************************************************
* private section, including private fields, method and embeded classes.
* ***********************************************************************
*/
/**
* as callback.
*/
private var as_on_ready:Function;
private var as_on_srs_info:Function;
private var as_on_status_change:Function;
private var as_on_progress_change:Function;
private var as_on_complete:Function;
/**
* js callback.
*/
private var js_id:String;
private var js_on_ready:String;
private var js_on_srs_info:String;
private var js_on_status_change:String;
private var js_on_progress_change:String;
private var js_on_complete:String;
/**
* js export functions.
*/
private var js_export_check_bandwidth:String;
private var js_export_stop:String;
/**
* srs debug infos
*/
private var srs_server:String = null;
private var srs_primary_authors:String = null;
private var srs_id:String = null;
private var srs_pid:String = null;
private var srs_server_ip:String = null;
/**
* the underlayer connection, to send call message to do the bandwidth
* check/test with server.
*/
private var connection:NetConnection = null;
/**
* use timeout to sendout publish call packets.
* when got stop publish packet from server, stop publish call loop.
*/
private var publish_timeout_handler:uint = 0;
/**
* system callack event, when js ready, register callback for js.
* the actual main function.
*/
private function system_on_js_ready():void {
if (!flash.external.ExternalInterface.available) {
trace("js not ready, try later.");
flash.utils.setTimeout(this.system_on_js_ready, 100);
return;
}
if (this.js_export_check_bandwidth != null) {
flash.external.ExternalInterface.addCallback(this.js_export_check_bandwidth, this.js_call_check_bandwidth);
}
if (this.js_export_stop != null) {
flash.external.ExternalInterface.addCallback(this.js_export_stop, this.js_call_stop);
}
if (as_on_ready != null) {
as_on_ready();
}
if (js_on_ready != null) {
flash.external.ExternalInterface.call(this.js_on_ready, this.js_id);
}
}
private function js_call_check_bandwidth(url:String):void {
js_call_stop();
__on_progress_change(0);
// init connection
connection = new NetConnection;
connection.objectEncoding = ObjectEncoding.AMF0;
connection.client = {
onStatus: onStatus,
// play
onSrsBandCheckStartPlayBytes: onSrsBandCheckStartPlayBytes,
onSrsBandCheckPlaying: onSrsBandCheckPlaying,
onSrsBandCheckStopPlayBytes: onSrsBandCheckStopPlayBytes,
// publish
onSrsBandCheckStartPublishBytes: onSrsBandCheckStartPublishBytes,
onSrsBandCheckStopPublishBytes: onSrsBandCheckStopPublishBytes,
onSrsBandCheckFinished: onSrsBandCheckFinished
};
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
connection.connect(url);
__on_progress_change(3);
}
private function js_call_stop():void {
if (connection) {
connection.close();
connection = null;
}
}
/**
* NetConnection callback this function, when recv server call "onSrsBandCheckStartPlayBytes"
* then start @updatePlayProgressTimer for updating the progressbar
* */
private function onSrsBandCheckStartPlayBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
trace("start play test, duration=" + duration_ms + ", interval=" + interval_ms);
connection.call("onSrsBandCheckStartingPlayBytes", null);
__on_status_change(SrsBandwidth.StatusSrsBwtcPlayStart);
__on_progress_change(10);
}
private function onSrsBandCheckPlaying(evt:Object):void{
}
private function onSrsBandCheckStopPlayBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
var duration_delta:Number = evt.duration_delta;
var bytes_delta:Number = evt.bytes_delta;
var kbps:Number = 0;
if(duration_delta > 0){
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
}
kbps = (int(kbps * 10))/10.0;
flash.utils.setTimeout(stopPlayTest, 0);
__on_status_change(SrsBandwidth.StatusSrsBwtcPlayStop, String(kbps));
__on_progress_change(40);
}
private function stopPlayTest():void{
connection.call("onSrsBandCheckStoppedPlayBytes", null);
}
/**
* publishing methods.
*/
private function onSrsBandCheckStartPublishBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
connection.call("onSrsBandCheckStartingPublishBytes", null);
flash.utils.setTimeout(publisher, 0);
__on_status_change(SrsBandwidth.StatusSrsBwtcPublishStart);
__on_progress_change(60);
}
private function publisher():void{
var data:Array = new Array();
var data_size:int = 100;
for(var i:int; i < data_size; i++) {
data.push("SrS band check data from client's publishing......");
}
connection.call("onSrsBandCheckPublishing", null, data);
publish_timeout_handler = flash.utils.setTimeout(publisher, 0);
}
private function onSrsBandCheckStopPublishBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
var duration_delta:Number = evt.duration_delta;
var bytes_delta:Number = evt.bytes_delta;
var kbps:Number = 0;
if(duration_delta > 0){
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
}
kbps = (int(kbps * 10))/10.0;
stopPublishTest();
__on_progress_change(90);
}
private function stopPublishTest():void{
// the stop publish response packet can not send out, for the queue is full.
//connection.call("onSrsBandCheckStoppedPublishBytes", null);
// clear the timeout to stop the send loop.
if (publish_timeout_handler > 0) {
flash.utils.clearTimeout(publish_timeout_handler);
publish_timeout_handler = 0;
}
}
private function onSrsBandCheckFinished(evt:Object):void{
var code:Number = evt.code;
var start_time:Number = evt.start_time;
var end_time:Number = evt.end_time;
var play_kbps:Number = evt.play_kbps;
var publish_kbps:Number = evt.publish_kbps;
var play_bytes:Number = evt.play_bytes;
var play_time:Number = evt.play_time;
var publish_bytes:Number = evt.publish_bytes;
var publish_time:Number = evt.publish_time;
if (this.as_on_complete != null) {
this.as_on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
}
if (this.js_on_complete != null) {
flash.external.ExternalInterface.call(this.js_on_complete, this.js_id,
start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
}
__on_progress_change(100);
// when got finish packet, directly close connection.
js_call_stop();
// the last final packet can not send out, for the queue is full.
//connection.call("finalClientPacket", null);
}
/**
* get NetConnection NetStatusEvent
*/
private function onStatus(evt:NetStatusEvent): void {
trace(evt.info.code);
if (evt.info.hasOwnProperty("data") && evt.info.data) {
if (evt.info.data.hasOwnProperty("srs_server")) {
srs_server = evt.info.data.srs_server;
}
if (evt.info.data.hasOwnProperty("srs_primary_authors")) {
srs_primary_authors = evt.info.data.srs_primary_authors;
}
if (evt.info.data.hasOwnProperty("srs_id")) {
srs_id = evt.info.data.srs_id;
}
if (evt.info.data.hasOwnProperty("srs_pid")) {
srs_pid = evt.info.data.srs_pid;
}
if (evt.info.data.hasOwnProperty("srs_server_ip")) {
srs_server_ip = evt.info.data.srs_server_ip;
}
if (this.as_on_srs_info != null) {
this.as_on_srs_info(srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip);
}
if (this.js_on_srs_info != null) {
flash.external.ExternalInterface.call(this.js_on_srs_info, this.js_id,
srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip);
}
}
if (evt.info.code) {
__on_status_change(evt.info.code);
}
switch(evt.info.code){
case "NetConnection.Connect.Success":
__on_progress_change(8);
break;
}
}
/**
* invoke the callback.
*/
private function __on_progress_change(percent:Number):void {
if (this.as_on_progress_change != null) {
this.as_on_progress_change(percent);
}
if (this.js_on_progress_change != null) {
flash.external.ExternalInterface.call(this.js_on_progress_change, this.js_id,
percent);
}
}
private function __on_status_change(code:String, data:String=""):void {
if (this.as_on_status_change != null) {
this.as_on_status_change(code, data);
}
if (this.js_on_status_change != null) {
flash.external.ExternalInterface.call(this.js_on_status_change, this.js_id,
code, data);
}
}
}
}

View file

@ -1,7 +1,5 @@
package
{
import SrsClass.SrsElapsedTimer;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.display.StageAlign;
@ -17,35 +15,20 @@ package
import flash.ui.ContextMenuItem;
import flash.utils.Timer;
import flash.utils.setTimeout;
import srs.SrsBandwidth;
public class srs_bwt extends Sprite
{
private var connection:NetConnection = null;
private var updatePlayProgressTimer:Timer = null;
private var elapTimer:SrsElapsedTimer = null;
{
/**
* the SRS bandwidth check/test library object.
*/
private var bandwidth:SrsBandwidth = new SrsBandwidth();
// user set id.
private var js_id:String = null;
// play param url.
private var user_url:String = null;
// server ip get from server
private var server_ip:String;
// test wheth publish should to stop
private var stop_pub:Boolean = false;
// js interface
private var js_on_player_ready:String;
private var js_update_progress:String;
private var js_update_status:String;
private var value_progressbar:Number = 0;
private var max_progressbar:Number = 0;
// set NetConnection ObjectEncoding to AMF0
NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;
/**
* when not specifies any param, directly run the swf.
*/
private var default_url:String = "rtmp://dev:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com";
public function srs_bwt()
{
@ -55,91 +38,81 @@ package
this.system_on_add_to_stage(null);
}
}
/**
* system event callback, when this control added to stage.
* the main function.
*/
private function system_on_add_to_stage(evt:Event):void {
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
var flashvars:Object = this.root.loaderInfo.parameters;
if (!flashvars.hasOwnProperty("id")) {
throw new Error("must specifies the id");
}
// init context menu
var myMenu:ContextMenu = new ContextMenu();
myMenu.hideBuiltInItems();
myMenu.customItems.push(new ContextMenuItem("SRS带宽测试工具", true));
this.contextMenu = myMenu;
this.js_id = flashvars.id;
this.js_on_player_ready = flashvars.on_bandwidth_ready;
this.js_update_progress = flashvars.on_update_progress;
this.js_update_status = flashvars.on_update_status;
// init context menu
var myMenu:ContextMenu = new ContextMenu();
myMenu.hideBuiltInItems();
myMenu.customItems.push(new ContextMenuItem("SRS 带宽测试工具", true));
this.contextMenu = myMenu;
flash.utils.setTimeout(this.system_on_js_ready, 0);
check_bandwidth();
}
/**
* system callack event, when js ready, register callback for js.
* the actual main function.
*/
private function system_on_js_ready():void {
if (!flash.external.ExternalInterface.available) {
trace("js not ready, try later.");
flash.utils.setTimeout(this.system_on_js_ready, 100);
return;
}
flash.external.ExternalInterface.addCallback("__check_bandwidth", this.js_call_check_bandwidth);
flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
flash.external.ExternalInterface.call(this.js_on_player_ready, this.js_id);
}
private function js_call_check_bandwidth(url:String):void {
js_call_stop();
// init connection
connection = new NetConnection;
connection.client = this;
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
connection.connect(url);
//connection.connect("rtmp://192.168.8.234:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com");
private function check_bandwidth():void {
// closure
var self:srs_bwt = this;
// for play to update progress bar
elapTimer = new SrsElapsedTimer;
// we suppose the check time = 7 S
updatePlayProgressTimer = new Timer(100);
updatePlayProgressTimer.addEventListener(TimerEvent.TIMER, onTimerTimeout);
updatePlayProgressTimer.start();
}
private function js_call_stop():void {
if (connection) {
connection.close();
connection = null;
}
if (updatePlayProgressTimer) {
updatePlayProgressTimer.stop();
updatePlayProgressTimer = null;
}
if (elapTimer) {
elapTimer.restart();
}
/////////////////////////////////////////////////////////////////////
// initialize the bandwidth check/test library
/////////////////////////////////////////////////////////////////////
// js callback, set to null if ignore.
var conf:Object = this.root.loaderInfo.parameters;
var js_id:String = conf.id? conf.id:null;
var js_on_ready:String = conf.on_bandwidth_ready? conf.on_bandwidth_ready:null;
var js_on_srs_info:String = conf.on_srs_info? conf.on_srs_info:null;
var js_on_progress_change:String = conf.on_update_progress? conf.on_update_progress:null;
var js_on_status_change:String = conf.on_update_status? conf.on_update_status:null;
var js_on_complete:String = conf.on_complete? conf.on_complete:null;
// js export, set to null to disable
var js_export_check_bandwidth:String = "__check_bandwidth";
var js_export_stop:String = "__stop";
// as callback, set to null if ignore.
var as_on_ready:Function = function():void {
self.on_ready();
};
var as_on_status_change:Function = function(code:String, data:String):void {
self.on_status_change(code, data);
};
var as_on_progress_change:Function = function(percent:Number):void {
self.on_progress(percent);
};
var as_on_srs_info:Function = function(srs_server:String, srs_primary_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void {
self.update_context_items(srs_server, srs_primary_authors, srs_id, srs_pid, srs_server_ip);
};
var as_on_complete:Function = function(start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void {
self.on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
};
bandwidth.initialize(
as_on_ready, as_on_status_change, as_on_progress_change, as_on_srs_info, as_on_complete,
js_id, js_on_ready, js_on_status_change, js_on_progress_change, js_on_srs_info, js_on_complete,
js_export_check_bandwidth, js_export_stop
);
/////////////////////////////////////////////////////////////////////
}
// srs infos
private var srs_server:String = null;
private var srs_primary_authors:String = null;
private var srs_id:String = null;
private var srs_pid:String = null;
private var srs_server_ip:String = null;
private function update_context_items():void {
private function on_ready():void {
var conf:Object = this.root.loaderInfo.parameters;
// for directly run swf.
if (!conf.id) {
trace("directly run swf, load default url: " + this.default_url);
this.bandwidth.check_bandwidth(this.default_url);
}
}
private function on_progress(percent:Number):void {
trace("progress:" + percent + "%");
}
private function update_context_items(
srs_server:String, srs_primary_authors:String,
srs_id:String, srs_pid:String, srs_server_ip:String
):void {
// for context menu
var customItems:Array = [new ContextMenuItem("SrsPlayer")];
if (srs_server != null) {
@ -159,172 +132,42 @@ package
}
contextMenu.customItems = customItems;
}
// get NetConnection NetStatusEvent
public function onStatus(evt:NetStatusEvent) : void{
trace(evt.info.code);
if (evt.info.hasOwnProperty("data") && evt.info.data) {
if (evt.info.data.hasOwnProperty("srs_server")) {
srs_server = evt.info.data.srs_server;
}
if (evt.info.data.hasOwnProperty("srs_primary_authors")) {
srs_primary_authors = evt.info.data.srs_primary_authors;
}
if (evt.info.data.hasOwnProperty("srs_id")) {
srs_id = evt.info.data.srs_id;
}
if (evt.info.data.hasOwnProperty("srs_pid")) {
srs_pid = evt.info.data.srs_pid;
}
if (evt.info.data.hasOwnProperty("srs_server_ip")) {
srs_server_ip = evt.info.data.srs_server_ip;
}
update_context_items();
}
switch(evt.info.code){
public function on_status_change(code:String, data:String): void {
trace(code);
switch(code){
case "NetConnection.Connect.Failed":
updateState("连接服务器失败!");
trace("连接服务器失败!");
break;
case "NetConnection.Connect.Rejected":
updateState("服务器拒绝连接!");
trace("服务器拒绝连接!");
break;
case "NetConnection.Connect.Success":
server_ip = evt.info.data.srs_server_ip;
updateState("连接服务器成功!");
trace("连接服务器成功!");
break;
case SrsBandwidth.StatusSrsBwtcPlayStart:
trace("开始测试下行带宽");
break;
case SrsBandwidth.StatusSrsBwtcPlayStop:
trace("下行带宽测试完毕," + data + "kbps开始测试上行带宽。");
break;
case SrsBandwidth.StatusSrsBwtcPublishStart:
trace("开始测试上行带宽");
break;
case SrsBandwidth.StatusSrsBwtcPublishStop:
trace("上行带宽测试完毕," + data + "kbps");
break;
case "NetConnection.Connect.Closed":
//updateState("连接已断开!");
trace("连接已断开!");
break;
}
}
public function onTimerTimeout(evt:TimerEvent):void
{
value_progressbar = elapTimer.elapsed();
updateProgess(value_progressbar, max_progressbar);
}
/**
* NetConnection callback this function, when recv server call "onSrsBandCheckStartPlayBytes"
* then start @updatePlayProgressTimer for updating the progressbar
* */
public function onSrsBandCheckStartPlayBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
connection.call("onSrsBandCheckStartingPlayBytes", null);
updateState("开始测试下行带宽服务器IP" + server_ip);
// we suppose play duration_ms = pub duration_ms
max_progressbar = duration_ms * 2;
}
public function onSrsBandCheckPlaying(evt:Object):void{
}
public function onSrsBandCheckStopPlayBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
var duration_delta:Number = evt.duration_delta;
var bytes_delta:Number = evt.bytes_delta;
var kbps:Number = 0;
if(duration_delta > 0){
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
}
kbps = (int(kbps * 10))/10.0;
flash.utils.setTimeout(stopPlayTest, 0);
updateState("下行带宽测试完毕,服务器: " + server_ip + "" + kbps + "kbps开始测试上行带宽。");
}
private function stopPlayTest():void{
connection.call("onSrsBandCheckStoppedPlayBytes", null);
}
public function onSrsBandCheckStartPublishBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
connection.call("onSrsBandCheckStartingPublishBytes", null);
flash.utils.setTimeout(publisher, 0);
}
private function publisher():void{
if (stop_pub) {
return;
}
var data:Array = new Array();
var data_size:int = 100;
for(var i:int; i < data_size; i++){
data.push("SrS band check data from client's publishing......");
}
data_size += 100;
connection.call("onSrsBandCheckPublishing", null, data);
flash.utils.setTimeout(publisher, 0);
}
public function onSrsBandCheckStopPublishBytes(evt:Object):void{
var duration_ms:Number = evt.duration_ms;
var interval_ms:Number = evt.interval_ms;
var duration_delta:Number = evt.duration_delta;
var bytes_delta:Number = evt.bytes_delta;
var kbps:Number = 0;
if(duration_delta > 0){
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
}
kbps = (int(kbps * 10))/10.0;
stopPublishTest();
}
private function stopPublishTest():void{
if(connection.connected){
connection.call("onSrsBandCheckStoppedPublishBytes", null);
}
stop_pub = true;
value_progressbar = max_progressbar;
updateProgess(value_progressbar, max_progressbar);
updatePlayProgressTimer.stop();
}
public function onSrsBandCheckFinished(evt:Object):void{
var code:Number = evt.code;
var start_time:Number = evt.start_time;
var end_time:Number = evt.end_time;
var play_kbps:Number = evt.play_kbps;
var publish_kbps:Number = evt.publish_kbps;
var play_bytes:Number = evt.play_bytes;
var play_time:Number = evt.play_time;
var publish_bytes:Number = evt.publish_bytes;
var publish_time:Number = evt.publish_time;
updateState("检测结束: 服务器: " + server_ip + " 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
+ " 测试时间: " + (end_time-start_time)/1000 + " 秒");
connection.call("finalClientPacket", null);
}
// update progressBar's value
private function updateProgess(value:Number, maxValue:Number):void{
flash.external.ExternalInterface.call(this.js_update_progress, this.js_id, value * 100 / maxValue);
trace(value + "-" + maxValue + "-" + value * 100 / maxValue + "%");
}
// update checking status
private function updateState(text:String):void{
flash.external.ExternalInterface.call(this.js_update_status, this.js_id, text);
trace(text);
}
public function onBWDone():void{
private function on_complete(
start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number,
play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number
):void {
var status:String = "检测结束: 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
+ " 测试时间: " + Number((end_time - start_time) / 1000).toFixed(1) + " 秒";
trace(status);
}
}
}

View file

@ -115,19 +115,23 @@ int SrsBandwidth::do_bandwidth_check()
int64_t start_time = srs_get_system_time_ms();
srs_info("start play test.");
ret = check_play(play_duration_ms,
play_interval_ms, play_actual_duration_ms, play_bytes, limit_kbps);
if (ret != ERROR_SUCCESS) {
srs_error("band width play check failed. ret=%d", ret);
return ret;
}
srs_info("stop play test.");
srs_info("start publish test.");
ret = check_publish(publish_duration_ms,
publish_interval_ms, publish_actual_duration_ms, publish_bytes, limit_kbps);
if (ret != ERROR_SUCCESS) {
srs_error("band width publish check failed. ret=%d", ret);
return ret;
}
srs_info("stop publish test.");
int64_t end_time = srs_get_system_time_ms();
int play_kbps = play_bytes * 8 / play_actual_duration_ms;
@ -138,7 +142,9 @@ int SrsBandwidth::do_bandwidth_check()
start_time, end_time, (int)(end_time - start_time), play_kbps, publish_kbps,
_req->tcUrl.c_str(), ret);
// send finished msg
// send finished msg,
// flash client will close connection when got this packet,
// for the publish queue may contains packets.
SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_finish();
pkt->data->set("code", SrsAmf0Any::number(ERROR_SUCCESS));
pkt->data->set("start_time", SrsAmf0Any::number(start_time));
@ -154,9 +160,12 @@ int SrsBandwidth::do_bandwidth_check()
srs_error("send bandwidth check finish message failed. ret=%d", ret);
return ret;
}
srs_info("send finish packet.");
// if flash, we notice the result, and expect a final packet.
while (true) {
// we notice the result, and expect a final packet if not flash.
// if flash client, client will disconnect when got finish packet.
bool is_flash = (_req->swfUrl != "");
while (!is_flash) {
SrsMessage* msg = NULL;
SrsBandwidthPacket* pkt = NULL;
if ((ret = _rtmp->expect_message<SrsBandwidthPacket>(&msg, &pkt)) != ERROR_SUCCESS) {
@ -196,8 +205,8 @@ int SrsBandwidth::check_play(
srs_error("send bandwidth check start play message failed. ret=%d", ret);
return ret;
}
srs_info("BW check begin.");
}
srs_info("BW check begin.");
while (true) {
// recv client's starting play response
@ -212,10 +221,10 @@ int SrsBandwidth::check_play(
srs_info("get bandwidth message succes.");
if (pkt->is_starting_play()) {
srs_info("BW check recv play begin response.");
break;
}
}
srs_info("BW check recv play begin response.");
// send play data to client
int64_t current_time = srs_get_system_time_ms();
@ -277,8 +286,8 @@ int SrsBandwidth::check_play(
srs_error("send bandwidth check stop play message failed. ret=%d", ret);
return ret;
}
srs_info("BW check stop play bytes.");
}
srs_info("BW check stop play bytes.");
while (true) {
// recv client's stop play response.
@ -293,10 +302,10 @@ int SrsBandwidth::check_play(
srs_info("get bandwidth message succes.");
if (pkt->is_stopped_play()) {
srs_info("BW check recv stop play response.");
break;
}
}
srs_info("BW check recv stop play response.");
return ret;
}
@ -318,8 +327,8 @@ int SrsBandwidth::check_publish(
srs_error("send bandwidth check start publish message failed. ret=%d", ret);
return ret;
}
srs_info("BW check publish begin.");
}
srs_info("BW check publish begin.");
while (true) {
// read client's notification of starting publish
@ -334,14 +343,14 @@ int SrsBandwidth::check_publish(
srs_info("get bandwidth message succes.");
if (pkt->is_starting_publish()) {
srs_info("BW check recv publish begin response.");
break;
}
}
srs_info("BW check recv publish begin response.");
// recv publish msgs until @duration_ms ms
int64_t current_time = srs_get_system_time_ms();
while ( (srs_get_system_time_ms() - current_time) < duration_ms ) {
while ((srs_get_system_time_ms() - current_time) < duration_ms) {
st_usleep(0);
SrsMessage* msg = NULL;
@ -380,16 +389,16 @@ int SrsBandwidth::check_publish(
srs_error("send bandwidth check stop publish message failed. ret=%d", ret);
return ret;
}
srs_info("BW check stop publish bytes.");
}
srs_info("BW check stop publish bytes.");
// expect client to stop publish
// if flash client, we never expect the client stop publish bytes,
// for the flash send call packet to test publish bandwidth,
// there are many many packets in the queue.
// we just ignore the packet and send the bandwidth test data.
// TODO: FIXME: check whether flash client.
while (false) {
bool is_flash = (_req->swfUrl != "");
while (!is_flash) {
// recv client's stop publish response.
SrsMessage* msg = NULL;
SrsBandwidthPacket* pkt = NULL;
@ -402,10 +411,10 @@ int SrsBandwidth::check_publish(
srs_info("get bandwidth message succes.");
if (pkt->is_stopped_publish()) {
srs_info("BW check recv stop publish response.");
break;
}
}
srs_info("BW check recv stop publish response.");
return ret;
}

View file

@ -67,10 +67,10 @@ class SrsRtmpServer;
* | final(2)------------> | finalClientPacket
* | <END> |
*
* 1. when flash client, server ignore the publish stopped result,
* and directly send the report to flash client.
* 2. flash client only. when got report, flash client should send out
* a final packet and close the connection immediately.
* 1. when flash client, server never wait the stop publish response,
* for the flash client queue is fullfill with other packets.
* 2. when flash client, server never wait the final packet,
* for the flash client directly close when got report packet.
*/
class SrsBandwidth
{

View file

@ -69,7 +69,7 @@ int SrsConnection::cycle()
// success.
if (ret == ERROR_SUCCESS) {
srs_trace("client process normally finished. ret=%d", ret);
srs_trace("client finished.");
}
// client close peer.

View file

@ -720,7 +720,7 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream,
*ppacket = packet = new SrsSetChunkSizePacket();
return packet->decode(stream);
} else {
if (!header.is_set_peer_bandwidth()) {
if (!header.is_set_peer_bandwidth() && !header.is_ackledgement()) {
srs_trace("drop unknown message, type=%d", header.message_type);
}
}

View file

@ -223,7 +223,9 @@ public:
while (true) {
SrsMessage* msg = NULL;
if ((ret = recv_message(&msg)) != ERROR_SUCCESS) {
srs_error("recv message failed. ret=%d", ret);
if (ret != ERROR_SOCKET_TIMEOUT && !srs_is_client_gracefully_close(ret)) {
srs_error("recv message failed. ret=%d", ret);
}
return ret;
}
srs_verbose("recv message success.");