diff --git a/README.md b/README.md index 507fab89a..728152999 100755 --- a/README.md +++ b/README.md @@ -149,7 +149,6 @@ For previous versions, please read: - [ ] Support publishing stream by WebRTC, [#307][bug #307]. - [ ] Support change user to run SRS, [#1111][bug #1111]. - [ ] Support HLS variant, [#463][bug #463]. -- [ ] Support playing stream by WebRTC. > Remark: About the milestone and product plan, please read ([CN][v1_CN_Product], [EN][v1_EN_Product]) wiki. diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 1d72c02ab..457b371a5 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -639,10 +639,11 @@ if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then --disable-programs --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \ --disable-avdevice --disable-avformat --disable-swscale --disable-postproc --disable-avfilter --disable-network \ --disable-dct --disable-dwt --disable-error-resilience --disable-lsp --disable-lzo --disable-faan --disable-pixelutils \ - --disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-appkit --disable-coreimage \ - --disable-avfoundation --disable-securetransport --disable-iconv --disable-lzma --disable-sdl2 --disable-everything \ - --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm --enable-decoder=libopus --enable-encoder=aac \ - --enable-encoder=opus --enable-encoder=libopus --enable-libopus && + --disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-cuda-llvm --disable-cuvid \ + --disable-d3d11va --disable-dxva2 --disable-ffnvcodec --disable-nvdec --disable-nvenc --disable-v4l2-m2m --disable-vaapi \ + --disable-vdpau --disable-appkit --disable-coreimage --disable-avfoundation --disable-securetransport --disable-iconv \ + --disable-lzma --disable-sdl2 --disable-everything --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm \ + --enable-decoder=libopus --enable-encoder=aac --enable-encoder=opus --enable-encoder=libopus --enable-libopus && make ${SRS_JOBS} && make install && cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/${SRS_PLATFORM}/_release ffmpeg ) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 513a55b87..7304edd06 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -430,6 +430,11 @@ rtc_server { # @remark Should always turn it on, or Chrome will fail. # default: on encrypt on; + # We listen multiple times at the same port, by REUSEPORT, to increase the UDP queue. + # Note that you can set to 1 and increase the system UDP buffer size by net.core.rmem_max + # and net.core.rmem_default or just increase this to get larger UDP recv and send buffer. + # default: 4 + reuseport 4; } vhost rtc.vhost.srs.com { diff --git a/trunk/configure b/trunk/configure index 3c8e71976..ed76da4d5 100755 --- a/trunk/configure +++ b/trunk/configure @@ -444,7 +444,7 @@ mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk # generate phony header cat << END > ${SRS_WORKDIR}/${SRS_MAKEFILE} .PHONY: default _default install install-api help clean destroy server srs_ingest_hls librtmp utest _prepare_dir $__mphonys -.PHONY: clean_srs clean_modules clean_openssl clean_nginx clean_cherrypy clean_srtp2 clean_opus +.PHONY: clean_srs clean_modules clean_openssl clean_nginx clean_cherrypy clean_srtp2 clean_opus clean_ffmpeg clean_st .PHONY: st ffmpeg # install prefix. @@ -481,6 +481,8 @@ help: @echo " clean_openssl Remove the openssl cache." @echo " clean_srtp2 Remove the libsrtp2 cache." @echo " clean_opus Remove the opus cache." + @echo " clean_ffmpeg Remove the FFmpeg cache." + @echo " clean_st Remove the ST cache." @echo "For example:" @echo " make" @echo " make help" @@ -519,6 +521,14 @@ clean_opus: (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf opus-1.3.1) @echo "Please rebuild opus by: ./configure" +clean_ffmpeg: + (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf ffmpeg-4.2-fit) + @echo "Please rebuild FFmpeg by: ./configure" + +clean_st: + (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf st-srs) + @echo "Please rebuild ST by: ./configure" + clean_nginx: (cd ${SRS_OBJS_DIR} && rm -rf nginx) diff --git a/trunk/src/app/srs_app_audio_recode.cpp b/trunk/src/app/srs_app_audio_recode.cpp index 77a2a440d..6e60c2e96 100644 --- a/trunk/src/app/srs_app_audio_recode.cpp +++ b/trunk/src/app/srs_app_audio_recode.cpp @@ -388,16 +388,13 @@ srs_error_t SrsAudioRecode::initialize() srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int &n) { srs_error_t err = srs_success; - - static char decode_buffer[kPacketBufMax]; - static char resample_buffer[kFrameBufMax]; - static char encode_buffer[kPacketBufMax]; if (!dec_) { return srs_error_new(ERROR_RTC_RTP_MUXER, "dec_ nullptr"); } int decode_len = kPacketBufMax; + static char decode_buffer[kPacketBufMax]; if ((err = dec_->decode(pkt, decode_buffer, decode_len)) != srs_success) { return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error"); } @@ -412,15 +409,18 @@ srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int if (!resample_) { return srs_error_new(ERROR_RTC_RTP_MUXER, "SrsAudioResample failed"); } - resample_->initialize(); + if ((err = resample_->initialize()) != srs_success) { + return srs_error_wrap(err, "init resample"); + } } SrsSample pcm; pcm.bytes = decode_buffer; pcm.size = decode_len; int resample_len = kFrameBufMax; + static char resample_buffer[kFrameBufMax]; if ((err = resample_->resample(&pcm, resample_buffer, resample_len)) != srs_success) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error"); + return srs_error_new(ERROR_RTC_RTP_MUXER, "resample error"); } n = 0; @@ -445,8 +445,9 @@ srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int int encode_len; pcm.bytes = (char *)data_; pcm.size = size_; + static char encode_buffer[kPacketBufMax]; if ((err = enc_->encode(&pcm, encode_buffer, encode_len)) != srs_success) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error"); + return srs_error_new(ERROR_RTC_RTP_MUXER, "encode error"); } memcpy(buf[n], encode_buffer, encode_len); diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f63c3a07c..d3e790426 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1540,6 +1540,11 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf) if ((err = reload_http_stream(old_root)) != srs_success) { return srs_error_wrap(err, "http steram");; } + + // Merge config: rtc_server + if ((err = reload_rtc_server(old_root)) != srs_success) { + return srs_error_wrap(err, "http steram");; + } // TODO: FIXME: support reload stream_caster. @@ -1697,6 +1702,40 @@ srs_error_t SrsConfig::reload_http_stream(SrsConfDirective* old_root) return err; } +srs_error_t SrsConfig::reload_rtc_server(SrsConfDirective* old_root) +{ + srs_error_t err = srs_success; + + // merge config. + std::vector::iterator it; + + // state graph + // old_rtc_server new_rtc_server + // ENABLED => ENABLED (modified) + + SrsConfDirective* new_rtc_server = root->get("rtc_server"); + SrsConfDirective* old_rtc_server = old_root->get("rtc_server"); + + // TODO: FIXME: Support disable or enable reloading. + + // ENABLED => ENABLED (modified) + if (get_rtc_server_enabled(old_rtc_server) && get_rtc_server_enabled(new_rtc_server) + && !srs_directive_equals(old_rtc_server, new_rtc_server) + ) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((err = subscribe->on_reload_rtc_server()) != srs_success) { + return srs_error_wrap(err, "rtc server enabled"); + } + } + srs_trace("reload rtc server success."); + return err; + } + + srs_trace("reload rtc server success, nothing changed."); + return err; +} + srs_error_t SrsConfig::reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost) { srs_error_t err = srs_success; @@ -3575,7 +3614,7 @@ srs_error_t SrsConfig::check_normal_config() for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" - && n != "sendmmsg" && n != "encrypt") { + && n != "sendmmsg" && n != "encrypt" && n != "reuseport") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4706,6 +4745,33 @@ int SrsConfig::get_rtc_server_sendmmsg() #endif } +int SrsConfig::get_rtc_server_reuseport() +{ +#if defined(SO_REUSEPORT) + static int DEFAULT = 4; +#else + static int DEFAULT = 1; +#endif + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("reuseport"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + int reuseport = ::atoi(conf->arg0().c_str()); +#if !defined(SO_REUSEPORT) + srs_warn("REUSEPORT not supported, reset %d to %d", reuseport, DEFAULT); + reuseport = DEFAULT +#endif + + return reuseport; +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index f7f449b08..ba46984e3 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -333,6 +333,8 @@ private: // Reload the http_stream section of config. // TODO: FIXME: rename to http_server. virtual srs_error_t reload_http_stream(SrsConfDirective* old_root); + // Reload the rtc_server section of config. + virtual srs_error_t reload_rtc_server(SrsConfDirective* old_root); // Reload the transcode section of vhost of config. virtual srs_error_t reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost); // Reload the ingest section of vhost of config. @@ -525,6 +527,7 @@ public: virtual bool get_rtc_server_ecdsa(); virtual int get_rtc_server_sendmmsg(); virtual bool get_rtc_server_encrypt(); + virtual int get_rtc_server_reuseport(); SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index a88bf1af3..2117983be 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -40,6 +40,7 @@ using namespace std; #include #include #include +#include // set the max packet size. #define SRS_UDP_MAX_PACKET_SIZE 65535 @@ -235,12 +236,21 @@ srs_error_t SrsTcpListener::cycle() return err; } -SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd) +ISrsUdpSender::ISrsUdpSender() +{ +} + +ISrsUdpSender::~ISrsUdpSender() +{ +} + +SrsUdpMuxSocket::SrsUdpMuxSocket(ISrsUdpSender* h, srs_netfd_t fd) { nb_buf = SRS_UDP_MAX_PACKET_SIZE; buf = new char[nb_buf]; nread = 0; + handler = h; lfd = fd; fromlen = 0; @@ -253,7 +263,7 @@ SrsUdpMuxSocket::~SrsUdpMuxSocket() SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly() { - SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(lfd); + SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(handler, lfd); // Don't copy buffer srs_freepa(sendonly->buf); @@ -339,16 +349,18 @@ std::string SrsUdpMuxSocket::get_peer_id() return string(id_buf, len); } -SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p) +SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, ISrsUdpSender* s, std::string i, int p) { handler = h; + sender = s; + ip = i; port = p; lfd = NULL; nb_buf = SRS_UDP_MAX_PACKET_SIZE; buf = new char[nb_buf]; - + trd = new SrsDummyCoroutine(); } @@ -390,60 +402,108 @@ srs_error_t SrsUdpMuxListener::listen() void SrsUdpMuxListener::set_socket_buffer() { - int sndbuf_size = 0; - socklen_t opt_len = sizeof(sndbuf_size); - getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); - srs_trace("default udp remux socket sndbuf=%d", sndbuf_size); + int default_sndbuf = 0; + // TODO: FIXME: Config it. + int expect_sndbuf = 1024*1024*10; // 10M + int actual_sndbuf = expect_sndbuf; + int r0_sndbuf = 0; + if (true) { + socklen_t opt_len = sizeof(default_sndbuf); + getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&default_sndbuf, &opt_len); - sndbuf_size = 1024*1024*10; // 10M - if (setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, sizeof(sndbuf_size)) < 0) { - srs_warn("set sock opt SO_SNDBUFFORCE failed"); + if ((r0_sndbuf = setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, sizeof(actual_sndbuf))) < 0) { + srs_warn("set SO_SNDBUF failed, expect=%d, r0=%d", expect_sndbuf, r0_sndbuf); + } + + opt_len = sizeof(actual_sndbuf); + getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, &opt_len); } - opt_len = sizeof(sndbuf_size); - getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); - srs_trace("udp remux socket sndbuf=%d", sndbuf_size); + int default_rcvbuf = 0; + // TODO: FIXME: Config it. + int expect_rcvbuf = 1024*1024*10; // 10M + int actual_rcvbuf = expect_rcvbuf; + int r0_rcvbuf = 0; + if (true) { + socklen_t opt_len = sizeof(default_rcvbuf); + getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&default_rcvbuf, &opt_len); - int rcvbuf_size = 0; - opt_len = sizeof(rcvbuf_size); - getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); - srs_trace("default udp remux socket rcvbuf=%d", rcvbuf_size); + if ((r0_rcvbuf = setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, sizeof(actual_rcvbuf))) < 0) { + srs_warn("set SO_RCVBUF failed, expect=%d, r0=%d", expect_rcvbuf, r0_rcvbuf); + } - rcvbuf_size = 1024*1024*10; // 10M - if (setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, sizeof(rcvbuf_size)) < 0) { - srs_warn("set sock opt SO_RCVBUFFORCE failed"); + opt_len = sizeof(actual_rcvbuf); + getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, &opt_len); } - opt_len = sizeof(rcvbuf_size); - getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); - srs_trace("udp remux socket rcvbuf=%d", rcvbuf_size); + srs_trace("UDP #%d LISTEN at %s:%d, SO_SNDBUF(default=%d, expect=%d, actual=%d, r0=%d), SO_RCVBUF(default=%d, expect=%d, actual=%d, r0=%d)", + srs_netfd_fileno(lfd), ip.c_str(), port, default_sndbuf, expect_sndbuf, actual_sndbuf, r0_sndbuf, default_rcvbuf, expect_rcvbuf, actual_rcvbuf, r0_rcvbuf); } srs_error_t SrsUdpMuxListener::cycle() { srs_error_t err = srs_success; + + SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_recv(srs_netfd_fileno(lfd)); + SrsAutoFree(SrsPithyPrint, pprint); + + uint64_t nn_msgs = 0; + uint64_t nn_msgs_stage = 0; + uint64_t nn_msgs_last = 0; + uint64_t nn_loop = 0; + srs_utime_t time_last = srs_get_system_time(); while (true) { if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "udp listener"); - } + } - SrsUdpMuxSocket udp_mux_skt(lfd); + nn_loop++; - int nread = udp_mux_skt.recvfrom(SRS_UTIME_NO_TIMEOUT); + SrsUdpMuxSocket skt(sender, lfd); + + int nread = skt.recvfrom(SRS_UTIME_NO_TIMEOUT); if (nread <= 0) { if (nread < 0) { srs_warn("udp recv error"); } // remux udp never return continue; - } + } + + nn_msgs++; + nn_msgs_stage++; - if ((err = handler->on_udp_packet(&udp_mux_skt)) != srs_success) { + if ((err = handler->on_udp_packet(&skt)) != srs_success) { // remux udp never return srs_warn("udp packet handler error:%s", srs_error_desc(err).c_str()); - continue; - } + srs_error_reset(err); + } + + pprint->elapse(); + if (pprint->can_print()) { + int pps_average = 0; int pps_last = 0; + if (true) { + if (srs_get_system_time() > srs_get_system_startup_time()) { + pps_average = (int)(nn_msgs * SRS_UTIME_SECONDS / (srs_get_system_time() - srs_get_system_startup_time())); + } + if (srs_get_system_time() > time_last) { + pps_last = (int)((nn_msgs - nn_msgs_last) * SRS_UTIME_SECONDS / (srs_get_system_time() - time_last)); + } + } + + string pps_unit = ""; + if (pps_last > 10000 || pps_average > 10000) { + pps_unit = "(w)"; pps_last /= 10000; pps_average /= 10000; + } else if (pps_last > 1000 || pps_average > 1000) { + pps_unit = "(k)"; pps_last /= 10000; pps_average /= 10000; + } + + srs_trace("<- RTC #%d RECV %" PRId64 ", pps %d/%d%s, schedule %" PRId64, + srs_netfd_fileno(lfd), nn_msgs_stage, pps_average, pps_last, pps_unit.c_str(), nn_loop); + nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); + nn_loop = 0; nn_msgs_stage = 0; + } if (SrsUdpPacketRecvCycleInterval > 0) { srs_usleep(SrsUdpPacketRecvCycleInterval); diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 0222413c1..8ef384dd9 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -69,7 +69,7 @@ public: virtual ~ISrsUdpMuxHandler(); public: virtual srs_error_t on_stfd_change(srs_netfd_t fd); - virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) = 0; + virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt) = 0; }; // The tcp connection handler. @@ -131,9 +131,22 @@ public: virtual srs_error_t cycle(); }; +class ISrsUdpSender +{ +public: + ISrsUdpSender(); + virtual ~ISrsUdpSender(); +public: + // Fetch a mmsghdr from sender's cache. + virtual srs_error_t fetch(mmsghdr** pphdr) = 0; + // Notify the sender to send out the msg. + virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0; +}; + class SrsUdpMuxSocket { private: + ISrsUdpSender* handler; char* buf; int nb_buf; int nread; @@ -143,7 +156,7 @@ private: std::string peer_ip; int peer_port; public: - SrsUdpMuxSocket(srs_netfd_t fd); + SrsUdpMuxSocket(ISrsUdpSender* h, srs_netfd_t fd); virtual ~SrsUdpMuxSocket(); int recvfrom(srs_utime_t timeout); @@ -160,6 +173,7 @@ public: std::string get_peer_id(); public: SrsUdpMuxSocket* copy_sendonly(); + ISrsUdpSender* sender() { return handler; }; private: // Don't allow copy, user copy_sendonly instead SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs); @@ -170,6 +184,7 @@ class SrsUdpMuxListener : public ISrsCoroutineHandler { protected: srs_netfd_t lfd; + ISrsUdpSender* sender; SrsCoroutine* trd; protected: char* buf; @@ -179,7 +194,7 @@ protected: std::string ip; int port; public: - SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p); + SrsUdpMuxListener(ISrsUdpMuxHandler* h, ISrsUdpSender* s, std::string i, int p); virtual ~SrsUdpMuxListener(); public: virtual int fd(); diff --git a/trunk/src/app/srs_app_pithy_print.cpp b/trunk/src/app/srs_app_pithy_print.cpp index cef07f1de..58f8bca4a 100644 --- a/trunk/src/app/srs_app_pithy_print.cpp +++ b/trunk/src/app/srs_app_pithy_print.cpp @@ -112,6 +112,10 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id) #define SRS_CONSTS_STAGE_EXEC 11 // for the rtc play #define SRS_CONSTS_STAGE_RTC_PLAY 12 +// for the rtc send +#define SRS_CONSTS_STAGE_RTC_SEND 13 +// for the rtc recv +#define SRS_CONSTS_STAGE_RTC_RECV 14 SrsPithyPrint* SrsPithyPrint::create_rtmp_play() { @@ -173,6 +177,16 @@ SrsPithyPrint* SrsPithyPrint::create_rtc_play() return new SrsPithyPrint(SRS_CONSTS_STAGE_RTC_PLAY); } +SrsPithyPrint* SrsPithyPrint::create_rtc_send(int fd) +{ + return new SrsPithyPrint(fd<<16 | SRS_CONSTS_STAGE_RTC_SEND); +} + +SrsPithyPrint* SrsPithyPrint::create_rtc_recv(int fd) +{ + return new SrsPithyPrint(fd<<16 | SRS_CONSTS_STAGE_RTC_RECV); +} + SrsPithyPrint::~SrsPithyPrint() { leave_stage(); diff --git a/trunk/src/app/srs_app_pithy_print.hpp b/trunk/src/app/srs_app_pithy_print.hpp index c3b9f1219..ab289e0e7 100644 --- a/trunk/src/app/srs_app_pithy_print.hpp +++ b/trunk/src/app/srs_app_pithy_print.hpp @@ -88,6 +88,9 @@ public: static SrsPithyPrint* create_http_stream(); static SrsPithyPrint* create_http_stream_cache(); static SrsPithyPrint* create_rtc_play(); + // For RTC sender and receiver, we create printer for each fd. + static SrsPithyPrint* create_rtc_send(int fd); + static SrsPithyPrint* create_rtc_recv(int fd); virtual ~SrsPithyPrint(); private: // Enter the specified stage, return the client id. diff --git a/trunk/src/app/srs_app_reload.cpp b/trunk/src/app/srs_app_reload.cpp index 175cbfc14..3546f44de 100644 --- a/trunk/src/app/srs_app_reload.cpp +++ b/trunk/src/app/srs_app_reload.cpp @@ -115,6 +115,11 @@ srs_error_t ISrsReloadHandler::on_reload_http_stream_crossdomain() return srs_success; } +srs_error_t ISrsReloadHandler::on_reload_rtc_server() +{ + return srs_success; +} + srs_error_t ISrsReloadHandler::on_reload_vhost_http_updated() { return srs_success; diff --git a/trunk/src/app/srs_app_reload.hpp b/trunk/src/app/srs_app_reload.hpp index 442f44ebd..a7af5e790 100644 --- a/trunk/src/app/srs_app_reload.hpp +++ b/trunk/src/app/srs_app_reload.hpp @@ -55,6 +55,7 @@ public: virtual srs_error_t on_reload_http_stream_disabled(); virtual srs_error_t on_reload_http_stream_updated(); virtual srs_error_t on_reload_http_stream_crossdomain(); + virtual srs_error_t on_reload_rtc_server(); public: // TODO: FIXME: should rename to http_static virtual srs_error_t on_reload_vhost_http_updated(); diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 8424216ce..7d2d44e82 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -54,7 +54,7 @@ using namespace std; #include // TODO: Add this function into SrsRtpMux class. -srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer** stream_ptr) +srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, char** pbuf, int* pnn_buf) { srs_error_t err = srs_success; @@ -62,37 +62,33 @@ srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFor return err; } - if (stream_ptr == NULL) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "adts"); - } - if (format->audio->nb_samples != 1) { return srs_error_new(ERROR_RTC_RTP_MUXER, "adts"); } int nb_buf = format->audio->samples[0].size + 7; char* buf = new char[nb_buf]; - SrsBuffer* stream = new SrsBuffer(buf, nb_buf); + SrsBuffer stream(buf, nb_buf); // TODO: Add comment. - stream->write_1bytes(0xFF); - stream->write_1bytes(0xF9); - stream->write_1bytes(((format->acodec->aac_object - 1) << 6) | ((format->acodec->aac_sample_rate & 0x0F) << 2) | ((format->acodec->aac_channels & 0x04) >> 2)); - stream->write_1bytes(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03)); - stream->write_1bytes((nb_buf >> 3) & 0xFF); - stream->write_1bytes(((nb_buf & 0x07) << 5) | 0x1F); - stream->write_1bytes(0xFC); + stream.write_1bytes(0xFF); + stream.write_1bytes(0xF9); + stream.write_1bytes(((format->acodec->aac_object - 1) << 6) | ((format->acodec->aac_sample_rate & 0x0F) << 2) | ((format->acodec->aac_channels & 0x04) >> 2)); + stream.write_1bytes(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03)); + stream.write_1bytes((nb_buf >> 3) & 0xFF); + stream.write_1bytes(((nb_buf & 0x07) << 5) | 0x1F); + stream.write_1bytes(0xFC); - stream->write_bytes(format->audio->samples[0].bytes, format->audio->samples[0].size); + stream.write_bytes(format->audio->samples[0].bytes, format->audio->samples[0].size); - *stream_ptr = stream; + *pbuf = buf; + *pnn_buf = nb_buf; return err; } SrsRtpH264Muxer::SrsRtpH264Muxer() { - sequence = 0; discard_bframe = false; } @@ -100,269 +96,114 @@ SrsRtpH264Muxer::~SrsRtpH264Muxer() { } -srs_error_t SrsRtpH264Muxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) +srs_error_t SrsRtpH264Muxer::filter(SrsSharedPtrMessage* shared_frame, SrsFormat* format) { srs_error_t err = srs_success; - if (format->is_avc_sequence_header()) { - sps.assign(format->vcodec->sequenceParameterSetNALUnit.data(), format->vcodec->sequenceParameterSetNALUnit.size()); - pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); - // only collect SPS/PPS. + // If IDR, we will insert SPS/PPS before IDR frame. + if (format->video && format->video->has_idr) { + shared_frame->set_has_idr(true); + } + + // Update samples to shared frame. + for (int i = 0; i < format->video->nb_samples; ++i) { + SrsSample* sample = &format->video->samples[i]; + + // Because RTC does not support B-frame, so we will drop them. + // TODO: Drop B-frame in better way, which not cause picture corruption. + if (discard_bframe) { + if ((err = sample->parse_bframe()) != srs_success) { + return srs_error_wrap(err, "parse bframe"); + } + if (sample->bframe) { + continue; + } + } + } + + if (format->video->nb_samples <= 0) { return err; } - vector rtp_packet_vec; - - for (int i = 0; i < format->video->nb_samples; ++i) { - SrsSample sample = format->video->samples[i]; - - uint8_t header = sample.bytes[0]; - uint8_t nal_type = header & kNalTypeMask; - - // TODO: Use config to determine should check avc stream. - if (nal_type == SrsAvcNaluTypeNonIDR || nal_type == SrsAvcNaluTypeDataPartitionA || nal_type == SrsAvcNaluTypeIDR) { - SrsBuffer* stream = new SrsBuffer(sample.bytes, sample.size); - SrsAutoFree(SrsBuffer, stream); - - // Skip nalu header. - stream->skip(1); - - SrsBitBuffer bitstream(stream); - int32_t first_mb_in_slice = 0; - if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) { - return srs_error_wrap(err, "nalu read uev"); - } - - int32_t slice_type = 0; - if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type)) != srs_success) { - return srs_error_wrap(err, "nalu read uev"); - } - - srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type); - if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) { - if (discard_bframe) { - continue; - } - } - } - - if (sample.size <= kRtpMaxPayloadSize) { - if ((err = packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { - return srs_error_wrap(err, "packet single nalu"); - } - } else { - if ((err = packet_fu_a(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { - return srs_error_wrap(err, "packet fu-a"); - } - } - } - - if (! rtp_packet_vec.empty()) { - // At the end of the frame, set marker bit. - // One frame may have multi nals. Set the marker bit in the last nal end, no the end of the nal. - if ((err = rtp_packet_vec.back()->modify_rtp_header_marker(true)) != srs_success) { - return srs_error_wrap(err, "set marker"); - } - } - - shared_frame->set_rtp_packets(rtp_packet_vec); - - return err; -} - -srs_error_t SrsRtpH264Muxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) -{ - srs_error_t err = srs_success; - - char* p = sample->bytes + 1; - int nb_left = sample->size - 1; - uint8_t header = sample->bytes[0]; - uint8_t nal_type = header & kNalTypeMask; - - if (nal_type == SrsAvcNaluTypeIDR) { - if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { - return srs_error_wrap(err, "packet stap-a"); - } - } - - int num_of_packet = (sample->size - 1 + kRtpMaxPayloadSize) / kRtpMaxPayloadSize; - for (int i = 0; i < num_of_packet; ++i) { - char buf[kRtpPacketSize]; - SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); - SrsAutoFree(SrsBuffer, stream); - - int packet_size = min(nb_left, kRtpMaxPayloadSize); - - // fu-indicate - uint8_t fu_indicate = kFuA; - fu_indicate |= (header & (~kNalTypeMask)); - stream->write_1bytes(fu_indicate); - - uint8_t fu_header = nal_type; - if (i == 0) - fu_header |= kStart; - if (i == num_of_packet - 1) - fu_header |= kEnd; - stream->write_1bytes(fu_header); - - stream->write_bytes(p, packet_size); - p += packet_size; - nb_left -= packet_size; - - srs_verbose("rtp fu-a nalu, size=%u, seq=%u, timestamp=%lu", sample->size, sequence, (shared_frame->timestamp * 90)); - - SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); - if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos())) != srs_success) { - return srs_error_wrap(err, "rtp packet encode"); - } - - rtp_packet_vec.push_back(rtp_shared_pkt); - } - - return err; -} - -srs_error_t SrsRtpH264Muxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) -{ - srs_error_t err = srs_success; - - uint8_t header = sample->bytes[0]; - uint8_t nal_type = header & kNalTypeMask; - - - if (nal_type == SrsAvcNaluTypeIDR) { - if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { - return srs_error_wrap(err, "packet stap-a"); - } - } - - srs_verbose("rtp single nalu, size=%u, seq=%u, timestamp=%lu", sample->size, sequence, (shared_frame->timestamp * 90)); - - SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); - if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, sample->bytes, sample->size)) != srs_success) { - return srs_error_wrap(err, "rtp packet encode"); - } - - rtp_packet_vec.push_back(rtp_shared_pkt); - - return err; -} - -srs_error_t SrsRtpH264Muxer::packet_stap_a(const string &sps, const string& pps, SrsSharedPtrMessage* shared_frame, vector& rtp_packet_vec) -{ - srs_error_t err = srs_success; - - if (sps.empty() || pps.empty()) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "sps/pps empty"); - } - - uint8_t header = sps[0]; - uint8_t nal_type = header & kNalTypeMask; - - char buf[kRtpPacketSize]; - SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); - SrsAutoFree(SrsBuffer, stream); - - // stap-a header - uint8_t stap_a_header = kStapA; - stap_a_header |= (nal_type & (~kNalTypeMask)); - stream->write_1bytes(stap_a_header); - - stream->write_2bytes(sps.size()); - stream->write_bytes((char*)sps.data(), sps.size()); - - stream->write_2bytes(pps.size()); - stream->write_bytes((char*)pps.data(), pps.size()); - - srs_verbose("rtp stap-a nalu, size=%u, seq=%u, timestamp=%lu", (sps.size() + pps.size()), sequence, (shared_frame->timestamp * 90)); - - SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); - if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos())) != srs_success) { - return srs_error_wrap(err, "rtp packet encode"); - } - - rtp_packet_vec.push_back(rtp_shared_pkt); + shared_frame->set_samples(format->video->samples, format->video->nb_samples); return err; } SrsRtpOpusMuxer::SrsRtpOpusMuxer() { - sequence = 0; - timestamp = 0; - transcode = NULL; + codec = NULL; } SrsRtpOpusMuxer::~SrsRtpOpusMuxer() { - if (transcode) { - delete transcode; - transcode = NULL; - } + srs_freep(codec); } srs_error_t SrsRtpOpusMuxer::initialize() { srs_error_t err = srs_success; - transcode = new SrsAudioRecode(kChannel, kSamplerate); - if (!transcode) { + codec = new SrsAudioRecode(kChannel, kSamplerate); + if (!codec) { return srs_error_new(ERROR_RTC_RTP_MUXER, "SrsAacOpus init failed"); } - transcode->initialize(); + + if ((err = codec->initialize()) != srs_success) { + return srs_error_wrap(err, "init codec"); + } return err; } -srs_error_t SrsRtpOpusMuxer::frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream) +// An AAC packet may be transcoded to many OPUS packets. +const int kMaxOpusPackets = 8; +// The max size for each OPUS packet. +const int kMaxOpusPacketSize = 4096; + +srs_error_t SrsRtpOpusMuxer::transcode(SrsSharedPtrMessage* shared_audio, char* adts_audio, int nn_adts_audio) { srs_error_t err = srs_success; - vector rtp_packet_vec; + // Opus packet cache. + static char* opus_payloads[kMaxOpusPackets]; - char* data_ptr[kArrayLength]; - static char data_array[kArrayLength][kArrayBuffer]; - int elen[kArrayLength], number = 0; + static bool initialized = false; + if (!initialized) { + initialized = true; - data_ptr[0] = &data_array[0][0]; - for (int i = 1; i < kArrayLength; i++) { - data_ptr[i] = data_array[i]; + static char opus_packets_cache[kMaxOpusPackets][kMaxOpusPacketSize]; + opus_payloads[0] = &opus_packets_cache[0][0]; + for (int i = 1; i < kMaxOpusPackets; i++) { + opus_payloads[i] = opus_packets_cache[i]; + } } - SrsSample pkt; - pkt.bytes = stream->data(); - pkt.size = stream->pos(); + // Transcode an aac packet to many opus packets. + SrsSample aac; + aac.bytes = adts_audio; + aac.size = nn_adts_audio; - if ((err = transcode->recode(&pkt, data_ptr, elen, number)) != srs_success) { + int nn_opus_packets = 0; + int opus_sizes[kMaxOpusPackets]; + if ((err = codec->recode(&aac, opus_payloads, opus_sizes, nn_opus_packets)) != srs_success) { return srs_error_wrap(err, "recode error"); } - for (int i = 0; i < number; i++) { - SrsSample sample; - sample.size = elen[i]; - sample.bytes = data_ptr[i]; - packet_opus(shared_audio, &sample, rtp_packet_vec); + // Save OPUS packets in shared message. + if (nn_opus_packets <= 0) { + return err; } - shared_audio->set_rtp_packets(rtp_packet_vec); - - return err; -} - -srs_error_t SrsRtpOpusMuxer::packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector& rtp_packet_vec) -{ - srs_error_t err = srs_success; - - SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); - rtp_shared_pkt->rtp_header.set_marker(true); - if ((err = rtp_shared_pkt->create(timestamp, sequence++, kAudioSSRC, kOpusPayloadType, sample->bytes, sample->size)) != srs_success) { - return srs_error_wrap(err, "rtp packet encode"); + SrsSample samples[nn_opus_packets]; + for (int i = 0; i < nn_opus_packets; i++) { + SrsSample* p = samples + i; + p->size = opus_sizes[i]; + p->bytes = new char[p->size]; + memcpy(p->bytes, opus_payloads[i], p->size); } - // TODO: FIXME: Why 960? Need Refactoring? - timestamp += 960; - - rtp_packet_vec.push_back(rtp_shared_pkt); + shared_audio->set_extra_payloads(samples, nn_opus_packets); return err; } @@ -485,17 +326,16 @@ srs_error_t SrsRtc::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma // ignore sequence header srs_assert(format->audio); - SrsBuffer* stream = NULL; - SrsAutoFree(SrsBuffer, stream); - if ((err = aac_raw_append_adts_header(shared_audio, format, &stream)) != srs_success) { + char* adts_audio = NULL; + int nn_adts_audio = 0; + // TODO: FIXME: Reserve 7 bytes header when create shared message. + if ((err = aac_raw_append_adts_header(shared_audio, format, &adts_audio, &nn_adts_audio)) != srs_success) { return srs_error_wrap(err, "aac append header"); } - if (stream) { - char* stream_data = stream->data(); - SrsAutoFreeA(char, stream_data); - - return rtp_opus_muxer->frame_to_packet(shared_audio, format, stream); + if (adts_audio) { + err = rtp_opus_muxer->transcode(shared_audio, adts_audio, nn_adts_audio); + srs_freep(adts_audio); } return err; @@ -522,5 +362,5 @@ srs_error_t SrsRtc::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma // ignore info frame, // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 srs_assert(format->video); - return rtp_h264_muxer->frame_to_packet(shared_video, format); + return rtp_h264_muxer->filter(shared_video, format); } diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp index cf3e36a31..d232ca31f 100644 --- a/trunk/src/app/srs_app_rtc.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -39,30 +39,15 @@ class SrsOriginHub; class SrsAudioRecode; class SrsBuffer; -// Rtp packet max payload size, not include rtp header. -// Must left some bytes to payload header, rtp header, udp header, ip header. -const int kRtpMaxPayloadSize = 1200; +// The RTP packet max size, should never exceed this size. const int kRtpPacketSize = 1500; // Payload type will rewrite in srs_app_rtc_conn.cpp when send to client. const uint8_t kOpusPayloadType = 111; const uint8_t kH264PayloadType = 102; -// H.264 nalu header type mask. -const uint8_t kNalTypeMask = 0x1F; - -// @see: https://tools.ietf.org/html/rfc6184#section-5.2 -const uint8_t kStapA = 24; -const uint8_t kFuA = 28; - -// @see: https://tools.ietf.org/html/rfc6184#section-5.8 -const uint8_t kStart = 0x80; // Fu-header start bit -const uint8_t kEnd = 0x40; // Fu-header end bit - const int kChannel = 2; const int kSamplerate = 48000; -const int kArrayLength = 8; -const int kArrayBuffer = 4096; // SSRC will rewrite in srs_app_rtc_conn.cpp when send to client. const uint32_t kAudioSSRC = 1; @@ -71,39 +56,26 @@ const uint32_t kVideoSSRC = 2; // TODO: Define interface class like ISrsRtpMuxer class SrsRtpH264Muxer { -private: - uint16_t sequence; - std::string sps; - std::string pps; public: bool discard_bframe; public: SrsRtpH264Muxer(); virtual ~SrsRtpH264Muxer(); public: - srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); -private: - srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); - srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); - srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); + srs_error_t filter(SrsSharedPtrMessage* shared_video, SrsFormat* format); }; // TODO: FIXME: It's not a muxer, but a transcoder. class SrsRtpOpusMuxer { private: - // TODO: FIXME: How to handle timestamp overflow? - uint32_t timestamp; - uint16_t sequence; - SrsAudioRecode* transcode; + SrsAudioRecode* codec; public: SrsRtpOpusMuxer(); virtual ~SrsRtpOpusMuxer(); virtual srs_error_t initialize(); public: - srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream); -private: - srs_error_t packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector& rtp_packet_vec); + srs_error_t transcode(SrsSharedPtrMessage* shared_audio, char* adts_audio, int nn_adts_audio); }; class SrsRtc diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d0d1b7024..d11d455ec 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -174,7 +174,7 @@ srs_error_t SrsDtlsSession::initialize(const SrsRequest& req) return err; } -srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; @@ -186,7 +186,7 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) int ssl_err = SSL_get_error(dtls, ret); switch(ssl_err) { case SSL_ERROR_NONE: { - if ((err = on_dtls_handshake_done(udp_mux_skt)) != srs_success) { + if ((err = on_dtls_handshake_done(skt)) != srs_success) { return srs_error_wrap(err, "dtls handshake done handle"); } break; @@ -205,6 +205,7 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) } } +<<<<<<< HEAD if (out_bio_len) { srs_netfd_t stfd = udp_mux_skt->stfd(); sockaddr_in* addr = udp_mux_skt->peer_addr(); @@ -214,12 +215,18 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) memcpy(buf, out_bio_data, out_bio_len); rtc_session->send_and_free_messages(stfd, addr, addrlen, buf, out_bio_len); +======= + if (out_bio_len) { + if ((err = skt->sendto(out_bio_data, out_bio_len, 0)) != srs_success) { + return srs_error_wrap(err, "send dtls packet"); + } +>>>>>>> upstream/feature/rtc } return err; } -srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; if (BIO_reset(bio_in) != 1) { @@ -229,13 +236,13 @@ srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); } - if (BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()) <= 0) { + if (BIO_write(bio_in, skt->data(), skt->size()) <= 0) { // TODO: 0 or -1 maybe block, use BIO_should_retry to check. return srs_error_new(ERROR_OpenSslBIOWrite, "BIO_write"); } if (! handshake_done) { - err = handshake(udp_mux_skt); + err = handshake(skt); } else { while (BIO_ctrl_pending(bio_in) > 0) { char dtls_read_buf[8092]; @@ -252,7 +259,7 @@ srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) return err; } -srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; srs_trace("rtc session=%s, DTLS handshake done.", rtc_session->id().c_str()); @@ -262,7 +269,7 @@ srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt) return srs_error_wrap(err, "srtp init failed"); } - return rtc_session->on_connection_established(udp_mux_skt); + return rtc_session->on_connection_established(skt); } srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) @@ -391,6 +398,28 @@ srs_error_t SrsDtlsSession::protect_rtp(char* out_buf, const char* in_buf, int& return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } +srs_error_t SrsDtlsSession::protect_rtp2(char* buf, int* pnn_buf, SrsRtpPacket2* pkt) +{ + srs_error_t err = srs_success; + + if (!srtp_send) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); + } + + SrsBuffer stream(buf, *pnn_buf); + if ((err = pkt->encode(&stream)) != srs_success) { + return srs_error_wrap(err, "encode packet"); + } + + *pnn_buf = stream.pos(); + + if (srtp_protect(srtp_send, buf, pnn_buf) != 0) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); + } + + return err; +} + srs_error_t SrsDtlsSession::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; @@ -447,6 +476,11 @@ SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int rtc_session = s; sendonly_ukt = u->copy_sendonly(); + + audio_timestamp = 0; + audio_sequence = 0; + + video_sequence = 0; } SrsRtcSenderThread::~SrsRtcSenderThread() @@ -497,6 +531,14 @@ void SrsRtcSenderThread::stop_loop() trd->interrupt(); } +void SrsRtcSenderThread::update_sendonly_socket(SrsUdpMuxSocket* skt) +{ + srs_trace("session %s address changed, update %s -> %s", + rtc_session->id().c_str(), sendonly_ukt->get_peer_id().c_str(), skt->get_peer_id().c_str()); + + srs_freep(sendonly_ukt); + sendonly_ukt = skt->copy_sendonly(); +} srs_error_t SrsRtcSenderThread::cycle() { @@ -536,13 +578,6 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc sender thread"); } - pprint->elapse(); - - if (pprint->can_print()) { - // TODO: FIXME: - // Print stat like frame/s, packet/s, loss_packets. - } - #ifdef SRS_PERF_QUEUE_COND_WAIT if (realtime) { // for realtime, min required msgs is 0, send when got one+ msgs. @@ -566,64 +601,307 @@ srs_error_t SrsRtcSenderThread::cycle() continue; } - send_and_free_messages(msgs.msgs, msg_count, sendonly_ukt); - } -} + int nn = 0; + int nn_rtp_pkts = 0; + if ((err = send_messages(source, msgs.msgs, msg_count, sendonly_ukt, &nn, &nn_rtp_pkts)) != srs_success) { + srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); + } +<<<<<<< HEAD void SrsRtcSenderThread::update_sendonly_socket(SrsUdpMuxSocket* ukt) { srs_trace("rtc session=%s address changed, update %s -> %s", rtc_session->id().c_str(), sendonly_ukt->get_peer_id().c_str(), ukt->get_peer_id().c_str()); +======= + for (int i = 0; i < msg_count; i++) { + SrsSharedPtrMessage* msg = msgs.msgs[i]; + srs_freep(msg); + } +>>>>>>> upstream/feature/rtc - srs_freep(sendonly_ukt); - sendonly_ukt = ukt->copy_sendonly(); + pprint->elapse(); + if (pprint->can_print()) { + // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. + srs_trace("-> RTC PLAY %d msgs, %d packets, %d bytes", msg_count, nn_rtp_pkts, nn); + } + } } -void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt) -{ +srs_error_t SrsRtcSenderThread::send_messages( + SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, + SrsUdpMuxSocket* skt, int* pnn, int* pnn_rtp_pkts +) { srs_error_t err = srs_success; +<<<<<<< HEAD srs_netfd_t stfd = udp_mux_skt->stfd(); sockaddr_in* addr = udp_mux_skt->peer_addr(); socklen_t addrlen = udp_mux_skt->peer_addrlen(); +======= + if (!rtc_session->dtls_session) { + return err; + } + + // Covert kernel messages to RTP packets. + vector packets; +>>>>>>> upstream/feature/rtc for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; + *pnn += msg->size; - for (int i = 0; i < (int)msg->rtp_packets.size(); ++i) { - if (!rtc_session->dtls_session) { + SrsRtpPacket2* packet = NULL; + if (msg->is_audio()) { + for (int i = 0; i < msg->nn_extra_payloads(); i++) { + SrsSample* sample = msg->extra_payloads() + i; + if ((err = packet_opus(sample, &packet)) != srs_success) { + return srs_error_wrap(err, "opus package"); + } + packets.push_back(packet); + } + + continue; + } + + // Well, for each IDR, we append a SPS/PPS before it, which is packaged in STAP-A. + if (msg->has_idr()) { + if ((err = packet_stap_a(source, msg, &packet)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } + packets.push_back(packet); + } + + for (int i = 0; i < msg->nn_samples(); i++) { + SrsSample* sample = msg->samples() + i; + + // We always ignore bframe here, if config to discard bframe, + // the bframe flag will not be set. + if (sample->bframe) { continue; } - SrsRtpSharedPacket* pkt = msg->rtp_packets[i]; - - if (msg->is_video()) { - pkt->modify_rtp_header_payload_type(video_payload_type); - pkt->modify_rtp_header_ssrc(video_ssrc); - srs_verbose("send video, ssrc=%u, seq=%u, timestamp=%u", video_ssrc, pkt->rtp_header.get_sequence(), pkt->rtp_header.get_timestamp()); - } - - if (msg->is_audio()) { - pkt->modify_rtp_header_payload_type(audio_payload_type); - pkt->modify_rtp_header_ssrc(audio_ssrc); - } - - int length = pkt->size; - char* buf = new char[kRtpPacketSize]; - if (rtc_session->encrypt) { - if ((err = rtc_session->dtls_session->protect_rtp(buf, pkt->payload, length)) != srs_success) { - srs_warn("srtp err %s", srs_error_desc(err).c_str()); srs_freep(err); srs_freepa(buf); - continue; + const int kRtpMaxPayloadSize = 1200; + if (sample->size <= kRtpMaxPayloadSize) { + if ((err = packet_single_nalu(msg, sample, &packet)) != srs_success) { + return srs_error_wrap(err, "packet single nalu"); } + + if (i == msg->nn_samples() - 1) { + packet->rtp_header.set_marker(true); + } + packets.push_back(packet); } else { - memcpy(buf, pkt->payload, length); + if ((err = packet_fu_a(msg, sample, kRtpMaxPayloadSize, packets)) != srs_success) { + return srs_error_wrap(err, "packet fu-a"); + } + + if (i == msg->nn_samples() - 1) { + packets.back()->rtp_header.set_marker(true); + } } - - rtc_session->send_and_free_messages(stfd, addr, addrlen, buf, length); } - - srs_freep(msg); } + + *pnn_rtp_pkts += (int)packets.size(); + +<<<<<<< HEAD + rtc_session->send_and_free_messages(stfd, addr, addrlen, buf, length); +======= + for (int j = 0; j < (int)packets.size(); j++) { + SrsRtpPacket2* packet = packets[j]; + if ((err = send_packet(packet, skt)) != srs_success) { + srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); +>>>>>>> upstream/feature/rtc + } + srs_freep(packet); + } + + return err; +} + +srs_error_t SrsRtcSenderThread::send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* skt) +{ + srs_error_t err = srs_success; + + ISrsUdpSender* sender = skt->sender(); + + // Fetch a cached message from queue. + // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. + mmsghdr* mhdr = NULL; + if ((err = sender->fetch(&mhdr)) != srs_success) { + return srs_error_wrap(err, "fetch msghdr"); + } +<<<<<<< HEAD +======= + char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; + + // Length of iov, default size. + int length = kRtpPacketSize; + + if (rtc_session->encrypt) { + if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length, pkt)) != srs_success) { + return srs_error_wrap(err, "srtp protect"); + } + } else { + SrsBuffer stream(buf, length); + if ((err = pkt->encode(&stream)) != srs_success) { + return srs_error_wrap(err, "encode packet"); + } + length = stream.pos(); + } + + sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); + socklen_t addrlen = (socklen_t)skt->peer_addrlen(); + + mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; + mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; + mhdr->msg_hdr.msg_iov->iov_len = length; + mhdr->msg_len = 0; + + if ((err = sender->sendmmsg(mhdr)) != srs_success) { + return srs_error_wrap(err, "send msghdr"); + } + return err; +} + +srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket) +{ + srs_error_t err = srs_success; + + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packet->rtp_header.set_marker(true); + packet->rtp_header.set_timestamp(audio_timestamp); + packet->rtp_header.set_sequence(audio_sequence++); + packet->rtp_header.set_ssrc(audio_ssrc); + packet->rtp_header.set_payload_type(audio_payload_type); + + SrsRtpRawPayload* raw = new SrsRtpRawPayload(); + raw->payload = sample->bytes; + raw->nn_payload = sample->size; + packet->payload = raw; + + // TODO: FIXME: Why 960? Need Refactoring? + audio_timestamp += 960; + + *ppacket = packet; + + return err; +} + +srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, vector& packets) +{ + srs_error_t err = srs_success; + + char* p = sample->bytes + 1; + int nb_left = sample->size - 1; + uint8_t header = sample->bytes[0]; + uint8_t nal_type = header & kNalTypeMask; + + int num_of_packet = 1 + (sample->size - 1) / fu_payload_size; + for (int i = 0; i < num_of_packet; ++i) { + int packet_size = srs_min(nb_left, fu_payload_size); + + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packets.push_back(packet); + + packet->rtp_header.set_timestamp(msg->timestamp * 90); + packet->rtp_header.set_sequence(video_sequence++); + packet->rtp_header.set_ssrc(video_ssrc); + packet->rtp_header.set_payload_type(video_payload_type); + + SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); + packet->payload = fua; + + fua->nri = (SrsAvcNaluType)header; + fua->nalu_type = (SrsAvcNaluType)nal_type; + fua->start = bool(i == 0); + fua->end = bool(i == num_of_packet - 1); + + SrsSample* sample = new SrsSample(); + sample->bytes = p; + sample->size = packet_size; + fua->nalus.push_back(sample); + + p += packet_size; + nb_left -= packet_size; + } + + return err; +} + +// Single NAL Unit Packet @see https://tools.ietf.org/html/rfc6184#section-5.6 +srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket) +{ + srs_error_t err = srs_success; + + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packet->rtp_header.set_timestamp(msg->timestamp * 90); + packet->rtp_header.set_sequence(video_sequence++); + packet->rtp_header.set_ssrc(video_ssrc); + packet->rtp_header.set_payload_type(video_payload_type); + + SrsRtpRawPayload* raw = new SrsRtpRawPayload(); + packet->payload = raw; + + raw->payload = sample->bytes; + raw->nn_payload = sample->size; + + *ppacket = packet; + + return err; +} + +srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket) +{ + srs_error_t err = srs_success; + + SrsMetaCache* meta = source->cached_meta(); + if (!meta) { + return err; + } + + SrsFormat* format = meta->vsh_format(); + if (!format || !format->vcodec) { + return err; + } + + const vector& sps = format->vcodec->sequenceParameterSetNALUnit; + const vector& pps = format->vcodec->pictureParameterSetNALUnit; + if (sps.empty() || pps.empty()) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "sps/pps empty"); + } + + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packet->rtp_header.set_marker(false); + packet->rtp_header.set_timestamp(msg->timestamp * 90); + packet->rtp_header.set_sequence(video_sequence++); + packet->rtp_header.set_ssrc(video_ssrc); + packet->rtp_header.set_payload_type(video_payload_type); + + SrsRtpSTAPPayload* stap = new SrsRtpSTAPPayload(); + packet->payload = stap; + + uint8_t header = sps[0]; + stap->nri = (SrsAvcNaluType)header; + + if (true) { + SrsSample* sample = new SrsSample(); + sample->bytes = (char*)&sps[0]; + sample->size = (int)sps.size(); + stap->nalus.push_back(sample); + } + + if (true) { + SrsSample* sample = new SrsSample(); + sample->bytes = (char*)&pps[0]; + sample->size = (int)pps.size(); + stap->nalus.push_back(sample); + } + + *ppacket = packet; + + return err; +>>>>>>> upstream/feature/rtc } SrsRtcSession::SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id) @@ -668,12 +946,12 @@ void SrsRtcSession::switch_to_context() _srs_context->set_id(cid); } -srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) +srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; if (stun_req->is_binding_request()) { - if ((err = on_binding_request(udp_mux_skt, stun_req)) != srs_success) { + if ((err = on_binding_request(skt, stun_req)) != srs_success) { return srs_error_wrap(err, "stun binding request failed"); } @@ -682,8 +960,8 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* if (strd && strd->sendonly_ukt) { // We are running in the ice-lite(server) mode. If client have multi network interface, // we only choose one candidate pair which is determined by client. - if (stun_req->get_use_candidate() && strd->sendonly_ukt->get_peer_id() != udp_mux_skt->get_peer_id()) { - strd->update_sendonly_socket(udp_mux_skt); + if (stun_req->get_use_candidate() && strd->sendonly_ukt->get_peer_id() != skt->get_peer_id()) { + strd->update_sendonly_socket(skt); } } } @@ -713,7 +991,7 @@ srs_error_t SrsRtcSession::check_source() #define be32toh ntohl #endif -srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) +srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; @@ -725,14 +1003,20 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS } SrsStunPacket stun_binding_response; +<<<<<<< HEAD +======= + char buf[kRtpPacketSize]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); +>>>>>>> upstream/feature/rtc stun_binding_response.set_message_type(BindingResponse); stun_binding_response.set_local_ufrag(stun_req->get_remote_ufrag()); stun_binding_response.set_remote_ufrag(stun_req->get_local_ufrag()); stun_binding_response.set_transcation_id(stun_req->get_transcation_id()); // FIXME: inet_addr is deprecated, IPV6 support - stun_binding_response.set_mapped_address(be32toh(inet_addr(udp_mux_skt->get_peer_ip().c_str()))); - stun_binding_response.set_mapped_port(udp_mux_skt->get_peer_port()); + stun_binding_response.set_mapped_address(be32toh(inet_addr(skt->get_peer_ip().c_str()))); + stun_binding_response.set_mapped_port(skt->get_peer_port()); char* buf = new char[1460]; SrsBuffer* stream = new SrsBuffer(buf, 1460); @@ -742,6 +1026,7 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS return srs_error_wrap(err, "stun binding response encode failed"); } +<<<<<<< HEAD srs_netfd_t stfd = udp_mux_skt->stfd(); sockaddr_in* addr = udp_mux_skt->peer_addr(); socklen_t addrlen = udp_mux_skt->peer_addrlen(); @@ -749,6 +1034,16 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS if (get_session_state() == WAITING_STUN) { peer_id = udp_mux_skt->get_peer_id(); +======= + if ((err = skt->sendto(stream->data(), stream->pos(), 0)) != srs_success) { + return srs_error_wrap(err, "stun binding response send failed"); + } + + if (get_session_state() == WAITING_STUN) { + set_session_state(DOING_DTLS_HANDSHAKE); + + peer_id = skt->get_peer_id(); +>>>>>>> upstream/feature/rtc rtc_server->insert_into_id_sessions(peer_id, this); set_session_state(DOING_DTLS_HANDSHAKE); @@ -758,7 +1053,7 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS return err; } -srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; @@ -843,18 +1138,22 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock srs_verbose("resend pkt sequence=%u", resend_pkts[i]->rtp_header.get_sequence()); dtls_session->protect_rtp(protected_buf, resend_pkts[i]->payload, nb_protected_buf); +<<<<<<< HEAD srs_netfd_t stfd = udp_mux_skt->stfd(); sockaddr_in* addr = udp_mux_skt->peer_addr(); socklen_t addrlen = udp_mux_skt->peer_addrlen(); send_and_free_messages(stfd, addr, addrlen, protected_buf, nb_protected_buf); +======= + skt->sendto(protected_buf, nb_protected_buf, 0); +>>>>>>> upstream/feature/rtc } } return err; } -srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; @@ -901,7 +1200,7 @@ srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxS return err; } -srs_error_t SrsRtcSession::on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; @@ -970,19 +1269,24 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ return err; } -srs_error_t SrsRtcSession::on_connection_established(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_connection_established(SrsUdpMuxSocket* skt) { +<<<<<<< HEAD srs_trace("rtc session=%s, timeout=%dms connection established", id().c_str(), srsu2msi(sessionStunTimeout)); set_session_state(ESTABLISHED); return start_play(udp_mux_skt); +======= + srs_trace("rtc session=%s, to=%dms connection established", id().c_str(), srsu2msi(sessionStunTimeout)); + return start_play(skt); +>>>>>>> upstream/feature/rtc } -srs_error_t SrsRtcSession::start_play(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::start_play(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; srs_freep(strd); - strd = new SrsRtcSenderThread(this, udp_mux_skt, _srs_context->get_id()); + strd = new SrsRtcSenderThread(this, skt, _srs_context->get_id()); uint32_t video_ssrc = 0; uint32_t audio_ssrc = 0; @@ -1015,12 +1319,12 @@ bool SrsRtcSession::is_stun_timeout() return last_stun_time + sessionStunTimeout < srs_get_system_time(); } -srs_error_t SrsRtcSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_dtls(SrsUdpMuxSocket* skt) { - return dtls_session->on_dtls(udp_mux_skt); + return dtls_session->on_dtls(skt); } -srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; @@ -1028,9 +1332,9 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done"); } - char unprotected_buf[1460]; - int nb_unprotected_buf = udp_mux_skt->size(); - if ((err = dtls_session->unprotect_rtcp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf)) != srs_success) { + char unprotected_buf[kRtpPacketSize]; + int nb_unprotected_buf = skt->size(); + if ((err = dtls_session->unprotect_rtcp(unprotected_buf, skt->data(), nb_unprotected_buf)) != srs_success) { return srs_error_wrap(err, "rtcp unprotect failed"); } @@ -1053,7 +1357,7 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) break; } case kRR: { - err = on_rtcp_receiver_report(ph, length, udp_mux_skt); + err = on_rtcp_receiver_report(ph, length, skt); break; } case kSDES: { @@ -1066,11 +1370,11 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) break; } case kRtpFb: { - err = on_rtcp_feedback(ph, length, udp_mux_skt); + err = on_rtcp_feedback(ph, length, skt); break; } case kPsFb: { - err = on_rtcp_ps_feedback(ph, length, udp_mux_skt); + err = on_rtcp_ps_feedback(ph, length, skt); break; } default:{ @@ -1090,32 +1394,222 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) return err; } +<<<<<<< HEAD void SrsRtcSession::send_and_free_messages(srs_netfd_t stfd, sockaddr_in* addr, socklen_t addrlen, char* buf, int length) { rtc_server->send_and_free_messages(stfd, addr, addrlen, buf, length); } SrsRtcServer::SrsRtcServer() +======= +SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s) +>>>>>>> upstream/feature/rtc { - listener = NULL; - timer = new SrsHourGlass(this, 1 * SRS_UTIME_SECONDS); + lfd = NULL; + server = s; - mmstfd = NULL; waiting_msgs = false; cond = srs_cond_new(); trd = new SrsDummyCoroutine(); + + cache_pos = 0; + + _srs_config->subscribe(this); } -SrsRtcServer::~SrsRtcServer() +SrsUdpMuxSender::~SrsUdpMuxSender() { - srs_freep(listener); - srs_freep(timer); + _srs_config->unsubscribe(this); srs_freep(trd); srs_cond_destroy(cond); - free_messages(mmhdrs); - mmhdrs.clear(); + free_mhdrs(hotspot); + hotspot.clear(); + + free_mhdrs(cache); + cache.clear(); +} + +srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) +{ + srs_error_t err = srs_success; + + lfd = fd; + + srs_freep(trd); + trd = new SrsSTCoroutine("udp", this); + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "start coroutine"); + } + + max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); + srs_trace("UDP sender #%d init ok, max_sendmmsg=%d", srs_netfd_fileno(fd), max_sendmmsg); + + return err; +} + +void SrsUdpMuxSender::free_mhdrs(std::vector& mhdrs) +{ + for (int i = 0; i < (int)mhdrs.size(); i++) { + mmsghdr* hdr = &mhdrs[i]; + + for (int j = (int)hdr->msg_hdr.msg_iovlen - 1; j >= 0 ; j--) { + iovec* iov = hdr->msg_hdr.msg_iov + j; + char* data = (char*)iov->iov_base; + srs_freep(data); + srs_freep(iov); + } + } +} + +srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) +{ + // TODO: FIXME: Maybe need to shrink? + if (cache_pos >= (int)cache.size()) { + mmsghdr mhdr; + memset(&mhdr, 0, sizeof(mmsghdr)); + + mhdr.msg_hdr.msg_iovlen = 1; + mhdr.msg_hdr.msg_iov = new iovec(); + mhdr.msg_hdr.msg_iov->iov_base = new char[kRtpPacketSize]; + mhdr.msg_hdr.msg_iov->iov_len = kRtpPacketSize; + mhdr.msg_len = 0; + + cache.push_back(mhdr); + } + + *pphdr = &cache[cache_pos++]; + return srs_success; +} + +srs_error_t SrsUdpMuxSender::sendmmsg(mmsghdr* hdr) +{ + if (waiting_msgs) { + waiting_msgs = false; + srs_cond_signal(cond); + } + + return srs_success; +} + +srs_error_t SrsUdpMuxSender::cycle() +{ + srs_error_t err = srs_success; + + uint64_t nn_msgs = 0; + uint64_t nn_msgs_last = 0; + int nn_msgs_max = 0; + int nn_loop = 0; + int nn_wait = 0; + srs_utime_t time_last = srs_get_system_time(); + SrsStatistic* stat = SrsStatistic::instance(); + + SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_send(srs_netfd_fileno(lfd)); + SrsAutoFree(SrsPithyPrint, pprint); + + while (true) { + if ((err = trd->pull()) != srs_success) { + return err; + } + + nn_loop++; + + int pos = cache_pos; + if (pos <= 0) { + waiting_msgs = true; + nn_wait++; + srs_cond_wait(cond); + continue; + } + + // We are working on hotspot now. + cache.swap(hotspot); + cache_pos = 0; + + mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; + for (; p < end; p += max_sendmmsg) { + int vlen = (int)(end - p); + vlen = srs_min(max_sendmmsg, vlen); + + int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT); + if (r0 != vlen) { + srs_warn("sendmsg %d msgs, %d done", vlen, r0); + } + + stat->perf_mw_on_packets(vlen); + } + + // Increase total messages. + nn_msgs += pos; + nn_msgs_max = srs_max(pos, nn_msgs_max); + + pprint->elapse(); + if (pprint->can_print()) { + // TODO: FIXME: Extract a PPS calculator. + int pps_average = 0; int pps_last = 0; + if (true) { + if (srs_get_system_time() > srs_get_system_startup_time()) { + pps_average = (int)(nn_msgs * SRS_UTIME_SECONDS / (srs_get_system_time() - srs_get_system_startup_time())); + } + if (srs_get_system_time() > time_last) { + pps_last = (int)((nn_msgs - nn_msgs_last) * SRS_UTIME_SECONDS / (srs_get_system_time() - time_last)); + } + } + + string pps_unit = ""; + if (pps_last > 10000 || pps_average > 10000) { + pps_unit = "(w)"; pps_last /= 10000; pps_average /= 10000; + } else if (pps_last > 1000 || pps_average > 1000) { + pps_unit = "(k)"; pps_last /= 1000; pps_average /= 1000; + } + + srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d/%d by sendmmsg %d", + srs_netfd_fileno(lfd), pos, nn_msgs_max, nn_msgs, pps_average, pps_last, pps_unit.c_str(), nn_loop, nn_wait, + (int)server->nn_sessions(), (int)cache.size(), (int)hotspot.size(), max_sendmmsg); + nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); + nn_loop = nn_wait = nn_msgs_max = 0; + } + } + + return err; +} + +srs_error_t SrsUdpMuxSender::on_reload_rtc_server() +{ + int v = _srs_config->get_rtc_server_sendmmsg(); + if (max_sendmmsg != v) { + max_sendmmsg = v; + srs_trace("Reload max_sendmmsg=%d", max_sendmmsg); + } + + return srs_success; +} + +SrsRtcServer::SrsRtcServer() +{ + timer = new SrsHourGlass(this, 1 * SRS_UTIME_SECONDS); +} + +SrsRtcServer::~SrsRtcServer() +{ + srs_freep(timer); + + if (true) { + vector::iterator it; + for (it = listeners.begin(); it != listeners.end(); ++it) { + SrsUdpMuxListener* listener = *it; + srs_freep(listener); + } + } + + if (true) { + vector::iterator it; + for (it = senders.begin(); it != senders.end(); ++it) { + SrsUdpMuxSender* sender = *it; + srs_freep(sender); + } + } } srs_error_t SrsRtcServer::initialize() @@ -1130,11 +1624,7 @@ srs_error_t SrsRtcServer::initialize() return srs_error_wrap(err, "start timer"); } - srs_freep(trd); - trd = new SrsSTCoroutine("udp", this); - if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "start coroutine"); - } + srs_trace("RTC server init ok"); return err; } @@ -1153,27 +1643,38 @@ srs_error_t SrsRtcServer::listen_udp() } string ip = srs_any_address_for_listener(); + srs_assert(listeners.empty()); - srs_freep(listener); - listener = new SrsUdpMuxListener(this, ip, port); + int nn_listeners = _srs_config->get_rtc_server_reuseport(); + for (int i = 0; i < nn_listeners; i++) { + SrsUdpMuxSender* sender = new SrsUdpMuxSender(this); + SrsUdpMuxListener* listener = new SrsUdpMuxListener(this, sender, ip, port); - if ((err = listener->listen()) != srs_success) { - return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + if ((err = listener->listen()) != srs_success) { + srs_freep(listener); + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + if ((err = sender->initialize(listener->stfd())) != srs_success) { + return srs_error_wrap(err, "init sender"); + } + + srs_trace("rtc listen at udp://%s:%d, fd=%d", ip.c_str(), port, listener->fd()); + listeners.push_back(listener); + senders.push_back(sender); } - srs_trace("rtc listen at udp://%s:%d, fd=%d", ip.c_str(), port, listener->fd()); - return err; } -srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt) { - if (is_stun(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { - return on_stun(udp_mux_skt); - } else if (is_dtls(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { - return on_dtls(udp_mux_skt); - } else if (is_rtp_or_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { - return on_rtp_or_rtcp(udp_mux_skt); + if (is_stun(reinterpret_cast(skt->data()), skt->size())) { + return on_stun(skt); + } else if (is_dtls(reinterpret_cast(skt->data()), skt->size())) { + return on_dtls(skt); + } else if (is_rtp_or_rtcp(reinterpret_cast(skt->data()), skt->size())) { + return on_rtp_or_rtcp(skt); } return srs_error_new(ERROR_RTC_UDP, "unknown udp packet type"); @@ -1242,17 +1743,17 @@ SrsRtcSession* SrsRtcServer::find_rtc_session_by_peer_id(const string& peer_id) return iter->second; } -srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; SrsStunPacket stun_req; - if ((err = stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size())) != srs_success) { + if ((err = stun_req.decode(skt->data(), skt->size())) != srs_success) { return srs_error_wrap(err, "decode stun packet failed"); } srs_verbose("recv stun packet from %s, use-candidate=%d, ice-controlled=%d, ice-controlling=%d", - udp_mux_skt->get_peer_id().c_str(), stun_req.get_use_candidate(), stun_req.get_ice_controlled(), stun_req.get_ice_controlling()); + skt->get_peer_id().c_str(), stun_req.get_use_candidate(), stun_req.get_ice_controlled(), stun_req.get_ice_controlling()); std::string username = stun_req.get_username(); SrsRtcSession* rtc_session = find_rtc_session_by_username(username); @@ -1264,44 +1765,44 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) // to make all logs write to the "correct" pid+cid. rtc_session->switch_to_context(); - return rtc_session->on_stun(udp_mux_skt, &stun_req); + return rtc_session->on_stun(skt, &stun_req); } -srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* skt) { - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_new(ERROR_RTC_DTLS, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); + return srs_error_new(ERROR_RTC_DTLS, "can not find rtc session by peer_id=%s", skt->get_peer_id().c_str()); } // Now, we got the RTC session to handle the packet, switch to its context // to make all logs write to the "correct" pid+cid. rtc_session->switch_to_context(); - return rtc_session->on_dtls(udp_mux_skt); + return rtc_session->on_dtls(skt); } -srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* skt) { srs_error_t err = srs_success; - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_new(ERROR_RTC_RTP, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); + return srs_error_new(ERROR_RTC_RTP, "can not find rtc session by peer_id=%s", skt->get_peer_id().c_str()); } // Now, we got the RTC session to handle the packet, switch to its context // to make all logs write to the "correct" pid+cid. rtc_session->switch_to_context(); - if (is_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { - err = rtc_session->on_rtcp(udp_mux_skt); + if (is_rtcp(reinterpret_cast(skt->data()), skt->size())) { + err = rtc_session->on_rtcp(skt); } else { // We disable it because no RTP for player. // see https://github.com/ossrs/srs/blob/018577e685a07d9de7a47354e7a9c5f77f5f4202/trunk/src/app/srs_app_rtc_conn.cpp#L1081 - // err = rtc_session->on_rtp(udp_mux_skt); + // err = rtc_session->on_rtp(skt); } return err; @@ -1354,6 +1855,7 @@ srs_error_t SrsRtcServer::notify(int type, srs_utime_t interval, srs_utime_t tic return srs_success; } +<<<<<<< HEAD void SrsRtcServer::send_and_free_messages(srs_netfd_t stfd, sockaddr_in* addr, socklen_t addrlen, char* buf, int length) { mmstfd = stfd; @@ -1440,6 +1942,8 @@ srs_error_t SrsRtcServer::cycle() return err; } +======= +>>>>>>> upstream/feature/rtc RtcServerAdapter::RtcServerAdapter() { rtc = new SrsRtcServer(); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 08be09929..a244c0070 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ class SrsRtcServer; class SrsRtcSession; class SrsSharedPtrMessage; class SrsSource; +class SrsRtpPacket2; const uint8_t kSR = 200; const uint8_t kRR = 201; @@ -98,16 +100,17 @@ public: srs_error_t initialize(const SrsRequest& req); - srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_dtls(SrsUdpMuxSocket* skt); + srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* skt); srs_error_t on_dtls_application_data(const char* data, const int len); public: srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t protect_rtp2(char* buf, int* pnn_buf, SrsRtpPacket2* pkt); srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); private: - srs_error_t handshake(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t handshake(SrsUdpMuxSocket* skt); private: srs_error_t srtp_initialize(); srs_error_t srtp_send_init(); @@ -125,6 +128,12 @@ private: uint32_t audio_ssrc; uint16_t video_payload_type; uint16_t audio_payload_type; +private: + // TODO: FIXME: How to handle timestamp overflow? + uint32_t audio_timestamp; + uint16_t audio_sequence; +private: + uint16_t video_sequence; public: SrsUdpMuxSocket* sendonly_ukt; public: @@ -139,11 +148,18 @@ public: virtual void stop(); virtual void stop_loop(); public: - virtual srs_error_t cycle(); + void update_sendonly_socket(SrsUdpMuxSocket* skt); public: - void update_sendonly_socket(SrsUdpMuxSocket* ukt); + virtual srs_error_t cycle(); private: - void send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt); + srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* skt, int* pnn, int* pnn_rtp_pkts); + srs_error_t send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* skt); +private: + srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); +private: + srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, std::vector& packets); + srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket); + srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket); }; class SrsRtcSession @@ -194,40 +210,73 @@ public: void switch_to_context(); public: - srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); - srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req); + srs_error_t on_dtls(SrsUdpMuxSocket* skt); + srs_error_t on_rtcp(SrsUdpMuxSocket* skt); public: - srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_connection_established(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t send_client_hello(SrsUdpMuxSocket* skt); + srs_error_t on_connection_established(SrsUdpMuxSocket* skt); + srs_error_t start_play(SrsUdpMuxSocket* skt); public: bool is_stun_timeout(); private: srs_error_t check_source(); private: - srs_error_t on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); + srs_error_t on_binding_request(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req); private: +<<<<<<< HEAD srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); // Internal only. public: void send_and_free_messages(srs_netfd_t stfd, sockaddr_in* addr, socklen_t addrlen, char* buf, int length); +======= + srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt); + srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt); + srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt); +>>>>>>> upstream/feature/rtc }; -class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass, virtual public ISrsCoroutineHandler +class SrsUdpMuxSender : virtual public ISrsUdpSender, virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler { private: - SrsUdpMuxListener* listener; - SrsHourGlass* timer; -private: + srs_netfd_t lfd; + SrsRtcServer* server; SrsCoroutine* trd; +private: srs_cond_t cond; bool waiting_msgs; - // TODO: FIXME: Support multiple stfd. - srs_netfd_t mmstfd; - std::vector mmhdrs; + // Hotspot msgs, we are working on it. + // @remark We will wait util all messages are ready. + std::vector hotspot; + // Cache msgs, for other coroutines to fill it. + std::vector cache; + int cache_pos; + // The max number of messages for sendmmsg. If 1, we use sendmsg to send. + int max_sendmmsg; +public: + SrsUdpMuxSender(SrsRtcServer* s); + virtual ~SrsUdpMuxSender(); +public: + virtual srs_error_t initialize(srs_netfd_t fd); +private: + void free_mhdrs(std::vector& mhdrs); +public: + virtual srs_error_t fetch(mmsghdr** pphdr); + virtual srs_error_t sendmmsg(mmsghdr* hdr); + virtual srs_error_t cycle(); +// interface ISrsReloadHandler +public: + virtual srs_error_t on_reload_rtc_server(); +}; + +class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass +{ +private: + SrsHourGlass* timer; + std::vector listeners; + std::vector senders; private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) @@ -240,27 +289,31 @@ public: // TODO: FIXME: Support gracefully quit. // TODO: FIXME: Support reload. virtual srs_error_t listen_udp(); - virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt); + virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt); public: virtual srs_error_t listen_api(); SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip); bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session); void check_and_clean_timeout_session(); + int nn_sessions() { return (int)map_username_session.size(); } private: - srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_stun(SrsUdpMuxSocket* skt); + srs_error_t on_dtls(SrsUdpMuxSocket* skt); + srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* skt); private: SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag); SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); // interface ISrsHourGlass public: virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick); +<<<<<<< HEAD // Internal only. public: void send_and_free_messages(srs_netfd_t stfd, sockaddr_in* addr, socklen_t addrlen, char* buf, int length); void free_messages(std::vector& hdrs); virtual srs_error_t cycle(); +======= +>>>>>>> upstream/feature/rtc }; // The RTC server adapter. diff --git a/trunk/src/app/srs_app_sdp.cpp b/trunk/src/app/srs_app_sdp.cpp index ab080d4fd..7b89e0ce6 100644 --- a/trunk/src/app/srs_app_sdp.cpp +++ b/trunk/src/app/srs_app_sdp.cpp @@ -78,6 +78,14 @@ srs_error_t parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264_par if (kv[0] == "profile-level-id") { h264_param.profile_level_id = kv[1]; } else if (kv[0] == "packetization-mode") { + // 6.3. Non-Interleaved Mode + // This mode is in use when the value of the OPTIONAL packetization-mode + // media type parameter is equal to 1. This mode SHOULD be supported. + // It is primarily intended for low-delay applications. Only single NAL + // unit packets, STAP-As, and FU-As MAY be used in this mode. STAP-Bs, + // MTAPs, and FU-Bs MUST NOT be used. The transmission order of NAL + // units MUST comply with the NAL unit decoding order. + // @see https://tools.ietf.org/html/rfc6184#section-6.3 h264_param.packetization_mode = kv[1]; } else if (kv[0] == "level-asymmetry-allowed") { h264_param.level_asymmerty_allow = kv[1]; diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index cb7d1b505..fcf3b071e 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1143,7 +1143,8 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se // TODO: FIXME: Refactor to move to rtp? // Save the RTP packets for find_rtp_packet() to rtx or restore it. - source->rtp_queue->push(msg->rtp_packets); + // TODO: FIXME: Remove dead code. + //source->rtp_queue->push(msg->rtp_packets); #endif if ((err = hls->on_video(msg, format)) != srs_success) { @@ -2718,4 +2719,9 @@ SrsRtpSharedPacket* SrsSource::find_rtp_packet(const uint16_t& seq) { return rtp_queue->find(seq); } + +SrsMetaCache* SrsSource::cached_meta() +{ + return meta; +} #endif diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index ac04f5a05..6e64e9b21 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -327,6 +327,7 @@ public: #ifdef SRS_AUTO_RTC // To find the RTP packet for RTX or restore. +// TODO: FIXME: Should queue RTP packets in connection level. class SrsRtpPacketQueue { private: @@ -634,6 +635,8 @@ public: #ifdef SRS_AUTO_RTC // Find rtp packet by sequence SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq); + // Get the cached meta, as such the sps/pps. + SrsMetaCache* cached_meta(); #endif }; diff --git a/trunk/src/kernel/srs_kernel_buffer.cpp b/trunk/src/kernel/srs_kernel_buffer.cpp index e6fcfe1fa..73c6cafe1 100644 --- a/trunk/src/kernel/srs_kernel_buffer.cpp +++ b/trunk/src/kernel/srs_kernel_buffer.cpp @@ -29,6 +29,14 @@ using namespace std; #include #include +ISrsEncoder::ISrsEncoder() +{ +} + +ISrsEncoder::~ISrsEncoder() +{ +} + ISrsCodec::ISrsCodec() { } diff --git a/trunk/src/kernel/srs_kernel_buffer.hpp b/trunk/src/kernel/srs_kernel_buffer.hpp index 3fdb7e74b..870da9ef8 100644 --- a/trunk/src/kernel/srs_kernel_buffer.hpp +++ b/trunk/src/kernel/srs_kernel_buffer.hpp @@ -31,6 +31,24 @@ class SrsBuffer; +// Encoder. +class ISrsEncoder +{ +public: + ISrsEncoder(); + virtual ~ISrsEncoder(); +public: + /** + * get the number of bytes to code to. + */ + // TODO: FIXME: change to uint64_t. + virtual int nb_bytes() = 0; + /** + * encode object to bytes in SrsBuffer. + */ + virtual srs_error_t encode(SrsBuffer* buf) = 0; +}; + /** * the srs codec, to code and decode object with bytes: * code: to encode/serialize object to bytes in buffer, @@ -56,21 +74,11 @@ class SrsBuffer; * @remark protocol or amf0 or json should implements this interface. */ // TODO: FIXME: protocol, amf0, json should implements it. -class ISrsCodec +class ISrsCodec : public ISrsEncoder { public: ISrsCodec(); virtual ~ISrsCodec(); -public: - /** - * get the number of bytes to code to. - */ - // TODO: FIXME: change to uint64_t. - virtual int nb_bytes() = 0; - /** - * encode object to bytes in SrsBuffer. - */ - virtual srs_error_t encode(SrsBuffer* buf) = 0; public: /** * decode object from bytes in SrsBuffer. diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index 2f6c14bff..a351dcc52 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -32,6 +32,7 @@ using namespace std; #include #include #include +#include string srs_video_codec_id2str(SrsVideoCodecId codec) { @@ -364,12 +365,50 @@ SrsSample::SrsSample() { size = 0; bytes = NULL; + bframe = false; } SrsSample::~SrsSample() { } +srs_error_t SrsSample::parse_bframe() +{ + srs_error_t err = srs_success; + + uint8_t header = bytes[0]; + SrsAvcNaluType nal_type = (SrsAvcNaluType)(header & kNalTypeMask); + + if (nal_type != SrsAvcNaluTypeNonIDR && nal_type != SrsAvcNaluTypeDataPartitionA && nal_type != SrsAvcNaluTypeIDR) { + return err; + } + + SrsBuffer* stream = new SrsBuffer(bytes, size); + SrsAutoFree(SrsBuffer, stream); + + // Skip nalu header. + stream->skip(1); + + SrsBitBuffer bitstream(stream); + int32_t first_mb_in_slice = 0; + if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) { + return srs_error_wrap(err, "nalu read uev"); + } + + int32_t slice_type_v = 0; + if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type_v)) != srs_success) { + return srs_error_wrap(err, "nalu read uev"); + } + SrsAvcSliceType slice_type = (SrsAvcSliceType)slice_type_v; + + if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) { + bframe = true; + srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type); + } + + return err; +} + SrsCodecConfig::SrsCodecConfig() { } @@ -458,6 +497,7 @@ srs_error_t SrsFrame::add_sample(char* bytes, int size) SrsSample* sample = &samples[nb_samples++]; sample->bytes = bytes; sample->size = size; + sample->bframe = false; return err; } @@ -488,6 +528,13 @@ SrsVideoFrame::~SrsVideoFrame() { } +srs_error_t SrsVideoFrame::initialize(SrsCodecConfig* c) +{ + first_nalu_type = SrsAvcNaluTypeForbidden; + has_idr = has_sps_pps = has_aud = false; + return SrsFrame::initialize(c); +} + srs_error_t SrsVideoFrame::add_sample(char* bytes, int size) { srs_error_t err = srs_success; diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index c820cbeef..49447b5de 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -532,11 +532,16 @@ class SrsSample public: // The size of unit. int size; - // The ptr of unit, user must manage it. + // The ptr of unit, user must free it. char* bytes; + // Whether is B frame. + bool bframe; public: SrsSample(); - virtual ~SrsSample(); + ~SrsSample(); +public: + // If we need to know whether sample is bframe, we have to parse the NALU payload. + srs_error_t parse_bframe(); }; /** @@ -703,6 +708,8 @@ public: SrsVideoFrame(); virtual ~SrsVideoFrame(); public: + // Initialize the frame, to parse sampels. + virtual srs_error_t initialize(SrsCodecConfig* c); // Add the sample without ANNEXB or IBMF header, or RAW AAC or MP3 data. virtual srs_error_t add_sample(char* bytes, int size); public: diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index f24dc2047..00e289feb 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -194,8 +194,11 @@ srs_error_t SrsCommonMessage::create(SrsMessageHeader* pheader, char* body, int return srs_success; } -SrsSharedMessageHeader::SrsSharedMessageHeader() : payload_length(0), message_type(0), perfer_cid(0) +SrsSharedMessageHeader::SrsSharedMessageHeader() { + payload_length = 0; + message_type = 0; + perfer_cid = 0; } SrsSharedMessageHeader::~SrsSharedMessageHeader() @@ -207,6 +210,15 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload() payload = NULL; size = 0; shared_count = 0; + +#ifdef SRS_AUTO_RTC + samples = NULL; + nn_samples = 0; + has_idr = false; + + extra_payloads = NULL; + nn_extra_payloads = 0; +#endif } SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() @@ -215,6 +227,16 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_memory_unwatch(payload); #endif srs_freepa(payload); + srs_freepa(samples); + +#ifdef SRS_AUTO_RTC + for (int i = 0; i < nn_extra_payloads; i++) { + SrsSample* p = extra_payloads + i; + srs_freep(p->bytes); + } + srs_freepa(extra_payloads); + nn_extra_payloads = 0; +#endif } SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL) @@ -231,12 +253,6 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage() ptr->shared_count--; } } - -#ifdef SRS_AUTO_RTC - for (int i = 0; i < (int)rtp_packets.size(); ++i) { - srs_freep(rtp_packets[i]); - } -#endif } srs_error_t SrsSharedPtrMessage::create(SrsCommonMessage* msg) @@ -355,19 +371,30 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() copy->payload = ptr->payload; copy->size = ptr->size; -#ifdef SRS_AUTO_RTC - for (int i = 0; i < (int)rtp_packets.size(); ++i) { - copy->rtp_packets.push_back(rtp_packets[i]->copy()); - } -#endif - return copy; } #ifdef SRS_AUTO_RTC -void SrsSharedPtrMessage::set_rtp_packets(const std::vector& pkts) +void SrsSharedPtrMessage::set_extra_payloads(SrsSample* payloads, int nn_payloads) { - rtp_packets = pkts; + srs_assert(nn_payloads); + srs_assert(!ptr->extra_payloads); + + ptr->nn_extra_payloads = nn_payloads; + + ptr->extra_payloads = new SrsSample[nn_payloads]; + memcpy(ptr->extra_payloads, payloads, nn_payloads * sizeof(SrsSample)); +} + +void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples) +{ + srs_assert(nn_samples); + srs_assert(!ptr->samples); + + ptr->nn_samples = nn_samples; + + ptr->samples = new SrsSample[nn_samples]; + memcpy(ptr->samples, samples, nn_samples * sizeof(SrsSample)); } #endif diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index 23fa0baf0..84d7d34d9 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -40,6 +40,7 @@ class ISrsReader; class SrsFileReader; class SrsPacket; class SrsRtpSharedPacket; +class SrsSample; #define SRS_FLV_TAG_HEADER_SIZE 11 #define SRS_FLV_PREVIOUS_TAG_SIZE 4 @@ -288,10 +289,6 @@ public: // video/audio packet use raw bytes, no video/audio packet. char* payload; -#ifdef SRS_AUTO_RTC - std::vector rtp_packets; -#endif - private: class SrsSharedPtrPayload { @@ -305,6 +302,19 @@ private: int size; // The reference count int shared_count; +#ifdef SRS_AUTO_RTC + public: + // For RTC video, we need to know the NALU structures, + // because the RTP STAP-A or FU-A based on NALU. + SrsSample* samples; + int nn_samples; + // For RTC video, whether NALUs has IDR. + bool has_idr; + // For RTC audio, we may need to transcode AAC to opus, + // so there must be an extra payloads, which is transformed from payload. + SrsSample* extra_payloads; + int nn_extra_payloads; +#endif public: SrsSharedPtrPayload(); virtual ~SrsSharedPtrPayload(); @@ -348,7 +358,18 @@ public: virtual SrsSharedPtrMessage* copy(); public: #ifdef SRS_AUTO_RTC - virtual void set_rtp_packets(const std::vector& pkts); + // Set extra samples, for example, when we transcode an AAC audio packet to OPUS, + // we may get more than one OPUS packets, we set these OPUS packets in extra payloads. + void set_extra_payloads(SrsSample* payloads, int nn_payloads); + int nn_extra_payloads() { return ptr->nn_extra_payloads; } + SrsSample* extra_payloads() { return ptr->extra_payloads; } + // Whether samples has idr. + bool has_idr() { return ptr->has_idr; } + void set_has_idr(bool v) { ptr->has_idr = v; } + // Set samples, each sample points to the address of payload. + void set_samples(SrsSample* samples, int nn_samples); + int nn_samples() { return ptr->nn_samples; } + SrsSample* samples() { return ptr->samples; } #endif }; diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 59ad7ca93..d00140005 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -32,6 +32,15 @@ using namespace std; #include #include +// @see: https://tools.ietf.org/html/rfc6184#section-5.2 +const uint8_t kStapA = 24; + +// @see: https://tools.ietf.org/html/rfc6184#section-5.2 +const uint8_t kFuA = 28; + +// @see: https://tools.ietf.org/html/rfc6184#section-5.8 +const uint8_t kStart = 0x80; // Fu-header start bit +const uint8_t kEnd = 0x40; // Fu-header end bit SrsRtpHeader::SrsRtpHeader() { @@ -77,7 +86,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* stream) { srs_error_t err = srs_success; - // TODO: + // TODO: FIXME: Implements it. return err; } @@ -86,19 +95,21 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream) { srs_error_t err = srs_success; - uint8_t first = 0x80 | cc; + uint8_t v = 0x80 | cc; if (padding) { - first |= 0x40; + v |= 0x40; } if (extension) { - first |= 0x10; + v |= 0x10; } - stream->write_1bytes(first); - uint8_t second = payload_type; + stream->write_1bytes(v); + + v = payload_type; if (marker) { - payload_type |= kRtpMarker; + v |= kRtpMarker; } - stream->write_1bytes(second); + stream->write_1bytes(v); + stream->write_2bytes(sequence); stream->write_4bytes(timestamp); stream->write_4bytes(ssrc); @@ -143,6 +154,200 @@ void SrsRtpHeader::set_ssrc(uint32_t ssrc) this->ssrc = ssrc; } +SrsRtpPacket2::SrsRtpPacket2() +{ + payload = NULL; + padding = 0; +} + +SrsRtpPacket2::~SrsRtpPacket2() +{ + srs_freep(payload); +} + +void SrsRtpPacket2::set_padding(int size) +{ + rtp_header.set_padding(size > 0); + padding = size; +} + +int SrsRtpPacket2::nb_bytes() +{ + return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding; +} + +srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + if ((err = rtp_header.encode(buf)) != srs_success) { + return srs_error_wrap(err, "rtp header"); + } + + if (payload && (err = payload->encode(buf)) != srs_success) { + return srs_error_wrap(err, "encode payload"); + } + + if (padding) { + if (!buf->require(padding)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding); + } + memset(buf->data(), padding, padding); + buf->skip(padding); + } + + return err; +} + +SrsRtpRawPayload::SrsRtpRawPayload() +{ + payload = NULL; + nn_payload = 0; +} + +SrsRtpRawPayload::~SrsRtpRawPayload() +{ +} + +int SrsRtpRawPayload::nb_bytes() +{ + return nn_payload; +} + +srs_error_t SrsRtpRawPayload::encode(SrsBuffer* buf) +{ + if (nn_payload <= 0) { + return srs_success; + } + + if (!buf->require(nn_payload)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", nn_payload); + } + + buf->write_bytes(payload, nn_payload); + + return srs_success; +} + +SrsRtpSTAPPayload::SrsRtpSTAPPayload() +{ + nri = (SrsAvcNaluType)0; +} + +SrsRtpSTAPPayload::~SrsRtpSTAPPayload() +{ + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + srs_freep(p); + } + nalus.clear(); +} + +int SrsRtpSTAPPayload::nb_bytes() +{ + int size = 1; + + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + size += 2 + p->size; + } + + return size; +} + +srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer* buf) +{ + if (!buf->require(1)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); + } + + // STAP header, RTP payload format for aggregation packets + // @see https://tools.ietf.org/html/rfc6184#section-5.7 + uint8_t v = kStapA; + v |= (nri & (~kNalTypeMask)); + buf->write_1bytes(v); + + // NALUs. + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + if (!buf->require(2 + p->size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size); + } + + buf->write_2bytes(p->size); + buf->write_bytes(p->bytes, p->size); + } + + return srs_success; +} + +SrsRtpFUAPayload::SrsRtpFUAPayload() +{ + start = end = false; + nri = nalu_type = (SrsAvcNaluType)0; +} + +SrsRtpFUAPayload::~SrsRtpFUAPayload() +{ + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + srs_freep(p); + } + nalus.clear(); +} + +int SrsRtpFUAPayload::nb_bytes() +{ + int size = 2; + + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + size += p->size; + } + + return size; +} + +srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf) +{ + if (!buf->require(2)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); + } + + // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 + uint8_t fu_indicate = kFuA; + fu_indicate |= (nri & (~kNalTypeMask)); + buf->write_1bytes(fu_indicate); + + // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 + uint8_t fu_header = nalu_type; + if (start) { + fu_header |= kStart; + } + if (end) { + fu_header |= kEnd; + } + buf->write_1bytes(fu_header); + + // FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8 + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + if (!buf->require(p->size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size); + } + + buf->write_bytes(p->bytes, p->size); + } + + return srs_success; +} + SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload() { payload = NULL; diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 396cb2687..975b2b463 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -26,11 +26,17 @@ #include +#include +#include + #include const int kRtpHeaderFixedSize = 12; const uint8_t kRtpMarker = 0x80; +// H.264 nalu header type mask. +const uint8_t kNalTypeMask = 0x1F; + class SrsBuffer; class SrsRtpHeader @@ -68,6 +74,78 @@ public: int64_t get_timestamp() const { return timestamp; } void set_ssrc(uint32_t ssrc); uint32_t get_ssrc() const { return ssrc; } + void set_padding(bool v) { padding = v; } +}; + +class SrsRtpPacket2 +{ +public: + SrsRtpHeader rtp_header; + ISrsEncoder* payload; + int padding; +public: + SrsRtpPacket2(); + virtual ~SrsRtpPacket2(); +public: + // Append size of bytes as padding. + virtual void set_padding(int size); +// interface ISrsEncoder +public: + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); +}; + +class SrsRtpRawPayload : public ISrsEncoder +{ +public: + // @remark We only refer to the memory, user must free it. + char* payload; + int nn_payload; +public: + SrsRtpRawPayload(); + virtual ~SrsRtpRawPayload(); +// interface ISrsEncoder +public: + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); +}; + +class SrsRtpSTAPPayload : public ISrsEncoder +{ +public: + // The NRI in NALU type. + SrsAvcNaluType nri; + // The NALU samples. + // @remark We only refer to the memory, user must free its bytes. + std::vector nalus; +public: + SrsRtpSTAPPayload(); + virtual ~SrsRtpSTAPPayload(); +// interface ISrsEncoder +public: + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); +}; + +class SrsRtpFUAPayload : public ISrsEncoder +{ +public: + // The NRI in NALU type. + SrsAvcNaluType nri; + // The FUA header. + bool start; + bool end; + SrsAvcNaluType nalu_type; + // The NALU samples. + // @remark We only refer to the memory, user must free its bytes. + std::vector nalus; +public: + SrsRtpFUAPayload(); + virtual ~SrsRtpFUAPayload(); +// interface ISrsEncoder +public: + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); }; class SrsRtpSharedPacket diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index e4641285c..8195d0020 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -209,7 +209,7 @@ srs_error_t do_main(int argc, char** argv) int main(int argc, char** argv) { srs_error_t err = do_main(argc, argv); - + if (err != srs_success) { srs_error("Failed, %s", srs_error_desc(err).c_str()); } diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index 8d3a2378e..6c0889d3f 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -4539,6 +4539,11 @@ srs_error_t SrsOnMetaDataPacket::decode(SrsBuffer* stream) return srs_error_wrap(err, "name"); } } + + // Allows empty body metadata. + if (stream->empty()) { + return err; + } // the metadata maybe object or ecma array SrsAmf0Any* any = NULL; diff --git a/trunk/src/utest/srs_utest_avc.cpp b/trunk/src/utest/srs_utest_avc.cpp index 4aa8f037f..60b4bb29d 100644 --- a/trunk/src/utest/srs_utest_avc.cpp +++ b/trunk/src/utest/srs_utest_avc.cpp @@ -462,7 +462,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader) codec.sound_rate = SrsAudioSampleRate44100; codec.sampling_frequency_index = 4; HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); - EXPECT_EQ(2, sh.length()); + EXPECT_EQ(2, (int)sh.length()); EXPECT_EQ(0x0a, (uint8_t)sh.at(0)); EXPECT_EQ(0x08, (uint8_t)sh.at(1)); } @@ -475,7 +475,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader) codec.sound_rate = SrsAudioSampleRate22050; codec.sampling_frequency_index = 4; HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); - EXPECT_EQ(2, sh.length()); + EXPECT_EQ(2, (int)sh.length()); EXPECT_EQ(0x0a, (uint8_t)sh.at(0)); EXPECT_EQ(0x08, (uint8_t)sh.at(1)); } diff --git a/trunk/src/utest/srs_utest_config.cpp b/trunk/src/utest/srs_utest_config.cpp index 1d03cefda..ec6bef58f 100644 --- a/trunk/src/utest/srs_utest_config.cpp +++ b/trunk/src/utest/srs_utest_config.cpp @@ -2010,7 +2010,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost) if (true) { HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF)); - EXPECT_EQ(0, conf.get_hls_dispose("")); + EXPECT_EQ(0, (int)conf.get_hls_dispose("")); EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_hls_fragment("")); EXPECT_EQ(60 * SRS_UTIME_SECONDS, conf.get_hls_window("")); @@ -2033,7 +2033,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost) if (true) { HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF)); EXPECT_EQ(30 * SRS_UTIME_SECONDS, conf.get_queue_length("")); - EXPECT_EQ(0, conf.get_send_min_interval("")); + EXPECT_EQ(0, (int)conf.get_send_min_interval("")); HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost v{play{queue_length 100;send_min_interval 10;}}")); EXPECT_EQ(100 * SRS_UTIME_SECONDS, conf.get_queue_length("v")); @@ -2042,7 +2042,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost) if (true) { HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF)); - EXPECT_EQ(0, conf.get_vhost_http_remux_fast_cache("")); + EXPECT_EQ(0, (int)conf.get_vhost_http_remux_fast_cache("")); HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost v{http_remux{fast_cache 10;}}")); EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_vhost_http_remux_fast_cache("v")); @@ -2768,19 +2768,19 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF)); - EXPECT_EQ(0, conf.get_stream_casters().size()); + EXPECT_EQ(0, (int)conf.get_stream_casters().size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); - EXPECT_EQ(1, conf.get_stream_casters().size()); + EXPECT_EQ(1, (int)conf.get_stream_casters().size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster; stream_caster;")); - EXPECT_EQ(2, conf.get_stream_casters().size()); + EXPECT_EQ(2, (int)conf.get_stream_casters().size()); } if (true) { @@ -2788,7 +2788,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_FALSE(conf.get_stream_caster_enabled(arr.at(0))); } @@ -2798,7 +2798,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {enabled off;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_FALSE(conf.get_stream_caster_enabled(arr.at(0))); } @@ -2808,7 +2808,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {enabled on;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_TRUE(conf.get_stream_caster_enabled(arr.at(0))); } @@ -2818,7 +2818,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_TRUE(conf.get_stream_caster_output(arr.at(0)).empty()); } @@ -2828,7 +2828,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {output xxx;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("xxx", conf.get_stream_caster_output(arr.at(0)).c_str()); } @@ -2838,9 +2838,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); - EXPECT_EQ(0, conf.get_stream_caster_listen(arr.at(0))); + EXPECT_EQ(0, (int)conf.get_stream_caster_listen(arr.at(0))); } if (true) { @@ -2848,7 +2848,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {listen 8080;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(8080, conf.get_stream_caster_listen(arr.at(0))); } @@ -2858,9 +2858,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); - EXPECT_EQ(0, conf.get_stream_caster_rtp_port_min(arr.at(0))); + EXPECT_EQ(0, (int)conf.get_stream_caster_rtp_port_min(arr.at(0))); } if (true) { @@ -2868,7 +2868,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {rtp_port_min 8080;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(8080, conf.get_stream_caster_rtp_port_min(arr.at(0))); } @@ -2878,9 +2878,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); - EXPECT_EQ(0, conf.get_stream_caster_rtp_port_max(arr.at(0))); + EXPECT_EQ(0, (int)conf.get_stream_caster_rtp_port_max(arr.at(0))); } if (true) { @@ -2888,7 +2888,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {rtp_port_max 8080;}")); vector arr = conf.get_stream_casters(); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(8080, conf.get_stream_caster_rtp_port_max(arr.at(0))); } @@ -2912,14 +2912,14 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2) EXPECT_TRUE(conf.get_debug_srs_upnode("ossrs.net")); EXPECT_FALSE(conf.get_atc("ossrs.net")); EXPECT_FALSE(conf.get_atc_auto("ossrs.net")); - EXPECT_EQ(1, conf.get_time_jitter("ossrs.net")); + EXPECT_EQ(1, (int)conf.get_time_jitter("ossrs.net")); EXPECT_FALSE(conf.get_mix_correct("ossrs.net")); EXPECT_EQ(30 * SRS_UTIME_SECONDS, conf.get_queue_length("ossrs.net")); EXPECT_FALSE(conf.get_refer_enabled("ossrs.net")); EXPECT_TRUE(conf.get_refer_all("ossrs.net") == NULL); EXPECT_TRUE(conf.get_refer_play("ossrs.net") == NULL); EXPECT_TRUE(conf.get_refer_publish("ossrs.net") == NULL); - EXPECT_EQ(0, conf.get_in_ack_size("ossrs.net")); + EXPECT_EQ(0, (int)conf.get_in_ack_size("ossrs.net")); EXPECT_EQ(2500000, conf.get_out_ack_size("ossrs.net")); EXPECT_EQ(60000, conf.get_chunk_size("ossrs.net")); EXPECT_TRUE(conf.get_parse_sps("ossrs.net")); @@ -2928,7 +2928,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2) EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mw_sleep("ossrs.net")); EXPECT_FALSE(conf.get_realtime_enabled("ossrs.net")); EXPECT_FALSE(conf.get_tcp_nodelay("ossrs.net")); - EXPECT_EQ(0, conf.get_send_min_interval("ossrs.net")); + EXPECT_EQ(0, (int)conf.get_send_min_interval("ossrs.net")); EXPECT_FALSE(conf.get_reduce_sequence_header("ossrs.net")); EXPECT_EQ(20000000, conf.get_publish_1stpkt_timeout("ossrs.net")); EXPECT_EQ(5000000, conf.get_publish_normal_timeout("ossrs.net")); @@ -3065,7 +3065,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2) if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{play{time_jitter zero;}}")); - EXPECT_EQ(2, conf.get_time_jitter("ossrs.net")); + EXPECT_EQ(2, (int)conf.get_time_jitter("ossrs.net")); } if (true) { @@ -3132,7 +3132,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig3) EXPECT_FALSE(conf.get_vhost_edge_token_traverse("ossrs.net")); EXPECT_STREQ("[vhost]", conf.get_vhost_edge_transform_vhost("ossrs.net").c_str()); EXPECT_FALSE(conf.get_vhost_origin_cluster("ossrs.net")); - EXPECT_EQ(0, conf.get_vhost_coworkers("ossrs.net").size()); + EXPECT_EQ(0, (int)conf.get_vhost_coworkers("ossrs.net").size()); EXPECT_FALSE(conf.get_security_enabled("ossrs.net")); EXPECT_TRUE(conf.get_security_rules("ossrs.net") == NULL); } @@ -3152,7 +3152,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig3) if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{cluster{coworkers xxx;}}")); - EXPECT_EQ(1, conf.get_vhost_coworkers("ossrs.net").size()); + EXPECT_EQ(1, (int)conf.get_vhost_coworkers("ossrs.net").size()); } if (true) { @@ -3286,14 +3286,14 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) EXPECT_TRUE(conf.get_transcode("ossrs.net", "") == NULL); EXPECT_FALSE(conf.get_transcode_enabled(conf.get_transcode("ossrs.net", ""))); EXPECT_TRUE(conf.get_transcode_ffmpeg(conf.get_transcode("ossrs.net", "")).empty()); - EXPECT_EQ(0, conf.get_transcode_engines(conf.get_transcode("ossrs.net", "")).size()); + EXPECT_EQ(0, (int)conf.get_transcode_engines(conf.get_transcode("ossrs.net", "")).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{output xxx;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("xxx", conf.get_engine_output(arr.at(0)).c_str()); } @@ -3301,7 +3301,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{oformat flv;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("flv", conf.get_engine_oformat(arr.at(0)).c_str()); } @@ -3309,15 +3309,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{aparams {i;}}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); - EXPECT_EQ(1, conf.get_engine_aparams(arr.at(0)).size()); + ASSERT_EQ(1, (int)arr.size()); + EXPECT_EQ(1, (int)conf.get_engine_aparams(arr.at(0)).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{achannels 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_achannels(arr.at(0))); } @@ -3325,7 +3325,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{asample_rate 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_asample_rate(arr.at(0))); } @@ -3333,7 +3333,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{abitrate 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_abitrate(arr.at(0))); } @@ -3341,7 +3341,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{acodec aac;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("aac", conf.get_engine_acodec(arr.at(0)).c_str()); } @@ -3349,15 +3349,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vparams {t;}}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); - EXPECT_EQ(1, conf.get_engine_vparams(arr.at(0)).size()); + ASSERT_EQ(1, (int)arr.size()); + EXPECT_EQ(1, (int)conf.get_engine_vparams(arr.at(0)).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vpreset main;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("main", conf.get_engine_vpreset(arr.at(0)).c_str()); } @@ -3365,7 +3365,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vprofile main;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("main", conf.get_engine_vprofile(arr.at(0)).c_str()); } @@ -3373,7 +3373,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vthreads 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_vthreads(arr.at(0))); } @@ -3381,7 +3381,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vheight 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_vheight(arr.at(0))); } @@ -3389,7 +3389,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vwidth 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_vwidth(arr.at(0))); } @@ -3397,7 +3397,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfps 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_vfps(arr.at(0))); } @@ -3405,7 +3405,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vbitrate 1000;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_EQ(1000, conf.get_engine_vbitrate(arr.at(0))); } @@ -3413,7 +3413,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vcodec x264;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("x264", conf.get_engine_vcodec(arr.at(0)).c_str()); } @@ -3421,23 +3421,23 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfilter {i;}}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); - EXPECT_EQ(1, conf.get_engine_vfilter(arr.at(0)).size()); + ASSERT_EQ(1, (int)arr.size()); + EXPECT_EQ(1, (int)conf.get_engine_vfilter(arr.at(0)).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfilter {i logo.png;}}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); - EXPECT_EQ(2, conf.get_engine_vfilter(arr.at(0)).size()); + ASSERT_EQ(1, (int)arr.size()); + EXPECT_EQ(2, (int)conf.get_engine_vfilter(arr.at(0)).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{iformat mp4;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_STREQ("mp4", conf.get_engine_iformat(arr.at(0)).c_str()); } @@ -3445,15 +3445,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{perfile {re;}}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); - EXPECT_EQ(1, conf.get_engine_perfile(arr.at(0)).size()); + ASSERT_EQ(1, (int)arr.size()); + EXPECT_EQ(1, (int)conf.get_engine_perfile(arr.at(0)).size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{enabled on;}}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); EXPECT_TRUE(conf.get_engine_enabled(arr.at(0))); } @@ -3461,7 +3461,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4) MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine;}}")); vector arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx")); - ASSERT_EQ(1, arr.size()); + ASSERT_EQ(1, (int)arr.size()); } if (true) { @@ -3492,13 +3492,13 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5) HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{exec{enabled on;publish xxx;}}")); EXPECT_TRUE(conf.get_exec("ossrs.net") != NULL); EXPECT_TRUE(conf.get_exec_enabled("ossrs.net")); - EXPECT_EQ(1, conf.get_exec_publishs("ossrs.net").size()); + EXPECT_EQ(1, (int)conf.get_exec_publishs("ossrs.net").size()); } if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{ingest xxx{enabled on;ffmpeg xxx2;input{type xxx3;url xxx4;}}}")); - EXPECT_EQ(1, conf.get_ingesters("ossrs.net").size()); + EXPECT_EQ(1, (int)conf.get_ingesters("ossrs.net").size()); ASSERT_TRUE(conf.get_ingest_by_id("ossrs.net", "xxx") != NULL); EXPECT_TRUE(conf.get_ingest_enabled(conf.get_ingest_by_id("ossrs.net", "xxx"))); EXPECT_STREQ("xxx2", conf.get_ingest_ffmpeg(conf.get_ingest_by_id("ossrs.net", "xxx")).c_str()); @@ -3584,7 +3584,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5) EXPECT_STREQ("xxx2", conf.get_dvr_plan("ossrs.net").c_str()); EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_dvr_duration("ossrs.net")); EXPECT_TRUE(conf.get_dvr_wait_keyframe("ossrs.net")); - EXPECT_EQ(1, conf.get_dvr_time_jitter("ossrs.net")); + EXPECT_EQ(1, (int)conf.get_dvr_time_jitter("ossrs.net")); } if (true) { @@ -3637,7 +3637,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5) if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stats{network 0;disk xxx;}")); - EXPECT_EQ(0, conf.get_stats_network()); + EXPECT_EQ(0, (int)conf.get_stats_network()); EXPECT_TRUE(conf.get_stats_disk_device() != NULL); } } diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index 29638dceb..72395fc61 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -4869,20 +4869,20 @@ VOID TEST(KernelMP4Test, CoverMP4CodecSingleFrame) // Sequence header. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); // Frame group #0 HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); } @@ -4984,20 +4984,20 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleVideos) // Sequence header. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); // Frames order by dts asc. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(40, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(40, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); } } @@ -5082,24 +5082,24 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleCTTs) // Sequence header. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); // Frames order by dts asc. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(40, (int)dts); EXPECT_EQ(80, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(40, (int)dts); EXPECT_EQ(80, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(80, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(80, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); } } @@ -5194,28 +5194,28 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleAVs) // Sequence header. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); // Frames order by dts asc. HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(20, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(20, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); - EXPECT_EQ(40, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); + EXPECT_EQ(40, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct); srs_freepa(sample); } } @@ -5338,3 +5338,16 @@ VOID TEST(KernelMP4Test, CoverMP4M2tsSegmentEncoder) HELPER_EXPECT_SUCCESS(enc.flush(dts)); } +VOID TEST(KernelUtilityTest, CoverStringAssign) +{ + string sps = "SRS"; + ASSERT_STREQ("SRS", sps.c_str()); + + sps.assign("Hello", 5); + ASSERT_STREQ("Hello", sps.c_str()); + + sps.assign("World", 0); + ASSERT_EQ(0, (int)sps.length()); + ASSERT_STREQ("", sps.c_str()); +} + diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp index 2b13b2835..ebd260aa1 100644 --- a/trunk/src/utest/srs_utest_protocol.cpp +++ b/trunk/src/utest/srs_utest_protocol.cpp @@ -5855,7 +5855,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) HELPER_EXPECT_SUCCESS(parser.parse("HelloGET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r\nWorld")); EXPECT_EQ(80, (int)parser.parsed); EXPECT_EQ(0, (int)parser.parser->nread); - EXPECT_EQ(0, parser.parser->content_length); + EXPECT_EQ(0, (int)parser.parser->content_length); } if (true) { @@ -5864,7 +5864,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r\nHel")); EXPECT_EQ(73, (int)parser.parsed); EXPECT_EQ(0, (int)parser.parser->nread); - EXPECT_EQ(2, parser.parser->content_length); + EXPECT_EQ(2, (int)parser.parser->content_length); } if (true) { @@ -5881,7 +5881,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 34, nparsed = 34, nread = 34 HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHo")); EXPECT_EQ(34, (int)parser.parsed); - EXPECT_EQ(34, parser.parser->nread); + EXPECT_EQ(34, (int)parser.parser->nread); // size = 41, nparsed = 41, nread = 0 HELPER_EXPECT_SUCCESS(parser.parse("st: ossrs.net\r\nContent-Length: 5\r\n\r\nHello")); @@ -5894,7 +5894,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 41, nparsed = 41, nread = 41 HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: oss")); EXPECT_EQ(41, (int)parser.parsed); - EXPECT_EQ(41, parser.parser->nread); + EXPECT_EQ(41, (int)parser.parser->nread); // size = 34, nparsed = 34, nread = 0 HELPER_EXPECT_SUCCESS(parser.parse("rs.net\r\nContent-Length: 5\r\n\r\nHello")); @@ -5907,7 +5907,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 48, nparsed = 48, nread = 48 HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r")); EXPECT_EQ(48, (int)parser.parsed); - EXPECT_EQ(48, parser.parser->nread); + EXPECT_EQ(48, (int)parser.parser->nread); // size = 27, nparsed = 27, nread = 0 HELPER_EXPECT_SUCCESS(parser.parse("\nContent-Length: 5\r\n\r\nHello")); @@ -5920,7 +5920,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 68, nparsed = 68, nread = 68 HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n")); EXPECT_EQ(68, (int)parser.parsed); - EXPECT_EQ(68, parser.parser->nread); + EXPECT_EQ(68, (int)parser.parser->nread); // size = 7, nparsed = 7, nread = 0 HELPER_EXPECT_SUCCESS(parser.parse("\r\nHello")); @@ -5933,7 +5933,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 69, nparsed = 69, nread = 69 HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r")); EXPECT_EQ(69, (int)parser.parsed); - EXPECT_EQ(69, parser.parser->nread); + EXPECT_EQ(69, (int)parser.parser->nread); // size = 6, nparsed = 6, nread = 0 HELPER_EXPECT_SUCCESS(parser.parse("\nHello")); @@ -5954,12 +5954,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // nparsed = 2, size = 2, nread = 2 HELPER_EXPECT_SUCCESS(parser.parse("GE")); EXPECT_EQ(2, (int)parser.parsed); - EXPECT_EQ(2, parser.parser->nread); + EXPECT_EQ(2, (int)parser.parser->nread); // size = 0, nparsed = 1, nread=2 HELPER_EXPECT_FAILED(parser.parse("")); EXPECT_EQ(1, (int)parser.parsed); - EXPECT_EQ(2, parser.parser->nread); + EXPECT_EQ(2, (int)parser.parser->nread); } if (true) { @@ -5967,12 +5967,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 2, nparsed = 2, nread = 2 HELPER_EXPECT_SUCCESS(parser.parse("GE")); EXPECT_EQ(2, (int)parser.parsed); - EXPECT_EQ(2, parser.parser->nread); + EXPECT_EQ(2, (int)parser.parser->nread); // size = 1, nparsed = 0, nread = 3 HELPER_EXPECT_FAILED(parser.parse("X")); EXPECT_EQ(0, (int)parser.parsed); - EXPECT_EQ(3, parser.parser->nread); + EXPECT_EQ(3, (int)parser.parser->nread); } if (true) { @@ -5980,12 +5980,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 2, nparsed = 2, nread = 2 HELPER_EXPECT_SUCCESS(parser.parse("GE")); EXPECT_EQ(2, (int)parser.parsed); - EXPECT_EQ(2, parser.parser->nread); + EXPECT_EQ(2, (int)parser.parser->nread); // size = 1, nparsed = 1, nread = 3 HELPER_EXPECT_SUCCESS(parser.parse("T")); EXPECT_EQ(1, (int)parser.parsed); - EXPECT_EQ(3, parser.parser->nread); + EXPECT_EQ(3, (int)parser.parser->nread); } if (true) { @@ -5993,7 +5993,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser) // size = 3, nparsed = 3, nread = 3 HELPER_EXPECT_SUCCESS(parser.parse("GET")); EXPECT_EQ(3, (int)parser.parsed); - EXPECT_EQ(3, parser.parser->nread); + EXPECT_EQ(3, (int)parser.parser->nread); } }