正在显示
31 个修改的文件
包含
569 行增加
和
403 行删除
| @@ -566,6 +566,9 @@ Supported operating systems and hardware: | @@ -566,6 +566,9 @@ Supported operating systems and hardware: | ||
| 566 | 566 | ||
| 567 | ### SRS 2.0 history | 567 | ### SRS 2.0 history |
| 568 | 568 | ||
| 569 | +* v2.0, 2015-05-22, fix [#397](https://github.com/simple-rtmp-server/srs/issues/397) the USER_HZ maybe not 100. 2.0.165 | ||
| 570 | +* v2.0, 2015-05-22, for [#400](https://github.com/simple-rtmp-server/srs/issues/400), parse when got entire http header, by feilong. 2.0.164. | ||
| 571 | +* v2.0, 2015-05-19, merge from bravo system, add the rtmfp to bms(commercial srs). 2.0.163. | ||
| 569 | * v2.0, 2015-05-10, support push flv stream over HTTP POST to SRS. | 572 | * v2.0, 2015-05-10, support push flv stream over HTTP POST to SRS. |
| 570 | * v2.0, 2015-04-20, support ingest hls live stream to RTMP. | 573 | * v2.0, 2015-04-20, support ingest hls live stream to RTMP. |
| 571 | * v2.0, 2015-04-15, for [#383](https://github.com/simple-rtmp-server/srs/issues/383), support mix_correct algorithm. 2.0.161. | 574 | * v2.0, 2015-04-15, for [#383](https://github.com/simple-rtmp-server/srs/issues/383), support mix_correct algorithm. 2.0.161. |
| @@ -674,6 +677,10 @@ Supported operating systems and hardware: | @@ -674,6 +677,10 @@ Supported operating systems and hardware: | ||
| 674 | 677 | ||
| 675 | ### SRS 1.0 history | 678 | ### SRS 1.0 history |
| 676 | 679 | ||
| 680 | +* v1.0, 2015-05-22, fix [#397](https://github.com/simple-rtmp-server/srs/issues/397) the USER_HZ maybe not 100. 1.0.32 | ||
| 681 | +* v1.0, 2015-03-26, fix hls aac adts bug, in aac mux. 1.0.31. | ||
| 682 | +* <strong>v1.0, 2015-03-19, [1.0r3 release(1.0.30)](https://github.com/simple-rtmp-server/srs/releases/tag/1.0r3) released. 59511 lines.</strong> | ||
| 683 | +* v1.0, 2015-03-17, remove the osx for 1.0.30. | ||
| 677 | * v1.0, 2015-02-17, the join maybe failed, should use a variable to ensure thread terminated. 1.0.28. | 684 | * v1.0, 2015-02-17, the join maybe failed, should use a variable to ensure thread terminated. 1.0.28. |
| 678 | * <strong>v1.0, 2015-02-12, [1.0r2 release(1.0.27)](https://github.com/simple-rtmp-server/srs/releases/tag/1.0r2) released. 59507 lines.</strong> | 685 | * <strong>v1.0, 2015-02-12, [1.0r2 release(1.0.27)](https://github.com/simple-rtmp-server/srs/releases/tag/1.0r2) released. 59507 lines.</strong> |
| 679 | * v1.0, 2015-02-11, dev code HuKaiqun for 1.0.27. | 686 | * v1.0, 2015-02-11, dev code HuKaiqun for 1.0.27. |
| @@ -408,17 +408,17 @@ | @@ -408,17 +408,17 @@ | ||
| 408 | isa = PBXGroup; | 408 | isa = PBXGroup; |
| 409 | children = ( | 409 | children = ( |
| 410 | 3C1232B81AAE824500CE8F6C /* configure */, | 410 | 3C1232B81AAE824500CE8F6C /* configure */, |
| 411 | - 3C36DB541ABD1CA70066CCAF /* libs */, | ||
| 412 | - 3C1EE6AF1AB107EE00576EE9 /* conf */, | ||
| 413 | - 3C1232EF1AAEAC5800CE8F6C /* etc */, | ||
| 414 | - 3C1232BA1AAE826F00CE8F6C /* auto */, | ||
| 415 | - 3C1232B91AAE825100CE8F6C /* scripts */, | ||
| 416 | - 3C12324B1AAE81CE00CE8F6C /* app */, | ||
| 417 | - 3C12322C1AAE819900CE8F6C /* protocol */, | 411 | + 3C1231EF1AAE651100CE8F6C /* core */, |
| 418 | 3C1232071AAE814200CE8F6C /* kernel */, | 412 | 3C1232071AAE814200CE8F6C /* kernel */, |
| 413 | + 3C12322C1AAE819900CE8F6C /* protocol */, | ||
| 414 | + 3C12324B1AAE81CE00CE8F6C /* app */, | ||
| 419 | 3C1232041AAE80CB00CE8F6C /* main */, | 415 | 3C1232041AAE80CB00CE8F6C /* main */, |
| 420 | 3C1231F91AAE670E00CE8F6C /* objs */, | 416 | 3C1231F91AAE670E00CE8F6C /* objs */, |
| 421 | - 3C1231EF1AAE651100CE8F6C /* core */, | 417 | + 3C1232BA1AAE826F00CE8F6C /* auto */, |
| 418 | + 3C1232B91AAE825100CE8F6C /* scripts */, | ||
| 419 | + 3C1EE6AF1AB107EE00576EE9 /* conf */, | ||
| 420 | + 3C36DB541ABD1CA70066CCAF /* libs */, | ||
| 421 | + 3C1232EF1AAEAC5800CE8F6C /* etc */, | ||
| 422 | ); | 422 | ); |
| 423 | path = srs_xcode; | 423 | path = srs_xcode; |
| 424 | sourceTree = "<group>"; | 424 | sourceTree = "<group>"; |
| @@ -514,12 +514,12 @@ | @@ -514,12 +514,12 @@ | ||
| 514 | 3C12324B1AAE81CE00CE8F6C /* app */ = { | 514 | 3C12324B1AAE81CE00CE8F6C /* app */ = { |
| 515 | isa = PBXGroup; | 515 | isa = PBXGroup; |
| 516 | children = ( | 516 | children = ( |
| 517 | - 3C28EDDD1AF5C43F00A3AEAC /* srs_app_caster_flv.cpp */, | ||
| 518 | - 3C28EDDE1AF5C43F00A3AEAC /* srs_app_caster_flv.hpp */, | ||
| 519 | 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */, | 517 | 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */, |
| 520 | 3CD88B3E1ACA9C58000359E0 /* srs_app_async_call.hpp */, | 518 | 3CD88B3E1ACA9C58000359E0 /* srs_app_async_call.hpp */, |
| 521 | 3C12324C1AAE81D900CE8F6C /* srs_app_bandwidth.cpp */, | 519 | 3C12324C1AAE81D900CE8F6C /* srs_app_bandwidth.cpp */, |
| 522 | 3C12324D1AAE81D900CE8F6C /* srs_app_bandwidth.hpp */, | 520 | 3C12324D1AAE81D900CE8F6C /* srs_app_bandwidth.hpp */, |
| 521 | + 3C28EDDD1AF5C43F00A3AEAC /* srs_app_caster_flv.cpp */, | ||
| 522 | + 3C28EDDE1AF5C43F00A3AEAC /* srs_app_caster_flv.hpp */, | ||
| 523 | 3C12324E1AAE81D900CE8F6C /* srs_app_config.cpp */, | 523 | 3C12324E1AAE81D900CE8F6C /* srs_app_config.cpp */, |
| 524 | 3C12324F1AAE81D900CE8F6C /* srs_app_config.hpp */, | 524 | 3C12324F1AAE81D900CE8F6C /* srs_app_config.hpp */, |
| 525 | 3C1232501AAE81D900CE8F6C /* srs_app_conn.cpp */, | 525 | 3C1232501AAE81D900CE8F6C /* srs_app_conn.cpp */, |
| @@ -536,10 +536,10 @@ | @@ -536,10 +536,10 @@ | ||
| 536 | 3C12325B1AAE81D900CE8F6C /* srs_app_ffmpeg.hpp */, | 536 | 3C12325B1AAE81D900CE8F6C /* srs_app_ffmpeg.hpp */, |
| 537 | 3C12325C1AAE81D900CE8F6C /* srs_app_forward.cpp */, | 537 | 3C12325C1AAE81D900CE8F6C /* srs_app_forward.cpp */, |
| 538 | 3C12325D1AAE81D900CE8F6C /* srs_app_forward.hpp */, | 538 | 3C12325D1AAE81D900CE8F6C /* srs_app_forward.hpp */, |
| 539 | - 3C12325E1AAE81D900CE8F6C /* srs_app_heartbeat.cpp */, | ||
| 540 | - 3C12325F1AAE81D900CE8F6C /* srs_app_heartbeat.hpp */, | ||
| 541 | 3C1EE6AC1AB1055800576EE9 /* srs_app_hds.cpp */, | 539 | 3C1EE6AC1AB1055800576EE9 /* srs_app_hds.cpp */, |
| 542 | 3C1EE6AD1AB1055800576EE9 /* srs_app_hds.hpp */, | 540 | 3C1EE6AD1AB1055800576EE9 /* srs_app_hds.hpp */, |
| 541 | + 3C12325E1AAE81D900CE8F6C /* srs_app_heartbeat.cpp */, | ||
| 542 | + 3C12325F1AAE81D900CE8F6C /* srs_app_heartbeat.hpp */, | ||
| 543 | 3C1232601AAE81D900CE8F6C /* srs_app_hls.cpp */, | 543 | 3C1232601AAE81D900CE8F6C /* srs_app_hls.cpp */, |
| 544 | 3C1232611AAE81D900CE8F6C /* srs_app_hls.hpp */, | 544 | 3C1232611AAE81D900CE8F6C /* srs_app_hls.hpp */, |
| 545 | 3C1232621AAE81D900CE8F6C /* srs_app_http_api.cpp */, | 545 | 3C1232621AAE81D900CE8F6C /* srs_app_http_api.cpp */, |
| @@ -441,10 +441,22 @@ int SrsConfig::reload_conf(SrsConfig* conf) | @@ -441,10 +441,22 @@ int SrsConfig::reload_conf(SrsConfig* conf) | ||
| 441 | // daemon | 441 | // daemon |
| 442 | // | 442 | // |
| 443 | // always support reload without additional code: | 443 | // always support reload without additional code: |
| 444 | - // chunk_size, ff_log_dir, max_connections, | 444 | + // chunk_size, ff_log_dir, |
| 445 | // bandcheck, http_hooks, heartbeat, | 445 | // bandcheck, http_hooks, heartbeat, |
| 446 | // token_traverse, debug_srs_upnode, | 446 | // token_traverse, debug_srs_upnode, |
| 447 | // security | 447 | // security |
| 448 | + | ||
| 449 | + // merge config: max_connections | ||
| 450 | + if (!srs_directive_equals(root->get("max_connections"), old_root->get("max_connections"))) { | ||
| 451 | + for (it = subscribes.begin(); it != subscribes.end(); ++it) { | ||
| 452 | + ISrsReloadHandler* subscribe = *it; | ||
| 453 | + if ((ret = subscribe->on_reload_max_conns()) != ERROR_SUCCESS) { | ||
| 454 | + srs_error("notify subscribes reload max_connections failed. ret=%d", ret); | ||
| 455 | + return ret; | ||
| 456 | + } | ||
| 457 | + } | ||
| 458 | + srs_trace("reload max_connections success."); | ||
| 459 | + } | ||
| 448 | 460 | ||
| 449 | // merge config: listen | 461 | // merge config: listen |
| 450 | if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { | 462 | if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { |
| @@ -1082,6 +1082,7 @@ SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) | @@ -1082,6 +1082,7 @@ SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) | ||
| 1082 | { | 1082 | { |
| 1083 | conn = c; | 1083 | conn = c; |
| 1084 | chunked = false; | 1084 | chunked = false; |
| 1085 | + keep_alive = true; | ||
| 1085 | _uri = new SrsHttpUri(); | 1086 | _uri = new SrsHttpUri(); |
| 1086 | _body = new SrsHttpResponseReader(this, io); | 1087 | _body = new SrsHttpResponseReader(this, io); |
| 1087 | _http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE]; | 1088 | _http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE]; |
| @@ -1106,6 +1107,9 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, | @@ -1106,6 +1107,9 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, | ||
| 1106 | std::string transfer_encoding = get_request_header("Transfer-Encoding"); | 1107 | std::string transfer_encoding = get_request_header("Transfer-Encoding"); |
| 1107 | chunked = (transfer_encoding == "chunked"); | 1108 | chunked = (transfer_encoding == "chunked"); |
| 1108 | 1109 | ||
| 1110 | + // whether keep alive. | ||
| 1111 | + keep_alive = http_should_keep_alive(header); | ||
| 1112 | + | ||
| 1109 | // set the buffer. | 1113 | // set the buffer. |
| 1110 | if ((ret = _body->initialize(body)) != ERROR_SUCCESS) { | 1114 | if ((ret = _body->initialize(body)) != ERROR_SUCCESS) { |
| 1111 | return ret; | 1115 | return ret; |
| @@ -1232,6 +1236,11 @@ bool SrsHttpMessage::is_chunked() | @@ -1232,6 +1236,11 @@ bool SrsHttpMessage::is_chunked() | ||
| 1232 | return chunked; | 1236 | return chunked; |
| 1233 | } | 1237 | } |
| 1234 | 1238 | ||
| 1239 | +bool SrsHttpMessage::is_keep_alive() | ||
| 1240 | +{ | ||
| 1241 | + return keep_alive; | ||
| 1242 | +} | ||
| 1243 | + | ||
| 1235 | string SrsHttpMessage::uri() | 1244 | string SrsHttpMessage::uri() |
| 1236 | { | 1245 | { |
| 1237 | std::string uri = _uri->get_schema(); | 1246 | std::string uri = _uri->get_schema(); |
| @@ -1447,10 +1456,17 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | @@ -1447,10 +1456,17 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 1447 | while (true) { | 1456 | while (true) { |
| 1448 | ssize_t nparsed = 0; | 1457 | ssize_t nparsed = 0; |
| 1449 | 1458 | ||
| 1450 | - // when buffer not empty, parse it. | ||
| 1451 | - if (buffer->size() > 0) { | ||
| 1452 | - nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size()); | ||
| 1453 | - srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed); | 1459 | + // when got entire http header, parse it. |
| 1460 | + // @see https://github.com/simple-rtmp-server/srs/issues/400 | ||
| 1461 | + char* start = buffer->bytes(); | ||
| 1462 | + char* end = start + buffer->size(); | ||
| 1463 | + for (char* p = start; p <= end - 4; p++) { | ||
| 1464 | + // SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A | ||
| 1465 | + if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) { | ||
| 1466 | + nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size()); | ||
| 1467 | + srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed); | ||
| 1468 | + break; | ||
| 1469 | + } | ||
| 1454 | } | 1470 | } |
| 1455 | 1471 | ||
| 1456 | // consume the parsed bytes. | 1472 | // consume the parsed bytes. |
| @@ -495,6 +495,11 @@ private: | @@ -495,6 +495,11 @@ private: | ||
| 495 | */ | 495 | */ |
| 496 | bool chunked; | 496 | bool chunked; |
| 497 | /** | 497 | /** |
| 498 | + * whether the request indicates should keep alive | ||
| 499 | + * for the http connection. | ||
| 500 | + */ | ||
| 501 | + bool keep_alive; | ||
| 502 | + /** | ||
| 498 | * uri parser | 503 | * uri parser |
| 499 | */ | 504 | */ |
| 500 | SrsHttpUri* _uri; | 505 | SrsHttpUri* _uri; |
| @@ -539,6 +544,10 @@ public: | @@ -539,6 +544,10 @@ public: | ||
| 539 | */ | 544 | */ |
| 540 | virtual bool is_chunked(); | 545 | virtual bool is_chunked(); |
| 541 | /** | 546 | /** |
| 547 | + * whether should keep the connection alive. | ||
| 548 | + */ | ||
| 549 | + virtual bool is_keep_alive(); | ||
| 550 | + /** | ||
| 542 | * the uri contains the host and path. | 551 | * the uri contains the host and path. |
| 543 | */ | 552 | */ |
| 544 | virtual std::string uri(); | 553 | virtual std::string uri(); |
| @@ -523,6 +523,10 @@ int SrsHttpApi::do_cycle() | @@ -523,6 +523,10 @@ int SrsHttpApi::do_cycle() | ||
| 523 | // underlayer socket | 523 | // underlayer socket |
| 524 | SrsStSocket skt(stfd); | 524 | SrsStSocket skt(stfd); |
| 525 | 525 | ||
| 526 | + // set the recv timeout, for some clients never disconnect the connection. | ||
| 527 | + // @see https://github.com/simple-rtmp-server/srs/issues/398 | ||
| 528 | + skt.set_recv_timeout(SRS_HTTP_RECV_TIMEOUT_US); | ||
| 529 | + | ||
| 526 | // process http messages. | 530 | // process http messages. |
| 527 | for (;;) { | 531 | for (;;) { |
| 528 | SrsHttpMessage* req = NULL; | 532 | SrsHttpMessage* req = NULL; |
| @@ -551,6 +555,12 @@ int SrsHttpApi::do_cycle() | @@ -551,6 +555,12 @@ int SrsHttpApi::do_cycle() | ||
| 551 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { | 555 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { |
| 552 | return ret; | 556 | return ret; |
| 553 | } | 557 | } |
| 558 | + | ||
| 559 | + // donot keep alive, disconnect it. | ||
| 560 | + // @see https://github.com/simple-rtmp-server/srs/issues/399 | ||
| 561 | + if (!req->is_keep_alive()) { | ||
| 562 | + break; | ||
| 563 | + } | ||
| 554 | } | 564 | } |
| 555 | 565 | ||
| 556 | return ret; | 566 | return ret; |
| @@ -1383,6 +1383,10 @@ int SrsHttpConn::do_cycle() | @@ -1383,6 +1383,10 @@ int SrsHttpConn::do_cycle() | ||
| 1383 | // underlayer socket | 1383 | // underlayer socket |
| 1384 | SrsStSocket skt(stfd); | 1384 | SrsStSocket skt(stfd); |
| 1385 | 1385 | ||
| 1386 | + // set the recv timeout, for some clients never disconnect the connection. | ||
| 1387 | + // @see https://github.com/simple-rtmp-server/srs/issues/398 | ||
| 1388 | + skt.set_recv_timeout(SRS_HTTP_RECV_TIMEOUT_US); | ||
| 1389 | + | ||
| 1386 | // process http messages. | 1390 | // process http messages. |
| 1387 | for (;;) { | 1391 | for (;;) { |
| 1388 | SrsHttpMessage* req = NULL; | 1392 | SrsHttpMessage* req = NULL; |
| @@ -1408,6 +1412,12 @@ int SrsHttpConn::do_cycle() | @@ -1408,6 +1412,12 @@ int SrsHttpConn::do_cycle() | ||
| 1408 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { | 1412 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { |
| 1409 | return ret; | 1413 | return ret; |
| 1410 | } | 1414 | } |
| 1415 | + | ||
| 1416 | + // donot keep alive, disconnect it. | ||
| 1417 | + // @see https://github.com/simple-rtmp-server/srs/issues/399 | ||
| 1418 | + if (!req->is_keep_alive()) { | ||
| 1419 | + break; | ||
| 1420 | + } | ||
| 1411 | } | 1421 | } |
| 1412 | 1422 | ||
| 1413 | return ret; | 1423 | return ret; |
| @@ -77,22 +77,22 @@ void SrsKbpsSlice::sample() | @@ -77,22 +77,22 @@ void SrsKbpsSlice::sample() | ||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | if (now - sample_30s.time > 30 * 1000) { | 79 | if (now - sample_30s.time > 30 * 1000) { |
| 80 | - sample_30s.kbps = (total_bytes - sample_30s.bytes) * 8 / (now - sample_30s.time); | 80 | + sample_30s.kbps = (int)((total_bytes - sample_30s.bytes) * 8 / (now - sample_30s.time)); |
| 81 | sample_30s.time = now; | 81 | sample_30s.time = now; |
| 82 | sample_30s.bytes = total_bytes; | 82 | sample_30s.bytes = total_bytes; |
| 83 | } | 83 | } |
| 84 | if (now - sample_1m.time > 60 * 1000) { | 84 | if (now - sample_1m.time > 60 * 1000) { |
| 85 | - sample_1m.kbps = (total_bytes - sample_1m.bytes) * 8 / (now - sample_1m.time); | 85 | + sample_1m.kbps = (int)((total_bytes - sample_1m.bytes) * 8 / (now - sample_1m.time)); |
| 86 | sample_1m.time = now; | 86 | sample_1m.time = now; |
| 87 | sample_1m.bytes = total_bytes; | 87 | sample_1m.bytes = total_bytes; |
| 88 | } | 88 | } |
| 89 | if (now - sample_5m.time > 300 * 1000) { | 89 | if (now - sample_5m.time > 300 * 1000) { |
| 90 | - sample_5m.kbps = (total_bytes - sample_5m.bytes) * 8 / (now - sample_5m.time); | 90 | + sample_5m.kbps = (int)((total_bytes - sample_5m.bytes) * 8 / (now - sample_5m.time)); |
| 91 | sample_5m.time = now; | 91 | sample_5m.time = now; |
| 92 | sample_5m.bytes = total_bytes; | 92 | sample_5m.bytes = total_bytes; |
| 93 | } | 93 | } |
| 94 | if (now - sample_60m.time > 3600 * 1000) { | 94 | if (now - sample_60m.time > 3600 * 1000) { |
| 95 | - sample_60m.kbps = (total_bytes - sample_60m.bytes) * 8 / (now - sample_60m.time); | 95 | + sample_60m.kbps = (int)((total_bytes - sample_60m.bytes) * 8 / (now - sample_60m.time)); |
| 96 | sample_60m.time = now; | 96 | sample_60m.time = now; |
| 97 | sample_60m.bytes = total_bytes; | 97 | sample_60m.bytes = total_bytes; |
| 98 | } | 98 | } |
| @@ -160,7 +160,7 @@ int SrsKbps::get_send_kbps() | @@ -160,7 +160,7 @@ int SrsKbps::get_send_kbps() | ||
| 160 | return 0; | 160 | return 0; |
| 161 | } | 161 | } |
| 162 | int64_t bytes = get_send_bytes(); | 162 | int64_t bytes = get_send_bytes(); |
| 163 | - return bytes * 8 / duration; | 163 | + return (int)(bytes * 8 / duration); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | int SrsKbps::get_recv_kbps() | 166 | int SrsKbps::get_recv_kbps() |
| @@ -170,7 +170,7 @@ int SrsKbps::get_recv_kbps() | @@ -170,7 +170,7 @@ int SrsKbps::get_recv_kbps() | ||
| 170 | return 0; | 170 | return 0; |
| 171 | } | 171 | } |
| 172 | int64_t bytes = get_recv_bytes(); | 172 | int64_t bytes = get_recv_bytes(); |
| 173 | - return bytes * 8 / duration; | 173 | + return (int)(bytes * 8 / duration); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | int SrsKbps::get_send_kbps_30s() | 176 | int SrsKbps::get_send_kbps_30s() |
| @@ -54,6 +54,11 @@ ISrsUdpHandler::~ISrsUdpHandler() | @@ -54,6 +54,11 @@ ISrsUdpHandler::~ISrsUdpHandler() | ||
| 54 | { | 54 | { |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | +int ISrsUdpHandler::on_stfd_change(st_netfd_t /*fd*/) | ||
| 58 | +{ | ||
| 59 | + return ERROR_SUCCESS; | ||
| 60 | +} | ||
| 61 | + | ||
| 57 | ISrsTcpHandler::ISrsTcpHandler() | 62 | ISrsTcpHandler::ISrsTcpHandler() |
| 58 | { | 63 | { |
| 59 | } | 64 | } |
| @@ -69,7 +74,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) | @@ -69,7 +74,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) | ||
| 69 | port = p; | 74 | port = p; |
| 70 | 75 | ||
| 71 | _fd = -1; | 76 | _fd = -1; |
| 72 | - stfd = NULL; | 77 | + _stfd = NULL; |
| 73 | 78 | ||
| 74 | nb_buf = SRS_UDP_MAX_PACKET_SIZE; | 79 | nb_buf = SRS_UDP_MAX_PACKET_SIZE; |
| 75 | buf = new char[nb_buf]; | 80 | buf = new char[nb_buf]; |
| @@ -80,7 +85,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) | @@ -80,7 +85,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) | ||
| 80 | SrsUdpListener::~SrsUdpListener() | 85 | SrsUdpListener::~SrsUdpListener() |
| 81 | { | 86 | { |
| 82 | // close the stfd to trigger thread to interrupted. | 87 | // close the stfd to trigger thread to interrupted. |
| 83 | - srs_close_stfd(stfd); | 88 | + srs_close_stfd(_stfd); |
| 84 | 89 | ||
| 85 | pthread->stop(); | 90 | pthread->stop(); |
| 86 | srs_freep(pthread); | 91 | srs_freep(pthread); |
| @@ -97,6 +102,11 @@ int SrsUdpListener::fd() | @@ -97,6 +102,11 @@ int SrsUdpListener::fd() | ||
| 97 | return _fd; | 102 | return _fd; |
| 98 | } | 103 | } |
| 99 | 104 | ||
| 105 | +st_netfd_t SrsUdpListener::stfd() | ||
| 106 | +{ | ||
| 107 | + return _stfd; | ||
| 108 | +} | ||
| 109 | + | ||
| 100 | int SrsUdpListener::listen() | 110 | int SrsUdpListener::listen() |
| 101 | { | 111 | { |
| 102 | int ret = ERROR_SUCCESS; | 112 | int ret = ERROR_SUCCESS; |
| @@ -127,7 +137,7 @@ int SrsUdpListener::listen() | @@ -127,7 +137,7 @@ int SrsUdpListener::listen() | ||
| 127 | } | 137 | } |
| 128 | srs_verbose("bind socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); | 138 | srs_verbose("bind socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); |
| 129 | 139 | ||
| 130 | - if ((stfd = st_netfd_open_socket(_fd)) == NULL){ | 140 | + if ((_stfd = st_netfd_open_socket(_fd)) == NULL){ |
| 131 | ret = ERROR_ST_OPEN_SOCKET; | 141 | ret = ERROR_ST_OPEN_SOCKET; |
| 132 | srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret); | 142 | srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret); |
| 133 | return ret; | 143 | return ret; |
| @@ -153,7 +163,7 @@ int SrsUdpListener::cycle() | @@ -153,7 +163,7 @@ int SrsUdpListener::cycle() | ||
| 153 | int nb_from = sizeof(sockaddr_in); | 163 | int nb_from = sizeof(sockaddr_in); |
| 154 | int nread = 0; | 164 | int nread = 0; |
| 155 | 165 | ||
| 156 | - if ((nread = st_recvfrom(stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, ST_UTIME_NO_TIMEOUT)) <= 0) { | 166 | + if ((nread = st_recvfrom(_stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, ST_UTIME_NO_TIMEOUT)) <= 0) { |
| 157 | srs_warn("ignore recv udp packet failed, nread=%d", nread); | 167 | srs_warn("ignore recv udp packet failed, nread=%d", nread); |
| 158 | continue; | 168 | continue; |
| 159 | } | 169 | } |
| @@ -178,7 +188,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) | @@ -178,7 +188,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) | ||
| 178 | port = p; | 188 | port = p; |
| 179 | 189 | ||
| 180 | _fd = -1; | 190 | _fd = -1; |
| 181 | - stfd = NULL; | 191 | + _stfd = NULL; |
| 182 | 192 | ||
| 183 | pthread = new SrsThread("tcp", this, 0, true); | 193 | pthread = new SrsThread("tcp", this, 0, true); |
| 184 | } | 194 | } |
| @@ -186,7 +196,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) | @@ -186,7 +196,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) | ||
| 186 | SrsTcpListener::~SrsTcpListener() | 196 | SrsTcpListener::~SrsTcpListener() |
| 187 | { | 197 | { |
| 188 | // close the stfd to trigger thread to interrupted. | 198 | // close the stfd to trigger thread to interrupted. |
| 189 | - srs_close_stfd(stfd); | 199 | + srs_close_stfd(_stfd); |
| 190 | 200 | ||
| 191 | pthread->stop(); | 201 | pthread->stop(); |
| 192 | srs_freep(pthread); | 202 | srs_freep(pthread); |
| @@ -238,7 +248,7 @@ int SrsTcpListener::listen() | @@ -238,7 +248,7 @@ int SrsTcpListener::listen() | ||
| 238 | } | 248 | } |
| 239 | srs_verbose("listen socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); | 249 | srs_verbose("listen socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); |
| 240 | 250 | ||
| 241 | - if ((stfd = st_netfd_open_socket(_fd)) == NULL){ | 251 | + if ((_stfd = st_netfd_open_socket(_fd)) == NULL){ |
| 242 | ret = ERROR_ST_OPEN_SOCKET; | 252 | ret = ERROR_ST_OPEN_SOCKET; |
| 243 | srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret); | 253 | srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret); |
| 244 | return ret; | 254 | return ret; |
| @@ -258,7 +268,7 @@ int SrsTcpListener::cycle() | @@ -258,7 +268,7 @@ int SrsTcpListener::cycle() | ||
| 258 | { | 268 | { |
| 259 | int ret = ERROR_SUCCESS; | 269 | int ret = ERROR_SUCCESS; |
| 260 | 270 | ||
| 261 | - st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); | 271 | + st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); |
| 262 | 272 | ||
| 263 | if(client_stfd == NULL){ | 273 | if(client_stfd == NULL){ |
| 264 | // ignore error. | 274 | // ignore error. |
| @@ -47,6 +47,12 @@ public: | @@ -47,6 +47,12 @@ public: | ||
| 47 | virtual ~ISrsUdpHandler(); | 47 | virtual ~ISrsUdpHandler(); |
| 48 | public: | 48 | public: |
| 49 | /** | 49 | /** |
| 50 | + * when fd changed, for instance, reload the listen port, | ||
| 51 | + * notify the handler and user can do something. | ||
| 52 | + */ | ||
| 53 | + virtual int on_stfd_change(st_netfd_t fd); | ||
| 54 | +public: | ||
| 55 | + /** | ||
| 50 | * when udp listener got a udp packet, notice server to process it. | 56 | * when udp listener got a udp packet, notice server to process it. |
| 51 | * @param type, the client type, used to create concrete connection, | 57 | * @param type, the client type, used to create concrete connection, |
| 52 | * for instance RTMP connection to serve client. | 58 | * for instance RTMP connection to serve client. |
| @@ -80,7 +86,7 @@ class SrsUdpListener : public ISrsThreadHandler | @@ -80,7 +86,7 @@ class SrsUdpListener : public ISrsThreadHandler | ||
| 80 | { | 86 | { |
| 81 | private: | 87 | private: |
| 82 | int _fd; | 88 | int _fd; |
| 83 | - st_netfd_t stfd; | 89 | + st_netfd_t _stfd; |
| 84 | SrsThread* pthread; | 90 | SrsThread* pthread; |
| 85 | private: | 91 | private: |
| 86 | char* buf; | 92 | char* buf; |
| @@ -94,6 +100,7 @@ public: | @@ -94,6 +100,7 @@ public: | ||
| 94 | virtual ~SrsUdpListener(); | 100 | virtual ~SrsUdpListener(); |
| 95 | public: | 101 | public: |
| 96 | virtual int fd(); | 102 | virtual int fd(); |
| 103 | + virtual st_netfd_t stfd(); | ||
| 97 | public: | 104 | public: |
| 98 | virtual int listen(); | 105 | virtual int listen(); |
| 99 | // interface ISrsThreadHandler. | 106 | // interface ISrsThreadHandler. |
| @@ -108,7 +115,7 @@ class SrsTcpListener : public ISrsThreadHandler | @@ -108,7 +115,7 @@ class SrsTcpListener : public ISrsThreadHandler | ||
| 108 | { | 115 | { |
| 109 | private: | 116 | private: |
| 110 | int _fd; | 117 | int _fd; |
| 111 | - st_netfd_t stfd; | 118 | + st_netfd_t _stfd; |
| 112 | SrsThread* pthread; | 119 | SrsThread* pthread; |
| 113 | private: | 120 | private: |
| 114 | ISrsTcpHandler* handler; | 121 | ISrsTcpHandler* handler; |
| @@ -40,6 +40,11 @@ int ISrsReloadHandler::on_reload_listen() | @@ -40,6 +40,11 @@ int ISrsReloadHandler::on_reload_listen() | ||
| 40 | return ERROR_SUCCESS; | 40 | return ERROR_SUCCESS; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | +int ISrsReloadHandler::on_reload_max_conns() | ||
| 44 | +{ | ||
| 45 | + return ERROR_SUCCESS; | ||
| 46 | +} | ||
| 47 | + | ||
| 43 | int ISrsReloadHandler::on_reload_pid() | 48 | int ISrsReloadHandler::on_reload_pid() |
| 44 | { | 49 | { |
| 45 | return ERROR_SUCCESS; | 50 | return ERROR_SUCCESS; |
| @@ -44,6 +44,7 @@ public: | @@ -44,6 +44,7 @@ public: | ||
| 44 | ISrsReloadHandler(); | 44 | ISrsReloadHandler(); |
| 45 | virtual ~ISrsReloadHandler(); | 45 | virtual ~ISrsReloadHandler(); |
| 46 | public: | 46 | public: |
| 47 | + virtual int on_reload_max_conns(); | ||
| 47 | virtual int on_reload_listen(); | 48 | virtual int on_reload_listen(); |
| 48 | virtual int on_reload_pid(); | 49 | virtual int on_reload_pid(); |
| 49 | virtual int on_reload_log_tank(); | 50 | virtual int on_reload_log_tank(); |
| @@ -55,6 +56,7 @@ public: | @@ -55,6 +56,7 @@ public: | ||
| 55 | virtual int on_reload_http_stream_enabled(); | 56 | virtual int on_reload_http_stream_enabled(); |
| 56 | virtual int on_reload_http_stream_disabled(); | 57 | virtual int on_reload_http_stream_disabled(); |
| 57 | virtual int on_reload_http_stream_updated(); | 58 | virtual int on_reload_http_stream_updated(); |
| 59 | +public: | ||
| 58 | virtual int on_reload_vhost_http_updated(); | 60 | virtual int on_reload_vhost_http_updated(); |
| 59 | virtual int on_reload_vhost_http_remux_updated(); | 61 | virtual int on_reload_vhost_http_remux_updated(); |
| 60 | virtual int on_reload_vhost_added(std::string vhost); | 62 | virtual int on_reload_vhost_added(std::string vhost); |
| @@ -1068,24 +1068,24 @@ int SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessag | @@ -1068,24 +1068,24 @@ int SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessag | ||
| 1068 | return ret; | 1068 | return ret; |
| 1069 | } | 1069 | } |
| 1070 | 1070 | ||
| 1071 | - // pause or other msg. | 1071 | + // pause |
| 1072 | SrsPausePacket* pause = dynamic_cast<SrsPausePacket*>(pkt); | 1072 | SrsPausePacket* pause = dynamic_cast<SrsPausePacket*>(pkt); |
| 1073 | - if (!pause) { | ||
| 1074 | - srs_info("ignore all amf0/amf3 command except pause."); | ||
| 1075 | - return ret; | ||
| 1076 | - } | ||
| 1077 | - | ||
| 1078 | - if ((ret = rtmp->on_play_client_pause(res->stream_id, pause->is_pause)) != ERROR_SUCCESS) { | ||
| 1079 | - srs_error("rtmp process play client pause failed. ret=%d", ret); | ||
| 1080 | - return ret; | ||
| 1081 | - } | ||
| 1082 | - | ||
| 1083 | - if ((ret = consumer->on_play_client_pause(pause->is_pause)) != ERROR_SUCCESS) { | ||
| 1084 | - srs_error("consumer process play client pause failed. ret=%d", ret); | 1073 | + if (pause) { |
| 1074 | + if ((ret = rtmp->on_play_client_pause(res->stream_id, pause->is_pause)) != ERROR_SUCCESS) { | ||
| 1075 | + srs_error("rtmp process play client pause failed. ret=%d", ret); | ||
| 1076 | + return ret; | ||
| 1077 | + } | ||
| 1078 | + | ||
| 1079 | + if ((ret = consumer->on_play_client_pause(pause->is_pause)) != ERROR_SUCCESS) { | ||
| 1080 | + srs_error("consumer process play client pause failed. ret=%d", ret); | ||
| 1081 | + return ret; | ||
| 1082 | + } | ||
| 1083 | + srs_info("process pause success, is_pause=%d, time=%d.", pause->is_pause, pause->time_ms); | ||
| 1085 | return ret; | 1084 | return ret; |
| 1086 | } | 1085 | } |
| 1087 | - srs_info("process pause success, is_pause=%d, time=%d.", pause->is_pause, pause->time_ms); | ||
| 1088 | 1086 | ||
| 1087 | + // other msg. | ||
| 1088 | + srs_info("ignore all amf0/amf3 command except pause and video control."); | ||
| 1089 | return ret; | 1089 | return ret; |
| 1090 | } | 1090 | } |
| 1091 | 1091 |
| @@ -113,23 +113,23 @@ std::string srs_listener_type2string(SrsListenerType type) | @@ -113,23 +113,23 @@ std::string srs_listener_type2string(SrsListenerType type) | ||
| 113 | } | 113 | } |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | -SrsListener::SrsListener(SrsServer* server, SrsListenerType type) | 116 | +SrsListener::SrsListener(SrsServer* svr, SrsListenerType t) |
| 117 | { | 117 | { |
| 118 | - _port = 0; | ||
| 119 | - _server = server; | ||
| 120 | - _type = type; | 118 | + port = 0; |
| 119 | + server = svr; | ||
| 120 | + type = t; | ||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | SrsListener::~SrsListener() | 123 | SrsListener::~SrsListener() |
| 124 | { | 124 | { |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | -SrsListenerType SrsListener::type() | 127 | +SrsListenerType SrsListener::listen_type() |
| 128 | { | 128 | { |
| 129 | - return _type; | 129 | + return type; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | -SrsStreamListener::SrsStreamListener(SrsServer* server, SrsListenerType type) : SrsListener(server, type) | 132 | +SrsStreamListener::SrsStreamListener(SrsServer* svr, SrsListenerType t) : SrsListener(svr, t) |
| 133 | { | 133 | { |
| 134 | listener = NULL; | 134 | listener = NULL; |
| 135 | } | 135 | } |
| @@ -139,12 +139,12 @@ SrsStreamListener::~SrsStreamListener() | @@ -139,12 +139,12 @@ SrsStreamListener::~SrsStreamListener() | ||
| 139 | srs_freep(listener); | 139 | srs_freep(listener); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | -int SrsStreamListener::listen(string ip, int port) | 142 | +int SrsStreamListener::listen(string i, int p) |
| 143 | { | 143 | { |
| 144 | int ret = ERROR_SUCCESS; | 144 | int ret = ERROR_SUCCESS; |
| 145 | 145 | ||
| 146 | - _ip = ip; | ||
| 147 | - _port = port; | 146 | + ip = i; |
| 147 | + port = p; | ||
| 148 | 148 | ||
| 149 | srs_freep(listener); | 149 | srs_freep(listener); |
| 150 | listener = new SrsTcpListener(this, ip, port); | 150 | listener = new SrsTcpListener(this, ip, port); |
| @@ -158,7 +158,7 @@ int SrsStreamListener::listen(string ip, int port) | @@ -158,7 +158,7 @@ int SrsStreamListener::listen(string ip, int port) | ||
| 158 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", | 158 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", |
| 159 | pthread->cid(), _srs_context->get_id(), _port, _type, fd, ip.c_str(), port); | 159 | pthread->cid(), _srs_context->get_id(), _port, _type, fd, ip.c_str(), port); |
| 160 | 160 | ||
| 161 | - srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(_type).c_str(), ip.c_str(), _port, listener->fd()); | 161 | + srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); |
| 162 | 162 | ||
| 163 | return ret; | 163 | return ret; |
| 164 | } | 164 | } |
| @@ -167,7 +167,7 @@ int SrsStreamListener::on_tcp_client(st_netfd_t stfd) | @@ -167,7 +167,7 @@ int SrsStreamListener::on_tcp_client(st_netfd_t stfd) | ||
| 167 | { | 167 | { |
| 168 | int ret = ERROR_SUCCESS; | 168 | int ret = ERROR_SUCCESS; |
| 169 | 169 | ||
| 170 | - if ((ret = _server->accept_client(_type, stfd)) != ERROR_SUCCESS) { | 170 | + if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) { |
| 171 | srs_warn("accept client error. ret=%d", ret); | 171 | srs_warn("accept client error. ret=%d", ret); |
| 172 | return ret; | 172 | return ret; |
| 173 | } | 173 | } |
| @@ -176,14 +176,14 @@ int SrsStreamListener::on_tcp_client(st_netfd_t stfd) | @@ -176,14 +176,14 @@ int SrsStreamListener::on_tcp_client(st_netfd_t stfd) | ||
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | #ifdef SRS_AUTO_STREAM_CASTER | 178 | #ifdef SRS_AUTO_STREAM_CASTER |
| 179 | -SrsRtspListener::SrsRtspListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c) : SrsListener(server, type) | 179 | +SrsRtspListener::SrsRtspListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsListener(svr, t) |
| 180 | { | 180 | { |
| 181 | listener = NULL; | 181 | listener = NULL; |
| 182 | 182 | ||
| 183 | // the caller already ensure the type is ok, | 183 | // the caller already ensure the type is ok, |
| 184 | // we just assert here for unknown stream caster. | 184 | // we just assert here for unknown stream caster. |
| 185 | - srs_assert(_type == SrsListenerRtsp); | ||
| 186 | - if (_type == SrsListenerRtsp) { | 185 | + srs_assert(type == SrsListenerRtsp); |
| 186 | + if (type == SrsListenerRtsp) { | ||
| 187 | caster = new SrsRtspCaster(c); | 187 | caster = new SrsRtspCaster(c); |
| 188 | } | 188 | } |
| 189 | } | 189 | } |
| @@ -194,16 +194,16 @@ SrsRtspListener::~SrsRtspListener() | @@ -194,16 +194,16 @@ SrsRtspListener::~SrsRtspListener() | ||
| 194 | srs_freep(listener); | 194 | srs_freep(listener); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | -int SrsRtspListener::listen(string ip, int port) | 197 | +int SrsRtspListener::listen(string i, int p) |
| 198 | { | 198 | { |
| 199 | int ret = ERROR_SUCCESS; | 199 | int ret = ERROR_SUCCESS; |
| 200 | 200 | ||
| 201 | // the caller already ensure the type is ok, | 201 | // the caller already ensure the type is ok, |
| 202 | // we just assert here for unknown stream caster. | 202 | // we just assert here for unknown stream caster. |
| 203 | - srs_assert(_type == SrsListenerRtsp); | 203 | + srs_assert(type == SrsListenerRtsp); |
| 204 | 204 | ||
| 205 | - _ip = ip; | ||
| 206 | - _port = port; | 205 | + ip = i; |
| 206 | + port = p; | ||
| 207 | 207 | ||
| 208 | srs_freep(listener); | 208 | srs_freep(listener); |
| 209 | listener = new SrsTcpListener(this, ip, port); | 209 | listener = new SrsTcpListener(this, ip, port); |
| @@ -215,9 +215,9 @@ int SrsRtspListener::listen(string ip, int port) | @@ -215,9 +215,9 @@ int SrsRtspListener::listen(string ip, int port) | ||
| 215 | 215 | ||
| 216 | srs_info("listen thread cid=%d, current_cid=%d, " | 216 | srs_info("listen thread cid=%d, current_cid=%d, " |
| 217 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", | 217 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", |
| 218 | - pthread->cid(), _srs_context->get_id(), _port, _type, fd, ip.c_str(), port); | 218 | + pthread->cid(), _srs_context->get_id(), port, type, fd, ip.c_str(), port); |
| 219 | 219 | ||
| 220 | - srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(_type).c_str(), ip.c_str(), _port, listener->fd()); | 220 | + srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); |
| 221 | 221 | ||
| 222 | return ret; | 222 | return ret; |
| 223 | } | 223 | } |
| @@ -234,14 +234,14 @@ int SrsRtspListener::on_tcp_client(st_netfd_t stfd) | @@ -234,14 +234,14 @@ int SrsRtspListener::on_tcp_client(st_netfd_t stfd) | ||
| 234 | return ret; | 234 | return ret; |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | -SrsHttpFlvListener::SrsHttpFlvListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c) : SrsListener(server, type) | 237 | +SrsHttpFlvListener::SrsHttpFlvListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsListener(svr, t) |
| 238 | { | 238 | { |
| 239 | listener = NULL; | 239 | listener = NULL; |
| 240 | 240 | ||
| 241 | // the caller already ensure the type is ok, | 241 | // the caller already ensure the type is ok, |
| 242 | // we just assert here for unknown stream caster. | 242 | // we just assert here for unknown stream caster. |
| 243 | - srs_assert(_type == SrsListenerFlv); | ||
| 244 | - if (_type == SrsListenerFlv) { | 243 | + srs_assert(type == SrsListenerFlv); |
| 244 | + if (type == SrsListenerFlv) { | ||
| 245 | caster = new SrsAppCasterFlv(c); | 245 | caster = new SrsAppCasterFlv(c); |
| 246 | } | 246 | } |
| 247 | } | 247 | } |
| @@ -252,16 +252,16 @@ SrsHttpFlvListener::~SrsHttpFlvListener() | @@ -252,16 +252,16 @@ SrsHttpFlvListener::~SrsHttpFlvListener() | ||
| 252 | srs_freep(listener); | 252 | srs_freep(listener); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | -int SrsHttpFlvListener::listen(string ip, int port) | 255 | +int SrsHttpFlvListener::listen(string i, int p) |
| 256 | { | 256 | { |
| 257 | int ret = ERROR_SUCCESS; | 257 | int ret = ERROR_SUCCESS; |
| 258 | 258 | ||
| 259 | // the caller already ensure the type is ok, | 259 | // the caller already ensure the type is ok, |
| 260 | // we just assert here for unknown stream caster. | 260 | // we just assert here for unknown stream caster. |
| 261 | - srs_assert(_type == SrsListenerFlv); | 261 | + srs_assert(type == SrsListenerFlv); |
| 262 | 262 | ||
| 263 | - _ip = ip; | ||
| 264 | - _port = port; | 263 | + ip = i; |
| 264 | + port = p; | ||
| 265 | 265 | ||
| 266 | if ((ret = caster->initialize()) != ERROR_SUCCESS) { | 266 | if ((ret = caster->initialize()) != ERROR_SUCCESS) { |
| 267 | return ret; | 267 | return ret; |
| @@ -277,9 +277,9 @@ int SrsHttpFlvListener::listen(string ip, int port) | @@ -277,9 +277,9 @@ int SrsHttpFlvListener::listen(string ip, int port) | ||
| 277 | 277 | ||
| 278 | srs_info("listen thread cid=%d, current_cid=%d, " | 278 | srs_info("listen thread cid=%d, current_cid=%d, " |
| 279 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", | 279 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", |
| 280 | - pthread->cid(), _srs_context->get_id(), _port, _type, fd, ip.c_str(), port); | 280 | + pthread->cid(), _srs_context->get_id(), port, type, fd, ip.c_str(), port); |
| 281 | 281 | ||
| 282 | - srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(_type).c_str(), ip.c_str(), _port, listener->fd()); | 282 | + srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); |
| 283 | 283 | ||
| 284 | return ret; | 284 | return ret; |
| 285 | } | 285 | } |
| @@ -295,36 +295,29 @@ int SrsHttpFlvListener::on_tcp_client(st_netfd_t stfd) | @@ -295,36 +295,29 @@ int SrsHttpFlvListener::on_tcp_client(st_netfd_t stfd) | ||
| 295 | 295 | ||
| 296 | return ret; | 296 | return ret; |
| 297 | } | 297 | } |
| 298 | +#endif | ||
| 298 | 299 | ||
| 299 | -SrsUdpCasterListener::SrsUdpCasterListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c) : SrsListener(server, type) | 300 | +SrsUdpStreamListener::SrsUdpStreamListener(SrsServer* svr, SrsListenerType t, ISrsUdpHandler* c) : SrsListener(svr, t) |
| 300 | { | 301 | { |
| 301 | - _type = type; | ||
| 302 | listener = NULL; | 302 | listener = NULL; |
| 303 | - | ||
| 304 | - // the caller already ensure the type is ok, | ||
| 305 | - // we just assert here for unknown stream caster. | ||
| 306 | - srs_assert(_type == SrsListenerMpegTsOverUdp); | ||
| 307 | - if (_type == SrsListenerMpegTsOverUdp) { | ||
| 308 | - caster = new SrsMpegtsOverUdp(c); | ||
| 309 | - } | 303 | + caster = c; |
| 310 | } | 304 | } |
| 311 | 305 | ||
| 312 | -SrsUdpCasterListener::~SrsUdpCasterListener() | 306 | +SrsUdpStreamListener::~SrsUdpStreamListener() |
| 313 | { | 307 | { |
| 314 | - srs_freep(caster); | ||
| 315 | srs_freep(listener); | 308 | srs_freep(listener); |
| 316 | } | 309 | } |
| 317 | 310 | ||
| 318 | -int SrsUdpCasterListener::listen(string ip, int port) | 311 | +int SrsUdpStreamListener::listen(string i, int p) |
| 319 | { | 312 | { |
| 320 | int ret = ERROR_SUCCESS; | 313 | int ret = ERROR_SUCCESS; |
| 321 | 314 | ||
| 322 | // the caller already ensure the type is ok, | 315 | // the caller already ensure the type is ok, |
| 323 | // we just assert here for unknown stream caster. | 316 | // we just assert here for unknown stream caster. |
| 324 | - srs_assert(_type == SrsListenerMpegTsOverUdp); | 317 | + srs_assert(type == SrsListenerMpegTsOverUdp); |
| 325 | 318 | ||
| 326 | - _ip = ip; | ||
| 327 | - _port = port; | 319 | + ip = i; |
| 320 | + port = p; | ||
| 328 | 321 | ||
| 329 | srs_freep(listener); | 322 | srs_freep(listener); |
| 330 | listener = new SrsUdpListener(caster, ip, port); | 323 | listener = new SrsUdpListener(caster, ip, port); |
| @@ -336,12 +329,34 @@ int SrsUdpCasterListener::listen(string ip, int port) | @@ -336,12 +329,34 @@ int SrsUdpCasterListener::listen(string ip, int port) | ||
| 336 | 329 | ||
| 337 | srs_info("listen thread cid=%d, current_cid=%d, " | 330 | srs_info("listen thread cid=%d, current_cid=%d, " |
| 338 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", | 331 | "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", |
| 339 | - pthread->cid(), _srs_context->get_id(), _port, _type, fd, ip.c_str(), port); | 332 | + pthread->cid(), _srs_context->get_id(), port, type, fd, ip.c_str(), port); |
| 333 | + | ||
| 334 | + // notify the handler the fd changed. | ||
| 335 | + if ((ret = caster->on_stfd_change(listener->stfd())) != ERROR_SUCCESS) { | ||
| 336 | + srs_error("notify handler fd changed. ret=%d", ret); | ||
| 337 | + return ret; | ||
| 338 | + } | ||
| 340 | 339 | ||
| 341 | - srs_trace("%s listen at udp://%s:%d, fd=%d", srs_listener_type2string(_type).c_str(), ip.c_str(), _port, listener->fd()); | 340 | + srs_trace("%s listen at udp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); |
| 342 | 341 | ||
| 343 | return ret; | 342 | return ret; |
| 344 | } | 343 | } |
| 344 | + | ||
| 345 | +#ifdef SRS_AUTO_STREAM_CASTER | ||
| 346 | +SrsUdpCasterListener::SrsUdpCasterListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsUdpStreamListener(svr, t, NULL) | ||
| 347 | +{ | ||
| 348 | + // the caller already ensure the type is ok, | ||
| 349 | + // we just assert here for unknown stream caster. | ||
| 350 | + srs_assert(type == SrsListenerMpegTsOverUdp); | ||
| 351 | + if (type == SrsListenerMpegTsOverUdp) { | ||
| 352 | + caster = new SrsMpegtsOverUdp(c); | ||
| 353 | + } | ||
| 354 | +} | ||
| 355 | + | ||
| 356 | +SrsUdpCasterListener::~SrsUdpCasterListener() | ||
| 357 | +{ | ||
| 358 | + srs_freep(caster); | ||
| 359 | +} | ||
| 345 | #endif | 360 | #endif |
| 346 | 361 | ||
| 347 | SrsSignalManager* SrsSignalManager::instance = NULL; | 362 | SrsSignalManager* SrsSignalManager::instance = NULL; |
| @@ -588,6 +603,34 @@ int SrsServer::initialize(ISrsServerCycle* cycle_handler) | @@ -588,6 +603,34 @@ int SrsServer::initialize(ISrsServerCycle* cycle_handler) | ||
| 588 | return ret; | 603 | return ret; |
| 589 | } | 604 | } |
| 590 | 605 | ||
| 606 | +int SrsServer::initialize_st() | ||
| 607 | +{ | ||
| 608 | + int ret = ERROR_SUCCESS; | ||
| 609 | + | ||
| 610 | + // init st | ||
| 611 | + if ((ret = srs_init_st()) != ERROR_SUCCESS) { | ||
| 612 | + srs_error("init st failed. ret=%d", ret); | ||
| 613 | + return ret; | ||
| 614 | + } | ||
| 615 | + | ||
| 616 | + // @remark, st alloc segment use mmap, which only support 32757 threads, | ||
| 617 | + // if need to support more, for instance, 100k threads, define the macro MALLOC_STACK. | ||
| 618 | + // TODO: FIXME: maybe can use "sysctl vm.max_map_count" to refine. | ||
| 619 | + if (_srs_config->get_max_connections() > 32756) { | ||
| 620 | + ret = ERROR_ST_EXCEED_THREADS; | ||
| 621 | + srs_error("st mmap for stack allocation must <= %d threads, " | ||
| 622 | + "@see Makefile of st for MALLOC_STACK, please build st manually by " | ||
| 623 | + "\"make EXTRA_CFLAGS=-DMALLOC_STACK linux-debug\", ret=%d", ret); | ||
| 624 | + return ret; | ||
| 625 | + } | ||
| 626 | + | ||
| 627 | + // set current log id. | ||
| 628 | + _srs_context->generate_id(); | ||
| 629 | + srs_trace("server main cid=%d", _srs_context->get_id()); | ||
| 630 | + | ||
| 631 | + return ret; | ||
| 632 | +} | ||
| 633 | + | ||
| 591 | int SrsServer::initialize_signal() | 634 | int SrsServer::initialize_signal() |
| 592 | { | 635 | { |
| 593 | return signal_manager->initialize(); | 636 | return signal_manager->initialize(); |
| @@ -669,34 +712,6 @@ int SrsServer::acquire_pid_file() | @@ -669,34 +712,6 @@ int SrsServer::acquire_pid_file() | ||
| 669 | return ret; | 712 | return ret; |
| 670 | } | 713 | } |
| 671 | 714 | ||
| 672 | -int SrsServer::initialize_st() | ||
| 673 | -{ | ||
| 674 | - int ret = ERROR_SUCCESS; | ||
| 675 | - | ||
| 676 | - // init st | ||
| 677 | - if ((ret = srs_init_st()) != ERROR_SUCCESS) { | ||
| 678 | - srs_error("init st failed. ret=%d", ret); | ||
| 679 | - return ret; | ||
| 680 | - } | ||
| 681 | - | ||
| 682 | - // @remark, st alloc segment use mmap, which only support 32757 threads, | ||
| 683 | - // if need to support more, for instance, 100k threads, define the macro MALLOC_STACK. | ||
| 684 | - // TODO: FIXME: maybe can use "sysctl vm.max_map_count" to refine. | ||
| 685 | - if (_srs_config->get_max_connections() > 32756) { | ||
| 686 | - ret = ERROR_ST_EXCEED_THREADS; | ||
| 687 | - srs_error("st mmap for stack allocation must <= %d threads, " | ||
| 688 | - "@see Makefile of st for MALLOC_STACK, please build st manually by " | ||
| 689 | - "\"make EXTRA_CFLAGS=-DMALLOC_STACK linux-debug\", ret=%d", ret); | ||
| 690 | - return ret; | ||
| 691 | - } | ||
| 692 | - | ||
| 693 | - // set current log id. | ||
| 694 | - _srs_context->generate_id(); | ||
| 695 | - srs_trace("server main cid=%d", _srs_context->get_id()); | ||
| 696 | - | ||
| 697 | - return ret; | ||
| 698 | -} | ||
| 699 | - | ||
| 700 | int SrsServer::listen() | 715 | int SrsServer::listen() |
| 701 | { | 716 | { |
| 702 | int ret = ERROR_SUCCESS; | 717 | int ret = ERROR_SUCCESS; |
| @@ -959,6 +974,7 @@ int SrsServer::do_cycle() | @@ -959,6 +974,7 @@ int SrsServer::do_cycle() | ||
| 959 | } | 974 | } |
| 960 | #endif | 975 | #endif |
| 961 | #endif | 976 | #endif |
| 977 | + | ||
| 962 | srs_info("server main thread loop"); | 978 | srs_info("server main thread loop"); |
| 963 | } | 979 | } |
| 964 | } | 980 | } |
| @@ -1103,7 +1119,7 @@ void SrsServer::close_listeners(SrsListenerType type) | @@ -1103,7 +1119,7 @@ void SrsServer::close_listeners(SrsListenerType type) | ||
| 1103 | for (it = listeners.begin(); it != listeners.end();) { | 1119 | for (it = listeners.begin(); it != listeners.end();) { |
| 1104 | SrsListener* listener = *it; | 1120 | SrsListener* listener = *it; |
| 1105 | 1121 | ||
| 1106 | - if (listener->type() != type) { | 1122 | + if (listener->listen_type() != type) { |
| 1107 | ++it; | 1123 | ++it; |
| 1108 | continue; | 1124 | continue; |
| 1109 | } | 1125 | } |
| @@ -1264,7 +1280,7 @@ int SrsServer::on_reload_http_stream_enabled() | @@ -1264,7 +1280,7 @@ int SrsServer::on_reload_http_stream_enabled() | ||
| 1264 | #ifdef SRS_AUTO_HTTP_SERVER | 1280 | #ifdef SRS_AUTO_HTTP_SERVER |
| 1265 | ret = listen_http_stream(); | 1281 | ret = listen_http_stream(); |
| 1266 | #endif | 1282 | #endif |
| 1267 | - | 1283 | + |
| 1268 | return ret; | 1284 | return ret; |
| 1269 | } | 1285 | } |
| 1270 | 1286 |
| @@ -80,17 +80,17 @@ enum SrsListenerType | @@ -80,17 +80,17 @@ enum SrsListenerType | ||
| 80 | class SrsListener | 80 | class SrsListener |
| 81 | { | 81 | { |
| 82 | protected: | 82 | protected: |
| 83 | - SrsListenerType _type; | 83 | + SrsListenerType type; |
| 84 | protected: | 84 | protected: |
| 85 | - std::string _ip; | ||
| 86 | - int _port; | ||
| 87 | - SrsServer* _server; | 85 | + std::string ip; |
| 86 | + int port; | ||
| 87 | + SrsServer* server; | ||
| 88 | public: | 88 | public: |
| 89 | - SrsListener(SrsServer* server, SrsListenerType type); | 89 | + SrsListener(SrsServer* svr, SrsListenerType t); |
| 90 | virtual ~SrsListener(); | 90 | virtual ~SrsListener(); |
| 91 | public: | 91 | public: |
| 92 | - virtual SrsListenerType type(); | ||
| 93 | - virtual int listen(std::string ip, int port) = 0; | 92 | + virtual SrsListenerType listen_type(); |
| 93 | + virtual int listen(std::string i, int p) = 0; | ||
| 94 | }; | 94 | }; |
| 95 | 95 | ||
| 96 | /** | 96 | /** |
| @@ -120,10 +120,10 @@ private: | @@ -120,10 +120,10 @@ private: | ||
| 120 | SrsTcpListener* listener; | 120 | SrsTcpListener* listener; |
| 121 | ISrsTcpHandler* caster; | 121 | ISrsTcpHandler* caster; |
| 122 | public: | 122 | public: |
| 123 | - SrsRtspListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c); | 123 | + SrsRtspListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); |
| 124 | virtual ~SrsRtspListener(); | 124 | virtual ~SrsRtspListener(); |
| 125 | public: | 125 | public: |
| 126 | - virtual int listen(std::string ip, int port); | 126 | + virtual int listen(std::string i, int p); |
| 127 | // ISrsTcpHandler | 127 | // ISrsTcpHandler |
| 128 | public: | 128 | public: |
| 129 | virtual int on_tcp_client(st_netfd_t stfd); | 129 | virtual int on_tcp_client(st_netfd_t stfd); |
| @@ -138,28 +138,40 @@ private: | @@ -138,28 +138,40 @@ private: | ||
| 138 | SrsTcpListener* listener; | 138 | SrsTcpListener* listener; |
| 139 | SrsAppCasterFlv* caster; | 139 | SrsAppCasterFlv* caster; |
| 140 | public: | 140 | public: |
| 141 | - SrsHttpFlvListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c); | 141 | + SrsHttpFlvListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); |
| 142 | virtual ~SrsHttpFlvListener(); | 142 | virtual ~SrsHttpFlvListener(); |
| 143 | public: | 143 | public: |
| 144 | - virtual int listen(std::string ip, int port); | 144 | + virtual int listen(std::string i, int p); |
| 145 | // ISrsTcpHandler | 145 | // ISrsTcpHandler |
| 146 | public: | 146 | public: |
| 147 | virtual int on_tcp_client(st_netfd_t stfd); | 147 | virtual int on_tcp_client(st_netfd_t stfd); |
| 148 | }; | 148 | }; |
| 149 | +#endif | ||
| 149 | 150 | ||
| 150 | /** | 151 | /** |
| 151 | -* the udp listener, for udp server. | ||
| 152 | -*/ | ||
| 153 | -class SrsUdpCasterListener : public SrsListener | 152 | + * the udp listener, for udp server. |
| 153 | + */ | ||
| 154 | +class SrsUdpStreamListener : public SrsListener | ||
| 154 | { | 155 | { |
| 155 | -private: | 156 | +protected: |
| 156 | SrsUdpListener* listener; | 157 | SrsUdpListener* listener; |
| 157 | ISrsUdpHandler* caster; | 158 | ISrsUdpHandler* caster; |
| 158 | public: | 159 | public: |
| 159 | - SrsUdpCasterListener(SrsServer* server, SrsListenerType type, SrsConfDirective* c); | ||
| 160 | - virtual ~SrsUdpCasterListener(); | 160 | + SrsUdpStreamListener(SrsServer* svr, SrsListenerType t, ISrsUdpHandler* c); |
| 161 | + virtual ~SrsUdpStreamListener(); | ||
| 161 | public: | 162 | public: |
| 162 | - virtual int listen(std::string ip, int port); | 163 | + virtual int listen(std::string i, int p); |
| 164 | +}; | ||
| 165 | + | ||
| 166 | +/** | ||
| 167 | + * the udp listener, for udp stream caster server. | ||
| 168 | + */ | ||
| 169 | +#ifdef SRS_AUTO_STREAM_CASTER | ||
| 170 | +class SrsUdpCasterListener : public SrsUdpStreamListener | ||
| 171 | +{ | ||
| 172 | +public: | ||
| 173 | + SrsUdpCasterListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); | ||
| 174 | + virtual ~SrsUdpCasterListener(); | ||
| 163 | }; | 175 | }; |
| 164 | #endif | 176 | #endif |
| 165 | 177 | ||
| @@ -337,7 +349,7 @@ public: | @@ -337,7 +349,7 @@ public: | ||
| 337 | * @param client_stfd, the client fd in st boxed, the underlayer fd. | 349 | * @param client_stfd, the client fd in st boxed, the underlayer fd. |
| 338 | */ | 350 | */ |
| 339 | virtual int accept_client(SrsListenerType type, st_netfd_t client_stfd); | 351 | virtual int accept_client(SrsListenerType type, st_netfd_t client_stfd); |
| 340 | -// interface ISrsThreadHandler. | 352 | +// interface ISrsReloadHandler. |
| 341 | public: | 353 | public: |
| 342 | virtual int on_reload_listen(); | 354 | virtual int on_reload_listen(); |
| 343 | virtual int on_reload_pid(); | 355 | virtual int on_reload_pid(); |
| @@ -45,6 +45,7 @@ using namespace std; | @@ -45,6 +45,7 @@ using namespace std; | ||
| 45 | #include <srs_app_hds.hpp> | 45 | #include <srs_app_hds.hpp> |
| 46 | #include <srs_app_statistic.hpp> | 46 | #include <srs_app_statistic.hpp> |
| 47 | #include <srs_core_autofree.hpp> | 47 | #include <srs_core_autofree.hpp> |
| 48 | +#include <srs_rtmp_utility.hpp> | ||
| 48 | 49 | ||
| 49 | #define CONST_MAX_JITTER_MS 500 | 50 | #define CONST_MAX_JITTER_MS 500 |
| 50 | #define DEFAULT_FRAME_TIME_MS 40 | 51 | #define DEFAULT_FRAME_TIME_MS 40 |
| @@ -759,6 +760,20 @@ SrsSource* SrsSource::fetch(SrsRequest* r) | @@ -759,6 +760,20 @@ SrsSource* SrsSource::fetch(SrsRequest* r) | ||
| 759 | return source; | 760 | return source; |
| 760 | } | 761 | } |
| 761 | 762 | ||
| 763 | +SrsSource* SrsSource::fetch(std::string vhost, std::string app, std::string stream) | ||
| 764 | +{ | ||
| 765 | + SrsSource* source = NULL; | ||
| 766 | + string stream_url = srs_generate_stream_url(vhost, app, stream); | ||
| 767 | + | ||
| 768 | + if (pool.find(stream_url) == pool.end()) { | ||
| 769 | + return NULL; | ||
| 770 | + } | ||
| 771 | + | ||
| 772 | + source = pool[stream_url]; | ||
| 773 | + | ||
| 774 | + return source; | ||
| 775 | +} | ||
| 776 | + | ||
| 762 | void SrsSource::destroy() | 777 | void SrsSource::destroy() |
| 763 | { | 778 | { |
| 764 | std::map<std::string, SrsSource*>::iterator it; | 779 | std::map<std::string, SrsSource*>::iterator it; |
| @@ -407,6 +407,10 @@ public: | @@ -407,6 +407,10 @@ public: | ||
| 407 | */ | 407 | */ |
| 408 | static SrsSource* fetch(SrsRequest* r); | 408 | static SrsSource* fetch(SrsRequest* r); |
| 409 | /** | 409 | /** |
| 410 | + * get the exists source by stream info(vhost, app, stream), NULL when not exists. | ||
| 411 | + */ | ||
| 412 | + static SrsSource* fetch(std::string vhost, std::string app, std::string stream); | ||
| 413 | + /** | ||
| 410 | * when system exit, destroy the sources, | 414 | * when system exit, destroy the sources, |
| 411 | * for gmc to analysis mem leaks. | 415 | * for gmc to analysis mem leaks. |
| 412 | */ | 416 | */ |
| @@ -195,6 +195,7 @@ int SrsStatistic::on_client(int id, SrsRequest* req) | @@ -195,6 +195,7 @@ int SrsStatistic::on_client(int id, SrsRequest* req) | ||
| 195 | SrsStatisticClient* client = NULL; | 195 | SrsStatisticClient* client = NULL; |
| 196 | if (clients.find(id) == clients.end()) { | 196 | if (clients.find(id) == clients.end()) { |
| 197 | client = new SrsStatisticClient(); | 197 | client = new SrsStatisticClient(); |
| 198 | + client->id = id; | ||
| 198 | client->stream = stream; | 199 | client->stream = stream; |
| 199 | clients[id] = client; | 200 | clients[id] = client; |
| 200 | } else { | 201 | } else { |
| @@ -32,93 +32,105 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -32,93 +32,105 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 32 | #include <srs_app_st.hpp> | 32 | #include <srs_app_st.hpp> |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| 35 | -* the handler for the thread, callback interface. | ||
| 36 | -* the thread model defines as: | ||
| 37 | -* handler->on_thread_start() | ||
| 38 | -* while loop: | ||
| 39 | -* handler->on_before_cycle() | ||
| 40 | -* handler->cycle() | ||
| 41 | -* handler->on_end_cycle() | ||
| 42 | -* if !loop then break for user stop thread. | ||
| 43 | -* sleep(CycleIntervalMilliseconds) | ||
| 44 | -* handler->on_thread_stop() | ||
| 45 | -* when stop, the thread will interrupt the st_thread, | ||
| 46 | -* which will cause the socket to return error and | ||
| 47 | -* terminate the cycle thread. | ||
| 48 | -* | ||
| 49 | -* Usage 1: stop by other thread. | ||
| 50 | -* user can create thread and stop then start again and again, | ||
| 51 | -* generally must provides a start and stop method, @see SrsIngester. | ||
| 52 | -* the step to create a thread stop by other thread: | ||
| 53 | -* 1. create SrsThread field, with joinable true. | ||
| 54 | -* 2. must use stop to stop and join the thread. | ||
| 55 | -* for example: | ||
| 56 | -* class SrsIngester : public ISrsThreadHandler { | ||
| 57 | -* public: SrsIngester() { pthread = new SrsThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US, true); } | ||
| 58 | -* public: virtual int start() { return pthread->start(); } | ||
| 59 | -* public: virtual void stop() { pthread->stop(); } | ||
| 60 | -* public: virtual int cycle() { | ||
| 61 | -* // check status, start ffmpeg when stopped. | ||
| 62 | -* } | ||
| 63 | -* }; | ||
| 64 | -* | ||
| 65 | -* Usage 2: stop by thread itself. | ||
| 66 | -* user can create thread which stop itself, | ||
| 67 | -* generally only need to provides a start method, | ||
| 68 | -* the object will destroy itself then terminate the thread, @see SrsConnection | ||
| 69 | -* 1. create SrsThread field, with joinable false. | ||
| 70 | -* 2. owner stop thread loop, destroy itself when thread stop. | ||
| 71 | -* for example: | ||
| 72 | -* class SrsConnection : public ISrsThreadHandler { | ||
| 73 | -* public: SrsConnection() { pthread = new SrsThread("conn", this, 0, false); } | ||
| 74 | -* public: virtual int start() { return pthread->start(); } | ||
| 75 | -* public: virtual int cycle() { | ||
| 76 | -* // serve client. | ||
| 77 | -* // set loop to stop to quit, stop thread itself. | ||
| 78 | -* pthread->stop_loop(); | ||
| 79 | -* } | ||
| 80 | -* public: virtual int on_thread_stop() { | ||
| 81 | -* // remove the connection in thread itself. | ||
| 82 | -* server->remove(this); | ||
| 83 | -* } | ||
| 84 | -* }; | ||
| 85 | -* | ||
| 86 | -* Usage 3: loop in the cycle method. | ||
| 87 | -* user can use loop code in the cycle method, @see SrsForwarder | ||
| 88 | -* 1. create SrsThread field, with or without joinable is ok. | ||
| 89 | -* 2. loop code in cycle method, check the can_loop() for thread to quit. | ||
| 90 | -* for example: | ||
| 91 | -* class SrsForwarder : public ISrsThreadHandler { | ||
| 92 | -* public: virtual int cycle() { | ||
| 93 | -* while (pthread->can_loop()) { | ||
| 94 | -* // read msgs from queue and forward to server. | ||
| 95 | -* } | ||
| 96 | -* } | ||
| 97 | -* }; | ||
| 98 | -* | ||
| 99 | -* @remark why should check can_loop() in cycle method? | ||
| 100 | -* when thread interrupt, the socket maybe not got EINT, | ||
| 101 | -* espectially on st_usleep(), so the cycle must check the loop, | ||
| 102 | -* when handler->cycle() has loop itself, for example: | ||
| 103 | -* while (true): | ||
| 104 | -* if (read_from_socket(skt) < 0) break; | ||
| 105 | -* if thread stop when read_from_socket, it's ok, the loop will break, | ||
| 106 | -* but when thread stop interrupt the s_usleep(0), then the loop is | ||
| 107 | -* death loop. | ||
| 108 | -* in a word, the handler->cycle() must: | ||
| 109 | -* while (pthread->can_loop()): | ||
| 110 | -* if (read_from_socket(skt) < 0) break; | ||
| 111 | -* check the loop, then it works. | ||
| 112 | -* | ||
| 113 | -* @remark why should use stop_loop() to terminate thread in itself? | ||
| 114 | -* in the thread itself, that is the cycle method, | ||
| 115 | -* if itself want to terminate the thread, should never use stop(), | ||
| 116 | -* but use stop_loop() to set the loop to false and terminate normally. | ||
| 117 | -* | ||
| 118 | -* @remark when should set the interval_us, and when not? | ||
| 119 | -* the cycle will invoke util cannot loop, eventhough the return code of cycle is error, | ||
| 120 | -* so the interval_us used to sleep for each cycle. | ||
| 121 | -*/ | 35 | + * the handler for the thread, callback interface. |
| 36 | + * the thread model defines as: | ||
| 37 | + * handler->on_thread_start() | ||
| 38 | + * while loop: | ||
| 39 | + * handler->on_before_cycle() | ||
| 40 | + * handler->cycle() | ||
| 41 | + * handler->on_end_cycle() | ||
| 42 | + * if !loop then break for user stop thread. | ||
| 43 | + * sleep(CycleIntervalMilliseconds) | ||
| 44 | + * handler->on_thread_stop() | ||
| 45 | + * when stop, the thread will interrupt the st_thread, | ||
| 46 | + * which will cause the socket to return error and | ||
| 47 | + * terminate the cycle thread. | ||
| 48 | + * | ||
| 49 | + * Usage 1: loop thread never quit. | ||
| 50 | + * user can create thread always running util server terminate. | ||
| 51 | + * the step to create a thread never stop: | ||
| 52 | + * 1. create SrsThread field, with joinable false. | ||
| 53 | + * for example: | ||
| 54 | + * class SrsStreamCache : public ISrsThreadHandler { | ||
| 55 | + * public: SrsStreamCache() { pthread = new SrsThread("http-stream", this, SRS_AUTO_STREAM_SLEEP_US, false); } | ||
| 56 | + * public: virtual int cycle() { | ||
| 57 | + * // check status, start ffmpeg when stopped. | ||
| 58 | + * } | ||
| 59 | + * } | ||
| 60 | + * | ||
| 61 | + * Usage 2: stop by other thread. | ||
| 62 | + * user can create thread and stop then start again and again, | ||
| 63 | + * generally must provides a start and stop method, @see SrsIngester. | ||
| 64 | + * the step to create a thread stop by other thread: | ||
| 65 | + * 1. create SrsThread field, with joinable true. | ||
| 66 | + * 2. must use stop to stop and join the thread. | ||
| 67 | + * for example: | ||
| 68 | + * class SrsIngester : public ISrsThreadHandler { | ||
| 69 | + * public: SrsIngester() { pthread = new SrsThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US, true); } | ||
| 70 | + * public: virtual int start() { return pthread->start(); } | ||
| 71 | + * public: virtual void stop() { pthread->stop(); } | ||
| 72 | + * public: virtual int cycle() { | ||
| 73 | + * // check status, start ffmpeg when stopped. | ||
| 74 | + * } | ||
| 75 | + * }; | ||
| 76 | + * | ||
| 77 | + * Usage 3: stop by thread itself. | ||
| 78 | + * user can create thread which stop itself, | ||
| 79 | + * generally only need to provides a start method, | ||
| 80 | + * the object will destroy itself then terminate the thread, @see SrsConnection | ||
| 81 | + * 1. create SrsThread field, with joinable false. | ||
| 82 | + * 2. owner stop thread loop, destroy itself when thread stop. | ||
| 83 | + * for example: | ||
| 84 | + * class SrsConnection : public ISrsThreadHandler { | ||
| 85 | + * public: SrsConnection() { pthread = new SrsThread("conn", this, 0, false); } | ||
| 86 | + * public: virtual int start() { return pthread->start(); } | ||
| 87 | + * public: virtual int cycle() { | ||
| 88 | + * // serve client. | ||
| 89 | + * // set loop to stop to quit, stop thread itself. | ||
| 90 | + * pthread->stop_loop(); | ||
| 91 | + * } | ||
| 92 | + * public: virtual int on_thread_stop() { | ||
| 93 | + * // remove the connection in thread itself. | ||
| 94 | + * server->remove(this); | ||
| 95 | + * } | ||
| 96 | + * }; | ||
| 97 | + * | ||
| 98 | + * Usage 4: loop in the cycle method. | ||
| 99 | + * user can use loop code in the cycle method, @see SrsForwarder | ||
| 100 | + * 1. create SrsThread field, with or without joinable is ok. | ||
| 101 | + * 2. loop code in cycle method, check the can_loop() for thread to quit. | ||
| 102 | + * for example: | ||
| 103 | + * class SrsForwarder : public ISrsThreadHandler { | ||
| 104 | + * public: virtual int cycle() { | ||
| 105 | + * while (pthread->can_loop()) { | ||
| 106 | + * // read msgs from queue and forward to server. | ||
| 107 | + * } | ||
| 108 | + * } | ||
| 109 | + * }; | ||
| 110 | + * | ||
| 111 | + * @remark why should check can_loop() in cycle method? | ||
| 112 | + * when thread interrupt, the socket maybe not got EINT, | ||
| 113 | + * espectially on st_usleep(), so the cycle must check the loop, | ||
| 114 | + * when handler->cycle() has loop itself, for example: | ||
| 115 | + * while (true): | ||
| 116 | + * if (read_from_socket(skt) < 0) break; | ||
| 117 | + * if thread stop when read_from_socket, it's ok, the loop will break, | ||
| 118 | + * but when thread stop interrupt the s_usleep(0), then the loop is | ||
| 119 | + * death loop. | ||
| 120 | + * in a word, the handler->cycle() must: | ||
| 121 | + * while (pthread->can_loop()): | ||
| 122 | + * if (read_from_socket(skt) < 0) break; | ||
| 123 | + * check the loop, then it works. | ||
| 124 | + * | ||
| 125 | + * @remark why should use stop_loop() to terminate thread in itself? | ||
| 126 | + * in the thread itself, that is the cycle method, | ||
| 127 | + * if itself want to terminate the thread, should never use stop(), | ||
| 128 | + * but use stop_loop() to set the loop to false and terminate normally. | ||
| 129 | + * | ||
| 130 | + * @remark when should set the interval_us, and when not? | ||
| 131 | + * the cycle will invoke util cannot loop, eventhough the return code of cycle is error, | ||
| 132 | + * so the interval_us used to sleep for each cycle. | ||
| 133 | + */ | ||
| 122 | class ISrsThreadHandler | 134 | class ISrsThreadHandler |
| 123 | { | 135 | { |
| 124 | public: | 136 | public: |
| @@ -418,15 +418,13 @@ bool get_proc_self_stat(SrsProcSelfStat& r) | @@ -418,15 +418,13 @@ bool get_proc_self_stat(SrsProcSelfStat& r) | ||
| 418 | 418 | ||
| 419 | void srs_update_proc_stat() | 419 | void srs_update_proc_stat() |
| 420 | { | 420 | { |
| 421 | - // always assert the USER_HZ is 1/100ths | ||
| 422 | // @see: http://stackoverflow.com/questions/7298646/calculating-user-nice-sys-idle-iowait-irq-and-sirq-from-proc-stat/7298711 | 421 | // @see: http://stackoverflow.com/questions/7298646/calculating-user-nice-sys-idle-iowait-irq-and-sirq-from-proc-stat/7298711 |
| 423 | - static bool user_hz_assert = false; | ||
| 424 | - if (!user_hz_assert) { | ||
| 425 | - user_hz_assert = true; | ||
| 426 | - | ||
| 427 | - int USER_HZ = sysconf(_SC_CLK_TCK); | ||
| 428 | - srs_trace("USER_HZ=%d", USER_HZ); | ||
| 429 | - srs_assert(USER_HZ == 100); | 422 | + // @see https://github.com/simple-rtmp-server/srs/issues/397 |
| 423 | + static int user_hz = 0; | ||
| 424 | + if (user_hz <= 0) { | ||
| 425 | + user_hz = sysconf(_SC_CLK_TCK); | ||
| 426 | + srs_trace("USER_HZ=%d", user_hz); | ||
| 427 | + srs_assert(user_hz > 0); | ||
| 430 | } | 428 | } |
| 431 | 429 | ||
| 432 | // system cpu stat | 430 | // system cpu stat |
| @@ -471,7 +469,7 @@ void srs_update_proc_stat() | @@ -471,7 +469,7 @@ void srs_update_proc_stat() | ||
| 471 | int64_t total = r.sample_time - o.sample_time; | 469 | int64_t total = r.sample_time - o.sample_time; |
| 472 | int64_t usage = (r.utime + r.stime) - (o.utime + o.stime); | 470 | int64_t usage = (r.utime + r.stime) - (o.utime + o.stime); |
| 473 | if (total > 0) { | 471 | if (total > 0) { |
| 474 | - r.percent = (float)(usage * 1000 / (double)total / 100); | 472 | + r.percent = (float)(usage * 1000 / (double)total / user_hz); |
| 475 | } | 473 | } |
| 476 | 474 | ||
| 477 | // upate cache. | 475 | // upate cache. |
| @@ -201,6 +201,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -201,6 +201,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 201 | // query string seprator | 201 | // query string seprator |
| 202 | #define SRS_CONSTS_HTTP_QUERY_SEP '?' | 202 | #define SRS_CONSTS_HTTP_QUERY_SEP '?' |
| 203 | 203 | ||
| 204 | +// the default recv timeout. | ||
| 205 | +#define SRS_HTTP_RECV_TIMEOUT_US 60 * 1000 * 1000 | ||
| 206 | + | ||
| 204 | // 6.1.1 Status Code and Reason Phrase | 207 | // 6.1.1 Status Code and Reason Phrase |
| 205 | #define SRS_CONSTS_HTTP_Continue 100 | 208 | #define SRS_CONSTS_HTTP_Continue 100 |
| 206 | #define SRS_CONSTS_HTTP_SwitchingProtocols 101 | 209 | #define SRS_CONSTS_HTTP_SwitchingProtocols 101 |
| @@ -33,6 +33,7 @@ bool srs_is_client_gracefully_close(int error_code) | @@ -33,6 +33,7 @@ bool srs_is_client_gracefully_close(int error_code) | ||
| 33 | { | 33 | { |
| 34 | return error_code == ERROR_SOCKET_READ | 34 | return error_code == ERROR_SOCKET_READ |
| 35 | || error_code == ERROR_SOCKET_READ_FULLY | 35 | || error_code == ERROR_SOCKET_READ_FULLY |
| 36 | - || error_code == ERROR_SOCKET_WRITE; | 36 | + || error_code == ERROR_SOCKET_WRITE |
| 37 | + || error_code == ERROR_SOCKET_TIMEOUT; | ||
| 37 | } | 38 | } |
| 38 | 39 |
| @@ -255,7 +255,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -255,7 +255,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 255 | #define ERROR_HTTP_INVALID_CHUNK_HEADER 4026 | 255 | #define ERROR_HTTP_INVALID_CHUNK_HEADER 4026 |
| 256 | #define ERROR_AVC_NALU_UEV 4027 | 256 | #define ERROR_AVC_NALU_UEV 4027 |
| 257 | #define ERROR_AAC_BYTES_INVALID 4028 | 257 | #define ERROR_AAC_BYTES_INVALID 4028 |
| 258 | -#define ERROR_HTTP_REQUEST_EOF 4029 | 258 | +#define ERROR_HTTP_REQUEST_EOF 4029 |
| 259 | 259 | ||
| 260 | /////////////////////////////////////////////////////// | 260 | /////////////////////////////////////////////////////// |
| 261 | // user-define error. | 261 | // user-define error. |
| @@ -723,8 +723,8 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | @@ -723,8 +723,8 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | ||
| 723 | // because when audio stream_number is 0, the elementary is ADTS(aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS). | 723 | // because when audio stream_number is 0, the elementary is ADTS(aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS). |
| 724 | 724 | ||
| 725 | // about the bytes of PES_packet_data_byte, defined in hls-mpeg-ts-iso13818-1.pdf, page 58 | 725 | // about the bytes of PES_packet_data_byte, defined in hls-mpeg-ts-iso13818-1.pdf, page 58 |
| 726 | - // PES_packet_data_byte "C PES_packet_data_bytes shall be contiguous bytes of data from the elementary stream | ||
| 727 | - // indicated by the packets stream_id or PID. When the elementary stream data conforms to ITU-T | 726 | + // PES_packet_data_byte ¨C PES_packet_data_bytes shall be contiguous bytes of data from the elementary stream |
| 727 | + // indicated by the packet¡¯s stream_id or PID. When the elementary stream data conforms to ITU-T | ||
| 728 | // Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 13818-3, the PES_packet_data_bytes shall be byte aligned to the bytes of this | 728 | // Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 13818-3, the PES_packet_data_bytes shall be byte aligned to the bytes of this |
| 729 | // Recommendation | International Standard. The byte-order of the elementary stream shall be preserved. The number of | 729 | // Recommendation | International Standard. The byte-order of the elementary stream shall be preserved. The number of |
| 730 | // PES_packet_data_bytes, N, is specified by the PES_packet_length field. N shall be equal to the value indicated in the | 730 | // PES_packet_data_bytes, N, is specified by the PES_packet_length field. N shall be equal to the value indicated in the |
| @@ -735,12 +735,12 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | @@ -735,12 +735,12 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | ||
| 735 | // PES_packet_data_byte field are user definable and will not be specified by ITU-T | ISO/IEC in the future. | 735 | // PES_packet_data_byte field are user definable and will not be specified by ITU-T | ISO/IEC in the future. |
| 736 | 736 | ||
| 737 | // about the bytes of stream_id, define in hls-mpeg-ts-iso13818-1.pdf, page 49 | 737 | // about the bytes of stream_id, define in hls-mpeg-ts-iso13818-1.pdf, page 49 |
| 738 | - // stream_id "C In Program Streams, the stream_id specifies the type and number of the elementary stream as defined by the | 738 | + // stream_id ¨C In Program Streams, the stream_id specifies the type and number of the elementary stream as defined by the |
| 739 | // stream_id Table 2-18. In Transport Streams, the stream_id may be set to any valid value which correctly describes the | 739 | // stream_id Table 2-18. In Transport Streams, the stream_id may be set to any valid value which correctly describes the |
| 740 | // elementary stream type as defined in Table 2-18. In Transport Streams, the elementary stream type is specified in the | 740 | // elementary stream type as defined in Table 2-18. In Transport Streams, the elementary stream type is specified in the |
| 741 | // Program Specific Information as specified in 2.4.4. | 741 | // Program Specific Information as specified in 2.4.4. |
| 742 | 742 | ||
| 743 | - // about the stream_id table, define in Table 2-18 "C Stream_id assignments, hls-mpeg-ts-iso13818-1.pdf, page 52. | 743 | + // about the stream_id table, define in Table 2-18 ¨C Stream_id assignments, hls-mpeg-ts-iso13818-1.pdf, page 52. |
| 744 | // | 744 | // |
| 745 | // 110x xxxx | 745 | // 110x xxxx |
| 746 | // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 or ISO/IEC | 746 | // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 or ISO/IEC |
| @@ -344,15 +344,15 @@ int run_master() | @@ -344,15 +344,15 @@ int run_master() | ||
| 344 | { | 344 | { |
| 345 | int ret = ERROR_SUCCESS; | 345 | int ret = ERROR_SUCCESS; |
| 346 | 346 | ||
| 347 | - if ((ret = _srs_server->initialize_signal()) != ERROR_SUCCESS) { | 347 | + if ((ret = _srs_server->initialize_st()) != ERROR_SUCCESS) { |
| 348 | return ret; | 348 | return ret; |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | - if ((ret = _srs_server->acquire_pid_file()) != ERROR_SUCCESS) { | 351 | + if ((ret = _srs_server->initialize_signal()) != ERROR_SUCCESS) { |
| 352 | return ret; | 352 | return ret; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | - if ((ret = _srs_server->initialize_st()) != ERROR_SUCCESS) { | 355 | + if ((ret = _srs_server->acquire_pid_file()) != ERROR_SUCCESS) { |
| 356 | return ret; | 356 | return ret; |
| 357 | } | 357 | } |
| 358 | 358 |
| @@ -38,36 +38,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -38,36 +38,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 38 | 38 | ||
| 39 | using namespace std; | 39 | using namespace std; |
| 40 | 40 | ||
| 41 | -/** | ||
| 42 | -* the signature for packets to client. | ||
| 43 | -*/ | ||
| 44 | -#define RTMP_SIG_FMS_VER "3,5,3,888" | ||
| 45 | -#define RTMP_SIG_AMF0_VER 0 | ||
| 46 | -#define RTMP_SIG_CLIENT_ID "ASAICiss" | ||
| 47 | - | ||
| 48 | -/** | ||
| 49 | -* onStatus consts. | ||
| 50 | -*/ | ||
| 51 | -#define StatusLevel "level" | ||
| 52 | -#define StatusCode "code" | ||
| 53 | -#define StatusDescription "description" | ||
| 54 | -#define StatusDetails "details" | ||
| 55 | -#define StatusClientId "clientid" | ||
| 56 | -// status value | ||
| 57 | -#define StatusLevelStatus "status" | ||
| 58 | -// status error | ||
| 59 | -#define StatusLevelError "error" | ||
| 60 | -// code value | ||
| 61 | -#define StatusCodeConnectSuccess "NetConnection.Connect.Success" | ||
| 62 | -#define StatusCodeConnectRejected "NetConnection.Connect.Rejected" | ||
| 63 | -#define StatusCodeStreamReset "NetStream.Play.Reset" | ||
| 64 | -#define StatusCodeStreamStart "NetStream.Play.Start" | ||
| 65 | -#define StatusCodeStreamPause "NetStream.Pause.Notify" | ||
| 66 | -#define StatusCodeStreamUnpause "NetStream.Unpause.Notify" | ||
| 67 | -#define StatusCodePublishStart "NetStream.Publish.Start" | ||
| 68 | -#define StatusCodeDataStart "NetStream.Data.Start" | ||
| 69 | -#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" | ||
| 70 | - | ||
| 71 | // FMLE | 41 | // FMLE |
| 72 | #define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" | 42 | #define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" |
| 73 | #define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" | 43 | #define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" |
| @@ -129,15 +99,7 @@ void SrsRequest::update_auth(SrsRequest* req) | @@ -129,15 +99,7 @@ void SrsRequest::update_auth(SrsRequest* req) | ||
| 129 | 99 | ||
| 130 | string SrsRequest::get_stream_url() | 100 | string SrsRequest::get_stream_url() |
| 131 | { | 101 | { |
| 132 | - std::string url = ""; | ||
| 133 | - | ||
| 134 | - url += vhost; | ||
| 135 | - url += "/"; | ||
| 136 | - url += app; | ||
| 137 | - url += "/"; | ||
| 138 | - url += stream; | ||
| 139 | - | ||
| 140 | - return url; | 102 | + return srs_generate_stream_url(vhost, app, stream); |
| 141 | } | 103 | } |
| 142 | 104 | ||
| 143 | void SrsRequest::strip() | 105 | void SrsRequest::strip() |
| @@ -49,6 +49,36 @@ class SrsAmf0Object; | @@ -49,6 +49,36 @@ class SrsAmf0Object; | ||
| 49 | class IMergeReadHandler; | 49 | class IMergeReadHandler; |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | + * the signature for packets to client. | ||
| 53 | + */ | ||
| 54 | +#define RTMP_SIG_FMS_VER "3,5,3,888" | ||
| 55 | +#define RTMP_SIG_AMF0_VER 0 | ||
| 56 | +#define RTMP_SIG_CLIENT_ID "ASAICiss" | ||
| 57 | + | ||
| 58 | +/** | ||
| 59 | + * onStatus consts. | ||
| 60 | + */ | ||
| 61 | +#define StatusLevel "level" | ||
| 62 | +#define StatusCode "code" | ||
| 63 | +#define StatusDescription "description" | ||
| 64 | +#define StatusDetails "details" | ||
| 65 | +#define StatusClientId "clientid" | ||
| 66 | +// status value | ||
| 67 | +#define StatusLevelStatus "status" | ||
| 68 | +// status error | ||
| 69 | +#define StatusLevelError "error" | ||
| 70 | +// code value | ||
| 71 | +#define StatusCodeConnectSuccess "NetConnection.Connect.Success" | ||
| 72 | +#define StatusCodeConnectRejected "NetConnection.Connect.Rejected" | ||
| 73 | +#define StatusCodeStreamReset "NetStream.Play.Reset" | ||
| 74 | +#define StatusCodeStreamStart "NetStream.Play.Start" | ||
| 75 | +#define StatusCodeStreamPause "NetStream.Pause.Notify" | ||
| 76 | +#define StatusCodeStreamUnpause "NetStream.Unpause.Notify" | ||
| 77 | +#define StatusCodePublishStart "NetStream.Publish.Start" | ||
| 78 | +#define StatusCodeDataStart "NetStream.Data.Start" | ||
| 79 | +#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" | ||
| 80 | + | ||
| 81 | +/** | ||
| 52 | * the original request from client. | 82 | * the original request from client. |
| 53 | */ | 83 | */ |
| 54 | class SrsRequest | 84 | class SrsRequest |
| @@ -47,89 +47,6 @@ using namespace std; | @@ -47,89 +47,6 @@ using namespace std; | ||
| 47 | ***************************************************************************** | 47 | ***************************************************************************** |
| 48 | ****************************************************************************/ | 48 | ****************************************************************************/ |
| 49 | /** | 49 | /** |
| 50 | -5. Protocol Control Messages | ||
| 51 | -RTMP reserves message type IDs 1-7 for protocol control messages. | ||
| 52 | -These messages contain information needed by the RTM Chunk Stream | ||
| 53 | -protocol or RTMP itself. Protocol messages with IDs 1 & 2 are | ||
| 54 | -reserved for usage with RTM Chunk Stream protocol. Protocol messages | ||
| 55 | -with IDs 3-6 are reserved for usage of RTMP. Protocol message with ID | ||
| 56 | -7 is used between edge server and origin server. | ||
| 57 | -*/ | ||
| 58 | -#define RTMP_MSG_SetChunkSize 0x01 | ||
| 59 | -#define RTMP_MSG_AbortMessage 0x02 | ||
| 60 | -#define RTMP_MSG_Acknowledgement 0x03 | ||
| 61 | -#define RTMP_MSG_UserControlMessage 0x04 | ||
| 62 | -#define RTMP_MSG_WindowAcknowledgementSize 0x05 | ||
| 63 | -#define RTMP_MSG_SetPeerBandwidth 0x06 | ||
| 64 | -#define RTMP_MSG_EdgeAndOriginServerCommand 0x07 | ||
| 65 | -/** | ||
| 66 | -3. Types of messages | ||
| 67 | -The server and the client send messages over the network to | ||
| 68 | -communicate with each other. The messages can be of any type which | ||
| 69 | -includes audio messages, video messages, command messages, shared | ||
| 70 | -object messages, data messages, and user control messages. | ||
| 71 | -3.1. Command message | ||
| 72 | -Command messages carry the AMF-encoded commands between the client | ||
| 73 | -and the server. These messages have been assigned message type value | ||
| 74 | -of 20 for AMF0 encoding and message type value of 17 for AMF3 | ||
| 75 | -encoding. These messages are sent to perform some operations like | ||
| 76 | -connect, createStream, publish, play, pause on the peer. Command | ||
| 77 | -messages like onstatus, result etc. are used to inform the sender | ||
| 78 | -about the status of the requested commands. A command message | ||
| 79 | -consists of command name, transaction ID, and command object that | ||
| 80 | -contains related parameters. A client or a server can request Remote | ||
| 81 | -Procedure Calls (RPC) over streams that are communicated using the | ||
| 82 | -command messages to the peer. | ||
| 83 | -*/ | ||
| 84 | -#define RTMP_MSG_AMF3CommandMessage 17 // 0x11 | ||
| 85 | -#define RTMP_MSG_AMF0CommandMessage 20 // 0x14 | ||
| 86 | -/** | ||
| 87 | -3.2. Data message | ||
| 88 | -The client or the server sends this message to send Metadata or any | ||
| 89 | -user data to the peer. Metadata includes details about the | ||
| 90 | -data(audio, video etc.) like creation time, duration, theme and so | ||
| 91 | -on. These messages have been assigned message type value of 18 for | ||
| 92 | -AMF0 and message type value of 15 for AMF3. | ||
| 93 | -*/ | ||
| 94 | -#define RTMP_MSG_AMF0DataMessage 18 // 0x12 | ||
| 95 | -#define RTMP_MSG_AMF3DataMessage 15 // 0x0F | ||
| 96 | -/** | ||
| 97 | -3.3. Shared object message | ||
| 98 | -A shared object is a Flash object (a collection of name value pairs) | ||
| 99 | -that are in synchronization across multiple clients, instances, and | ||
| 100 | -so on. The message types kMsgContainer=19 for AMF0 and | ||
| 101 | -kMsgContainerEx=16 for AMF3 are reserved for shared object events. | ||
| 102 | -Each message can contain multiple events. | ||
| 103 | -*/ | ||
| 104 | -#define RTMP_MSG_AMF3SharedObject 16 // 0x10 | ||
| 105 | -#define RTMP_MSG_AMF0SharedObject 19 // 0x13 | ||
| 106 | -/** | ||
| 107 | -3.4. Audio message | ||
| 108 | -The client or the server sends this message to send audio data to the | ||
| 109 | -peer. The message type value of 8 is reserved for audio messages. | ||
| 110 | -*/ | ||
| 111 | -#define RTMP_MSG_AudioMessage 8 // 0x08 | ||
| 112 | -/* * | ||
| 113 | -3.5. Video message | ||
| 114 | -The client or the server sends this message to send video data to the | ||
| 115 | -peer. The message type value of 9 is reserved for video messages. | ||
| 116 | -These messages are large and can delay the sending of other type of | ||
| 117 | -messages. To avoid such a situation, the video message is assigned | ||
| 118 | -the lowest priority. | ||
| 119 | -*/ | ||
| 120 | -#define RTMP_MSG_VideoMessage 9 // 0x09 | ||
| 121 | -/** | ||
| 122 | -3.6. Aggregate message | ||
| 123 | -An aggregate message is a single message that contains a list of submessages. | ||
| 124 | -The message type value of 22 is reserved for aggregate | ||
| 125 | -messages. | ||
| 126 | -*/ | ||
| 127 | -#define RTMP_MSG_AggregateMessage 22 // 0x16 | ||
| 128 | - | ||
| 129 | -/**************************************************************************** | ||
| 130 | -***************************************************************************** | ||
| 131 | -****************************************************************************/ | ||
| 132 | -/** | ||
| 133 | * 6.1.2. Chunk Message Header | 50 | * 6.1.2. Chunk Message Header |
| 134 | * There are four different formats for the chunk message header, | 51 | * There are four different formats for the chunk message header, |
| 135 | * selected by the "fmt" field in the chunk basic header. | 52 | * selected by the "fmt" field in the chunk basic header. |
| @@ -173,24 +90,6 @@ messages. | @@ -173,24 +90,6 @@ messages. | ||
| 173 | ***************************************************************************** | 90 | ***************************************************************************** |
| 174 | ****************************************************************************/ | 91 | ****************************************************************************/ |
| 175 | /** | 92 | /** |
| 176 | -* amf0 command message, command name macros | ||
| 177 | -*/ | ||
| 178 | -#define RTMP_AMF0_COMMAND_CONNECT "connect" | ||
| 179 | -#define RTMP_AMF0_COMMAND_CREATE_STREAM "createStream" | ||
| 180 | -#define RTMP_AMF0_COMMAND_CLOSE_STREAM "closeStream" | ||
| 181 | -#define RTMP_AMF0_COMMAND_PLAY "play" | ||
| 182 | -#define RTMP_AMF0_COMMAND_PAUSE "pause" | ||
| 183 | -#define RTMP_AMF0_COMMAND_ON_BW_DONE "onBWDone" | ||
| 184 | -#define RTMP_AMF0_COMMAND_ON_STATUS "onStatus" | ||
| 185 | -#define RTMP_AMF0_COMMAND_RESULT "_result" | ||
| 186 | -#define RTMP_AMF0_COMMAND_ERROR "_error" | ||
| 187 | -#define RTMP_AMF0_COMMAND_RELEASE_STREAM "releaseStream" | ||
| 188 | -#define RTMP_AMF0_COMMAND_FC_PUBLISH "FCPublish" | ||
| 189 | -#define RTMP_AMF0_COMMAND_UNPUBLISH "FCUnpublish" | ||
| 190 | -#define RTMP_AMF0_COMMAND_PUBLISH "publish" | ||
| 191 | -#define RTMP_AMF0_DATA_SAMPLE_ACCESS "|RtmpSampleAccess" | ||
| 192 | - | ||
| 193 | -/** | ||
| 194 | * band width check method name, which will be invoked by client. | 93 | * band width check method name, which will be invoked by client. |
| 195 | * band width check mothods use SrsBandwidthPacket as its internal packet type, | 94 | * band width check mothods use SrsBandwidthPacket as its internal packet type, |
| 196 | * so ensure you set command name when you use it. | 95 | * so ensure you set command name when you use it. |
| @@ -57,6 +57,110 @@ class SrsSharedPtrMessage; | @@ -57,6 +57,110 @@ class SrsSharedPtrMessage; | ||
| 57 | class IMergeReadHandler; | 57 | class IMergeReadHandler; |
| 58 | 58 | ||
| 59 | /**************************************************************************** | 59 | /**************************************************************************** |
| 60 | + ***************************************************************************** | ||
| 61 | + ****************************************************************************/ | ||
| 62 | +/** | ||
| 63 | + 5. Protocol Control Messages | ||
| 64 | + RTMP reserves message type IDs 1-7 for protocol control messages. | ||
| 65 | + These messages contain information needed by the RTM Chunk Stream | ||
| 66 | + protocol or RTMP itself. Protocol messages with IDs 1 & 2 are | ||
| 67 | + reserved for usage with RTM Chunk Stream protocol. Protocol messages | ||
| 68 | + with IDs 3-6 are reserved for usage of RTMP. Protocol message with ID | ||
| 69 | + 7 is used between edge server and origin server. | ||
| 70 | + */ | ||
| 71 | +#define RTMP_MSG_SetChunkSize 0x01 | ||
| 72 | +#define RTMP_MSG_AbortMessage 0x02 | ||
| 73 | +#define RTMP_MSG_Acknowledgement 0x03 | ||
| 74 | +#define RTMP_MSG_UserControlMessage 0x04 | ||
| 75 | +#define RTMP_MSG_WindowAcknowledgementSize 0x05 | ||
| 76 | +#define RTMP_MSG_SetPeerBandwidth 0x06 | ||
| 77 | +#define RTMP_MSG_EdgeAndOriginServerCommand 0x07 | ||
| 78 | +/** | ||
| 79 | + 3. Types of messages | ||
| 80 | + The server and the client send messages over the network to | ||
| 81 | + communicate with each other. The messages can be of any type which | ||
| 82 | + includes audio messages, video messages, command messages, shared | ||
| 83 | + object messages, data messages, and user control messages. | ||
| 84 | + 3.1. Command message | ||
| 85 | + Command messages carry the AMF-encoded commands between the client | ||
| 86 | + and the server. These messages have been assigned message type value | ||
| 87 | + of 20 for AMF0 encoding and message type value of 17 for AMF3 | ||
| 88 | + encoding. These messages are sent to perform some operations like | ||
| 89 | + connect, createStream, publish, play, pause on the peer. Command | ||
| 90 | + messages like onstatus, result etc. are used to inform the sender | ||
| 91 | + about the status of the requested commands. A command message | ||
| 92 | + consists of command name, transaction ID, and command object that | ||
| 93 | + contains related parameters. A client or a server can request Remote | ||
| 94 | + Procedure Calls (RPC) over streams that are communicated using the | ||
| 95 | + command messages to the peer. | ||
| 96 | + */ | ||
| 97 | +#define RTMP_MSG_AMF3CommandMessage 17 // 0x11 | ||
| 98 | +#define RTMP_MSG_AMF0CommandMessage 20 // 0x14 | ||
| 99 | +/** | ||
| 100 | + 3.2. Data message | ||
| 101 | + The client or the server sends this message to send Metadata or any | ||
| 102 | + user data to the peer. Metadata includes details about the | ||
| 103 | + data(audio, video etc.) like creation time, duration, theme and so | ||
| 104 | + on. These messages have been assigned message type value of 18 for | ||
| 105 | + AMF0 and message type value of 15 for AMF3. | ||
| 106 | + */ | ||
| 107 | +#define RTMP_MSG_AMF0DataMessage 18 // 0x12 | ||
| 108 | +#define RTMP_MSG_AMF3DataMessage 15 // 0x0F | ||
| 109 | +/** | ||
| 110 | + 3.3. Shared object message | ||
| 111 | + A shared object is a Flash object (a collection of name value pairs) | ||
| 112 | + that are in synchronization across multiple clients, instances, and | ||
| 113 | + so on. The message types kMsgContainer=19 for AMF0 and | ||
| 114 | + kMsgContainerEx=16 for AMF3 are reserved for shared object events. | ||
| 115 | + Each message can contain multiple events. | ||
| 116 | + */ | ||
| 117 | +#define RTMP_MSG_AMF3SharedObject 16 // 0x10 | ||
| 118 | +#define RTMP_MSG_AMF0SharedObject 19 // 0x13 | ||
| 119 | +/** | ||
| 120 | + 3.4. Audio message | ||
| 121 | + The client or the server sends this message to send audio data to the | ||
| 122 | + peer. The message type value of 8 is reserved for audio messages. | ||
| 123 | + */ | ||
| 124 | +#define RTMP_MSG_AudioMessage 8 // 0x08 | ||
| 125 | +/* * | ||
| 126 | + 3.5. Video message | ||
| 127 | + The client or the server sends this message to send video data to the | ||
| 128 | + peer. The message type value of 9 is reserved for video messages. | ||
| 129 | + These messages are large and can delay the sending of other type of | ||
| 130 | + messages. To avoid such a situation, the video message is assigned | ||
| 131 | + the lowest priority. | ||
| 132 | + */ | ||
| 133 | +#define RTMP_MSG_VideoMessage 9 // 0x09 | ||
| 134 | +/** | ||
| 135 | + 3.6. Aggregate message | ||
| 136 | + An aggregate message is a single message that contains a list of submessages. | ||
| 137 | + The message type value of 22 is reserved for aggregate | ||
| 138 | + messages. | ||
| 139 | + */ | ||
| 140 | +#define RTMP_MSG_AggregateMessage 22 // 0x16 | ||
| 141 | + | ||
| 142 | +/**************************************************************************** | ||
| 143 | + ***************************************************************************** | ||
| 144 | + ****************************************************************************/ | ||
| 145 | +/** | ||
| 146 | + * amf0 command message, command name macros | ||
| 147 | + */ | ||
| 148 | +#define RTMP_AMF0_COMMAND_CONNECT "connect" | ||
| 149 | +#define RTMP_AMF0_COMMAND_CREATE_STREAM "createStream" | ||
| 150 | +#define RTMP_AMF0_COMMAND_CLOSE_STREAM "closeStream" | ||
| 151 | +#define RTMP_AMF0_COMMAND_PLAY "play" | ||
| 152 | +#define RTMP_AMF0_COMMAND_PAUSE "pause" | ||
| 153 | +#define RTMP_AMF0_COMMAND_ON_BW_DONE "onBWDone" | ||
| 154 | +#define RTMP_AMF0_COMMAND_ON_STATUS "onStatus" | ||
| 155 | +#define RTMP_AMF0_COMMAND_RESULT "_result" | ||
| 156 | +#define RTMP_AMF0_COMMAND_ERROR "_error" | ||
| 157 | +#define RTMP_AMF0_COMMAND_RELEASE_STREAM "releaseStream" | ||
| 158 | +#define RTMP_AMF0_COMMAND_FC_PUBLISH "FCPublish" | ||
| 159 | +#define RTMP_AMF0_COMMAND_UNPUBLISH "FCUnpublish" | ||
| 160 | +#define RTMP_AMF0_COMMAND_PUBLISH "publish" | ||
| 161 | +#define RTMP_AMF0_DATA_SAMPLE_ACCESS "|RtmpSampleAccess" | ||
| 162 | + | ||
| 163 | +/**************************************************************************** | ||
| 60 | ***************************************************************************** | 164 | ***************************************************************************** |
| 61 | ****************************************************************************/ | 165 | ****************************************************************************/ |
| 62 | /** | 166 | /** |
| @@ -31,6 +31,7 @@ using namespace std; | @@ -31,6 +31,7 @@ using namespace std; | ||
| 31 | #include <srs_kernel_stream.hpp> | 31 | #include <srs_kernel_stream.hpp> |
| 32 | #include <srs_rtmp_stack.hpp> | 32 | #include <srs_rtmp_stack.hpp> |
| 33 | #include <srs_kernel_codec.hpp> | 33 | #include <srs_kernel_codec.hpp> |
| 34 | +#include <srs_kernel_consts.hpp> | ||
| 34 | 35 | ||
| 35 | void srs_discovery_tc_url( | 36 | void srs_discovery_tc_url( |
| 36 | string tcUrl, | 37 | string tcUrl, |
| @@ -78,22 +79,22 @@ void srs_vhost_resolve(string& vhost, string& app, string& param) | @@ -78,22 +79,22 @@ void srs_vhost_resolve(string& vhost, string& app, string& param) | ||
| 78 | app = srs_string_replace(app, "&&", "?"); | 79 | app = srs_string_replace(app, "&&", "?"); |
| 79 | app = srs_string_replace(app, "=", "?"); | 80 | app = srs_string_replace(app, "=", "?"); |
| 80 | 81 | ||
| 81 | - if ((pos = app.find("?")) == std::string::npos) { | ||
| 82 | - return; | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | - std::string query = app.substr(pos + 1); | ||
| 86 | - app = app.substr(0, pos); | ||
| 87 | - | ||
| 88 | - if ((pos = query.find("vhost?")) != std::string::npos) { | ||
| 89 | - query = query.substr(pos + 6); | ||
| 90 | - if (!query.empty()) { | ||
| 91 | - vhost = query; | ||
| 92 | - } | ||
| 93 | - if ((pos = vhost.find("?")) != std::string::npos) { | ||
| 94 | - vhost = vhost.substr(0, pos); | 82 | + if ((pos = app.find("?")) != std::string::npos) { |
| 83 | + std::string query = app.substr(pos + 1); | ||
| 84 | + app = app.substr(0, pos); | ||
| 85 | + | ||
| 86 | + if ((pos = query.find("vhost?")) != std::string::npos) { | ||
| 87 | + query = query.substr(pos + 6); | ||
| 88 | + if (!query.empty()) { | ||
| 89 | + vhost = query; | ||
| 90 | + } | ||
| 91 | + if ((pos = vhost.find("?")) != std::string::npos) { | ||
| 92 | + vhost = vhost.substr(0, pos); | ||
| 93 | + } | ||
| 95 | } | 94 | } |
| 96 | } | 95 | } |
| 96 | + | ||
| 97 | + /* others */ | ||
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | void srs_random_generate(char* bytes, int size) | 100 | void srs_random_generate(char* bytes, int size) |
| @@ -346,3 +347,18 @@ int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, in | @@ -346,3 +347,18 @@ int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, in | ||
| 346 | return ret; | 347 | return ret; |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 350 | +std::string srs_generate_stream_url(std::string vhost, std::string app, std::string stream) | ||
| 351 | +{ | ||
| 352 | + std::string url = ""; | ||
| 353 | + | ||
| 354 | + if (SRS_CONSTS_RTMP_DEFAULT_VHOST != vhost){ | ||
| 355 | + url += vhost; | ||
| 356 | + } | ||
| 357 | + url += "/"; | ||
| 358 | + url += app; | ||
| 359 | + url += "/"; | ||
| 360 | + url += stream; | ||
| 361 | + | ||
| 362 | + return url; | ||
| 363 | +} | ||
| 364 | + |
| @@ -63,7 +63,9 @@ extern void srs_discovery_tc_url( | @@ -63,7 +63,9 @@ extern void srs_discovery_tc_url( | ||
| 63 | * app...vhost...request_vhost | 63 | * app...vhost...request_vhost |
| 64 | * @param param, the query, for example, ?vhost=xxx | 64 | * @param param, the query, for example, ?vhost=xxx |
| 65 | */ | 65 | */ |
| 66 | -extern void srs_vhost_resolve(std::string& vhost, std::string& app, std::string& param); | 66 | +extern void srs_vhost_resolve( |
| 67 | + std::string& vhost, std::string& app, std::string& param | ||
| 68 | +); | ||
| 67 | 69 | ||
| 68 | /** | 70 | /** |
| 69 | * generate ramdom data for handshake. | 71 | * generate ramdom data for handshake. |
| @@ -118,5 +120,8 @@ extern int srs_chunk_header_c3( | @@ -118,5 +120,8 @@ extern int srs_chunk_header_c3( | ||
| 118 | */ | 120 | */ |
| 119 | extern int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg); | 121 | extern int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg); |
| 120 | 122 | ||
| 123 | +// get the stream identify, vhost/app/stream. | ||
| 124 | +extern std::string srs_generate_stream_url(std::string vhost, std::string app, std::string stream); | ||
| 125 | + | ||
| 121 | #endif | 126 | #endif |
| 122 | 127 |
-
请 注册 或 登录 后发表评论