正在显示
15 个修改的文件
包含
971 行增加
和
19 行删除
| @@ -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 |
trunk/src/core/srs_core.cpp
100755 → 100644
trunk/src/core/srs_core.hpp
100755 → 100644
| @@ -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 |
trunk/src/core/srs_core_bandwidth.cpp
0 → 100644
| 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 | +} |
trunk/src/core/srs_core_bandwidth.hpp
0 → 100644
| 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(); |
trunk/src/core/srs_core_config.cpp
100755 → 100644
| @@ -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"); |
trunk/src/core/srs_core_config.hpp
100755 → 100644
| @@ -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, |
-
请 注册 或 登录 后发表评论