winlin

merge from wenjie, support banwidth test.

@@ -116,7 +116,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server" @@ -116,7 +116,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server"
116 "srs_core_handshake" "srs_core_pithy_print" 116 "srs_core_handshake" "srs_core_pithy_print"
117 "srs_core_config" "srs_core_refer" "srs_core_reload" 117 "srs_core_config" "srs_core_refer" "srs_core_reload"
118 "srs_core_hls" "srs_core_forward" "srs_core_encoder" 118 "srs_core_hls" "srs_core_forward" "srs_core_encoder"
119 - "srs_core_http" "srs_core_thread") 119 + "srs_core_http" "srs_core_thread" "srs_core_bandwidth")
120 MODULE_DIR="src/core" . auto/modules.sh 120 MODULE_DIR="src/core" . auto/modules.sh
121 CORE_OBJS="${MODULE_OBJS[@]}" 121 CORE_OBJS="${MODULE_OBJS[@]}"
122 122
@@ -107,4 +107,15 @@ extern void srs_vhost_resolve(std::string& vhost, std::string& app); @@ -107,4 +107,15 @@ extern void srs_vhost_resolve(std::string& vhost, std::string& app);
107 // close the netfd, and close the underlayer fd. 107 // close the netfd, and close the underlayer fd.
108 extern void srs_close_stfd(st_netfd_t& stfd); 108 extern void srs_close_stfd(st_netfd_t& stfd);
109 109
  110 +/**
  111 +* disable copy constructor of class
  112 +*/
  113 +#define disable_default_copy(className)\
  114 + private:\
  115 + /** \
  116 + * disable the copy constructor and operator=, donot allow directly copy. \
  117 + */ \
  118 + className(const className&); \
  119 + className& operator= (const className&)
  120 +
110 #endif 121 #endif
  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 <srs_core_bandwidth.hpp>
  25 +
  26 +#include <arpa/inet.h>
  27 +
  28 +using namespace std;
  29 +
  30 +#include <srs_core_rtmp.hpp>
  31 +#include <srs_core_error.hpp>
  32 +#include <srs_core_amf0.hpp>
  33 +#include <srs_core_protocol.hpp>
  34 +#include <srs_core_config.hpp>
  35 +#include <srs_core_autofree.hpp>
  36 +
  37 +SrsBandwidth::SrsBandwidth()
  38 +{
  39 +}
  40 +
  41 +SrsBandwidth::~SrsBandwidth()
  42 +{
  43 +}
  44 +
  45 +int SrsBandwidth::bandwidth_test(SrsRequest* _req, st_netfd_t stfd, SrsRtmp* _rtmp)
  46 +{
  47 + int ret = ERROR_SUCCESS;
  48 +
  49 + rtmp = _rtmp;
  50 + req = _req;
  51 +
  52 + if (!config->get_bw_check_enabled(req->vhost)) {
  53 + return ret;
  54 + }
  55 +
  56 + // validate the bandwidth check key
  57 + std::string key = "key=" + config->get_bw_check_key(req->vhost);
  58 + if (req->tcUrl.find(key) == std::string::npos) {
  59 + ret = ERROR_SYSTEM_BANDWIDTH_KEY;
  60 + srs_error("check the vhost=%s %s failed, tcUrl=%s, ret=%d",
  61 + req->vhost.c_str(), key.c_str(), req->tcUrl.c_str(), ret);
  62 + return ret;
  63 + }
  64 +
  65 + // shared global last check time,
  66 + // to avoid attach by bandwidth check,
  67 + // if client request check in the window(specifeid by interval),
  68 + // directly reject the request.
  69 + static int64_t last_check_time = 0;
  70 + int interval_ms = config->get_bw_check_interval_ms(req->vhost);
  71 +
  72 + int64_t time_now = srs_get_system_time_ms();
  73 + // reject the connection in the interval window.
  74 + if (last_check_time > 0 && time_now - last_check_time < interval_ms) {
  75 + ret = ERROR_SYSTEM_BANDWIDTH_DENIED;
  76 + srs_trace("bandcheck denied, "
  77 + "last_check=%"PRId64", now=%"PRId64", interval=%d",
  78 + last_check_time, time_now, interval_ms);
  79 +
  80 + rtmp->response_connect_reject(req, "bandcheck rejected");
  81 + return ret;
  82 + }
  83 +
  84 + // accept and do bandwidth check.
  85 + last_check_time = time_now;
  86 +
  87 + char* local_ip = 0;
  88 + if ((ret = get_local_ip(stfd, local_ip)) != ERROR_SUCCESS) {
  89 + srs_error("get local ip failed. ret = %d", ret);
  90 + return ret;
  91 + }
  92 +
  93 + if ((ret = rtmp->response_connect_app(req, local_ip)) != ERROR_SUCCESS) {
  94 + srs_error("response connect app failed. ret=%d", ret);
  95 + return ret;
  96 + }
  97 +
  98 + return do_bandwidth_check();
  99 +}
  100 +
  101 +int SrsBandwidth::get_local_ip(st_netfd_t stfd, char *&local_ip)
  102 +{
  103 + int ret = ERROR_SUCCESS;
  104 +
  105 + int fd = st_netfd_fileno(stfd);
  106 +
  107 + // discovery client information
  108 + sockaddr_in addr;
  109 + socklen_t addrlen = sizeof(addr);
  110 + if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) {
  111 + ret = ERROR_SOCKET_GET_LOCAL_IP;
  112 + srs_error("discovery local ip information failed. ret=%d", ret);
  113 + return ret;
  114 + }
  115 + srs_verbose("get local ip success.");
  116 +
  117 + // ip v4 or v6
  118 + char buf[INET6_ADDRSTRLEN];
  119 + memset(buf, 0, sizeof(buf));
  120 +
  121 + if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) {
  122 + ret = ERROR_SOCKET_GET_LOCAL_IP;
  123 + srs_error("convert local ip information failed. ret=%d", ret);
  124 + return ret;
  125 + }
  126 +
  127 + local_ip = new char[strlen(buf) + 1];
  128 + strcpy(local_ip, buf);
  129 +
  130 + srs_verbose("get local ip of client ip=%s, fd=%d", buf, fd);
  131 +
  132 + return ret;
  133 +}
  134 +
  135 +int SrsBandwidth::do_bandwidth_check()
  136 +{
  137 + int ret = ERROR_SUCCESS;
  138 +
  139 + SrsProtocol* protocol = rtmp->get_protocol();
  140 +
  141 + int play_duration_ms = 3000;
  142 + int play_interval_ms = 0;
  143 + int play_actual_duration_ms = 0;
  144 + int play_bytes = 0;
  145 +
  146 + int publish_duration_ms = 3000;
  147 + int publish_interval_ms = 0;
  148 + int publish_actual_duration_ms = 0;
  149 + int publish_bytes = 0;
  150 +
  151 + int limit_kbps = config->get_bw_check_limit_kbps(req->vhost);
  152 +
  153 + int64_t start_time = srs_get_system_time_ms();
  154 +
  155 + ret = check_play(play_duration_ms,
  156 + play_interval_ms, play_actual_duration_ms, play_bytes, limit_kbps);
  157 + if (ret != ERROR_SUCCESS) {
  158 + srs_error("band width play check failed. ret=%d", ret);
  159 + return ret;
  160 + }
  161 +
  162 + ret = check_publish(publish_duration_ms,
  163 + publish_interval_ms, publish_actual_duration_ms, publish_bytes, limit_kbps);
  164 + if (ret != ERROR_SUCCESS) {
  165 + srs_error("band width publish check failed. ret=%d", ret);
  166 + return ret;
  167 + }
  168 +
  169 + int64_t end_time = srs_get_system_time_ms();
  170 + int play_kbps = play_bytes * 8 / play_actual_duration_ms;
  171 + int publish_kbps = publish_bytes * 8 / publish_actual_duration_ms;
  172 +
  173 + // send finished msg
  174 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_finish();
  175 + pkt->data->set("code", new SrsAmf0Number(ERROR_SUCCESS));
  176 + pkt->data->set("start_time", new SrsAmf0Number(start_time));
  177 + pkt->data->set("end_time", new SrsAmf0Number(end_time));
  178 + pkt->data->set("play_kbps", new SrsAmf0Number(play_kbps));
  179 + pkt->data->set("publish_kbps", new SrsAmf0Number(publish_kbps));
  180 + pkt->data->set("play_bytes", new SrsAmf0Number(play_bytes));
  181 + pkt->data->set("play_time", new SrsAmf0Number(play_actual_duration_ms));
  182 + pkt->data->set("publish_bytes", new SrsAmf0Number(publish_bytes));
  183 + pkt->data->set("publish_time", new SrsAmf0Number(publish_actual_duration_ms));
  184 +
  185 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  186 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  187 + srs_error("send bandwidth check finish message failed. ret=%d", ret);
  188 + return ret;
  189 + }
  190 +
  191 + // if flash, we notice the result, and expect a final packet.
  192 + while (true) {
  193 + SrsCommonMessage* msg = NULL;
  194 + SrsBandwidthPacket* pkt = NULL;
  195 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  196 + srs_error("expect final message failed. ret=%d", ret);
  197 + return ret;
  198 + }
  199 + SrsAutoFree(SrsCommonMessage, msg, false);
  200 + srs_info("get final message succes.");
  201 +
  202 + if (pkt->is_flash_final()) {
  203 + srs_trace("BW check recv flash final response.");
  204 + break;
  205 + }
  206 + }
  207 +
  208 + srs_trace("BW check finished.");
  209 +
  210 + return ret;
  211 +}
  212 +
  213 +int SrsBandwidth::check_play(
  214 + int duration_ms, int interval_ms, int& actual_duration_ms,
  215 + int& play_bytes, int max_play_kbps)
  216 +{
  217 + int ret = ERROR_SUCCESS;
  218 +
  219 + SrsProtocol* protocol = rtmp->get_protocol();
  220 +
  221 + if (true) {
  222 + // send start play command to client
  223 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_start_play();
  224 +
  225 + pkt->data->set("duration_ms", new SrsAmf0Number(duration_ms));
  226 + pkt->data->set("interval_ms", new SrsAmf0Number(interval_ms));
  227 +
  228 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  229 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  230 + srs_error("send bandwidth check start play message failed. ret=%d", ret);
  231 + return ret;
  232 + }
  233 + srs_trace("BW check begin.");
  234 + }
  235 +
  236 + while (true) {
  237 + // recv client's starting play response
  238 + SrsCommonMessage* msg = NULL;
  239 + SrsBandwidthPacket* pkt = NULL;
  240 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  241 + srs_error("expect bandwidth message failed. ret=%d", ret);
  242 + return ret;
  243 + }
  244 + SrsAutoFree(SrsCommonMessage, msg, false);
  245 + srs_info("get bandwidth message succes.");
  246 +
  247 + if (pkt->is_starting_play()) {
  248 + srs_trace("BW check recv play begin response.");
  249 + break;
  250 + }
  251 + }
  252 +
  253 + // send play data to client
  254 + int64_t current_time = srs_get_system_time_ms();
  255 + int size = 1024; // TODO: FIXME: magic number
  256 + char random_data[size];
  257 + memset(random_data, 0x01, size);
  258 +
  259 + int interval = 0;
  260 + while ( (srs_get_system_time_ms() - current_time) < duration_ms ) {
  261 + st_usleep(interval);
  262 +
  263 + // TODO: FIXME: use shared ptr message.
  264 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_playing();
  265 +
  266 + // TODO: FIXME: magic number
  267 + for (int i = 0; i < 100; ++i) {
  268 + char buf[32]; // TODO: FIXME: magic number
  269 + sprintf(buf, "%d", i);
  270 + pkt->data->set(buf, new SrsAmf0String(random_data));
  271 + }
  272 +
  273 + // TODO: FIXME: get length from the rtmp protocol stack.
  274 + play_bytes += pkt->get_payload_length();
  275 +
  276 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  277 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  278 + srs_error("send bandwidth check play messages failed. ret=%d", ret);
  279 + return ret;
  280 + }
  281 +
  282 + // sleep while current kbps <= max_play_kbps
  283 + int kbps = 0;
  284 + while (true) {
  285 + if(srs_get_system_time_ms() - current_time != 0)
  286 + kbps = play_bytes * 8 / (srs_get_system_time_ms() - current_time);
  287 +
  288 + if (kbps > max_play_kbps) {
  289 + st_usleep(500);
  290 + } else {
  291 + break;
  292 + }
  293 + }
  294 + }
  295 + actual_duration_ms = srs_get_system_time_ms() - current_time;
  296 + srs_trace("BW check send play bytes over.");
  297 +
  298 + if (true) {
  299 + // notify client to stop play
  300 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_stop_play();
  301 + pkt->data->set("duration_ms", new SrsAmf0Number(duration_ms));
  302 + pkt->data->set("interval_ms", new SrsAmf0Number(interval_ms));
  303 + pkt->data->set("duration_delta", new SrsAmf0Number(actual_duration_ms));
  304 + pkt->data->set("bytes_delta", new SrsAmf0Number(play_bytes));
  305 +
  306 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  307 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  308 + srs_error("send bandwidth check stop play message failed. ret=%d", ret);
  309 + return ret;
  310 + }
  311 + srs_trace("BW check stop play bytes.");
  312 + }
  313 +
  314 + while (true) {
  315 + // recv client's stop play response.
  316 + SrsCommonMessage* msg = NULL;
  317 + SrsBandwidthPacket* pkt = NULL;
  318 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  319 + srs_error("expect bandwidth message failed. ret=%d", ret);
  320 + return ret;
  321 + }
  322 + SrsAutoFree(SrsCommonMessage, msg, false);
  323 + srs_info("get bandwidth message succes.");
  324 +
  325 + if (pkt->is_stopped_play()) {
  326 + srs_trace("BW check recv stop play response.");
  327 + break;
  328 + }
  329 + }
  330 +
  331 + return ret;
  332 +}
  333 +
  334 +int SrsBandwidth::check_publish(
  335 + int duration_ms, int interval_ms, int& actual_duration_ms,
  336 + int& publish_bytes, int max_pub_kbps)
  337 +{
  338 + int ret = ERROR_SUCCESS;
  339 +
  340 + SrsProtocol* protocol = rtmp->get_protocol();
  341 +
  342 + if (true) {
  343 + // notify client to start publish
  344 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_start_publish();
  345 +
  346 + pkt->data->set("duration_ms", new SrsAmf0Number(duration_ms));
  347 + pkt->data->set("interval_ms", new SrsAmf0Number(interval_ms));
  348 +
  349 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  350 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  351 + srs_error("send bandwidth check start publish message failed. ret=%d", ret);
  352 + return ret;
  353 + }
  354 + srs_trace("BW check publish begin.");
  355 + }
  356 +
  357 + while (true) {
  358 + // read client's notification of starting publish
  359 + SrsCommonMessage* msg = NULL;
  360 + SrsBandwidthPacket* pkt = NULL;
  361 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  362 + srs_error("expect bandwidth message failed. ret=%d", ret);
  363 + return ret;
  364 + }
  365 + SrsAutoFree(SrsCommonMessage, msg, false);
  366 + srs_info("get bandwidth message succes.");
  367 +
  368 + if (pkt->is_starting_publish()) {
  369 + srs_trace("BW check recv publish begin response.");
  370 + break;
  371 + }
  372 + }
  373 +
  374 + // recv publish msgs until @duration_ms ms
  375 + int64_t current_time = srs_get_system_time_ms();
  376 + while ( (srs_get_system_time_ms() - current_time) < duration_ms ) {
  377 + st_usleep(0);
  378 +
  379 + SrsCommonMessage* msg = NULL;
  380 + if ((ret = rtmp->recv_message(&msg)) != ERROR_SUCCESS) {
  381 + srs_error("recv message failed. ret=%d", ret);
  382 + return ret;
  383 + }
  384 + SrsAutoFree(SrsCommonMessage, msg, false);
  385 +
  386 + // TODO: FIXME.
  387 + publish_bytes += msg->header.payload_length;
  388 +
  389 + int kbps = 0;
  390 + while (true) {
  391 + if(srs_get_system_time_ms() - current_time != 0)
  392 + kbps = publish_bytes * 8 / (srs_get_system_time_ms() - current_time);
  393 +
  394 + if (kbps > max_pub_kbps) {
  395 + st_usleep(500);
  396 + } else {
  397 + break;
  398 + }
  399 + }
  400 + }
  401 + actual_duration_ms = srs_get_system_time_ms() - current_time;
  402 + srs_trace("BW check recv publish data over.");
  403 +
  404 + if (true) {
  405 + // notify client to stop publish
  406 + SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_stop_publish();
  407 + pkt->data->set("duration_ms", new SrsAmf0Number(duration_ms));
  408 + pkt->data->set("interval_ms", new SrsAmf0Number(interval_ms));
  409 + pkt->data->set("duration_delta", new SrsAmf0Number(actual_duration_ms));
  410 + pkt->data->set("bytes_delta", new SrsAmf0Number(publish_bytes));
  411 +
  412 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  413 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  414 + srs_error("send bandwidth check stop publish message failed. ret=%d", ret);
  415 + return ret;
  416 + }
  417 + srs_trace("BW check stop publish bytes.");
  418 + }
  419 +
  420 + // expect client to stop publish
  421 + // if flash client, we never expect the client stop publish bytes,
  422 + // for the flash send call packet to test publish bandwidth,
  423 + // there are many many packets in the queue.
  424 + // we just ignore the packet and send the bandwidth test data.
  425 + // TODO: FIXME: check whether flash client.
  426 + while (false) {
  427 + // recv client's stop publish response.
  428 + SrsCommonMessage* msg = NULL;
  429 + SrsBandwidthPacket* pkt = NULL;
  430 + if ((ret = srs_rtmp_expect_message<SrsBandwidthPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  431 + srs_error("expect bandwidth message failed. ret=%d", ret);
  432 + return ret;
  433 + }
  434 + SrsAutoFree(SrsCommonMessage, msg, false);
  435 + srs_info("get bandwidth message succes.");
  436 +
  437 + if (pkt->is_stopped_publish()) {
  438 + srs_trace("BW check recv stop publish response.");
  439 + break;
  440 + }
  441 + }
  442 +
  443 + return ret;
  444 +}
  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 +#ifndef SRS_CORE_BANDWIDTH_HPP
  25 +#define SRS_CORE_BANDWIDTH_HPP
  26 +
  27 +/*
  28 +#include <srs_core_bandwidth.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +class SrsRequest;
  33 +class SrsRtmp;
  34 +
  35 +/**
  36 +* bandwidth test agent which provides the interfaces for bandwidth check.
  37 +* 1. if vhost disabled bandwidth check, ignore.
  38 +* 2. otherwise, check the key, error if verify failed.
  39 +* 3. check the interval limit, error if bandwidth in the interval window.
  40 +* 4. check the bandwidth under the max kbps.
  41 +* 5. send the bandwidth data to client.
  42 +* bandwidth workflow:
  43 +* +------------+ +----------+
  44 +* | Client | | Server |
  45 +* +-----+------+ +-----+----+
  46 +* | |
  47 +* | connect vhost------> | if vhost enable bandwidth,
  48 +* | <-----result(success) | do bandwidth check.
  49 +* | |
  50 +* | <----call(start play) | onSrsBandCheckStartPlayBytes
  51 +* | result(playing)-----> | onSrsBandCheckStartingPlayBytes
  52 +* | <-------data(playing) | onSrsBandCheckStartingPlayBytes
  53 +* | <-----call(stop play) | onSrsBandCheckStopPlayBytes
  54 +* | result(stopped)-----> | onSrsBandCheckStoppedPlayBytes
  55 +* | |
  56 +* | <-call(start publish) | onSrsBandCheckStartPublishBytes
  57 +* | result(publishing)--> | onSrsBandCheckStartingPublishBytes
  58 +* | data(publishing)----> | onSrsBandCheckStartingPublishBytes
  59 +* | <--call(stop publish) | onSrsBandCheckStopPublishBytes
  60 +* | result(stopped)-----> | onSrsBandCheckStoppedPublishBytes(1)
  61 +* | |
  62 +* | <--------------report |
  63 +* | <END> |
  64 +* 1. when flash client, server ignore the publish stopped result.
  65 +* and flash client should close connection when got the report.
  66 +*/
  67 +class SrsBandwidth
  68 +{
  69 +private:
  70 + SrsRequest* req;
  71 + SrsRtmp* rtmp;
  72 +public:
  73 + SrsBandwidth();
  74 + virtual ~SrsBandwidth();
  75 +public:
  76 + /**
  77 + * do the bandwidth test.
  78 + */
  79 + virtual int bandwidth_test(SrsRequest* _req, st_netfd_t stfd, SrsRtmp* _rtmp);
  80 +private:
  81 + virtual int get_local_ip(st_netfd_t stfd, char *&local_ip);
  82 + /**
  83 + * used to process band width check from client.
  84 + */
  85 + virtual int do_bandwidth_check();
  86 + virtual int check_play(int duration_ms, int interval_ms, int& actual_duration_ms, int& play_bytes, int max_play_kbps);
  87 + virtual int check_publish(int duration_ms, int interval_ms, int& actual_duration_ms, int& publish_bytes, int max_pub_kbps);
  88 +};
  89 +
  90 +#endif
@@ -40,6 +40,7 @@ using namespace std; @@ -40,6 +40,7 @@ using namespace std;
40 #include <srs_core_refer.hpp> 40 #include <srs_core_refer.hpp>
41 #include <srs_core_hls.hpp> 41 #include <srs_core_hls.hpp>
42 #include <srs_core_http.hpp> 42 #include <srs_core_http.hpp>
  43 +#include <srs_core_bandwidth.hpp>
43 44
44 #define SRS_PULSE_TIMEOUT_MS 100 45 #define SRS_PULSE_TIMEOUT_MS 100
45 #define SRS_SEND_TIMEOUT_US 5000000L 46 #define SRS_SEND_TIMEOUT_US 5000000L
@@ -57,6 +58,7 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) @@ -57,6 +58,7 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd)
57 #ifdef SRS_HTTP 58 #ifdef SRS_HTTP
58 http_hooks = new SrsHttpHooks(); 59 http_hooks = new SrsHttpHooks();
59 #endif 60 #endif
  61 + bandwidth = new SrsBandwidth();
60 62
61 config->subscribe(this); 63 config->subscribe(this);
62 } 64 }
@@ -73,6 +75,7 @@ SrsClient::~SrsClient() @@ -73,6 +75,7 @@ SrsClient::~SrsClient()
73 #ifdef SRS_HTTP 75 #ifdef SRS_HTTP
74 srs_freep(http_hooks); 76 srs_freep(http_hooks);
75 #endif 77 #endif
  78 + srs_freep(bandwidth);
76 } 79 }
77 80
78 // TODO: return detail message when error for client. 81 // TODO: return detail message when error for client.
@@ -152,7 +155,12 @@ int SrsClient::service_cycle() @@ -152,7 +155,12 @@ int SrsClient::service_cycle()
152 return ret; 155 return ret;
153 } 156 }
154 srs_verbose("set peer bandwidth success"); 157 srs_verbose("set peer bandwidth success");
155 - 158 +
  159 + // do bandwidth test if connect to the vhost which is for bandwidth check.
  160 + if (config->get_bw_check_enabled(req->vhost)) {
  161 + return bandwidth->bandwidth_test(req, stfd, rtmp);
  162 + }
  163 +
156 if ((ret = rtmp->response_connect_app(req)) != ERROR_SUCCESS) { 164 if ((ret = rtmp->response_connect_app(req)) != ERROR_SUCCESS) {
157 srs_error("response connect app failed. ret=%d", ret); 165 srs_error("response connect app failed. ret=%d", ret);
158 return ret; 166 return ret;
@@ -43,6 +43,7 @@ class SrsCommonMessage; @@ -43,6 +43,7 @@ class SrsCommonMessage;
43 #ifdef SRS_HTTP 43 #ifdef SRS_HTTP
44 class SrsHttpHooks; 44 class SrsHttpHooks;
45 #endif 45 #endif
  46 +class SrsBandwidth;
46 47
47 /** 48 /**
48 * the client provides the main logic control for RTMP clients. 49 * the client provides the main logic control for RTMP clients.
@@ -58,6 +59,7 @@ private: @@ -58,6 +59,7 @@ private:
58 #ifdef SRS_HTTP 59 #ifdef SRS_HTTP
59 SrsHttpHooks* http_hooks; 60 SrsHttpHooks* http_hooks;
60 #endif 61 #endif
  62 + SrsBandwidth* bandwidth;
61 public: 63 public:
62 SrsClient(SrsServer* srs_server, st_netfd_t client_stfd); 64 SrsClient(SrsServer* srs_server, st_netfd_t client_stfd);
63 virtual ~SrsClient(); 65 virtual ~SrsClient();
@@ -1510,6 +1510,90 @@ int SrsConfig::get_pithy_print_hls() @@ -1510,6 +1510,90 @@ int SrsConfig::get_pithy_print_hls()
1510 return ::atoi(pithy->arg0().c_str()); 1510 return ::atoi(pithy->arg0().c_str());
1511 } 1511 }
1512 1512
  1513 +bool SrsConfig::get_bw_check_enabled(const string &vhost)
  1514 +{
  1515 + SrsConfDirective* conf = get_vhost(vhost);
  1516 +
  1517 + if (!conf) {
  1518 + return false;
  1519 + }
  1520 +
  1521 + conf = conf->get("bandcheck");
  1522 + if (!conf) {
  1523 + return false;
  1524 + }
  1525 +
  1526 + conf = conf->get("enabled");
  1527 + if (!conf || conf->arg0() != "on") {
  1528 + return false;
  1529 + }
  1530 +
  1531 + return true;
  1532 +}
  1533 +
  1534 +string SrsConfig::get_bw_check_key(const string &vhost)
  1535 +{
  1536 + SrsConfDirective* conf = get_vhost(vhost);
  1537 +
  1538 + if (!conf) {
  1539 + return "";
  1540 + }
  1541 +
  1542 + conf = conf->get("bandcheck");
  1543 + if (!conf) {
  1544 + return "";
  1545 + }
  1546 +
  1547 + conf = conf->get("key");
  1548 + if (!conf) {
  1549 + return "";
  1550 + }
  1551 +
  1552 + return conf->arg0();
  1553 +}
  1554 +
  1555 +int SrsConfig::get_bw_check_interval_ms(const string &vhost)
  1556 +{
  1557 + SrsConfDirective* conf = get_vhost(vhost);
  1558 +
  1559 + if (!conf) {
  1560 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1561 + }
  1562 +
  1563 + conf = conf->get("bandcheck");
  1564 + if (!conf) {
  1565 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1566 + }
  1567 +
  1568 + conf = conf->get("interval_ms");
  1569 + if (!conf) {
  1570 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1571 + }
  1572 +
  1573 + return ::atoi(conf->arg0().c_str()) * 1000;
  1574 +}
  1575 +
  1576 +int SrsConfig::get_bw_check_limit_kbps(const string &vhost)
  1577 +{
  1578 + SrsConfDirective* conf = get_vhost(vhost);
  1579 +
  1580 + if (!conf) {
  1581 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1582 + }
  1583 +
  1584 + conf = conf->get("bandcheck");
  1585 + if (!conf) {
  1586 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1587 + }
  1588 +
  1589 + conf = conf->get("limit_kbps");
  1590 + if (!conf) {
  1591 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1592 + }
  1593 +
  1594 + return ::atoi(conf->arg0().c_str());
  1595 +}
  1596 +
1513 int SrsConfig::get_pithy_print_encoder() 1597 int SrsConfig::get_pithy_print_encoder()
1514 { 1598 {
1515 SrsConfDirective* pithy = root->get("encoder"); 1599 SrsConfDirective* pithy = root->get("encoder");
@@ -52,6 +52,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -52,6 +52,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 #define SRS_CONF_DEFAULT_QUEUE_LENGTH 30 52 #define SRS_CONF_DEFAULT_QUEUE_LENGTH 30
53 // in seconds, the paused queue length. 53 // in seconds, the paused queue length.
54 #define SRS_CONF_DEFAULT_PAUSED_LENGTH 10 54 #define SRS_CONF_DEFAULT_PAUSED_LENGTH 10
  55 +// the interval in seconds for bandwidth check
  56 +#define SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL 30
  57 +// the interval in seconds for bandwidth check
  58 +#define SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS 1000
55 59
56 #define SRS_CONF_DEFAULT_CHUNK_SIZE 4096 60 #define SRS_CONF_DEFAULT_CHUNK_SIZE 4096
57 61
@@ -168,6 +172,10 @@ public: @@ -168,6 +172,10 @@ public:
168 virtual int get_pithy_print_encoder(); 172 virtual int get_pithy_print_encoder();
169 virtual int get_pithy_print_hls(); 173 virtual int get_pithy_print_hls();
170 virtual int get_pithy_print_play(); 174 virtual int get_pithy_print_play();
  175 + virtual bool get_bw_check_enabled(const std::string& vhost);
  176 + virtual std::string get_bw_check_key(const std::string& vhost);
  177 + virtual int get_bw_check_interval_ms(const std::string& vhost);
  178 + virtual int get_bw_check_limit_kbps(const std::string& vhost);
171 }; 179 };
172 180
173 /** 181 /**
@@ -51,6 +51,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -51,6 +51,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51 #define ERROR_SOCKET_WRITE 209 51 #define ERROR_SOCKET_WRITE 209
52 #define ERROR_SOCKET_WAIT 210 52 #define ERROR_SOCKET_WAIT 210
53 #define ERROR_SOCKET_TIMEOUT 211 53 #define ERROR_SOCKET_TIMEOUT 211
  54 +#define ERROR_SOCKET_GET_LOCAL_IP 212
54 55
55 #define ERROR_RTMP_PLAIN_REQUIRED 300 56 #define ERROR_RTMP_PLAIN_REQUIRED 300
56 #define ERROR_RTMP_CHUNK_START 301 57 #define ERROR_RTMP_CHUNK_START 301
@@ -85,6 +86,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -85,6 +86,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85 #define ERROR_SYSTEM_IP_INVALID 411 86 #define ERROR_SYSTEM_IP_INVALID 411
86 #define ERROR_SYSTEM_FORWARD_LOOP 412 87 #define ERROR_SYSTEM_FORWARD_LOOP 412
87 #define ERROR_SYSTEM_WAITPID 413 88 #define ERROR_SYSTEM_WAITPID 413
  89 +#define ERROR_SYSTEM_BANDWIDTH_KEY 414
  90 +#define ERROR_SYSTEM_BANDWIDTH_DENIED 415
88 91
89 // see librtmp. 92 // see librtmp.
90 // failed when open ssl create the dh 93 // failed when open ssl create the dh
@@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <srs_core_stream.hpp> 31 #include <srs_core_stream.hpp>
32 #include <srs_core_autofree.hpp> 32 #include <srs_core_autofree.hpp>
33 33
  34 +using namespace std;
  35 +
34 /**************************************************************************** 36 /****************************************************************************
35 ***************************************************************************** 37 *****************************************************************************
36 ****************************************************************************/ 38 ****************************************************************************/
@@ -208,6 +210,33 @@ messages. @@ -208,6 +210,33 @@ messages.
208 #define RTMP_AMF0_DATA_SET_DATAFRAME "@setDataFrame" 210 #define RTMP_AMF0_DATA_SET_DATAFRAME "@setDataFrame"
209 #define RTMP_AMF0_DATA_ON_METADATA "onMetaData" 211 #define RTMP_AMF0_DATA_ON_METADATA "onMetaData"
210 212
  213 +/**
  214 +* band width check method name, which will be invoked by client.
  215 +* band width check mothods use SrsBandwidthPacket as its internal packet type,
  216 +* so ensure you set command name when you use it.
  217 +*/
  218 +// server play control
  219 +#define SRS_BW_CHECK_START_PLAY "onSrsBandCheckStartPlayBytes"
  220 +#define SRS_BW_CHECK_STARTING_PLAY "onSrsBandCheckStartingPlayBytes"
  221 +#define SRS_BW_CHECK_STOP_PLAY "onSrsBandCheckStopPlayBytes"
  222 +#define SRS_BW_CHECK_STOPPED_PLAY "onSrsBandCheckStoppedPlayBytes"
  223 +
  224 +// server publish control
  225 +#define SRS_BW_CHECK_START_PUBLISH "onSrsBandCheckStartPublishBytes"
  226 +#define SRS_BW_CHECK_STARTING_PUBLISH "onSrsBandCheckStartingPublishBytes"
  227 +#define SRS_BW_CHECK_STOP_PUBLISH "onSrsBandCheckStopPublishBytes"
  228 +#define SRS_BW_CHECK_STOPPED_PUBLISH "onSrsBandCheckStoppedPublishBytes"
  229 +
  230 +// EOF control.
  231 +#define SRS_BW_CHECK_FINISHED "onSrsBandCheckFinished"
  232 +// for flash, it will sendout a final call,
  233 +// used to confirm got the report.
  234 +#define SRS_BW_CHECK_FLASH_FINAL "finalClientPacket"
  235 +
  236 +// client only
  237 +#define SRS_BW_CHECK_PLAYING "onSrsBandCheckPlaying"
  238 +#define SRS_BW_CHECK_PUBLISHING "onSrsBandCheckPublishing"
  239 +
211 /**************************************************************************** 240 /****************************************************************************
212 ***************************************************************************** 241 *****************************************************************************
213 ****************************************************************************/ 242 ****************************************************************************/
@@ -283,7 +312,7 @@ SrsProtocol::~SrsProtocol() @@ -283,7 +312,7 @@ SrsProtocol::~SrsProtocol()
283 srs_freep(skt); 312 srs_freep(skt);
284 } 313 }
285 314
286 -std::string SrsProtocol::get_request_name(double transcationId) 315 +string SrsProtocol::get_request_name(double transcationId)
287 { 316 {
288 if (requests.find(transcationId) == requests.end()) { 317 if (requests.find(transcationId) == requests.end()) {
289 return ""; 318 return "";
@@ -1318,7 +1347,21 @@ int SrsCommonMessage::decode_packet(SrsProtocol* protocol) @@ -1318,7 +1347,21 @@ int SrsCommonMessage::decode_packet(SrsProtocol* protocol)
1318 srs_info("decode the AMF0/AMF3 data(onMetaData message)."); 1347 srs_info("decode the AMF0/AMF3 data(onMetaData message).");
1319 packet = new SrsOnMetaDataPacket(); 1348 packet = new SrsOnMetaDataPacket();
1320 return packet->decode(stream); 1349 return packet->decode(stream);
1321 - } 1350 + } else if(command == SRS_BW_CHECK_FINISHED
  1351 + || command == SRS_BW_CHECK_PLAYING
  1352 + || command == SRS_BW_CHECK_PUBLISHING
  1353 + || command == SRS_BW_CHECK_STARTING_PLAY
  1354 + || command == SRS_BW_CHECK_STARTING_PUBLISH
  1355 + || command == SRS_BW_CHECK_START_PLAY
  1356 + || command == SRS_BW_CHECK_START_PUBLISH
  1357 + || command == SRS_BW_CHECK_STOPPED_PLAY
  1358 + || command == SRS_BW_CHECK_STOP_PLAY
  1359 + || command == SRS_BW_CHECK_STOP_PUBLISH)
  1360 + {
  1361 + srs_info("decode the AMF0/AMF3 band width check message.");
  1362 + packet = new SrsBandwidthPacket();
  1363 + return packet->decode(stream);
  1364 + }
1322 1365
1323 // default packet to drop message. 1366 // default packet to drop message.
1324 srs_trace("drop the AMF0/AMF3 command message, command_name=%s", command.c_str()); 1367 srs_trace("drop the AMF0/AMF3 command message, command_name=%s", command.c_str());
@@ -1370,7 +1413,7 @@ int SrsCommonMessage::get_perfer_cid() @@ -1370,7 +1413,7 @@ int SrsCommonMessage::get_perfer_cid()
1370 return packet->get_perfer_cid(); 1413 return packet->get_perfer_cid();
1371 } 1414 }
1372 1415
1373 -void SrsCommonMessage::set_packet(SrsPacket* pkt, int stream_id) 1416 +SrsCommonMessage* SrsCommonMessage::set_packet(SrsPacket* pkt, int stream_id)
1374 { 1417 {
1375 srs_freep(packet); 1418 srs_freep(packet);
1376 1419
@@ -1379,6 +1422,8 @@ void SrsCommonMessage::set_packet(SrsPacket* pkt, int stream_id) @@ -1379,6 +1422,8 @@ void SrsCommonMessage::set_packet(SrsPacket* pkt, int stream_id)
1379 header.message_type = packet->get_message_type(); 1422 header.message_type = packet->get_message_type();
1380 header.payload_length = packet->get_payload_length(); 1423 header.payload_length = packet->get_payload_length();
1381 header.stream_id = stream_id; 1424 header.stream_id = stream_id;
  1425 +
  1426 + return this;
1382 } 1427 }
1383 1428
1384 int SrsCommonMessage::encode_packet() 1429 int SrsCommonMessage::encode_packet()
@@ -1782,8 +1827,17 @@ int SrsConnectAppResPacket::get_message_type() @@ -1782,8 +1827,17 @@ int SrsConnectAppResPacket::get_message_type()
1782 1827
1783 int SrsConnectAppResPacket::get_size() 1828 int SrsConnectAppResPacket::get_size()
1784 { 1829 {
1785 - return srs_amf0_get_string_size(command_name) + srs_amf0_get_number_size()  
1786 - + srs_amf0_get_object_size(props)+ srs_amf0_get_object_size(info); 1830 + int size = srs_amf0_get_string_size(command_name) + srs_amf0_get_number_size();
  1831 +
  1832 + if (props->size() > 0) {
  1833 + size += srs_amf0_get_object_size(props);
  1834 + }
  1835 +
  1836 + if (info->size() > 0) {
  1837 + size += srs_amf0_get_object_size(info);
  1838 + }
  1839 +
  1840 + return size;
1787 } 1841 }
1788 1842
1789 int SrsConnectAppResPacket::encode_packet(SrsStream* stream) 1843 int SrsConnectAppResPacket::encode_packet(SrsStream* stream)
@@ -1802,16 +1856,22 @@ int SrsConnectAppResPacket::encode_packet(SrsStream* stream) @@ -1802,16 +1856,22 @@ int SrsConnectAppResPacket::encode_packet(SrsStream* stream)
1802 } 1856 }
1803 srs_verbose("encode transaction_id success."); 1857 srs_verbose("encode transaction_id success.");
1804 1858
1805 - if ((ret = srs_amf0_write_object(stream, props)) != ERROR_SUCCESS) {  
1806 - srs_error("encode props failed. ret=%d", ret);  
1807 - return ret;  
1808 - } 1859 + if (props->size() > 0) {
  1860 + if ((ret = srs_amf0_write_object(stream, props)) != ERROR_SUCCESS) {
  1861 + srs_error("encode props failed. ret=%d", ret);
  1862 + return ret;
  1863 + }
  1864 + }
  1865 +
1809 srs_verbose("encode props success."); 1866 srs_verbose("encode props success.");
1810 1867
1811 - if ((ret = srs_amf0_write_object(stream, info)) != ERROR_SUCCESS) {  
1812 - srs_error("encode info failed. ret=%d", ret);  
1813 - return ret;  
1814 - } 1868 + if (info->size() > 0) {
  1869 + if ((ret = srs_amf0_write_object(stream, info)) != ERROR_SUCCESS) {
  1870 + srs_error("encode info failed. ret=%d", ret);
  1871 + return ret;
  1872 + }
  1873 + }
  1874 +
1815 srs_verbose("encode info success."); 1875 srs_verbose("encode info success.");
1816 1876
1817 srs_info("encode connect app response packet success."); 1877 srs_info("encode connect app response packet success.");
@@ -2596,6 +2656,163 @@ int SrsOnStatusCallPacket::encode_packet(SrsStream* stream) @@ -2596,6 +2656,163 @@ int SrsOnStatusCallPacket::encode_packet(SrsStream* stream)
2596 return ret; 2656 return ret;
2597 } 2657 }
2598 2658
  2659 +SrsBandwidthPacket::SrsBandwidthPacket()
  2660 +{
  2661 + command_name = RTMP_AMF0_COMMAND_ON_STATUS;
  2662 + transaction_id = 0;
  2663 + args = new SrsAmf0Null();
  2664 + data = new SrsAmf0Object();
  2665 +}
  2666 +
  2667 +SrsBandwidthPacket::~SrsBandwidthPacket()
  2668 +{
  2669 + srs_freep(args);
  2670 + srs_freep(data);
  2671 +}
  2672 +
  2673 +int SrsBandwidthPacket::get_perfer_cid()
  2674 +{
  2675 + return RTMP_CID_OverStream;
  2676 +}
  2677 +
  2678 +int SrsBandwidthPacket::get_message_type()
  2679 +{
  2680 + return RTMP_MSG_AMF0CommandMessage;
  2681 +}
  2682 +
  2683 +int SrsBandwidthPacket::get_size()
  2684 +{
  2685 + return srs_amf0_get_string_size(command_name) + srs_amf0_get_number_size()
  2686 + + srs_amf0_get_null_size() + srs_amf0_get_object_size(data);
  2687 +}
  2688 +
  2689 +int SrsBandwidthPacket::encode_packet(SrsStream* stream)
  2690 +{
  2691 + int ret = ERROR_SUCCESS;
  2692 +
  2693 + if ((ret = srs_amf0_write_string(stream, command_name)) != ERROR_SUCCESS) {
  2694 + srs_error("encode command_name failed. ret=%d", ret);
  2695 + return ret;
  2696 + }
  2697 + srs_verbose("encode command_name success.");
  2698 +
  2699 + if ((ret = srs_amf0_write_number(stream, transaction_id)) != ERROR_SUCCESS) {
  2700 + srs_error("encode transaction_id failed. ret=%d", ret);
  2701 + return ret;
  2702 + }
  2703 + srs_verbose("encode transaction_id success.");
  2704 +
  2705 + if ((ret = srs_amf0_write_null(stream)) != ERROR_SUCCESS) {
  2706 + srs_error("encode args failed. ret=%d", ret);
  2707 + return ret;
  2708 + }
  2709 + srs_verbose("encode args success.");;
  2710 +
  2711 + if ((ret = srs_amf0_write_object(stream, data)) != ERROR_SUCCESS) {
  2712 + srs_error("encode data failed. ret=%d", ret);
  2713 + return ret;
  2714 + }
  2715 + srs_verbose("encode data success.");
  2716 +
  2717 + srs_info("encode onStatus(Call) packet success.");
  2718 +
  2719 + return ret;
  2720 +}
  2721 +
  2722 +int SrsBandwidthPacket::decode(SrsStream *stream)
  2723 +{
  2724 + int ret = ERROR_SUCCESS;
  2725 +
  2726 + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) {
  2727 + srs_error("amf0 decode play command_name failed. ret=%d", ret);
  2728 + return ret;
  2729 + }
  2730 +
  2731 + if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) {
  2732 + srs_error("amf0 decode play transaction_id failed. ret=%d", ret);
  2733 + return ret;
  2734 + }
  2735 +
  2736 + if ((ret = srs_amf0_read_null(stream)) != ERROR_SUCCESS) {
  2737 + srs_error("amf0 decode play command_object failed. ret=%d", ret);
  2738 + return ret;
  2739 + }
  2740 +
  2741 + // @remark, for bandwidth test, ignore the data field.
  2742 +
  2743 + srs_info("decode SrsBandwidthPacket success.");
  2744 +
  2745 + return ret;
  2746 +}
  2747 +
  2748 +bool SrsBandwidthPacket::is_starting_play()
  2749 +{
  2750 + return command_name == SRS_BW_CHECK_STARTING_PLAY;
  2751 +}
  2752 +
  2753 +bool SrsBandwidthPacket::is_stopped_play()
  2754 +{
  2755 + return command_name == SRS_BW_CHECK_STOPPED_PLAY;
  2756 +}
  2757 +
  2758 +bool SrsBandwidthPacket::is_starting_publish()
  2759 +{
  2760 + return command_name == SRS_BW_CHECK_STARTING_PUBLISH;
  2761 +}
  2762 +
  2763 +bool SrsBandwidthPacket::is_stopped_publish()
  2764 +{
  2765 + return command_name == SRS_BW_CHECK_STOPPED_PUBLISH;
  2766 +}
  2767 +
  2768 +bool SrsBandwidthPacket::is_flash_final()
  2769 +{
  2770 + return command_name == SRS_BW_CHECK_FLASH_FINAL;
  2771 +}
  2772 +
  2773 +SrsBandwidthPacket* SrsBandwidthPacket::create_finish()
  2774 +{
  2775 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2776 + return pkt->set_command(SRS_BW_CHECK_FINISHED);
  2777 +}
  2778 +
  2779 +SrsBandwidthPacket* SrsBandwidthPacket::create_start_play()
  2780 +{
  2781 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2782 + return pkt->set_command(SRS_BW_CHECK_START_PLAY);
  2783 +}
  2784 +
  2785 +SrsBandwidthPacket* SrsBandwidthPacket::create_playing()
  2786 +{
  2787 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2788 + return pkt->set_command(SRS_BW_CHECK_STARTING_PLAY);
  2789 +}
  2790 +
  2791 +SrsBandwidthPacket* SrsBandwidthPacket::create_stop_play()
  2792 +{
  2793 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2794 + return pkt->set_command(SRS_BW_CHECK_STOP_PLAY);
  2795 +}
  2796 +
  2797 +SrsBandwidthPacket* SrsBandwidthPacket::create_start_publish()
  2798 +{
  2799 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2800 + return pkt->set_command(SRS_BW_CHECK_START_PUBLISH);
  2801 +}
  2802 +
  2803 +SrsBandwidthPacket* SrsBandwidthPacket::create_stop_publish()
  2804 +{
  2805 + SrsBandwidthPacket* pkt = new SrsBandwidthPacket();
  2806 + return pkt->set_command(SRS_BW_CHECK_STOP_PUBLISH);
  2807 +}
  2808 +
  2809 +SrsBandwidthPacket* SrsBandwidthPacket::set_command(string command)
  2810 +{
  2811 + command_name = command;
  2812 +
  2813 + return this;
  2814 +}
  2815 +
2599 SrsOnStatusDataPacket::SrsOnStatusDataPacket() 2816 SrsOnStatusDataPacket::SrsOnStatusDataPacket()
2600 { 2817 {
2601 command_name = RTMP_AMF0_COMMAND_ON_STATUS; 2818 command_name = RTMP_AMF0_COMMAND_ON_STATUS;
@@ -310,6 +310,7 @@ class SrsCommonMessage : public ISrsMessage @@ -310,6 +310,7 @@ class SrsCommonMessage : public ISrsMessage
310 { 310 {
311 private: 311 private:
312 typedef ISrsMessage super; 312 typedef ISrsMessage super;
  313 + disable_default_copy(SrsCommonMessage);
313 // decoded message payload. 314 // decoded message payload.
314 private: 315 private:
315 SrsStream* stream; 316 SrsStream* stream;
@@ -345,9 +346,10 @@ public: @@ -345,9 +346,10 @@ public:
345 * set the encoded packet to encode_packet() to payload. 346 * set the encoded packet to encode_packet() to payload.
346 * @stream_id, the id of stream which is created by createStream. 347 * @stream_id, the id of stream which is created by createStream.
347 * @remark, user never free the pkt, the message will auto free it. 348 * @remark, user never free the pkt, the message will auto free it.
  349 + * @return message itself.
348 */ 350 */
349 // TODO: refine the send methods. 351 // TODO: refine the send methods.
350 - virtual void set_packet(SrsPacket* pkt, int stream_id); 352 + virtual SrsCommonMessage* set_packet(SrsPacket* pkt, int stream_id);
351 /** 353 /**
352 * encode the packet to message payload bytes. 354 * encode the packet to message payload bytes.
353 * @remark there exists empty packet, so maybe the payload is NULL. 355 * @remark there exists empty packet, so maybe the payload is NULL.
@@ -832,6 +834,55 @@ protected: @@ -832,6 +834,55 @@ protected:
832 }; 834 };
833 835
834 /** 836 /**
  837 +* the special packet for the bandwidth test.
  838 +* actually, it's a SrsOnStatusCallPacket, but
  839 +* 1. encode with data field, to send data to client.
  840 +* 2. decode ignore the data field, donot care.
  841 +*/
  842 +class SrsBandwidthPacket : public SrsPacket
  843 +{
  844 +private:
  845 + typedef SrsPacket super;
  846 + disable_default_copy(SrsBandwidthPacket);
  847 +protected:
  848 + virtual const char* get_class_name()
  849 + {
  850 + return CLASS_NAME_STRING(SrsBandwidthPacket);
  851 + }
  852 +public:
  853 + std::string command_name;
  854 + double transaction_id;
  855 + SrsAmf0Null* args;
  856 + SrsAmf0Object* data;
  857 +public:
  858 + SrsBandwidthPacket();
  859 + virtual ~SrsBandwidthPacket();
  860 +public:
  861 + virtual int get_perfer_cid();
  862 +public:
  863 + virtual int get_message_type();
  864 +protected:
  865 + virtual int get_size();
  866 + virtual int encode_packet(SrsStream* stream);
  867 +public:
  868 + virtual int decode(SrsStream* stream);
  869 +public:
  870 + virtual bool is_starting_play();
  871 + virtual bool is_stopped_play();
  872 + virtual bool is_starting_publish();
  873 + virtual bool is_stopped_publish();
  874 + virtual bool is_flash_final();
  875 + static SrsBandwidthPacket* create_finish();
  876 + static SrsBandwidthPacket* create_start_play();
  877 + static SrsBandwidthPacket* create_playing();
  878 + static SrsBandwidthPacket* create_stop_play();
  879 + static SrsBandwidthPacket* create_start_publish();
  880 + static SrsBandwidthPacket* create_stop_publish();
  881 +private:
  882 + virtual SrsBandwidthPacket* set_command(std::string command);
  883 +};
  884 +
  885 +/**
835 * onStatus data, AMF0 Data 886 * onStatus data, AMF0 Data
836 * @remark, user must set the stream_id by SrsMessage.set_packet(). 887 * @remark, user must set the stream_id by SrsMessage.set_packet().
837 */ 888 */
@@ -51,8 +51,11 @@ using namespace std; @@ -51,8 +51,11 @@ using namespace std;
51 #define StatusClientId "clientid" 51 #define StatusClientId "clientid"
52 // status value 52 // status value
53 #define StatusLevelStatus "status" 53 #define StatusLevelStatus "status"
  54 +// status error
  55 +#define StatusLevelError "error"
54 // code value 56 // code value
55 #define StatusCodeConnectSuccess "NetConnection.Connect.Success" 57 #define StatusCodeConnectSuccess "NetConnection.Connect.Success"
  58 +#define StatusCodeConnectRejected "NetConnection.Connect.Rejected"
56 #define StatusCodeStreamReset "NetStream.Play.Reset" 59 #define StatusCodeStreamReset "NetStream.Play.Reset"
57 #define StatusCodeStreamStart "NetStream.Play.Start" 60 #define StatusCodeStreamStart "NetStream.Play.Start"
58 #define StatusCodeStreamPause "NetStream.Pause.Notify" 61 #define StatusCodeStreamPause "NetStream.Pause.Notify"
@@ -577,7 +580,7 @@ int SrsRtmp::set_peer_bandwidth(int bandwidth, int type) @@ -577,7 +580,7 @@ int SrsRtmp::set_peer_bandwidth(int bandwidth, int type)
577 return ret; 580 return ret;
578 } 581 }
579 582
580 -int SrsRtmp::response_connect_app(SrsRequest* req) 583 +int SrsRtmp::response_connect_app(SrsRequest *req, const char* server_ip)
581 { 584 {
582 int ret = ERROR_SUCCESS; 585 int ret = ERROR_SUCCESS;
583 586
@@ -606,6 +609,10 @@ int SrsRtmp::response_connect_app(SrsRequest* req) @@ -606,6 +609,10 @@ int SrsRtmp::response_connect_app(SrsRequest* req)
606 data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT)); 609 data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT));
607 data->set("srs_contributor", new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR)); 610 data->set("srs_contributor", new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR));
608 611
  612 + if (server_ip) {
  613 + data->set("srs_server_ip", new SrsAmf0String(server_ip));
  614 + }
  615 +
609 msg->set_packet(pkt, 0); 616 msg->set_packet(pkt, 0);
610 617
611 if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) { 618 if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
@@ -614,7 +621,28 @@ int SrsRtmp::response_connect_app(SrsRequest* req) @@ -614,7 +621,28 @@ int SrsRtmp::response_connect_app(SrsRequest* req)
614 } 621 }
615 srs_info("send connect app response message success."); 622 srs_info("send connect app response message success.");
616 623
617 - return ret; 624 + return ret;
  625 +}
  626 +
  627 +void SrsRtmp::response_connect_reject(SrsRequest *req, const char* desc)
  628 +{
  629 + int ret = ERROR_SUCCESS;
  630 +
  631 + SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();
  632 + pkt->command_name = "_error";
  633 + pkt->props->set(StatusLevel, new SrsAmf0String(StatusLevelError));
  634 + pkt->props->set(StatusCode, new SrsAmf0String(StatusCodeConnectRejected));
  635 + pkt->props->set(StatusDescription, new SrsAmf0String(desc));
  636 + //pkt->props->set("objectEncoding", new SrsAmf0Number(req->objectEncoding));
  637 +
  638 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  639 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  640 + srs_error("send connect app response rejected message failed. ret=%d", ret);
  641 + return;
  642 + }
  643 + srs_info("send connect app response rejected message success.");
  644 +
  645 + return;
618 } 646 }
619 647
620 int SrsRtmp::on_bw_done() 648 int SrsRtmp::on_bw_done()
@@ -167,7 +167,11 @@ public: @@ -167,7 +167,11 @@ public:
167 * using the Limit type field. 167 * using the Limit type field.
168 */ 168 */
169 virtual int set_peer_bandwidth(int bandwidth, int type); 169 virtual int set_peer_bandwidth(int bandwidth, int type);
170 - virtual int response_connect_app(SrsRequest* req); 170 + /**
  171 + * @param server_ip the ip of server.
  172 + */
  173 + virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL);
  174 + virtual void response_connect_reject(SrsRequest* req, const char* desc);
171 virtual int on_bw_done(); 175 virtual int on_bw_done();
172 /** 176 /**
173 * recv some message to identify the client. 177 * recv some message to identify the client.
@@ -10,6 +10,8 @@ file @@ -10,6 +10,8 @@ file
10 ..\core\srs_core_amf0.cpp, 10 ..\core\srs_core_amf0.cpp,
11 ..\core\srs_core_autofree.hpp, 11 ..\core\srs_core_autofree.hpp,
12 ..\core\srs_core_autofree.cpp, 12 ..\core\srs_core_autofree.cpp,
  13 + ..\core\srs_core_bandwidth.hpp,
  14 + ..\core\srs_core_bandwidth.cpp,
13 ..\core\srs_core_buffer.hpp, 15 ..\core\srs_core_buffer.hpp,
14 ..\core\srs_core_buffer.cpp, 16 ..\core\srs_core_buffer.cpp,
15 ..\core\srs_core_client.hpp, 17 ..\core\srs_core_client.hpp,