wenjiegit

add linux version of band check app; add web version of band check app

  1 +// for bw to init url
  2 +// url: scheme://host:port/path?query#fragment
  3 +function srs_init_bwt(rtmp_url, hls_url) {
  4 + update_nav();
  5 +
  6 + if (rtmp_url) {
  7 + //var query = parse_query_string();
  8 + var search_filed = String(window.location.search).replace(" ", "").split("?")[1];
  9 + $(rtmp_url).val("rtmp://" + window.location.host + ":" + 1935 + "/app?" + search_filed);
  10 + }
  11 + if (hls_url) {
  12 + $(hls_url).val(build_default_hls_url());
  13 + }
  14 +}
  15 +
  16 +function srs_bwt_check_url(url) {
  17 + if (url.indexOf("key") != -1 && url.indexOf("vhost") != -1) {
  18 + return true;
  19 + }
  20 +
  21 + return false;
  22 +}
  23 +
  24 +function srs_bwt_build_default_url() {
  25 + var url_default = "rtmp://" + window.location.host + ":" + 1935 + "/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com";
  26 + return url_default;
  27 +}
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<actionScriptProperties analytics="false" mainApplicationPath="srs_bwt.as" projectUUID="00251213-e6a2-4dd5-a033-125cc78f843c" version="10">
  3 + <compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="true" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="true" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="bin-debug" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
  4 + <compilerSourcePath/>
  5 + <libraryPath defaultLinkType="0">
  6 + <libraryPathEntry kind="4" path="">
  7 + <excludedEntries>
  8 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
  9 + <libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
  10 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
  11 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
  12 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
  13 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
  14 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
  15 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
  16 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
  17 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
  18 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
  19 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
  20 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
  21 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
  22 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
  23 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
  24 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
  25 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
  26 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
  27 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
  28 + <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
  29 + </excludedEntries>
  30 + </libraryPathEntry>
  31 + </libraryPath>
  32 + <sourceAttachmentPath/>
  33 + </compiler>
  34 + <applications>
  35 + <application path="srs_bwt.as"/>
  36 + </applications>
  37 + <modules/>
  38 + <buildCSSFiles/>
  39 + <flashCatalyst validateFlashCatalystCompatibility="false"/>
  40 +</actionScriptProperties>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<projectDescription>
  3 + <name>srs_bwt</name>
  4 + <comment></comment>
  5 + <projects>
  6 + </projects>
  7 + <buildSpec>
  8 + <buildCommand>
  9 + <name>com.adobe.flexbuilder.project.flexbuilder</name>
  10 + <arguments>
  11 + </arguments>
  12 + </buildCommand>
  13 + </buildSpec>
  14 + <natures>
  15 + <nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
  16 + </natures>
  17 +</projectDescription>
  1 +package SrsClass
  2 +{
  3 + import flash.system.System;
  4 +
  5 + public class SrsElapsedTimer
  6 + {
  7 + private var beginDate:Date;
  8 + public function SrsElapsedTimer()
  9 + {
  10 + beginDate = new Date;
  11 + }
  12 +
  13 + public function elapsed():Number{
  14 + var endDate:Date = new Date;
  15 +
  16 + // get deiff by ms
  17 + return (endDate.time - beginDate.time);
  18 + }
  19 +
  20 + public function restart():void{
  21 + beginDate = new Date;
  22 + }
  23 + }
  24 +}
  1 +package SrsClass
  2 +{
  3 + import flash.net.SharedObject;
  4 +
  5 + public class SrsSettings
  6 + {
  7 + private var settings:SharedObject;
  8 + private var key:String = "SrsBandCheck";
  9 +
  10 + public function SrsSettings()
  11 + {
  12 + settings = SharedObject.getLocal(key);
  13 + }
  14 +
  15 + public function addAddressText(val:String):void{
  16 + settings.data.address_text = val;
  17 + }
  18 +
  19 + public function addressText():String{
  20 + return settings.data.address_text;
  21 + }
  22 +
  23 + static public function instance():SrsSettings{
  24 + return new SrsSettings;
  25 + }
  26 + }
  27 +}
  1 +package
  2 +{
  3 + import SrsClass.SrsElapsedTimer;
  4 +
  5 + import flash.display.LoaderInfo;
  6 + import flash.display.Sprite;
  7 + import flash.display.StageAlign;
  8 + import flash.display.StageScaleMode;
  9 + import flash.events.Event;
  10 + import flash.events.NetStatusEvent;
  11 + import flash.events.TimerEvent;
  12 + import flash.external.ExternalInterface;
  13 + import flash.net.NetConnection;
  14 + import flash.net.ObjectEncoding;
  15 + import flash.system.System;
  16 + import flash.ui.ContextMenu;
  17 + import flash.ui.ContextMenuItem;
  18 + import flash.utils.Timer;
  19 + import flash.utils.setTimeout;
  20 +
  21 + public class srs_bwt extends Sprite
  22 + {
  23 + private var connection:NetConnection;
  24 +
  25 + private var updatePlayProgressTimer:Timer;
  26 + private var elapTimer:SrsElapsedTimer;
  27 +
  28 + // server ip get from server
  29 + private var server_ip:String;
  30 +
  31 + // test wheth publish should to stop
  32 + private var stop_pub:Boolean = false;
  33 +
  34 + // js interface
  35 + private var js_update_progress:String;
  36 + private var js_progress_reset:String;
  37 + private var js_update_status:String;
  38 +
  39 + private var value_progressbar:Number = 0;
  40 + private var max_progressbar:Number = 0;
  41 +
  42 + // set NetConnection ObjectEncoding to AMF0
  43 + NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;
  44 +
  45 + public function srs_bwt()
  46 + {
  47 + this.stage.scaleMode = StageScaleMode.NO_SCALE;
  48 + this.stage.align = StageAlign.TOP_LEFT;
  49 +
  50 + var flashvars:Object = this.root.loaderInfo.parameters;
  51 + this.js_update_progress = flashvars.update_progress;
  52 + this.js_progress_reset = flashvars.progress_reset;
  53 + this.js_update_status = flashvars.update_status;
  54 +
  55 + // init context menu, add action "Srs 带宽测试工具 0.1"
  56 + var myMenu:ContextMenu = new ContextMenu();
  57 + myMenu.hideBuiltInItems();
  58 + myMenu.customItems.push(new ContextMenuItem("Srs 带宽测试工具 0.1", true));
  59 + this.contextMenu = myMenu;
  60 +
  61 + // init connection
  62 + connection = new NetConnection;
  63 + connection.client = this;
  64 + connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
  65 + connection.connect(flashvars.url);
  66 + //connection.connect("rtmp://192.168.8.234:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com");
  67 +
  68 + // for play to update progress bar
  69 + elapTimer = new SrsElapsedTimer;
  70 +
  71 + // we suppose the check time = 7 S
  72 + updatePlayProgressTimer = new Timer(100);
  73 + updatePlayProgressTimer.addEventListener(TimerEvent.TIMER, onTimerTimeout);
  74 + updatePlayProgressTimer.start();
  75 + }
  76 +
  77 + // get NetConnection NetStatusEvent
  78 + public function onStatus(evt:NetStatusEvent) : void{
  79 + trace(evt.info.code);
  80 + switch(evt.info.code){
  81 + case "NetConnection.Connect.Failed":
  82 + updateState("连接服务器失败!");
  83 + break;
  84 + case "NetConnection.Connect.Rejected":
  85 + updateState("服务器拒绝连接!");
  86 + break;
  87 + case "NetConnection.Connect.Success":
  88 + server_ip = evt.info.data.srs_server_ip;
  89 + updateState("连接服务器成功!");
  90 + break;
  91 + case "NetConnection.Connect.Closed":
  92 + //updateState("连接已断开!");
  93 + break;
  94 + }
  95 +
  96 + }
  97 +
  98 + /**
  99 + * NetConnection callback this function, when recv server call "onSrsBandCheckStartPlayBytes"
  100 + * then start @updatePlayProgressTimer for updating the progressbar
  101 + * */
  102 + public function onSrsBandCheckStartPlayBytes(evt:Object):void{
  103 + var duration_ms:Number = evt.duration_ms;
  104 + var interval_ms:Number = evt.interval_ms;
  105 +
  106 + connection.call("onSrsBandCheckStartingPlayBytes", null);
  107 + updateState("测试下行带宽(" + server_ip + ")");
  108 +
  109 + // we suppose play duration_ms = pub duration_ms
  110 + max_progressbar = duration_ms * 2;
  111 + }
  112 +
  113 + public function onSrsBandCheckPlaying(evt:Object):void{
  114 +
  115 + }
  116 +
  117 + public function onTimerTimeout(evt:TimerEvent):void
  118 + {
  119 + value_progressbar = elapTimer.elapsed();
  120 + updateProgess(value_progressbar, max_progressbar);
  121 + }
  122 +
  123 + public function onSrsBandCheckStopPlayBytes(evt:Object):void{
  124 + var duration_ms:Number = evt.duration_ms;
  125 + var interval_ms:Number = evt.interval_ms;
  126 + var duration_delta:Number = evt.duration_delta;
  127 + var bytes_delta:Number = evt.bytes_delta;
  128 +
  129 + var kbps:Number = 0;
  130 + if(duration_delta > 0){
  131 + kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
  132 + }
  133 + kbps = (int(kbps * 10))/10.0;
  134 +
  135 + flash.utils.setTimeout(stopPlayTest, 0);
  136 + }
  137 +
  138 + private function stopPlayTest():void{
  139 + connection.call("onSrsBandCheckStoppedPlayBytes", null);
  140 + }
  141 +
  142 + public function onSrsBandCheckStartPublishBytes(evt:Object):void{
  143 + var duration_ms:Number = evt.duration_ms;
  144 + var interval_ms:Number = evt.interval_ms;
  145 +
  146 + connection.call("onSrsBandCheckStartingPublishBytes", null);
  147 + updateState("测试上行带宽(" + server_ip + ")");
  148 +
  149 + flash.utils.setTimeout(publisher, 0);
  150 + }
  151 +
  152 + private function publisher():void{
  153 + if (stop_pub) {
  154 + return;
  155 + }
  156 +
  157 + var data:Array = new Array();
  158 +
  159 + var data_size:int = 100;
  160 + for(var i:int; i < data_size; i++){
  161 + data.push("SrS band check data from client's publishing......");
  162 + }
  163 + data_size += 100;
  164 + connection.call("onSrsBandCheckPublishing", null, data);
  165 +
  166 + flash.utils.setTimeout(publisher, 0);
  167 + }
  168 +
  169 + public function onSrsBandCheckStopPublishBytes(evt:Object):void{
  170 + var duration_ms:Number = evt.duration_ms;
  171 + var interval_ms:Number = evt.interval_ms;
  172 + var duration_delta:Number = evt.duration_delta;
  173 + var bytes_delta:Number = evt.bytes_delta;
  174 +
  175 + var kbps:Number = 0;
  176 + if(duration_delta > 0){
  177 + kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
  178 + }
  179 + kbps = (int(kbps * 10))/10.0;
  180 +
  181 + stopPublishTest();
  182 + }
  183 +
  184 + private function stopPublishTest():void{
  185 + if(connection.connected){
  186 + connection.call("onSrsBandCheckStoppedPublishBytes", null);
  187 + }
  188 + stop_pub = true;
  189 +
  190 + value_progressbar = max_progressbar;
  191 + updateProgess(value_progressbar, max_progressbar);
  192 + updatePlayProgressTimer.stop();
  193 + }
  194 +
  195 + public function onSrsBandCheckFinished(evt:Object):void{
  196 + var code:Number = evt.code;
  197 + var start_time:Number = evt.start_time;
  198 + var end_time:Number = evt.end_time;
  199 + var play_kbps:Number = evt.play_kbps;
  200 + var publish_kbps:Number = evt.publish_kbps;
  201 + var play_bytes:Number = evt.play_bytes;
  202 + var play_time:Number = evt.play_time;
  203 + var publish_bytes:Number = evt.publish_bytes;
  204 + var publish_time:Number = evt.publish_time;
  205 +
  206 + updateState("检测结束: 服务器: " + server_ip + " 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
  207 + + " 测试时间: " + (end_time-start_time)/1000 + " 秒");
  208 + connection.call("finalClientPacket", null);
  209 + }
  210 +
  211 + public function onBWDone():void{
  212 + // do nothing
  213 + }
  214 +
  215 + // update progressBar's value
  216 + private function updateProgess(value:Number, maxValue:Number):void{
  217 + flash.external.ExternalInterface.call(this.js_update_progress, value * 100 / maxValue + "%");
  218 + trace(value + "-" + maxValue + "-" + value * 100 / maxValue + "%");
  219 + }
  220 +
  221 + // update checking status
  222 + private function updateState(text:String):void{
  223 + flash.external.ExternalInterface.call(this.js_update_status, text);
  224 + trace(text);
  225 + }
  226 + }
  227 +}
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 wenjiegit
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <sys/socket.h>
  25 +#include <netinet/in.h>
  26 +#include <arpa/inet.h>
  27 +#include <sstream>
  28 +#include <getopt.h>
  29 +#include <stdlib.h>
  30 +
  31 +#include <srs_core_rtmp.hpp>
  32 +#include <srs_core_protocol.hpp>
  33 +#include <srs_core_error.hpp>
  34 +#include <srs_core_amf0.hpp>
  35 +#include <srs_core_autofree.hpp>
  36 +#include <srs_core_stream.hpp>
  37 +
  38 +#include <st.h>
  39 +
  40 +// server play control
  41 +#define SRS_BW_CHECK_START_PLAY "onSrsBandCheckStartPlayBytes"
  42 +#define SRS_BW_CHECK_STARTING_PLAY "onSrsBandCheckStartingPlayBytes"
  43 +#define SRS_BW_CHECK_STOP_PLAY "onSrsBandCheckStopPlayBytes"
  44 +#define SRS_BW_CHECK_STOPPED_PLAY "onSrsBandCheckStoppedPlayBytes"
  45 +
  46 +// server publish control
  47 +#define SRS_BW_CHECK_START_PUBLISH "onSrsBandCheckStartPublishBytes"
  48 +#define SRS_BW_CHECK_STARTING_PUBLISH "onSrsBandCheckStartingPublishBytes"
  49 +#define SRS_BW_CHECK_STOP_PUBLISH "onSrsBandCheckStopPublishBytes"
  50 +#define SRS_BW_CHECK_STOPPED_PUBLISH "onSrsBandCheckStoppedPublishBytes"
  51 +
  52 +// EOF control.
  53 +#define SRS_BW_CHECK_FINISHED "onSrsBandCheckFinished"
  54 +#define SRS_BW_CHECK_FLASH_FINAL "finalClientPacket"
  55 +
  56 +// client only
  57 +#define SRS_BW_CHECK_PLAYING "onSrsBandCheckPlaying"
  58 +#define SRS_BW_CHECK_PUBLISHING "onSrsBandCheckPublishing"
  59 +
  60 +/**
  61 +* @brief class of Linux version band check client
  62 +* check play and publish speed.
  63 +*/
  64 +class SrsBandCheckClient : public SrsRtmpClient
  65 +{
  66 +public:
  67 + SrsBandCheckClient(st_netfd_t _stfd);
  68 + ~SrsBandCheckClient();
  69 +
  70 +public:
  71 + /**
  72 + * @brief test play
  73 + *
  74 + */
  75 + int check_play();
  76 + /**
  77 + * @brief test publish
  78 + *
  79 + */
  80 + int check_publish();
  81 +
  82 +private:
  83 + /**
  84 + * @brief just return success.
  85 + */
  86 + int create_stream(int& stream_id);
  87 + /**
  88 + * @brief just return success.
  89 + */
  90 + int play(std::string stream, int stream_id);
  91 + /**
  92 + * @brief just return success.
  93 + */
  94 + int publish(std::string stream, int stream_id);
  95 +
  96 +private:
  97 + int expect_start_play();
  98 + int send_starting_play();
  99 + int expect_stop_play();
  100 + int send_stopped_play();
  101 + int expect_start_pub();
  102 + int send_starting_pub();
  103 + int send_pub_data();
  104 + int expect_stop_pub();
  105 + /**
  106 + * @brief expect result.
  107 + * because the core module has no method to decode this packet
  108 + * so we must get the internal data and decode it here.
  109 + */
  110 + int expect_finished();
  111 + int send_stopped_pub();
  112 + /**
  113 + * @brief notify server the check procedure is over.
  114 + */
  115 + int send_final();
  116 +};
  117 +
  118 +/**
  119 +* @brief class of band check
  120 +* used to check band width with a client @param bandCheck_Client
  121 +*/
  122 +class SrsBandCheck
  123 +{
  124 +public:
  125 + SrsBandCheck();
  126 + ~SrsBandCheck();
  127 +
  128 +public:
  129 + /**
  130 + * @brief band check method
  131 + *
  132 + * connect to server------>rtmp handshake------>rtmp connect------>play------>publish
  133 + * @retval ERROR_SUCCESS when success.
  134 + */
  135 + int check(const std::string& app, const std::string& tcUrl);
  136 +
  137 + /**
  138 + * @brief set the address and port of test server
  139 + *
  140 + * @param server server address, domain or ip
  141 + * @param server listened port ,default is 1935
  142 + */
  143 + void set_server(const std::string& server, int port = 1935);
  144 +
  145 +private:
  146 + int connect_server();
  147 +
  148 +private:
  149 + SrsBandCheckClient* bandCheck_Client;
  150 + std::string server_address;
  151 + int server_port;
  152 +};
  153 +
  154 +/**
  155 +* @brief init st lib
  156 +*/
  157 +static int init_st();
  158 +static void print_help();
  159 +static void print_version();
  160 +
  161 +/**
  162 +* @brief get user option
  163 +* @internal ip Mandatory arguments
  164 +* @internal key Mandatory arguments
  165 +* @internal port default 1935
  166 +* @internal vhost default bandcheck.srs.com
  167 +*/
  168 +static int get_opt(int argc ,char* argv[]);
  169 +
  170 +/**
  171 +* global var.
  172 +*/
  173 +static struct option long_options[] =
  174 +{
  175 + {"ip", required_argument, 0, 'i'},
  176 + {"port", optional_argument, 0, 'p'},
  177 + {"key", required_argument, 0, 'k'},
  178 + {"vhost", optional_argument, 0, 'v'},
  179 + {"help", no_argument, 0, 'h'},
  180 + {"version", no_argument, 0, 'V'},
  181 +};
  182 +
  183 +static const char* short_options = "i:p::k:v::hV";
  184 +
  185 +static std::string g_ip;
  186 +static int g_port = 1935;
  187 +static std::string g_key;
  188 +static std::string g_vhost = "bandcheck.srs.com";
  189 +
  190 +#define BUILD_VERSION "srs band check 0.1"
  191 +
  192 +int main(int argc ,char* argv[])
  193 +{
  194 + int ret = ERROR_SUCCESS;
  195 +
  196 + if ((ret = get_opt(argc, argv)) != ERROR_SUCCESS) {
  197 + return -1;
  198 + }
  199 +
  200 + // check param
  201 + if (g_ip.empty()) {
  202 + printf("ip address should not be empty.");
  203 + return -1;
  204 + }
  205 +
  206 + if (g_key.empty()) {
  207 + printf("test key should not be empty.");
  208 + return -1;
  209 + }
  210 +
  211 + if ((ret = init_st()) != ERROR_SUCCESS) {
  212 + srs_error("band check init failed. ret=%d", ret);
  213 + return ret;
  214 + }
  215 +
  216 + std::string app = "app?key=" + g_key + "&vhost=" + g_vhost;
  217 +
  218 + char tcUrl_buffer[1024] = {0};
  219 + sprintf(tcUrl_buffer, "rtmp://%s:%d/%s", g_ip.c_str(), g_port, app.c_str());
  220 + std::string tcUrl = tcUrl_buffer;
  221 +
  222 + SrsBandCheck band_check;
  223 + band_check.set_server(g_ip, g_port);
  224 + if ((ret = band_check.check(app, tcUrl)) != ERROR_SUCCESS) {
  225 + srs_error("band check failed. address=%s ret=%d", "xx.com", ret);
  226 + return -1;
  227 + }
  228 +
  229 + return 0;
  230 +}
  231 +
  232 +SrsBandCheckClient::SrsBandCheckClient(st_netfd_t _stfd)
  233 + : SrsRtmpClient(_stfd)
  234 +{
  235 +}
  236 +
  237 +SrsBandCheckClient::~SrsBandCheckClient()
  238 +{
  239 +}
  240 +
  241 +int SrsBandCheckClient::check_play()
  242 +{
  243 + int ret = ERROR_SUCCESS;
  244 +
  245 + if ((ret = expect_start_play()) != ERROR_SUCCESS) {
  246 + srs_error("expect_start_play failed. ret=%d", ret);
  247 + return ret;
  248 + }
  249 +
  250 + if ((ret = send_starting_play()) != ERROR_SUCCESS) {
  251 + srs_error("send starting play failed. ret=%d", ret);
  252 + return ret;
  253 + }
  254 +
  255 + if ((ret = expect_stop_play()) != ERROR_SUCCESS) {
  256 + srs_error("expect stop play failed. ret=%d", ret);
  257 + return ret;
  258 + }
  259 +
  260 + if ((ret = send_stopped_play()) != ERROR_SUCCESS) {
  261 + srs_error("send stopped play failed. ret=%d", ret);
  262 + return ret;
  263 + }
  264 +
  265 + return ret;
  266 +}
  267 +
  268 +int SrsBandCheckClient::check_publish()
  269 +{
  270 + int ret = ERROR_SUCCESS;
  271 +
  272 + if ((ret = expect_start_pub()) != ERROR_SUCCESS) {
  273 + srs_error("expect start pub failed. ret=%d", ret);
  274 + return ret;
  275 + }
  276 +
  277 + if ((ret = send_starting_pub())!= ERROR_SUCCESS) {
  278 + srs_error("send starting pub failed. ret=%d", ret);
  279 + return ret;
  280 + }
  281 +
  282 + if ((ret = send_pub_data()) != ERROR_SUCCESS) {
  283 + srs_error("publish data failed. ret=%d", ret);
  284 + return ret;
  285 + }
  286 +
  287 + if ((ret = send_stopped_pub()) != ERROR_SUCCESS) {
  288 + srs_error("send stopped pub failed. ret=%d", ret);
  289 + return ret;
  290 + }
  291 +
  292 + if ((ret = expect_finished()) != ERROR_SUCCESS) {
  293 + srs_error("expect finished msg failed. ret=%d", ret);
  294 + return ret;
  295 + }
  296 +
  297 + if ((ret = send_final()) != ERROR_SUCCESS) {
  298 + srs_error("send final msg failed. ret=%d", ret);
  299 + return ret;
  300 + }
  301 +
  302 + return ret;
  303 +}
  304 +
  305 +int SrsBandCheckClient::create_stream(int &stream_id)
  306 +{
  307 + return ERROR_SUCCESS;
  308 +}
  309 +
  310 +int SrsBandCheckClient::play(std::string stream, int stream_id)
  311 +{
  312 + return ERROR_SUCCESS;
  313 +}
  314 +
  315 +int SrsBandCheckClient::publish(std::string stream, int stream_id)
  316 +{
  317 + return ERROR_SUCCESS;
  318 +}
  319 +
  320 +int SrsBandCheckClient::expect_start_play()
  321 +{
  322 + int ret = ERROR_SUCCESS;
  323 +
  324 + // expect connect _result
  325 + SrsCommonMessage* msg = NULL;
  326 + SrsBandwidthPacket* pkt = NULL;
  327 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(get_protocol(), &msg, &pkt)) != ERROR_SUCCESS) {
  328 + srs_error("expect bandcheck start play message failed. ret=%d", ret);
  329 + return ret;
  330 + }
  331 + SrsAutoFree(SrsCommonMessage, msg, false);
  332 + srs_info("get bandcheck start play message");
  333 +
  334 + if (pkt->command_name != SRS_BW_CHECK_START_PLAY) {
  335 + srs_error("pkt error. expect=%s, actual=%s", SRS_BW_CHECK_START_PLAY, pkt->command_name.c_str());
  336 + return -1;
  337 + }
  338 +
  339 + return ret;
  340 +}
  341 +
  342 +int SrsBandCheckClient::send_starting_play()
  343 +{
  344 + int ret = ERROR_SUCCESS;
  345 +
  346 + SrsCommonMessage* msg = new SrsCommonMessage;
  347 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  348 + pkt->command_name = SRS_BW_CHECK_STARTING_PLAY;
  349 + msg->set_packet(pkt, 0);
  350 +
  351 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  352 + srs_error("send starting play msg failed. ret=%d", ret);
  353 + return ret;
  354 + }
  355 +
  356 + return ret;
  357 +}
  358 +
  359 +int SrsBandCheckClient::expect_stop_play()
  360 +{
  361 + int ret = ERROR_SUCCESS;
  362 +
  363 + while (true) {
  364 + SrsCommonMessage* msg = NULL;
  365 + SrsBandwidthPacket* pkt = NULL;
  366 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(get_protocol(), &msg, &pkt)) != ERROR_SUCCESS) {
  367 + srs_error("expect stop play message failed. ret=%d", ret);
  368 + return ret;
  369 + }
  370 + SrsAutoFree(SrsCommonMessage, msg, false);
  371 + srs_info("get bandcheck stop play message");
  372 +
  373 + if (pkt->command_name == SRS_BW_CHECK_STOP_PLAY) {
  374 + break;
  375 + }
  376 + }
  377 +
  378 + return ret;
  379 +}
  380 +
  381 +int SrsBandCheckClient::send_stopped_play()
  382 +{
  383 + int ret = ERROR_SUCCESS;
  384 +
  385 + SrsCommonMessage* msg = new SrsCommonMessage;
  386 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  387 + pkt->command_name = SRS_BW_CHECK_STOPPED_PLAY;
  388 + msg->set_packet(pkt, 0);
  389 +
  390 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  391 + srs_error("send stopped play msg failed. ret=%d", ret);
  392 + return ret;
  393 + }
  394 +
  395 + return ret;
  396 +}
  397 +
  398 +int SrsBandCheckClient::expect_start_pub()
  399 +{
  400 + int ret = ERROR_SUCCESS;
  401 +
  402 + while (true) {
  403 + SrsCommonMessage* msg = NULL;
  404 + SrsBandwidthPacket* pkt = NULL;
  405 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(get_protocol(), &msg, &pkt)) != ERROR_SUCCESS) {
  406 + srs_error("expect start pub message failed. ret=%d", ret);
  407 + return ret;
  408 + }
  409 + SrsAutoFree(SrsCommonMessage, msg, false);
  410 + srs_info("get bandcheck start pub message");
  411 +
  412 + if (pkt->command_name == SRS_BW_CHECK_START_PUBLISH) {
  413 + break;
  414 + }
  415 + }
  416 +
  417 + return ret;
  418 +}
  419 +
  420 +int SrsBandCheckClient::send_starting_pub()
  421 +{
  422 + int ret = ERROR_SUCCESS;
  423 +
  424 + SrsCommonMessage* msg = new SrsCommonMessage;
  425 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  426 + pkt->command_name = SRS_BW_CHECK_STARTING_PUBLISH;
  427 + msg->set_packet(pkt, 0);
  428 +
  429 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  430 + srs_error("send starting play msg failed. ret=%d", ret);
  431 + return ret;
  432 + }
  433 + srs_info("send starting play msg success.");
  434 +
  435 + return ret;
  436 +}
  437 +
  438 +int SrsBandCheckClient::send_pub_data()
  439 +{
  440 + int ret = ERROR_SUCCESS;
  441 +
  442 + int data_count = 100;
  443 + while (true) {
  444 + SrsCommonMessage* msg = new SrsCommonMessage;
  445 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  446 + pkt->command_name = SRS_BW_CHECK_PUBLISHING;
  447 + msg->set_packet(pkt, 0);
  448 +
  449 + for (int i = 0; i < data_count; ++i) {
  450 + std::stringstream seq;
  451 + seq << i;
  452 + std::string play_data = "SrS band check data from client's publishing......";
  453 + pkt->data->set(seq.str(), new SrsAmf0String(play_data.c_str()));
  454 + }
  455 + data_count += 100;
  456 +
  457 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  458 + srs_error("send publish message failed.ret=%d", ret);
  459 + return ret;
  460 + }
  461 +
  462 + if ((ret = expect_stop_pub()) == ERROR_SUCCESS) {
  463 + break;
  464 + }
  465 + }
  466 +
  467 + return ret;
  468 +}
  469 +
  470 +int SrsBandCheckClient::expect_stop_pub()
  471 +{
  472 + int ret = ERROR_SUCCESS;
  473 +
  474 + while (true) {
  475 + if ((ret = st_netfd_poll(get_st_fd(), POLLIN, 1000)) == ERROR_SUCCESS) {
  476 + SrsCommonMessage* msg = 0;
  477 + if ((ret = recv_message(&msg)) != ERROR_SUCCESS)
  478 + {
  479 + srs_error("recv message failed while expect stop pub. ret=%d", ret);
  480 + return ret;
  481 + }
  482 +
  483 + if ((ret = msg->decode_packet(get_protocol())) != ERROR_SUCCESS) {
  484 + srs_error("decode packet error while expect stop pub. ret=%d", ret);
  485 + return ret;
  486 + }
  487 +
  488 + SrsBandwidthPacket* pkt = dynamic_cast<SrsBandwidthPacket*>(msg->get_packet());
  489 + if (pkt && pkt->command_name == SRS_BW_CHECK_STOP_PUBLISH) {
  490 +
  491 + return ret;
  492 + }
  493 + } else {
  494 + break;
  495 + }
  496 + }
  497 +
  498 + return ret;
  499 +}
  500 +
  501 +int SrsBandCheckClient::expect_finished()
  502 +{
  503 + int ret = ERROR_SUCCESS;
  504 +
  505 + while (true) {
  506 + SrsCommonMessage* msg = NULL;
  507 + SrsBandwidthPacket* pkt = NULL;
  508 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(get_protocol(), &msg, &pkt)) != ERROR_SUCCESS) {
  509 + srs_error("expect finished message failed. ret=%d", ret);
  510 + return ret;
  511 + }
  512 + SrsAutoFree(SrsCommonMessage, msg, false);
  513 + srs_info("get bandcheck finished message");
  514 +
  515 + if (pkt->command_name == SRS_BW_CHECK_FINISHED) {
  516 + SrsStream *stream = new SrsStream;
  517 + SrsAutoFree(SrsStream, stream, false);
  518 +
  519 + if ((ret = stream->initialize((char*)msg->payload, msg->size)) != ERROR_SUCCESS) {
  520 + srs_error("initialize stream error. ret=%d", ret);
  521 + return ret;
  522 + }
  523 +
  524 + std::string command_name;
  525 + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) {
  526 + srs_error("amfo read string error. ret=%d", ret);
  527 + return ret;
  528 + }
  529 +
  530 + double action_id;
  531 + if ((ret = srs_amf0_read_number(stream, action_id)) != ERROR_SUCCESS) {
  532 + srs_error("amfo read number error. ret=%d", ret);
  533 + return ret;
  534 + }
  535 +
  536 + if ((ret = srs_amf0_read_null(stream)) != ERROR_SUCCESS) {
  537 + srs_error("amfo read number error. ret=%d", ret);
  538 + return ret;
  539 + }
  540 +
  541 + SrsAmf0Object* object;
  542 + if ((ret = srs_amf0_read_object(stream, object)) != ERROR_SUCCESS) {
  543 + srs_error("amfo read object error. ret=%d", ret);
  544 + return ret;
  545 + }
  546 +
  547 + int64_t start_time = 0;
  548 + int64_t end_time = 0;
  549 +
  550 + SrsAmf0Any* start_time_any = object->get_property("start_time");
  551 + if (start_time_any && start_time_any->is_number()) {
  552 + SrsAmf0Number* start_time_number = dynamic_cast<SrsAmf0Number*> (start_time_any);
  553 + if (start_time_number) {
  554 + start_time = start_time_number->value;
  555 + }
  556 + }
  557 +
  558 + SrsAmf0Any* end_time_any = object->get_property("end_time");
  559 + if (end_time_any && end_time_any->is_number()) {
  560 + SrsAmf0Number* end_time_number = dynamic_cast<SrsAmf0Number*> (end_time_any);
  561 + if (end_time_number) {
  562 + end_time = end_time_number->value;
  563 + }
  564 + }
  565 +
  566 + int play_kbps = 0;
  567 + int pub_kbps = 0;
  568 + SrsAmf0Any* play_kbp_any = object->get_property("play_kbps");
  569 + if (play_kbp_any && play_kbp_any->is_number()) {
  570 + SrsAmf0Number* play_kbps_number = dynamic_cast<SrsAmf0Number*> (play_kbp_any);
  571 + if (play_kbps_number) {
  572 + play_kbps = play_kbps_number->value;
  573 + }
  574 + }
  575 +
  576 + SrsAmf0Any* pub_kbp_any = object->get_property("publish_kbps");
  577 + if (pub_kbp_any && pub_kbp_any->is_number()) {
  578 + SrsAmf0Number* pub_kbps_number = dynamic_cast<SrsAmf0Number*> (pub_kbp_any);
  579 + if (pub_kbps_number) {
  580 + pub_kbps = pub_kbps_number->value;
  581 + }
  582 + }
  583 +
  584 + float time_elapsed;
  585 + if (end_time - start_time > 0) {
  586 + time_elapsed = (end_time - start_time) / 1000.00;
  587 + }
  588 +
  589 + srs_trace("result: play %d kbps, publish %d kbps, check time %.4f S\n"
  590 + , play_kbps, pub_kbps, time_elapsed);
  591 +
  592 + break;
  593 + }
  594 + }
  595 +
  596 + return ret;
  597 +}
  598 +
  599 +int SrsBandCheckClient::send_stopped_pub()
  600 +{
  601 + int ret = ERROR_SUCCESS;
  602 +
  603 + SrsCommonMessage* msg = new SrsCommonMessage;
  604 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  605 + pkt->command_name = SRS_BW_CHECK_STOPPED_PUBLISH;
  606 + msg->set_packet(pkt, 0);
  607 +
  608 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  609 + srs_error("send stopped pub msg failed. ret=%d", ret);
  610 + return ret;
  611 + }
  612 + srs_info("send stopped pub msg success.");
  613 +
  614 + return ret;
  615 +}
  616 +
  617 +int SrsBandCheckClient::send_final()
  618 +{
  619 + int ret = ERROR_SUCCESS;
  620 +
  621 + SrsCommonMessage* msg = new SrsCommonMessage;
  622 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket;
  623 + pkt->command_name = SRS_BW_CHECK_FLASH_FINAL;
  624 + msg->set_packet(pkt, 0);
  625 +
  626 + if ((ret = send_message(msg)) != ERROR_SUCCESS) {
  627 + srs_error("send final msg failed. ret=%d", ret);
  628 + return ret;
  629 + }
  630 + srs_info("send final msg success.");
  631 +
  632 + return ret;
  633 +}
  634 +
  635 +SrsBandCheck::SrsBandCheck()
  636 + : bandCheck_Client(0)
  637 +{
  638 +}
  639 +
  640 +SrsBandCheck::~SrsBandCheck()
  641 +{
  642 + if (bandCheck_Client) {
  643 + srs_freep(bandCheck_Client);
  644 + }
  645 +}
  646 +
  647 +int SrsBandCheck::check(const std::string &app, const std::string &tcUrl)
  648 +{
  649 + int ret = ERROR_SUCCESS;
  650 +
  651 + if ((ret = connect_server()) != ERROR_SUCCESS) {
  652 + srs_error("connect to server failed. ret = %d", ret);
  653 + return ret;
  654 + }
  655 +
  656 + if ((ret = bandCheck_Client->handshake()) != ERROR_SUCCESS) {
  657 + srs_error("handshake failed. ret = %d", ret);
  658 + return ret;
  659 + }
  660 +
  661 + if ((ret = bandCheck_Client->connect_app(app, tcUrl)) != ERROR_SUCCESS) {
  662 + srs_error("handshake failed. ret = %d", ret);
  663 + return ret;
  664 + }
  665 +
  666 + if ((ret = bandCheck_Client->check_play()) != ERROR_SUCCESS) {
  667 + srs_error("band check play failed.");
  668 + return ret;
  669 + }
  670 +
  671 + if ((ret = bandCheck_Client->check_publish()) != ERROR_SUCCESS) {
  672 + srs_error("band check publish failed.");
  673 + return ret;
  674 + }
  675 +
  676 + return ret;
  677 +}
  678 +
  679 +void SrsBandCheck::set_server(const std::string &server, int port)
  680 +{
  681 + server_address = server;
  682 + server_port = port;
  683 +}
  684 +
  685 +int SrsBandCheck::connect_server()
  686 +{
  687 + int ret = ERROR_SUCCESS;
  688 +
  689 + int sock = socket(AF_INET, SOCK_STREAM, 0);
  690 + if(sock == -1){
  691 + ret = ERROR_SOCKET_CREATE;
  692 + srs_error("create socket error. ret=%d", ret);
  693 + return ret;
  694 + }
  695 +
  696 + st_netfd_t stfd = st_netfd_open_socket(sock);
  697 + if(stfd == NULL){
  698 + ret = ERROR_ST_OPEN_SOCKET;
  699 + srs_error("st_netfd_open_socket failed. ret=%d", ret);
  700 + return ret;
  701 + }
  702 +
  703 + bandCheck_Client = new SrsBandCheckClient(stfd);
  704 +
  705 + // connect to server.
  706 + std::string ip = srs_dns_resolve(server_address);
  707 + if (ip.empty()) {
  708 + ret = ERROR_SYSTEM_IP_INVALID;
  709 + srs_error("dns resolve server error, ip empty. ret=%d", ret);
  710 + return ret;
  711 + }
  712 +
  713 + sockaddr_in addr;
  714 + addr.sin_family = AF_INET;
  715 + addr.sin_port = htons(server_port);
  716 + addr.sin_addr.s_addr = inet_addr(ip.c_str());
  717 +
  718 + if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1){
  719 + ret = ERROR_ST_CONNECT;
  720 + srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), server_port, ret);
  721 + return ret;
  722 + }
  723 + srs_trace("connect to server success. server=%s, ip=%s, port=%d", server_address.c_str(), ip.c_str(), server_port);
  724 +
  725 + return ret;
  726 +}
  727 +
  728 +int init_st()
  729 +{
  730 + int ret = ERROR_SUCCESS;
  731 +
  732 + if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) {
  733 + ret = ERROR_ST_SET_EPOLL;
  734 + srs_error("st_set_eventsys use linux epoll failed. ret=%d", ret);
  735 + return ret;
  736 + }
  737 +
  738 + if(st_init() != 0){
  739 + ret = ERROR_ST_INITIALIZE;
  740 + srs_error("st_init failed. ret=%d", ret);
  741 + return ret;
  742 + }
  743 +
  744 + return ret;
  745 +}
  746 +
  747 +void print_help()
  748 +{
  749 + const char *help = "Usage: srs-bandcheck [OPTION]...\n"
  750 + "test band width from client to rtmp server.\n"
  751 +
  752 + "Mandatory arguments to long options are mandatory for short options too.\n"
  753 + " -i, --ip the ip or domain that to test\n"
  754 + " -p, --port the port that server listen \n"
  755 + " -k, --key the key used to test \n"
  756 + " -v, --vhost the vhost used to test \n"
  757 + " -V, --version output version information and exit \n"
  758 + " -h, --help display this help and exit \n"
  759 + "\n\n\n"
  760 + "Exit status:\n"
  761 + "0 if OK,\n"
  762 + "other if error occured, and the detail should be printed.\n"
  763 + "\n\n"
  764 + "srs home page: <winlin(winterserver): http://blog.csdn.net/win_lin>\n"
  765 + "srs home page: <http://blog.chinaunix.net/uid/25006789.html>\n";
  766 +
  767 + printf("%s", help);
  768 +}
  769 +
  770 +void print_version()
  771 +{
  772 + const char *version = ""
  773 + "srs_bandcheck "BUILD_VERSION"\n"
  774 + "Copyright (C) 2013 wenjiegit.\n"
  775 + "License MIT\n"
  776 + "This is free software: you are free to change and redistribute it.\n"
  777 + "There is NO WARRANTY, to the extent permitted by law.\n"
  778 + "\n"
  779 + "Written by wenjie.\n";
  780 +
  781 + printf("%s", version);
  782 +}
  783 +
  784 +int get_opt(int argc, char *argv[])
  785 +{
  786 + int ret = ERROR_SUCCESS;
  787 +
  788 + int c;
  789 + while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1) {
  790 + switch (c) {
  791 + case 'i':
  792 + if (optarg) {
  793 + g_ip = optarg;
  794 + }
  795 + break;
  796 + case 'p':
  797 + if (optarg) {
  798 + g_port = atoi(optarg);
  799 + }
  800 + break;
  801 + case 'k':
  802 + if (optarg) {
  803 + g_key = optarg;
  804 + }
  805 + break;
  806 + case 'v':
  807 + if (optarg) {
  808 + g_vhost = optarg;
  809 + }
  810 + break;
  811 + case 'V':
  812 + print_version();
  813 + exit(0);
  814 + break;
  815 + case 'h':
  816 + print_help();
  817 + exit(0);
  818 + break;
  819 + default:
  820 + printf("see --help or -h\n");
  821 + ret = -1;
  822 + }
  823 + }
  824 +
  825 + return ret;
  826 +}