正在显示
10 个修改的文件
包含
340 行增加
和
32 行删除
| @@ -48,6 +48,7 @@ url: rtmp://127.0.0.1:1935/live/livestream | @@ -48,6 +48,7 @@ url: rtmp://127.0.0.1:1935/live/livestream | ||
| 48 | * nginx v1.5.0: 139524 lines <br/> | 48 | * nginx v1.5.0: 139524 lines <br/> |
| 49 | 49 | ||
| 50 | ### History | 50 | ### History |
| 51 | +* v0.4, 2013-11-09, support pause for live stream. | ||
| 51 | * v0.3, 2013-11-04, v0.3 released. 11773 lines. | 52 | * v0.3, 2013-11-04, v0.3 released. 11773 lines. |
| 52 | * v0.3, 2013-11-04, support refer/play-refer/publish-refer. | 53 | * v0.3, 2013-11-04, support refer/play-refer/publish-refer. |
| 53 | * v0.3, 2013-11-04, support vhosts specified config. | 54 | * v0.3, 2013-11-04, support vhosts specified config. |
| @@ -63,7 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -63,7 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 63 | (void)0 | 63 | (void)0 |
| 64 | 64 | ||
| 65 | // current release version | 65 | // current release version |
| 66 | -#define RTMP_SIG_SRS_VERSION "0.2.0" | 66 | +#define RTMP_SIG_SRS_VERSION "0.3.0" |
| 67 | // server info. | 67 | // server info. |
| 68 | #define RTMP_SIG_SRS_KEY "srs" | 68 | #define RTMP_SIG_SRS_KEY "srs" |
| 69 | #define RTMP_SIG_SRS_ROLE "origin server" | 69 | #define RTMP_SIG_SRS_ROLE "origin server" |
| @@ -270,10 +270,9 @@ int SrsClient::playing(SrsSource* source) | @@ -270,10 +270,9 @@ int SrsClient::playing(SrsSource* source) | ||
| 270 | srs_error("recv client control message failed. ret=%d", ret); | 270 | srs_error("recv client control message failed. ret=%d", ret); |
| 271 | return ret; | 271 | return ret; |
| 272 | } | 272 | } |
| 273 | - if (ret == ERROR_SUCCESS && !msg) { | ||
| 274 | - srs_info("play loop got a message."); | ||
| 275 | - SrsAutoFree(SrsCommonMessage, msg, false); | ||
| 276 | - // TODO: process it. | 273 | + if ((ret = process_play_control_msg(consumer, msg)) != ERROR_SUCCESS) { |
| 274 | + srs_error("process play control message failed. ret=%d", ret); | ||
| 275 | + return ret; | ||
| 277 | } | 276 | } |
| 278 | } | 277 | } |
| 279 | 278 | ||
| @@ -442,3 +441,44 @@ int SrsClient::get_peer_ip() | @@ -442,3 +441,44 @@ int SrsClient::get_peer_ip() | ||
| 442 | return ret; | 441 | return ret; |
| 443 | } | 442 | } |
| 444 | 443 | ||
| 444 | +int SrsClient::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg) | ||
| 445 | +{ | ||
| 446 | + int ret = ERROR_SUCCESS; | ||
| 447 | + | ||
| 448 | + if (!msg) { | ||
| 449 | + srs_verbose("ignore all empty message."); | ||
| 450 | + return ret; | ||
| 451 | + } | ||
| 452 | + SrsAutoFree(SrsCommonMessage, msg, false); | ||
| 453 | + | ||
| 454 | + if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) { | ||
| 455 | + srs_info("ignore all message except amf0/amf3 command."); | ||
| 456 | + return ret; | ||
| 457 | + } | ||
| 458 | + | ||
| 459 | + if ((ret = msg->decode_packet()) != ERROR_SUCCESS) { | ||
| 460 | + srs_error("decode the amf0/amf3 command packet failed. ret=%d", ret); | ||
| 461 | + return ret; | ||
| 462 | + } | ||
| 463 | + srs_info("decode the amf0/amf3 command packet success."); | ||
| 464 | + | ||
| 465 | + SrsPausePacket* pause = dynamic_cast<SrsPausePacket*>(msg->get_packet()); | ||
| 466 | + if (!pause) { | ||
| 467 | + srs_info("ignore all amf0/amf3 command except pause."); | ||
| 468 | + return ret; | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + if ((ret = rtmp->on_play_client_pause(res->stream_id, pause->is_pause)) != ERROR_SUCCESS) { | ||
| 472 | + srs_error("rtmp process play client pause failed. ret=%d", ret); | ||
| 473 | + return ret; | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + if ((ret = consumer->on_play_client_pause(pause->is_pause)) != ERROR_SUCCESS) { | ||
| 477 | + srs_error("consumer process play client pause failed. ret=%d", ret); | ||
| 478 | + return ret; | ||
| 479 | + } | ||
| 480 | + srs_info("process pause success, is_pause=%d, time=%d.", pause->is_pause, pause->time_ms); | ||
| 481 | + | ||
| 482 | + return ret; | ||
| 483 | +} | ||
| 484 | + |
| @@ -37,6 +37,8 @@ class SrsRequest; | @@ -37,6 +37,8 @@ class SrsRequest; | ||
| 37 | class SrsResponse; | 37 | class SrsResponse; |
| 38 | class SrsSource; | 38 | class SrsSource; |
| 39 | class SrsRefer; | 39 | class SrsRefer; |
| 40 | +class SrsConsumer; | ||
| 41 | +class SrsCommonMessage; | ||
| 40 | 42 | ||
| 41 | /** | 43 | /** |
| 42 | * the client provides the main logic control for RTMP clients. | 44 | * the client provides the main logic control for RTMP clients. |
| @@ -59,6 +61,7 @@ private: | @@ -59,6 +61,7 @@ private: | ||
| 59 | virtual int playing(SrsSource* source); | 61 | virtual int playing(SrsSource* source); |
| 60 | virtual int publish(SrsSource* source, bool is_fmle); | 62 | virtual int publish(SrsSource* source, bool is_fmle); |
| 61 | virtual int get_peer_ip(); | 63 | virtual int get_peer_ip(); |
| 64 | + virtual int process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg); | ||
| 62 | }; | 65 | }; |
| 63 | 66 | ||
| 64 | #endif | 67 | #endif |
| @@ -195,6 +195,7 @@ messages. | @@ -195,6 +195,7 @@ messages. | ||
| 195 | #define RTMP_AMF0_COMMAND_CONNECT "connect" | 195 | #define RTMP_AMF0_COMMAND_CONNECT "connect" |
| 196 | #define RTMP_AMF0_COMMAND_CREATE_STREAM "createStream" | 196 | #define RTMP_AMF0_COMMAND_CREATE_STREAM "createStream" |
| 197 | #define RTMP_AMF0_COMMAND_PLAY "play" | 197 | #define RTMP_AMF0_COMMAND_PLAY "play" |
| 198 | +#define RTMP_AMF0_COMMAND_PAUSE "pause" | ||
| 198 | #define RTMP_AMF0_COMMAND_ON_BW_DONE "onBWDone" | 199 | #define RTMP_AMF0_COMMAND_ON_BW_DONE "onBWDone" |
| 199 | #define RTMP_AMF0_COMMAND_ON_STATUS "onStatus" | 200 | #define RTMP_AMF0_COMMAND_ON_STATUS "onStatus" |
| 200 | #define RTMP_AMF0_COMMAND_RESULT "_result" | 201 | #define RTMP_AMF0_COMMAND_RESULT "_result" |
| @@ -1219,6 +1220,10 @@ int SrsCommonMessage::decode_packet() | @@ -1219,6 +1220,10 @@ int SrsCommonMessage::decode_packet() | ||
| 1219 | srs_info("decode the AMF0/AMF3 command(paly message)."); | 1220 | srs_info("decode the AMF0/AMF3 command(paly message)."); |
| 1220 | packet = new SrsPlayPacket(); | 1221 | packet = new SrsPlayPacket(); |
| 1221 | return packet->decode(stream); | 1222 | return packet->decode(stream); |
| 1223 | + } else if(command == RTMP_AMF0_COMMAND_PAUSE) { | ||
| 1224 | + srs_info("decode the AMF0/AMF3 command(pause message)."); | ||
| 1225 | + packet = new SrsPausePacket(); | ||
| 1226 | + return packet->decode(stream); | ||
| 1222 | } else if(command == RTMP_AMF0_COMMAND_RELEASE_STREAM) { | 1227 | } else if(command == RTMP_AMF0_COMMAND_RELEASE_STREAM) { |
| 1223 | srs_info("decode the AMF0/AMF3 command(FMLE releaseStream message)."); | 1228 | srs_info("decode the AMF0/AMF3 command(FMLE releaseStream message)."); |
| 1224 | packet = new SrsFMLEStartPacket(); | 1229 | packet = new SrsFMLEStartPacket(); |
| @@ -1896,6 +1901,61 @@ int SrsPublishPacket::decode(SrsStream* stream) | @@ -1896,6 +1901,61 @@ int SrsPublishPacket::decode(SrsStream* stream) | ||
| 1896 | return ret; | 1901 | return ret; |
| 1897 | } | 1902 | } |
| 1898 | 1903 | ||
| 1904 | +SrsPausePacket::SrsPausePacket() | ||
| 1905 | +{ | ||
| 1906 | + command_name = RTMP_AMF0_COMMAND_PAUSE; | ||
| 1907 | + transaction_id = 0; | ||
| 1908 | + command_object = new SrsAmf0Null(); | ||
| 1909 | + | ||
| 1910 | + time_ms = 0; | ||
| 1911 | + is_pause = true; | ||
| 1912 | +} | ||
| 1913 | + | ||
| 1914 | +SrsPausePacket::~SrsPausePacket() | ||
| 1915 | +{ | ||
| 1916 | + srs_freep(command_object); | ||
| 1917 | +} | ||
| 1918 | + | ||
| 1919 | +int SrsPausePacket::decode(SrsStream* stream) | ||
| 1920 | +{ | ||
| 1921 | + int ret = ERROR_SUCCESS; | ||
| 1922 | + | ||
| 1923 | + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) { | ||
| 1924 | + srs_error("amf0 decode pause command_name failed. ret=%d", ret); | ||
| 1925 | + return ret; | ||
| 1926 | + } | ||
| 1927 | + if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_PAUSE) { | ||
| 1928 | + ret = ERROR_RTMP_AMF0_DECODE; | ||
| 1929 | + srs_error("amf0 decode pause command_name failed. " | ||
| 1930 | + "command_name=%s, ret=%d", command_name.c_str(), ret); | ||
| 1931 | + return ret; | ||
| 1932 | + } | ||
| 1933 | + | ||
| 1934 | + if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) { | ||
| 1935 | + srs_error("amf0 decode pause transaction_id failed. ret=%d", ret); | ||
| 1936 | + return ret; | ||
| 1937 | + } | ||
| 1938 | + | ||
| 1939 | + if ((ret = srs_amf0_read_null(stream)) != ERROR_SUCCESS) { | ||
| 1940 | + srs_error("amf0 decode pause command_object failed. ret=%d", ret); | ||
| 1941 | + return ret; | ||
| 1942 | + } | ||
| 1943 | + | ||
| 1944 | + if ((ret = srs_amf0_read_boolean(stream, is_pause)) != ERROR_SUCCESS) { | ||
| 1945 | + srs_error("amf0 decode pause is_pause failed. ret=%d", ret); | ||
| 1946 | + return ret; | ||
| 1947 | + } | ||
| 1948 | + | ||
| 1949 | + if ((ret = srs_amf0_read_number(stream, time_ms)) != ERROR_SUCCESS) { | ||
| 1950 | + srs_error("amf0 decode pause time_ms failed. ret=%d", ret); | ||
| 1951 | + return ret; | ||
| 1952 | + } | ||
| 1953 | + | ||
| 1954 | + srs_info("amf0 decode pause packet success"); | ||
| 1955 | + | ||
| 1956 | + return ret; | ||
| 1957 | +} | ||
| 1958 | + | ||
| 1899 | SrsPlayPacket::SrsPlayPacket() | 1959 | SrsPlayPacket::SrsPlayPacket() |
| 1900 | { | 1960 | { |
| 1901 | command_name = RTMP_AMF0_COMMAND_PLAY; | 1961 | command_name = RTMP_AMF0_COMMAND_PLAY; |
| @@ -637,6 +637,33 @@ public: | @@ -637,6 +637,33 @@ public: | ||
| 637 | }; | 637 | }; |
| 638 | 638 | ||
| 639 | /** | 639 | /** |
| 640 | +* 4.2.8. pause | ||
| 641 | +* The client sends the pause command to tell the server to pause or | ||
| 642 | +* start playing. | ||
| 643 | +*/ | ||
| 644 | +class SrsPausePacket : public SrsPacket | ||
| 645 | +{ | ||
| 646 | +private: | ||
| 647 | + typedef SrsPacket super; | ||
| 648 | +protected: | ||
| 649 | + virtual const char* get_class_name() | ||
| 650 | + { | ||
| 651 | + return CLASS_NAME_STRING(SrsPausePacket); | ||
| 652 | + } | ||
| 653 | +public: | ||
| 654 | + std::string command_name; | ||
| 655 | + double transaction_id; | ||
| 656 | + SrsAmf0Null* command_object; | ||
| 657 | + bool is_pause; | ||
| 658 | + double time_ms; | ||
| 659 | +public: | ||
| 660 | + SrsPausePacket(); | ||
| 661 | + virtual ~SrsPausePacket(); | ||
| 662 | +public: | ||
| 663 | + virtual int decode(SrsStream* stream); | ||
| 664 | +}; | ||
| 665 | + | ||
| 666 | +/** | ||
| 640 | * 4.2.1. play | 667 | * 4.2.1. play |
| 641 | * The client sends this command to the server to play a stream. | 668 | * The client sends this command to the server to play a stream. |
| 642 | */ | 669 | */ |
| @@ -960,12 +987,12 @@ protected: | @@ -960,12 +987,12 @@ protected: | ||
| 960 | enum SrcPCUCEventType | 987 | enum SrcPCUCEventType |
| 961 | { | 988 | { |
| 962 | // generally, 4bytes event-data | 989 | // generally, 4bytes event-data |
| 963 | - SrcPCUCStreamBegin = 0x00, | 990 | + SrcPCUCStreamBegin = 0x00, |
| 964 | SrcPCUCStreamEOF = 0x01, | 991 | SrcPCUCStreamEOF = 0x01, |
| 965 | SrcPCUCStreamDry = 0x02, | 992 | SrcPCUCStreamDry = 0x02, |
| 966 | - SrcPCUCSetBufferLength = 0x03, // 8bytes event-data | 993 | + SrcPCUCSetBufferLength = 0x03, // 8bytes event-data |
| 967 | SrcPCUCStreamIsRecorded = 0x04, | 994 | SrcPCUCStreamIsRecorded = 0x04, |
| 968 | - SrcPCUCPingRequest = 0x06, | 995 | + SrcPCUCPingRequest = 0x06, |
| 969 | SrcPCUCPingResponse = 0x07, | 996 | SrcPCUCPingResponse = 0x07, |
| 970 | }; | 997 | }; |
| 971 | 998 |
| @@ -34,34 +34,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -34,34 +34,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 34 | /** | 34 | /** |
| 35 | * the signature for packets to client. | 35 | * the signature for packets to client. |
| 36 | */ | 36 | */ |
| 37 | -#define RTMP_SIG_FMS_VER "3,5,3,888" | ||
| 38 | -#define RTMP_SIG_AMF0_VER 0 | ||
| 39 | -#define RTMP_SIG_CLIENT_ID "ASAICiss" | 37 | +#define RTMP_SIG_FMS_VER "3,5,3,888" |
| 38 | +#define RTMP_SIG_AMF0_VER 0 | ||
| 39 | +#define RTMP_SIG_CLIENT_ID "ASAICiss" | ||
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | * onStatus consts. | 42 | * onStatus consts. |
| 43 | */ | 43 | */ |
| 44 | -#define StatusLevel "level" | ||
| 45 | -#define StatusCode "code" | ||
| 46 | -#define StatusDescription "description" | ||
| 47 | -#define StatusDetails "details" | ||
| 48 | -#define StatusClientId "clientid" | 44 | +#define StatusLevel "level" |
| 45 | +#define StatusCode "code" | ||
| 46 | +#define StatusDescription "description" | ||
| 47 | +#define StatusDetails "details" | ||
| 48 | +#define StatusClientId "clientid" | ||
| 49 | // status value | 49 | // status value |
| 50 | -#define StatusLevelStatus "status" | 50 | +#define StatusLevelStatus "status" |
| 51 | // code value | 51 | // code value |
| 52 | -#define StatusCodeConnectSuccess "NetConnection.Connect.Success" | ||
| 53 | -#define StatusCodeStreamReset "NetStream.Play.Reset" | ||
| 54 | -#define StatusCodeStreamStart "NetStream.Play.Start" | ||
| 55 | -#define StatusCodePublishStart "NetStream.Publish.Start" | ||
| 56 | -#define StatusCodeDataStart "NetStream.Data.Start" | ||
| 57 | -#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" | 52 | +#define StatusCodeConnectSuccess "NetConnection.Connect.Success" |
| 53 | +#define StatusCodeStreamReset "NetStream.Play.Reset" | ||
| 54 | +#define StatusCodeStreamStart "NetStream.Play.Start" | ||
| 55 | +#define StatusCodeStreamPause "NetStream.Pause.Notify" | ||
| 56 | +#define StatusCodeStreamUnpause "NetStream.Unpause.Notify" | ||
| 57 | +#define StatusCodePublishStart "NetStream.Publish.Start" | ||
| 58 | +#define StatusCodeDataStart "NetStream.Data.Start" | ||
| 59 | +#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" | ||
| 58 | 60 | ||
| 59 | // FMLE | 61 | // FMLE |
| 60 | #define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" | 62 | #define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" |
| 61 | #define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" | 63 | #define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" |
| 62 | 64 | ||
| 63 | // default stream id for response the createStream request. | 65 | // default stream id for response the createStream request. |
| 64 | -#define SRS_DEFAULT_SID 1 | 66 | +#define SRS_DEFAULT_SID 1 |
| 65 | 67 | ||
| 66 | SrsRequest::SrsRequest() | 68 | SrsRequest::SrsRequest() |
| 67 | { | 69 | { |
| @@ -570,6 +572,81 @@ int SrsRtmp::start_play(int stream_id) | @@ -570,6 +572,81 @@ int SrsRtmp::start_play(int stream_id) | ||
| 570 | return ret; | 572 | return ret; |
| 571 | } | 573 | } |
| 572 | 574 | ||
| 575 | +int SrsRtmp::on_play_client_pause(int stream_id, bool is_pause) | ||
| 576 | +{ | ||
| 577 | + int ret = ERROR_SUCCESS; | ||
| 578 | + | ||
| 579 | + if (is_pause) { | ||
| 580 | + // onStatus(NetStream.Pause.Notify) | ||
| 581 | + if (true) { | ||
| 582 | + SrsCommonMessage* msg = new SrsCommonMessage(); | ||
| 583 | + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); | ||
| 584 | + | ||
| 585 | + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus)); | ||
| 586 | + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamPause)); | ||
| 587 | + pkt->data->set(StatusDescription, new SrsAmf0String("Paused stream.")); | ||
| 588 | + | ||
| 589 | + msg->set_packet(pkt, stream_id); | ||
| 590 | + | ||
| 591 | + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) { | ||
| 592 | + srs_error("send onStatus(NetStream.Pause.Notify) message failed. ret=%d", ret); | ||
| 593 | + return ret; | ||
| 594 | + } | ||
| 595 | + srs_info("send onStatus(NetStream.Pause.Notify) message success."); | ||
| 596 | + } | ||
| 597 | + // StreamEOF | ||
| 598 | + if (true) { | ||
| 599 | + SrsCommonMessage* msg = new SrsCommonMessage(); | ||
| 600 | + SrsUserControlPacket* pkt = new SrsUserControlPacket(); | ||
| 601 | + | ||
| 602 | + pkt->event_type = SrcPCUCStreamEOF; | ||
| 603 | + pkt->event_data = stream_id; | ||
| 604 | + msg->set_packet(pkt, 0); | ||
| 605 | + | ||
| 606 | + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) { | ||
| 607 | + srs_error("send PCUC(StreamEOF) message failed. ret=%d", ret); | ||
| 608 | + return ret; | ||
| 609 | + } | ||
| 610 | + srs_info("send PCUC(StreamEOF) message success."); | ||
| 611 | + } | ||
| 612 | + } else { | ||
| 613 | + // onStatus(NetStream.Unpause.Notify) | ||
| 614 | + if (true) { | ||
| 615 | + SrsCommonMessage* msg = new SrsCommonMessage(); | ||
| 616 | + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); | ||
| 617 | + | ||
| 618 | + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus)); | ||
| 619 | + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamUnpause)); | ||
| 620 | + pkt->data->set(StatusDescription, new SrsAmf0String("Unpaused stream.")); | ||
| 621 | + | ||
| 622 | + msg->set_packet(pkt, stream_id); | ||
| 623 | + | ||
| 624 | + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) { | ||
| 625 | + srs_error("send onStatus(NetStream.Unpause.Notify) message failed. ret=%d", ret); | ||
| 626 | + return ret; | ||
| 627 | + } | ||
| 628 | + srs_info("send onStatus(NetStream.Unpause.Notify) message success."); | ||
| 629 | + } | ||
| 630 | + // StreanBegin | ||
| 631 | + if (true) { | ||
| 632 | + SrsCommonMessage* msg = new SrsCommonMessage(); | ||
| 633 | + SrsUserControlPacket* pkt = new SrsUserControlPacket(); | ||
| 634 | + | ||
| 635 | + pkt->event_type = SrcPCUCStreamBegin; | ||
| 636 | + pkt->event_data = stream_id; | ||
| 637 | + msg->set_packet(pkt, 0); | ||
| 638 | + | ||
| 639 | + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) { | ||
| 640 | + srs_error("send PCUC(StreanBegin) message failed. ret=%d", ret); | ||
| 641 | + return ret; | ||
| 642 | + } | ||
| 643 | + srs_info("send PCUC(StreanBegin) message success."); | ||
| 644 | + } | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | + return ret; | ||
| 648 | +} | ||
| 649 | + | ||
| 573 | int SrsRtmp::start_fmle_publish(int stream_id) | 650 | int SrsRtmp::start_fmle_publish(int stream_id) |
| 574 | { | 651 | { |
| 575 | int ret = ERROR_SUCCESS; | 652 | int ret = ERROR_SUCCESS; |
| @@ -148,6 +148,16 @@ public: | @@ -148,6 +148,16 @@ public: | ||
| 148 | */ | 148 | */ |
| 149 | virtual int start_play(int stream_id); | 149 | virtual int start_play(int stream_id); |
| 150 | /** | 150 | /** |
| 151 | + * when client(type is play) send pause message, | ||
| 152 | + * if is_pause, response the following packets: | ||
| 153 | + * onStatus(NetStream.Pause.Notify) | ||
| 154 | + * StreamEOF | ||
| 155 | + * if not is_pause, response the following packets: | ||
| 156 | + * onStatus(NetStream.Unpause.Notify) | ||
| 157 | + * StreamBegin | ||
| 158 | + */ | ||
| 159 | + virtual int on_play_client_pause(int stream_id, bool is_pause); | ||
| 160 | + /** | ||
| 151 | * when client type is publish, response with packets: | 161 | * when client type is publish, response with packets: |
| 152 | * releaseStream response | 162 | * releaseStream response |
| 153 | * FCPublish | 163 | * FCPublish |
| @@ -31,8 +31,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,8 +31,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 31 | #include <srs_core_amf0.hpp> | 31 | #include <srs_core_amf0.hpp> |
| 32 | #include <srs_core_codec.hpp> | 32 | #include <srs_core_codec.hpp> |
| 33 | 33 | ||
| 34 | -#define CONST_MAX_JITTER_MS 500 | ||
| 35 | -#define DEFAULT_FRAME_TIME_MS 10 | 34 | +#define CONST_MAX_JITTER_MS 500 |
| 35 | +#define DEFAULT_FRAME_TIME_MS 10 | ||
| 36 | +#define PAUSED_SHRINK_SIZE 250 | ||
| 36 | 37 | ||
| 37 | std::map<std::string, SrsSource*> SrsSource::pool; | 38 | std::map<std::string, SrsSource*> SrsSource::pool; |
| 38 | 39 | ||
| @@ -50,16 +51,14 @@ SrsConsumer::SrsConsumer(SrsSource* _source) | @@ -50,16 +51,14 @@ SrsConsumer::SrsConsumer(SrsSource* _source) | ||
| 50 | { | 51 | { |
| 51 | source = _source; | 52 | source = _source; |
| 52 | last_pkt_correct_time = last_pkt_time = 0; | 53 | last_pkt_correct_time = last_pkt_time = 0; |
| 54 | + paused = false; | ||
| 55 | + codec = new SrsCodec(); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | SrsConsumer::~SrsConsumer() | 58 | SrsConsumer::~SrsConsumer() |
| 56 | { | 59 | { |
| 57 | - std::vector<SrsSharedPtrMessage*>::iterator it; | ||
| 58 | - for (it = msgs.begin(); it != msgs.end(); ++it) { | ||
| 59 | - SrsSharedPtrMessage* msg = *it; | ||
| 60 | - srs_freep(msg); | ||
| 61 | - } | ||
| 62 | - msgs.clear(); | 60 | + clear(); |
| 61 | + srs_freep(codec); | ||
| 63 | 62 | ||
| 64 | source->on_consumer_destroy(this); | 63 | source->on_consumer_destroy(this); |
| 65 | } | 64 | } |
| @@ -89,6 +88,13 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c | @@ -89,6 +88,13 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c | ||
| 89 | if (msgs.empty()) { | 88 | if (msgs.empty()) { |
| 90 | return ret; | 89 | return ret; |
| 91 | } | 90 | } |
| 91 | + | ||
| 92 | + if (paused) { | ||
| 93 | + if ((int)msgs.size() >= PAUSED_SHRINK_SIZE) { | ||
| 94 | + shrink(); | ||
| 95 | + } | ||
| 96 | + return ret; | ||
| 97 | + } | ||
| 92 | 98 | ||
| 93 | if (max_count == 0) { | 99 | if (max_count == 0) { |
| 94 | count = (int)msgs.size(); | 100 | count = (int)msgs.size(); |
| @@ -111,6 +117,68 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c | @@ -111,6 +117,68 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c | ||
| 111 | return ret; | 117 | return ret; |
| 112 | } | 118 | } |
| 113 | 119 | ||
| 120 | +int SrsConsumer::on_play_client_pause(bool is_pause) | ||
| 121 | +{ | ||
| 122 | + int ret = ERROR_SUCCESS; | ||
| 123 | + | ||
| 124 | + srs_trace("stream consumer change pause state %d=>%d", paused, is_pause); | ||
| 125 | + paused = is_pause; | ||
| 126 | + | ||
| 127 | + return ret; | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +void SrsConsumer::shrink() | ||
| 131 | +{ | ||
| 132 | + int i = 0; | ||
| 133 | + std::vector<SrsSharedPtrMessage*>::iterator it; | ||
| 134 | + | ||
| 135 | + // issue the last video iframe. | ||
| 136 | + bool has_video = false; | ||
| 137 | + int frame_to_remove = 0; | ||
| 138 | + std::vector<SrsSharedPtrMessage*>::iterator iframe = msgs.end(); | ||
| 139 | + for (i = 0, it = msgs.begin(); it != msgs.end(); ++it, i++) { | ||
| 140 | + SrsSharedPtrMessage* msg = *it; | ||
| 141 | + if (msg->header.is_video()) { | ||
| 142 | + has_video = true; | ||
| 143 | + if (codec->video_is_keyframe(msg->payload, msg->size)) { | ||
| 144 | + iframe = it; | ||
| 145 | + frame_to_remove = i + 1; | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + // last iframe is the first elem, ignore it. | ||
| 151 | + if (iframe == msgs.begin()) { | ||
| 152 | + return; | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + // recalc the frame to remove | ||
| 156 | + if (iframe == msgs.end()) { | ||
| 157 | + frame_to_remove = 0; | ||
| 158 | + } | ||
| 159 | + if (!has_video) { | ||
| 160 | + frame_to_remove = (int)msgs.size(); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + srs_trace("shrink the cache queue, has_video=%d, has_iframe=%d, size=%d, removed=%d", | ||
| 164 | + has_video, iframe != msgs.end(), (int)msgs.size(), frame_to_remove); | ||
| 165 | + | ||
| 166 | + // if no video, remove all audio. | ||
| 167 | + if (!has_video) { | ||
| 168 | + clear(); | ||
| 169 | + return; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + // if exists video Iframe, remove the frames before it. | ||
| 173 | + if (iframe != msgs.end()) { | ||
| 174 | + for (it = msgs.begin(); it != iframe; ++it) { | ||
| 175 | + SrsSharedPtrMessage* msg = *it; | ||
| 176 | + srs_freep(msg); | ||
| 177 | + } | ||
| 178 | + msgs.erase(msgs.begin(), iframe); | ||
| 179 | + } | ||
| 180 | +} | ||
| 181 | + | ||
| 114 | int SrsConsumer::jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate) | 182 | int SrsConsumer::jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate) |
| 115 | { | 183 | { |
| 116 | int ret = ERROR_SUCCESS; | 184 | int ret = ERROR_SUCCESS; |
| @@ -156,6 +224,16 @@ int SrsConsumer::jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate) | @@ -156,6 +224,16 @@ int SrsConsumer::jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate) | ||
| 156 | return ret; | 224 | return ret; |
| 157 | } | 225 | } |
| 158 | 226 | ||
| 227 | +void SrsConsumer::clear() | ||
| 228 | +{ | ||
| 229 | + std::vector<SrsSharedPtrMessage*>::iterator it; | ||
| 230 | + for (it = msgs.begin(); it != msgs.end(); ++it) { | ||
| 231 | + SrsSharedPtrMessage* msg = *it; | ||
| 232 | + srs_freep(msg); | ||
| 233 | + } | ||
| 234 | + msgs.clear(); | ||
| 235 | +} | ||
| 236 | + | ||
| 159 | SrsSource::SrsSource(std::string _stream_url) | 237 | SrsSource::SrsSource(std::string _stream_url) |
| 160 | { | 238 | { |
| 161 | stream_url = _stream_url; | 239 | stream_url = _stream_url; |
| @@ -50,6 +50,8 @@ private: | @@ -50,6 +50,8 @@ private: | ||
| 50 | int32_t last_pkt_correct_time; | 50 | int32_t last_pkt_correct_time; |
| 51 | SrsSource* source; | 51 | SrsSource* source; |
| 52 | std::vector<SrsSharedPtrMessage*> msgs; | 52 | std::vector<SrsSharedPtrMessage*> msgs; |
| 53 | + bool paused; | ||
| 54 | + SrsCodec* codec; | ||
| 53 | public: | 55 | public: |
| 54 | SrsConsumer(SrsSource* _source); | 56 | SrsConsumer(SrsSource* _source); |
| 55 | virtual ~SrsConsumer(); | 57 | virtual ~SrsConsumer(); |
| @@ -69,11 +71,21 @@ public: | @@ -69,11 +71,21 @@ public: | ||
| 69 | * @max_count the max count to dequeue, 0 to dequeue all. | 71 | * @max_count the max count to dequeue, 0 to dequeue all. |
| 70 | */ | 72 | */ |
| 71 | virtual int get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count); | 73 | virtual int get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count); |
| 74 | + /** | ||
| 75 | + * when client send the pause message. | ||
| 76 | + */ | ||
| 77 | + virtual int on_play_client_pause(bool is_pause); | ||
| 72 | private: | 78 | private: |
| 73 | /** | 79 | /** |
| 80 | + * when paused, shrink the cache queue, | ||
| 81 | + * remove to cache only one gop. | ||
| 82 | + */ | ||
| 83 | + virtual void shrink(); | ||
| 84 | + /** | ||
| 74 | * detect the time jitter and correct it. | 85 | * detect the time jitter and correct it. |
| 75 | */ | 86 | */ |
| 76 | virtual int jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate); | 87 | virtual int jitter_correct(SrsSharedPtrMessage* msg, int audio_sample_rate); |
| 88 | + virtual void clear(); | ||
| 77 | }; | 89 | }; |
| 78 | 90 | ||
| 79 | /** | 91 | /** |
-
请 注册 或 登录 后发表评论