From aff61025f84b7b0d3bc6e05b0440c41372cad72b Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Fri, 15 Apr 2022 13:54:24 +0800 Subject: [PATCH 01/36] Refine SRT code, with StateThread adpater --- trunk/auto/options.sh | 6 - trunk/conf/srt.conf | 5 + trunk/configure | 32 +- trunk/src/app/srs_app_config.cpp | 45 +- trunk/src/app/srs_app_config.hpp | 8 +- trunk/src/app/srs_app_pithy_print.cpp | 19 + trunk/src/app/srs_app_pithy_print.hpp | 4 + trunk/src/app/srs_app_srt_conn.cpp | 678 +++++++++++++++++ trunk/src/app/srs_app_srt_conn.hpp | 109 +++ trunk/src/app/srs_app_srt_listener.cpp | 100 +++ trunk/src/app/srs_app_srt_listener.hpp | 53 ++ trunk/src/app/srs_app_srt_server.cpp | 392 ++++++++++ trunk/src/app/srs_app_srt_server.hpp | 130 ++++ trunk/src/app/srs_app_srt_source.cpp | 798 ++++++++++++++++++++ trunk/src/app/srs_app_srt_source.hpp | 205 +++++ trunk/src/app/srs_app_srt_utility.cpp | 143 ++++ trunk/src/app/srs_app_srt_utility.hpp | 32 + trunk/src/app/srs_app_threads.cpp | 8 + trunk/src/kernel/srs_kernel_consts.hpp | 4 + trunk/src/kernel/srs_kernel_error.hpp | 12 + trunk/src/main/srs_main_server.cpp | 16 +- trunk/src/protocol/srs_protocol_utility.cpp | 1 + trunk/src/protocol/srs_service_st_srt.cpp | 789 +++++++++++++++++++ trunk/src/protocol/srs_service_st_srt.hpp | 154 ++++ trunk/src/utest/srs_utest.cpp | 18 + trunk/src/utest/srs_utest_srt.cpp | 439 ++++++++++- 26 files changed, 4132 insertions(+), 68 deletions(-) create mode 100644 trunk/src/app/srs_app_srt_conn.cpp create mode 100644 trunk/src/app/srs_app_srt_conn.hpp create mode 100644 trunk/src/app/srs_app_srt_listener.cpp create mode 100644 trunk/src/app/srs_app_srt_listener.hpp create mode 100644 trunk/src/app/srs_app_srt_server.cpp create mode 100644 trunk/src/app/srs_app_srt_server.hpp create mode 100644 trunk/src/app/srs_app_srt_source.cpp create mode 100644 trunk/src/app/srs_app_srt_source.hpp create mode 100644 trunk/src/app/srs_app_srt_utility.cpp create mode 100644 trunk/src/app/srs_app_srt_utility.hpp create mode 100644 trunk/src/protocol/srs_service_st_srt.cpp create mode 100644 trunk/src/protocol/srs_service_st_srt.hpp diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 59bc9f7d555..7ab9e8feca0 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -432,12 +432,6 @@ function apply_auto_options() { SRS_TOOL_LD=$SRS_TOOL_CC fi - # The SRT code in SRS requires c++11, although we build libsrt without c++11. - # TODO: FIXME: Remove c++11 code in SRT of SRS. - if [[ $SRS_SRT == YES ]]; then - SRS_CXX11=YES - fi - # Enable FFmpeg fit for RTC to transcode audio from AAC to OPUS, if user enabled it. if [[ $SRS_RTC == YES && $SRS_FFMPEG_FIT == RESERVED ]]; then SRS_FFMPEG_FIT=YES diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index 396dccd3aee..ed1c57f0b16 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -18,6 +18,11 @@ http_server { srt_server { enabled on; + tsbpdmode off; + tlpktdrop off; + latency 0; + sendbuf 2000000; + recvbuf 2000000; listen 10080; maxbw 1000000000; connect_timeout 4000; diff --git a/trunk/configure b/trunk/configure index aa812011a05..c28404154fe 100755 --- a/trunk/configure +++ b/trunk/configure @@ -164,7 +164,6 @@ fi # srt code path if [[ $SRS_SRT == YES ]]; then - SrsSRTRoot="${SRS_WORKDIR}/src/srt" LibSRTRoot="${SRS_OBJS_DIR}/srt/include"; LibSRTfile="${SRS_OBJS_DIR}/srt/lib/libsrt.a" if [[ $SRS_SHARED_SRT == YES ]]; then LibSRTfile="-L${SRS_OBJS_DIR}/srt/lib -lsrt"; fi fi @@ -228,6 +227,10 @@ MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json" "srs_protocol_format" "srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") +if [[ $SRS_SRT == YES ]]; then + MODULE_FILES+=("srs_service_st_srt") + ModuleLibIncs+=(${LibSRTRoot}) +fi if [[ $SRS_RTC == YES ]]; then MODULE_FILES+=("srs_rtc_stun_stack") ModuleLibIncs+=(${LibSrtpRoot}) @@ -237,16 +240,6 @@ if [[ $SRS_FFMPEG_FIT == YES ]]; then fi PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" -# -#srt protocol features. -if [[ $SRS_SRT == YES ]]; then - MODULE_ID="SRT" - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot} ${LibSRTRoot}) - MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data" "srt_log") - SRT_INCS=(${LibSRTRoot} ${SrsSRTRoot}); MODULE_DIR=${SrsSRTRoot} . auto/modules.sh - SRT_OBJS="${MODULE_OBJS[@]}" -fi # #App Module, for SRS server only. @@ -262,6 +255,9 @@ fi if [[ $SRS_FFMPEG_FIT == YES ]]; then ModuleLibIncs+=("${LibFfmpegRoot[*]}") fi +if [[ $SRS_SRT == YES ]]; then + ModuleLibIncs+=("${LibSRTRoot[*]}") +fi MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -273,6 +269,9 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_sourc "srs_app_caster_flv" "srs_app_latest_version" "srs_app_uuid" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid" "srs_app_threads") +if [[ $SRS_SRT == YES ]]; then + MODULE_FILES+=("srs_app_srt_server" "srs_app_srt_listener" "srs_app_srt_conn" "srs_app_srt_utility" "srs_app_srt_source") +fi if [[ $SRS_RTC == YES ]]; then MODULE_FILES+=("srs_app_rtc_conn" "srs_app_rtc_dtls" "srs_app_rtc_sdp" "srs_app_rtc_queue" "srs_app_rtc_server" "srs_app_rtc_source" "srs_app_rtc_api") @@ -294,9 +293,6 @@ APP_OBJS="${MODULE_OBJS[@]}" #Server Module, for SRS only. MODULE_ID="SERVER" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") -if [[ $SRS_SRT == YES ]]; then - MODULE_DEPENDS+=("SRT") -fi ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_RTC == YES ]]; then ModuleLibIncs+=(${LibSrtpRoot}) @@ -306,7 +302,6 @@ if [[ $SRS_FFMPEG_FIT == YES ]]; then fi if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=(${LibSRTRoot}) - ModuleLibIncs+=("${SrsSRTRoot[*]}") fi MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh @@ -324,7 +319,6 @@ if [[ $SRS_FFMPEG_FIT == YES ]]; then fi if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=(${LibSRTRoot}) - ModuleLibIncs+=("${SrsSRTRoot[*]}") fi MODULE_FILES=() DEFINES="" @@ -370,7 +364,6 @@ if [[ $SRS_FFMPEG_FIT == YES ]]; then fi if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=(${LibSRTRoot}) - ModuleLibIncs+=("${SrsSRTRoot[*]}") MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" @@ -413,7 +406,7 @@ if [ $SRS_UTEST = YES ]; then ModuleLibIncs+=("${LibFfmpegRoot[*]}") fi if [[ $SRS_SRT == YES ]]; then - ModuleLibIncs+=("${SrsSRTRoot[*]}") + ModuleLibIncs+=("${LibSRTRoot[*]}") fi ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) if [[ $SRS_RTC == YES ]]; then @@ -426,9 +419,6 @@ if [ $SRS_UTEST = YES ]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") - if [[ $SRS_SRT == YES ]]; then - MODULE_DEPENDS+=("SRT") - fi MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${SRT_OBJS[@]}" LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh fi diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 204ca2eeed3..f15296933fb 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2546,8 +2546,9 @@ srs_error_t SrsConfig::check_normal_config() && n != "mss" && n != "latency" && n != "recvlatency" && n != "peerlatency" && n != "tlpkdrop" && n != "connect_timeout" && n != "sendbuf" && n != "recvbuf" && n != "payloadsize" - && n != "default_app" && n != "mix_correct" && n != "sei_filter") { - return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_stream.%s", n.c_str()); + && n != "default_app" && n != "mix_correct" && n != "sei_filter" + && n != "tlpktdrop" && n != "tsbpdmode") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_server.%s", n.c_str()); } } } @@ -6798,6 +6799,20 @@ int SrsConfig::get_srto_mss() { return atoi(conf->arg0().c_str()); } +bool SrsConfig::get_srto_tsbpdmode() { + static bool DEFAULT = false; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("tsbpdmode"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + int SrsConfig::get_srto_latency() { static int DEFAULT = 120; SrsConfDirective* conf = root->get("srt_server"); @@ -6854,14 +6869,18 @@ bool SrsConfig::get_srt_sei_filter() { return SRS_CONF_PERFER_TRUE(conf->arg0()); } -bool SrsConfig::get_srto_tlpkdrop() { +bool SrsConfig::get_srto_tlpktdrop() { static bool DEFAULT = true; - SrsConfDirective* conf = root->get("srt_server"); - if (!conf) { + SrsConfDirective* srt_server_conf = root->get("srt_server"); + if (!srt_server_conf) { return DEFAULT; } - conf = conf->get("tlpkdrop"); + SrsConfDirective* conf = srt_server_conf->get("tlpkdrop"); + if (! conf) { + // make it compatible tlpkdrop and tlpktdrop opt. + conf = srt_server_conf->get("tlpktdrop"); + } if (!conf || conf->arg0().empty()) { return DEFAULT; } @@ -6882,6 +6901,20 @@ int SrsConfig::get_srto_conntimeout() { return atoi(conf->arg0().c_str()); } +int SrsConfig::get_srto_peeridletimeout() { + static int DEFAULT = 10000; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("peer_idle_timeout"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return atoi(conf->arg0().c_str()); +} + int SrsConfig::get_srto_sendbuf() { static int64_t DEFAULT = 8192 * (1500-28); SrsConfDirective* conf = root->get("srt_server"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 5d4fdddbabc..7cebd5c8023 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -636,6 +636,8 @@ class SrsConfig virtual int get_srto_maxbw(); // Get the srt SRTO_MSS, Maximum Segment Size, default is 1500. virtual int get_srto_mss(); + // Get the srt SRTO_TSBPDMODE, timestamp base packet delivery mode, default is false. + virtual bool get_srto_tsbpdmode(); // Get the srt SRTO_LATENCY, latency, default is 0 which means peer/recv latency is 120ms. virtual int get_srto_latency(); // Get the srt SRTO_RCVLATENCY, recv latency, default is 120ms. @@ -644,10 +646,12 @@ class SrsConfig virtual int get_srto_peer_latency(); // Get the srt h264 sei filter, default is on, it will drop h264 sei packet. virtual bool get_srt_sei_filter(); - // Get the srt SRTO_TLPKDROP, Too-late Packet Drop, default is true. - virtual bool get_srto_tlpkdrop(); + // Get the srt SRTO_TLPKTDROP, Too-late Packet Drop, default is true. + virtual bool get_srto_tlpktdrop(); // Get the srt SRTO_CONNTIMEO, connection timeout, default is 3000ms. virtual int get_srto_conntimeout(); + // Get the srt SRTO_PEERIDLETIMEO, peer idle timeout, default is 10000ms. + virtual int get_srto_peeridletimeout(); // Get the srt SRTO_SNDBUF, send buffer, default is 8192 × (1500-28). virtual int get_srto_sendbuf(); // Get the srt SRTO_RCVBUF, recv buffer, default is 8192 × (1500-28). diff --git a/trunk/src/app/srs_app_pithy_print.cpp b/trunk/src/app/srs_app_pithy_print.cpp index ecbb3306ee1..d4891f40255 100644 --- a/trunk/src/app/srs_app_pithy_print.cpp +++ b/trunk/src/app/srs_app_pithy_print.cpp @@ -219,6 +219,13 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id) // for the rtc recv #define SRS_CONSTS_STAGE_RTC_RECV 14 +#ifdef SRS_SRT +// the pithy stage for srt play clients. +#define SRS_CONSTS_STAGE_SRT_PLAY 15 +// the pithy stage for srt publish clients. +#define SRS_CONSTS_STAGE_SRT_PUBLISH 16 +#endif + SrsPithyPrint* SrsPithyPrint::create_rtmp_play() { return new SrsPithyPrint(SRS_CONSTS_STAGE_PLAY_USER); @@ -289,6 +296,18 @@ SrsPithyPrint* SrsPithyPrint::create_rtc_recv(int fd) return new SrsPithyPrint(fd<<16 | SRS_CONSTS_STAGE_RTC_RECV); } +#ifdef SRS_SRT +SrsPithyPrint* SrsPithyPrint::create_srt_play() +{ + return new SrsPithyPrint(SRS_CONSTS_STAGE_SRT_PLAY); +} + +SrsPithyPrint* SrsPithyPrint::create_srt_publish() +{ + return new SrsPithyPrint(SRS_CONSTS_STAGE_SRT_PUBLISH); +} +#endif + 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 b0173f630be..961d13ed8c8 100644 --- a/trunk/src/app/srs_app_pithy_print.hpp +++ b/trunk/src/app/srs_app_pithy_print.hpp @@ -130,6 +130,10 @@ class SrsPithyPrint // 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); +#ifdef SRS_SRT + static SrsPithyPrint* create_srt_play(); + static SrsPithyPrint* create_srt_publish(); +#endif virtual ~SrsPithyPrint(); private: // Enter the specified stage, return the client id. diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp new file mode 100644 index 00000000000..a0a279c0700 --- /dev/null +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -0,0 +1,678 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SrsSrtConnection::SrsSrtConnection(SRTSOCKET srt_fd) +{ + srt_fd_ = srt_fd; + srt_skt_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_fd_); +} + +SrsSrtConnection::~SrsSrtConnection() +{ + srs_freep(srt_skt_); +} + +srs_error_t SrsSrtConnection::initialize() +{ + srs_error_t err = srs_success; + return err; +} + +void SrsSrtConnection::set_recv_timeout(srs_utime_t tm) +{ + srt_skt_->set_recv_timeout(tm); +} + +srs_utime_t SrsSrtConnection::get_recv_timeout() +{ + return srt_skt_->get_recv_timeout(); +} + +srs_error_t SrsSrtConnection::read_fully(void* buf, size_t size, ssize_t* nread) +{ + return srs_error_new(ERROR_SRT_CONN, "unsupport method"); +} + +int64_t SrsSrtConnection::get_recv_bytes() +{ + return srt_skt_->get_recv_bytes(); +} + +int64_t SrsSrtConnection::get_send_bytes() +{ + return srt_skt_->get_send_bytes(); +} + +srs_error_t SrsSrtConnection::read(void* buf, size_t size, ssize_t* nread) +{ + return srt_skt_->recvmsg(buf, size, nread); +} + +void SrsSrtConnection::set_send_timeout(srs_utime_t tm) +{ + srt_skt_->set_send_timeout(tm); +} + +srs_utime_t SrsSrtConnection::get_send_timeout() +{ + return srt_skt_->get_send_timeout(); +} + +srs_error_t SrsSrtConnection::write(void* buf, size_t size, ssize_t* nwrite) +{ + return srt_skt_->sendmsg(buf, size, nwrite); +} + +srs_error_t SrsSrtConnection::writev(const iovec *iov, int iov_size, ssize_t* nwrite) +{ + return srs_error_new(ERROR_SRT_CONN, "unsupport method"); +} + +SrsMpegtsSrtConn::SrsMpegtsSrtConn(SrsSrtServer* srt_server, SRTSOCKET srt_fd, std::string ip, int port) +{ + // Create a identify for this client. + _srs_context->set_id(_srs_context->generate_id()); + + srt_server_ = srt_server; + + srt_fd_ = srt_fd; + srt_conn_ = new SrsSrtConnection(srt_fd_); + clock_ = new SrsWallClock(); + kbps_ = new SrsKbps(clock_); + kbps_->set_io(srt_conn_, srt_conn_); + ip_ = ip; + port_ = port; + + trd_ = new SrsSTCoroutine("ts-srt", this, _srs_context->get_id()); + + srt_source_ = NULL; + req_ = new SrsRequest(); + mode_ = SrtModePull; +} + +SrsMpegtsSrtConn::~SrsMpegtsSrtConn() +{ + srs_freep(trd_); + + srs_freep(kbps_); + srs_freep(clock_); + + srs_freep(srt_conn_); + + srs_freep(req_); +} + +std::string SrsMpegtsSrtConn::desc() +{ + return "srt-ts-conn"; +} + +void SrsMpegtsSrtConn::remark(int64_t* in, int64_t* out) +{ + // TODO: FIXME: no impl currently. + kbps_->remark(in, out); +} + +srs_error_t SrsMpegtsSrtConn::start() +{ + srs_error_t err = srs_success; + + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "coroutine"); + } + + return err; +} + +std::string SrsMpegtsSrtConn::remote_ip() +{ + return ip_; +} + +const SrsContextId& SrsMpegtsSrtConn::get_id() +{ + return trd_->cid(); +} + +srs_error_t SrsMpegtsSrtConn::cycle() +{ + srs_error_t err = srs_success; + + err = do_cycle(); + + // Notify manager to remove it. + // Note that we create this object, so we use manager to remove it. + srt_server_->remove(this); + + // success. + if (err == srs_success) { + srs_trace("srt client finished."); + return err; + } + + srs_error("srt serve error %s", srs_error_desc(err).c_str()); + srs_freep(err); + return srs_success; +} + +srs_error_t SrsMpegtsSrtConn::do_cycle() +{ + srs_error_t err = srs_success; + + if ((err != fetch_or_create_source()) != srs_success) { + return srs_error_wrap(err, "fetch or create srt source"); + } + + if ((err = http_hooks_on_connect()) != srs_success) { + return srs_error_wrap(err, "on connect"); + } + + if (mode_ == SrtModePush) { + err = publishing(); + } else if (mode_ == SrtModePull) { + err = playing(); + } + + http_hooks_on_close(); + + return err; +} + +srs_error_t SrsMpegtsSrtConn::fetch_or_create_source() +{ + srs_error_t err = srs_success; + + string streamid = ""; + if ((err = srs_srt_get_streamid(srt_fd_, streamid)) != srs_success) { + return srs_error_wrap(err, "get srt streamid"); + } + + // Must have streamid, because srt ts packet will convert to rtmp or rtc. + if (streamid.empty()) { + return srs_error_new(ERROR_SRT_CONN, "empty srt streamid"); + } + + // Detect streamid of srt to request. + if (! srs_srt_streamid_to_request(streamid, mode_, req_)) { + return srs_error_new(ERROR_SRT_CONN, "invalid srt streamid=%s", streamid.c_str()); + } + + srs_trace("@srt, streamid=%s, stream_url=%s, vhost=%s, app=%s, stream=%s, param=%s", + streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); + + if ((err = _srs_srt_sources->fetch_or_create(req_, &srt_source_)) != srs_success) { + return srs_error_wrap(err, "fetch srt source"); + } + + return err; +} + +srs_error_t SrsMpegtsSrtConn::publishing() +{ + srs_error_t err = srs_success; + + if ((err = http_hooks_on_publish()) != srs_success) { + return srs_error_wrap(err, "srt: callback on publish"); + } + + if ((err = acquire_publish()) == srs_success) { + err = do_publishing(); + release_publish(); + } + + http_hooks_on_unpublish(); + + return err; +} + +srs_error_t SrsMpegtsSrtConn::playing() +{ + srs_error_t err = srs_success; + + if ((err = http_hooks_on_play()) != srs_success) { + return srs_error_wrap(err, "rtmp: callback on play"); + } + + err = do_playing(); + http_hooks_on_stop(); + + return err; +} + +srs_error_t SrsMpegtsSrtConn::acquire_publish() +{ + srs_error_t err = srs_success; + + // Check srt stream is busy. + if (! srt_source_->can_publish()) { + return srs_error_new(ERROR_SRT_SOURCE_BUSY, "srt stream %s busy", req_->get_stream_url().c_str()); + } + + // Check rtmp stream is busy. + SrsLiveSource *live_source = _srs_sources->fetch(req_); + if (live_source && !live_source->can_publish(false)) { + return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str()); + } + + if ((err = _srs_sources->fetch_or_create(req_, _srs_hybrid->srs()->instance(), &live_source)) != srs_success) { + return srs_error_wrap(err, "create source"); + } + + SrsRtmpFromTsBridge *bridger = new SrsRtmpFromTsBridge(live_source); + if ((err = bridger->initialize(req_)) != srs_success) { + srs_freep(bridger); + return srs_error_wrap(err, "create bridger"); + } + + srt_source_->set_bridger(bridger); + + if ((err = srt_source_->on_publish()) != srs_success) { + return srs_error_wrap(err, "srt source publish"); + } + + return err; +} + +void SrsMpegtsSrtConn::release_publish() +{ + srt_source_->on_unpublish(); +} + +/* +srs_error_t SrsMpegtsSrtConn::do_cycle() +{ + srs_error_t err = srs_success; + + string streamid = ""; + if ((err = srs_srt_get_streamid(srt_fd_, streamid)) != srs_success) { + return srs_error_wrap(err, "get srt streamid"); + } + + // Must have streamid, because srt ts packet will convert to rtmp or rtc. + if (streamid.empty()) { + return srs_error_new(ERROR_SRT_CONN, "empty srt streamid"); + } + + // Detect streamid of srt to request. + if (! srs_srt_streamid_to_request(streamid, mode_, req_)) { + return srs_error_new(ERROR_SRT_CONN, "invalid srt streamid=%s", streamid.c_str()); + } + + srs_trace("@srt, streamid=%s, stream_url=%s, vhost=%s, app=%s, stream=%s, param=%s", + streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); + + if ((err = _srs_srt_sources->fetch_or_create(req_, &srt_source_)) != srs_success) { + return srs_error_wrap(err, "fetch srt source"); + } + + if (mode_ == SrtModePush) { + if ((err = http_hooks_on_publish()) != srs_success) { + return srs_error_wrap(err, "srt: callback on publish"); + } + // Do srt publish. + if (! srt_source_->can_publish()) { + return srs_error_new(ERROR_SRT_SOURCE_BUSY, "srt stream %s busy", req_->get_stream_url().c_str()); + } + + SrsLiveSource *live_source = _srs_sources->fetch(req_); + if (live_source && !live_source->can_publish(false)) { + return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str()); + } + + if ((err = _srs_sources->fetch_or_create(req_, _srs_hybrid->srs()->instance(), &live_source)) != srs_success) { + return srs_error_wrap(err, "create source"); + } + + SrsRtmpFromTsBridge *bridger = new SrsRtmpFromTsBridge(live_source); + if ((err = bridger->initialize(req_)) != srs_success) { + srs_freep(bridger); + return srs_error_wrap(err, "create bridger"); + } + + srt_source_->set_bridger(bridger); + + if ((err = srt_source_->on_publish()) != srs_success) { + return srs_error_wrap(err, "srt source publish"); + } + + err = do_publish_cycle(); + + srt_source_->on_unpublish(); + http_hooks_on_unpublish(); + } else if (mode_ == SrtModePull) { + if ((err = http_hooks_on_play()) != srs_success) { + return srs_error_wrap(err, "srt: callback on play"); + } + // Do srt play. + err = do_play_cycle(); + + http_hooks_on_stop(); + } else { + srs_assert(false); + } + + return err; +} +*/ + +srs_error_t SrsMpegtsSrtConn::do_publishing() +{ + srs_error_t err = srs_success; + + SrsPithyPrint* pprint = SrsPithyPrint::create_srt_publish(); + SrsAutoFree(SrsPithyPrint, pprint); + + int nb_packets = 0; + + // Max udp packet size equal to 1500. + char buf[1500]; + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt: thread quit"); + } + + pprint->elapse(); + + // reportable + if (pprint->can_print()) { + kbps_->sample(); + srs_trace("<- " SRS_CONSTS_LOG_SRT_PUBLISH " time=%d, packets=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", + (int)pprint->age(), nb_packets, kbps_->get_send_kbps(), kbps_->get_send_kbps_30s(), kbps_->get_send_kbps_5m(), + kbps_->get_recv_kbps(), kbps_->get_recv_kbps_30s(), kbps_->get_recv_kbps_5m()); + nb_packets = 0; + } + + ssize_t nb = 0; + if ((err = srt_conn_->read(buf, sizeof(buf), &nb)) != srs_success) { + return srs_error_wrap(err, "srt: recvmsg"); + } + + ++nb_packets; + + if ((err = on_srt_packet(buf, nb)) != srs_success) { + return srs_error_wrap(err, "srt: process packet"); + } + } + + return err; +} + +srs_error_t SrsMpegtsSrtConn::do_playing() +{ + srs_error_t err = srs_success; + + SrsSrtConsumer* consumer = NULL; + SrsAutoFree(SrsSrtConsumer, consumer); + if ((err = srt_source_->create_consumer(consumer)) != srs_success) { + return srs_error_wrap(err, "create consumer, ts source=%s", req_->get_stream_url().c_str()); + } + + srs_assert(consumer); + + // TODO: FIXME: Dumps the SPS/PPS from gop cache, without other frames. + if ((err = srt_source_->consumer_dumps(consumer)) != srs_success) { + return srs_error_wrap(err, "dumps consumer, url=%s", req_->get_stream_url().c_str()); + } + + SrsPithyPrint* pprint = SrsPithyPrint::create_srt_play(); + SrsAutoFree(SrsPithyPrint, pprint); + + int nb_packets = 0; + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt play thread"); + } + + pprint->elapse(); + + // Wait for amount of packets. + SrsSrtPacket* pkt = NULL; + SrsAutoFree(SrsSrtPacket, pkt); + consumer->dump_packet(&pkt); + if (!pkt) { + // TODO: FIXME: We should check the quit event. + consumer->wait(1); + continue; + } + + // reportable + if (pprint->can_print()) { + kbps_->sample(); + srs_trace("-> " SRS_CONSTS_LOG_SRT_PLAY " time=%d, packets=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", + (int)pprint->age(), nb_packets, kbps_->get_send_kbps(), kbps_->get_send_kbps_30s(), kbps_->get_send_kbps_5m(), + kbps_->get_recv_kbps(), kbps_->get_recv_kbps_30s(), kbps_->get_recv_kbps_5m()); + nb_packets = 0; + } + + ++nb_packets; + + ssize_t nb_write = 0; + if ((err = srt_conn_->write(pkt->data(), pkt->size(), &nb_write)) != srs_success) { + return srs_error_wrap(err, "srt send, size=%d", pkt->size()); + } + } + + return err; +} + +srs_error_t SrsMpegtsSrtConn::on_srt_packet(char* buf, int nb_buf) +{ + srs_error_t err = srs_success; + + // Check srt payload, mpegts must be N times of SRS_TS_PACKET_SIZE, and the first byte must be 0x47 + if ((nb_buf <= 0) || (nb_buf % SRS_TS_PACKET_SIZE != 0) || (buf[0] != 0x47)) { + return srs_error_new(ERROR_SRT_CONN, "invalid ts packet"); + } + + SrsSrtPacket* packet = new SrsSrtPacket(); + SrsAutoFree(SrsSrtPacket, packet); + packet->wrap(buf, nb_buf); + + if ((err = srt_source_->on_packet(packet)) != srs_success) { + return srs_error_wrap(err, "on srt packet"); + } + + return err; +} + +srs_error_t SrsMpegtsSrtConn::http_hooks_on_connect() +{ + srs_error_t err = srs_success; + + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return err; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_connect(req_->vhost); + + if (!conf) { + return err; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + if ((err = SrsHttpHooks::on_connect(url, req_)) != srs_success) { + return srs_error_wrap(err, "srt on_connect %s", url.c_str()); + } + } + + return err; +} + +void SrsMpegtsSrtConn::http_hooks_on_close() +{ + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_close(req_->vhost); + + if (!conf) { + return; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + SrsHttpHooks::on_close(url, req_, kbps_->get_send_bytes(), kbps_->get_recv_bytes()); + } +} + +srs_error_t SrsMpegtsSrtConn::http_hooks_on_publish() +{ + srs_error_t err = srs_success; + + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return err; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_publish(req_->vhost); + + if (!conf) { + return err; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + if ((err = SrsHttpHooks::on_publish(url, req_)) != srs_success) { + return srs_error_wrap(err, "srt on_publish %s", url.c_str()); + } + } + + return err; +} + +void SrsMpegtsSrtConn::http_hooks_on_unpublish() +{ + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_unpublish(req_->vhost); + + if (!conf) { + return; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + SrsHttpHooks::on_unpublish(url, req_); + } +} + +srs_error_t SrsMpegtsSrtConn::http_hooks_on_play() +{ + srs_error_t err = srs_success; + + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return err; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_play(req_->vhost); + + if (!conf) { + return err; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + if ((err = SrsHttpHooks::on_play(url, req_)) != srs_success) { + return srs_error_wrap(err, "srt on_play %s", url.c_str()); + } + } + + return err; +} + +void SrsMpegtsSrtConn::http_hooks_on_stop() +{ + if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost)) { + return; + } + + // the http hooks will cause context switch, + // so we must copy all hooks for the on_connect may freed. + // @see https://github.com/ossrs/srs/issues/475 + vector hooks; + + if (true) { + SrsConfDirective* conf = _srs_config->get_vhost_on_stop(req_->vhost); + + if (!conf) { + return; + } + + hooks = conf->args; + } + + for (int i = 0; i < (int)hooks.size(); i++) { + std::string url = hooks.at(i); + SrsHttpHooks::on_stop(url, req_); + } + + return; +} diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp new file mode 100644 index 00000000000..351894f7087 --- /dev/null +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -0,0 +1,109 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_APP_SRT_CONN_HPP +#define SRS_APP_SRT_CONN_HPP + +#include + +#include +#include + +#include +#include +#include +#include + +class SrsBuffer; +class SrsLiveSource; +class SrsSrtSource; +class SrsSrtServer; + +// The basic connection of SRS, for SRT based protocols, +// all srt connections accept from srt listener must extends from this base class, +// srt server will add the connection to manager, and delete it when remove. +class SrsSrtConnection : public ISrsProtocolReadWriter +{ +public: + SrsSrtConnection(SRTSOCKET srt_fd); + virtual ~SrsSrtConnection(); +public: + virtual srs_error_t initialize(); +// Interface ISrsProtocolReadWriter +public: + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual srs_error_t read_fully(void* buf, size_t size, ssize_t* nread); + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + virtual srs_error_t read(void* buf, size_t size, ssize_t* nread); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual srs_error_t write(void* buf, size_t size, ssize_t* nwrite); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t* nwrite); +private: + // The underlayer srt fd handler. + SRTSOCKET srt_fd_; + // The underlayer srt socket. + SrsSrtSocket* srt_skt_; +}; + +class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHandler +{ +public: + SrsMpegtsSrtConn(SrsSrtServer* srt_server, SRTSOCKET srt_fd, std::string ip, int port); + virtual ~SrsMpegtsSrtConn(); +// Interface ISrsResource. +public: + virtual std::string desc(); +// Interface ISrsKbpsDelta +public: + virtual void remark(int64_t* in, int64_t* out); +public: + virtual srs_error_t start(); +// Interface ISrsConnection. +public: + virtual std::string remote_ip(); + virtual const SrsContextId& get_id(); +// Interface ISrsCoroutineHandler +public: + virtual srs_error_t cycle(); +protected: + virtual srs_error_t do_cycle(); +private: + srs_error_t fetch_or_create_source(); + srs_error_t publishing(); + srs_error_t playing(); + srs_error_t acquire_publish(); + void release_publish(); + srs_error_t do_publishing(); + srs_error_t do_playing(); +private: + srs_error_t on_srt_packet(char* buf, int nb_buf); +private: + srs_error_t http_hooks_on_connect(); + void http_hooks_on_close(); + srs_error_t http_hooks_on_publish(); + void http_hooks_on_unpublish(); + srs_error_t http_hooks_on_play(); + void http_hooks_on_stop(); +private: + SrsSrtServer* srt_server_; + SRTSOCKET srt_fd_; + SrsSrtConnection* srt_conn_; + SrsWallClock* clock_; + SrsKbps* kbps_; + std::string ip_; + int port_; + SrsCoroutine* trd_; + + SrsRequest* req_; + SrtMode mode_; + SrsSrtSource* srt_source_; +}; + +#endif + diff --git a/trunk/src/app/srs_app_srt_listener.cpp b/trunk/src/app/srs_app_srt_listener.cpp new file mode 100644 index 00000000000..f3b9951f4b9 --- /dev/null +++ b/trunk/src/app/srs_app_srt_listener.cpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +#include + +using namespace std; + +#include + +ISrsSrtHandler::ISrsSrtHandler() +{ +} + +ISrsSrtHandler::~ISrsSrtHandler() +{ +} + +SrsSrtListener::SrsSrtListener(ISrsSrtHandler* h, std::string i, int p) +{ + handler_ = h; + ip_ = i; + port_ = p; + + lfd_ = SRT_INVALID_SOCK; + srt_skt_ = NULL; + + trd_ = new SrsDummyCoroutine(); +} + +SrsSrtListener::~SrsSrtListener() +{ + srs_freep(trd_); + srs_freep(srt_skt_); + srt_close(lfd_); +} + +int SrsSrtListener::fd() +{ + return lfd_; +} + +srs_error_t SrsSrtListener::create_socket() +{ + srs_error_t err = srs_success; + if ((err = srs_srt_socket(&lfd_)) != srs_success) { + return srs_error_wrap(err, "create_socket"); + } + return err; +} + +srs_error_t SrsSrtListener::listen() +{ + srs_error_t err = srs_success; + + if ((err = srs_srt_listen(lfd_, ip_, port_)) != srs_success) { + return srs_error_wrap(err, "srs_srt_listen"); + } + + srt_skt_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), lfd_); + // Accept never timeout. + srt_skt_->set_recv_timeout(ST_UTIME_NO_TIMEOUT); + srt_skt_->set_send_timeout(ST_UTIME_NO_TIMEOUT); + + srs_freep(trd_); + trd_ = new SrsSTCoroutine("srt_listener", this); + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "start coroutine"); + } + + return err; +} + +srs_error_t SrsSrtListener::cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt listener"); + } + + SRTSOCKET client_srt_fd = SRT_INVALID_SOCK; + if ((err = srt_skt_->accept(&client_srt_fd)) != srs_success) { + return srs_error_wrap(err, "srt accept"); + } + + // TODO: FIXME: print some log and client srt options. + + if ((err = handler_->on_srt_client(client_srt_fd)) != srs_success) { + return srs_error_wrap(err, "handle srt fd=%d", client_srt_fd); + } + } + + return err; +} diff --git a/trunk/src/app/srs_app_srt_listener.hpp b/trunk/src/app/srs_app_srt_listener.hpp new file mode 100644 index 00000000000..6bd3e2501a3 --- /dev/null +++ b/trunk/src/app/srs_app_srt_listener.hpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_APP_SRT_LISTENER_HPP +#define SRS_APP_SRT_LISTENER_HPP + +#include +#include +#include + +#include + +// The srt connection handler. +class ISrsSrtHandler +{ +public: + ISrsSrtHandler(); + virtual ~ISrsSrtHandler(); +public: + // When got srt client. + virtual srs_error_t on_srt_client(SRTSOCKET srt_fd) = 0; +}; + +// Bind and listen SRT(udp) port, use handler to process the client. +class SrsSrtListener : public ISrsCoroutineHandler +{ +private: + SRTSOCKET lfd_; + SrsSrtSocket* srt_skt_; + SrsCoroutine* trd_; +private: + ISrsSrtHandler* handler_; + std::string ip_; + int port_; +public: + SrsSrtListener(ISrsSrtHandler* h, std::string i, int p); + virtual ~SrsSrtListener(); +public: + virtual SRTSOCKET fd(); +public: + // Create srt socket, separate this step because of srt have some option must set before listen. + virtual srs_error_t create_socket(); + virtual srs_error_t listen(); +// Interface ISrsReusableThreadHandler. +public: + virtual srs_error_t cycle(); +}; + +#endif + diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp new file mode 100644 index 00000000000..7e709706d15 --- /dev/null +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -0,0 +1,392 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +std::string srs_srt_listener_type2string(SrsSrtListenerType type) +{ + switch (type) { + case SrsSrtListenerMpegts: + return "SRT-MPEGTS"; + default: + return "UNKONWN"; + } +} + +SrsSrtAcceptor::SrsSrtAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType t) +{ + port_ = 0; + srt_server_ = srt_server; + type_ = t; +} + +SrsSrtAcceptor::~SrsSrtAcceptor() +{ +} + +SrsSrtListenerType SrsSrtAcceptor::listen_type() +{ + return type_; +} + +SrsSrtMessageAcceptor::SrsSrtMessageAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type) + : SrsSrtAcceptor(srt_server, listen_type) +{ + listener_ = NULL; +} + +SrsSrtMessageAcceptor::~SrsSrtMessageAcceptor() +{ + srs_freep(listener_); +} + +srs_error_t SrsSrtMessageAcceptor::listen(std::string ip, int port) +{ + srs_error_t err = srs_success; + + ip_ = ip; + port_ = port; + + srs_freep(listener_); + listener_ = new SrsSrtListener(this, ip_, port_); + + // Create srt socket. + if ((err = listener_->create_socket()) != srs_success) { + return srs_error_wrap(err, "message srt acceptor"); + } + + // Set all the srt option from config. + if ((err = set_srt_opt()) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + // Start listen srt socket, this function will set the socket in async mode. + if ((err = listener_->listen()) != srs_success) { + return srs_error_wrap(err, "message srt acceptor"); + } + + string v = srs_srt_listener_type2string(type_); + srs_trace("%s listen at srt://%s:%d, fd=%d", v.c_str(), ip_.c_str(), port_, listener_->fd()); + + return err; +} + +srs_error_t SrsSrtMessageAcceptor::set_srt_opt() +{ + srs_error_t err = srs_success; + + if ((err = srs_srt_set_maxbw(listener_->fd(), _srs_config->get_srto_maxbw())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_mss(listener_->fd(), _srs_config->get_srto_mss())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_tsbpdmode(listener_->fd(), _srs_config->get_srto_tsbpdmode())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_latency(listener_->fd(), _srs_config->get_srto_latency())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_rcv_latency(listener_->fd(), _srs_config->get_srto_recv_latency())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_peer_latency(listener_->fd(), _srs_config->get_srto_peer_latency())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_tlpktdrop(listener_->fd(), _srs_config->get_srto_tlpktdrop())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_connect_timeout(listener_->fd(), _srs_config->get_srto_conntimeout())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_peer_idle_timeout(listener_->fd(), _srs_config->get_srto_peeridletimeout())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_sndbuf(listener_->fd(), _srs_config->get_srto_sendbuf())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_rcvbuf(listener_->fd(), _srs_config->get_srto_recvbuf())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + if ((err = srs_srt_set_payload_size(listener_->fd(), _srs_config->get_srto_payloadsize())) != srs_success) { + return srs_error_wrap(err, "set opt"); + } + + return err; +} + +srs_error_t SrsSrtMessageAcceptor::on_srt_client(SRTSOCKET srt_fd) +{ + // Notify srt server to accept srt client, and create new SrsSrtConn on it. + srs_error_t err = srt_server_->accept_srt_client(type_, srt_fd); + if (err != srs_success) { + srs_warn("accept srt client failed, err is %s", srs_error_desc(err).c_str()); + srs_freep(err); + } + + return srs_success; +} + +SrsSrtServer::SrsSrtServer() +{ + conn_manager_ = new SrsResourceManager("SRT", true); +} + +SrsSrtServer::~SrsSrtServer() +{ + srs_freep(conn_manager_); +} + +srs_error_t SrsSrtServer::initialize() +{ + srs_error_t err = srs_success; + return err; +} + +srs_error_t SrsSrtServer::listen() +{ + srs_error_t err = srs_success; + + // Listen mpegts over srt. + if ((err = listen_srt_mpegts()) != srs_success) { + return srs_error_wrap(err, "srt mpegts listen"); + } + + if ((err = conn_manager_->start()) != srs_success) { + return srs_error_wrap(err, "srt connection manager"); + } + + return err; +} + +srs_error_t SrsSrtServer::listen_srt_mpegts() +{ + srs_error_t err = srs_success; + + if (! _srs_config->get_srt_enabled()) { + return err; + } + + // TODO: FIXME: bad code, refine it. + std::vector ip_ports; + std::stringstream ss; + ss << _srs_config->get_srt_listen_port(); + ip_ports.push_back(ss.str()); + + close_listeners(SrsSrtListenerMpegts); + + for (int i = 0; i < (int)ip_ports.size(); i++) { + SrsSrtAcceptor* acceptor = new SrsSrtMessageAcceptor(this, SrsSrtListenerMpegts); + acceptors_.push_back(acceptor); + + int port; string ip; + srs_parse_endpoint(ip_ports[i], ip, port); + + if ((err = acceptor->listen(ip, port)) != srs_success) { + return srs_error_wrap(err, "srt listen %s:%d", ip.c_str(), port); + } + } + + return err; +} + +void SrsSrtServer::close_listeners(SrsSrtListenerType type) +{ + std::vector::iterator it; + for (it = acceptors_.begin(); it != acceptors_.end();) { + SrsSrtAcceptor* acceptor = *it; + + if (acceptor->listen_type() != type) { + ++it; + continue; + } + + srs_freep(acceptor); + it = acceptors_.erase(it); + } +} + +srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, SRTSOCKET srt_fd) +{ + srs_error_t err = srs_success; + + ISrsStartableConneciton* conn = NULL; + + if ((err = fd_to_resource(type, srt_fd, &conn)) != srs_success) { + //close fd on conn error, otherwise will lead to fd leak -gs + srt_close(srt_fd); + return srs_error_wrap(err, "srt fd to resource"); + } + srs_assert(conn); + + // directly enqueue, the cycle thread will remove the client. + conn_manager_->add(conn); + + if ((err = conn->start()) != srs_success) { + return srs_error_wrap(err, "start srt conn coroutine"); + } + + return err; +} + +srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, SRTSOCKET srt_fd, ISrsStartableConneciton** pr) +{ + srs_error_t err = srs_success; + + string ip = ""; + int port = 0; + + if ((err = srs_srt_get_remote_ip_port(srt_fd, ip, port)) != srs_success) { + return srs_error_wrap(err, "get srt ip port"); + } + + srs_trace("accept srt client from %s:%d, fd=%d", ip.c_str(), port, srt_fd); + + // TODO: FIXME: need to check max connection? + + // The context id may change during creating the bellow objects. + SrsContextRestore(_srs_context->get_id()); + + if (type == SrsSrtListenerMpegts) { + *pr = new SrsMpegtsSrtConn(this, srt_fd, ip, port); + } else { + srs_warn("close for no service handler. srtfd=%d, ip=%s:%d", srt_fd, ip.c_str(), port); + srt_close(srt_fd); + return err; + } + + return err; +} + +void SrsSrtServer::remove(ISrsResource* c) +{ + // TODO: FIXME: add some statistic of srt. + // ISrsStartableConneciton* conn = dynamic_cast(c); + + // SrsStatistic* stat = SrsStatistic::instance(); + // stat->kbps_add_delta(c->get_id().c_str(), conn); + // stat->on_disconnect(c->get_id().c_str()); + + // use manager to free it async. + conn_manager_->remove(c); +} + +SrsSrtServerAdapter::SrsSrtServerAdapter() +{ + srt_server_ = new SrsSrtServer(); +} + +SrsSrtServerAdapter::~SrsSrtServerAdapter() +{ + srs_freep(srt_server_); +} + +srs_error_t SrsSrtServerAdapter::initialize() +{ + srs_error_t err = srs_success; + return err; +} + +srs_error_t SrsSrtServerAdapter::run(SrsWaitGroup* wg) +{ + srs_error_t err = srs_success; + + // Initialize the whole system, set hooks to handle server level events. + if ((err = srt_server_->initialize()) != srs_success) { + return srs_error_wrap(err, "srt server initialize"); + } + + if ((err = srt_server_->listen()) != srs_success) { + return srs_error_wrap(err, "srt listen"); + } + + return err; +} + +void SrsSrtServerAdapter::stop() +{ +} + +SrsSrtServer* SrsSrtServerAdapter::instance() +{ + return srt_server_; +} + +SrsSrtEventLoop::SrsSrtEventLoop() +{ + srt_poller_ = NULL; + trd_ = NULL; +} + +SrsSrtEventLoop::~SrsSrtEventLoop() +{ + srs_freep(trd_); + srs_freep(srt_poller_); +} + +srs_error_t SrsSrtEventLoop::initialize() +{ + srs_error_t err = srs_success; + + srt_poller_ = new SrsSrtPoller(); + + if ((err = srt_poller_->initialize()) != srs_success) { + return srs_error_wrap(err, "srt poller initialize"); + } + + return err; +} + +srs_error_t SrsSrtEventLoop::start() +{ + srs_error_t err = srs_success; + + trd_ = new SrsSTCoroutine("srt_listener", this); + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "start coroutine"); + } + + return err; +} + +srs_error_t SrsSrtEventLoop::cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt listener"); + } + + if ((err = srt_poller_->wait(0)) != srs_success) { + srs_error("srt poll wait failed, err=%s", srs_error_desc(err).c_str()); + srs_error_reset(err); + } + + srs_usleep(10 * SRS_UTIME_MILLISECONDS); + } + + return err; +} diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp new file mode 100644 index 00000000000..e3311a77ac3 --- /dev/null +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -0,0 +1,130 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_APP_SRT_SERVER_HPP +#define SRS_APP_SRT_SERVER_HPP + +#include + +#include +#include +#include + +class SrsSrtServer; + +enum SrsSrtListenerType +{ + SrsSrtListenerMpegts = 1, +}; + +// A common srt acceptor, for SRT server. +class SrsSrtAcceptor +{ +protected: + SrsSrtListenerType type_; +protected: + std::string ip_; + int port_; + SrsSrtServer* srt_server_; +public: + SrsSrtAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type); + virtual ~SrsSrtAcceptor(); +public: + virtual SrsSrtListenerType listen_type(); + virtual srs_error_t listen(std::string ip, int port) = 0; +}; + +// A srt messge acceptor. +class SrsSrtMessageAcceptor : public SrsSrtAcceptor, public ISrsSrtHandler +{ +private: + SrsSrtListener* listener_; +public: + SrsSrtMessageAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type); + virtual ~SrsSrtMessageAcceptor(); +public: + virtual srs_error_t listen(std::string i, int p); + virtual srs_error_t set_srt_opt(); +// Interface ISrsSrtHandler +public: + virtual srs_error_t on_srt_client(SRTSOCKET srt_fd); +}; + +// SRS SRT server, initialize and listen, start connection service thread, destroy client. +class SrsSrtServer : public ISrsResourceManager +{ +private: + SrsResourceManager* conn_manager_; +private: + std::vector acceptors_; +public: + SrsSrtServer(); + virtual ~SrsSrtServer(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t listen(); +private: + // listen at specified srt protocol. + virtual srs_error_t listen_srt_mpegts(); + // Close the listeners for specified type, + // Remove the listen object from manager. + virtual void close_listeners(SrsSrtListenerType type); +// For internal only +public: + // When listener got a fd, notice server to accept it. + // @param type, the client type, used to create concrete connection, + // for instance SRT connection to serve client. + // @param srt_fd, the client fd in srt boxed, the underlayer fd. + virtual srs_error_t accept_srt_client(SrsSrtListenerType type, SRTSOCKET srt_fd); +private: + virtual srs_error_t fd_to_resource(SrsSrtListenerType type, SRTSOCKET srt_fd, ISrsStartableConneciton** pr); +// Interface ISrsResourceManager +public: + // A callback for connection to remove itself. + // When connection thread cycle terminated, callback this to delete connection. + virtual void remove(ISrsResource* c); +}; + +// The srt server adapter, the master server. +class SrsSrtServerAdapter : public ISrsHybridServer +{ +private: + SrsSrtServer* srt_server_; +public: + SrsSrtServerAdapter(); + virtual ~SrsSrtServerAdapter(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t run(SrsWaitGroup* wg); + virtual void stop(); +public: + virtual SrsSrtServer* instance(); +}; + +// The srt event loop, run srt poller and wait event happeed. +class SrsSrtEventLoop : public ISrsCoroutineHandler +{ +public: + SrsSrtEventLoop(); + virtual ~SrsSrtEventLoop(); +public: + SrsSrtPoller* get_srt_poller() { return srt_poller_; } +public: + srs_error_t initialize(); + srs_error_t start(); +// Interface ISrsCoroutineHandler. +public: + virtual srs_error_t cycle(); +private: + SrsSrtPoller* srt_poller_; + SrsCoroutine* trd_; +}; + +// SrsSrtEventLoop is global singleton instance. +extern SrsSrtEventLoop* _srt_eventloop; + +#endif + diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp new file mode 100644 index 00000000000..f3025ca4a45 --- /dev/null +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -0,0 +1,798 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SrsSrtPacket::SrsSrtPacket() +{ + shared_buffer_ = NULL; + actual_buffer_size_ = 0; +} + +SrsSrtPacket::~SrsSrtPacket() +{ + srs_freep(shared_buffer_); +} + +char* SrsSrtPacket::wrap(int size) +{ + // The buffer size is larger or equals to the size of packet. + actual_buffer_size_ = size; + + // If the buffer is large enough, reuse it. + if (shared_buffer_ && shared_buffer_->size >= size) { + return shared_buffer_->payload; + } + + // Create a large enough message, with under-layer buffer. + srs_freep(shared_buffer_); + shared_buffer_ = new SrsSharedPtrMessage(); + + char* buf = new char[size]; + shared_buffer_->wrap(buf, size); + + return shared_buffer_->payload; +} + +char* SrsSrtPacket::wrap(char* data, int size) +{ + char* buf = wrap(size); + memcpy(buf, data, size); + return buf; +} + +char* SrsSrtPacket::wrap(SrsSharedPtrMessage* msg) +{ + // Generally, the wrap(msg) is used for RTMP to SRT, where the msg + // is not generated by SRT. + srs_freep(shared_buffer_); + + // Copy from the new message. + shared_buffer_ = msg->copy(); + // If we wrap a message, the size of packet equals to the message size. + actual_buffer_size_ = shared_buffer_->size; + + return msg->payload; +} + +SrsSrtPacket* SrsSrtPacket::copy() +{ + SrsSrtPacket* cp = new SrsSrtPacket(); + + cp->shared_buffer_ = shared_buffer_? shared_buffer_->copy2() : NULL; + cp->actual_buffer_size_ = actual_buffer_size_; + + return cp; +} + +char* SrsSrtPacket::data() +{ + return shared_buffer_->payload; +} + +int SrsSrtPacket::size() +{ + return shared_buffer_->size; +} + +SrsSrtSourceManager::SrsSrtSourceManager() +{ + lock = srs_mutex_new(); +} + +SrsSrtSourceManager::~SrsSrtSourceManager() +{ + srs_mutex_destroy(lock); +} + +srs_error_t SrsSrtSourceManager::fetch_or_create(SrsRequest* r, SrsSrtSource** pps) +{ + srs_error_t err = srs_success; + + // Use lock to protect coroutine switch. + // @bug https://github.com/ossrs/srs/issues/1230 + SrsLocker(lock); + + SrsSrtSource* source = NULL; + if ((source = fetch(r)) != NULL) { + // we always update the request of resource, + // for origin auth is on, the token in request maybe invalid, + // and we only need to update the token of request, it's simple. + source->update_auth(r); + *pps = source; + return err; + } + + string stream_url = r->get_stream_url(); + string vhost = r->vhost; + + // should always not exists for create a source. + srs_assert (pool.find(stream_url) == pool.end()); + + srs_trace("new ts source, stream_url=%s", stream_url.c_str()); + + source = new SrsSrtSource(); + if ((err = source->initialize(r)) != srs_success) { + return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); + } + + pool[stream_url] = source; + + *pps = source; + + return err; +} + +SrsSrtSource* SrsSrtSourceManager::fetch(SrsRequest* r) +{ + SrsSrtSource* source = NULL; + + string stream_url = r->get_stream_url(); + if (pool.find(stream_url) == pool.end()) { + return NULL; + } + + source = pool[stream_url]; + + return source; +} + +SrsSrtSourceManager* _srs_srt_sources = NULL; + +SrsSrtConsumer::SrsSrtConsumer(SrsSrtSource* s) +{ + source = s; + should_update_source_id = false; + + mw_wait = srs_cond_new(); + mw_min_msgs = 0; + mw_waiting = false; +} + +SrsSrtConsumer::~SrsSrtConsumer() +{ + source->on_consumer_destroy(this); + + vector::iterator it; + for (it = queue.begin(); it != queue.end(); ++it) { + SrsSrtPacket* pkt = *it; + srs_freep(pkt); + } + + srs_cond_destroy(mw_wait); +} + +void SrsSrtConsumer::update_source_id() +{ + should_update_source_id = true; +} + +srs_error_t SrsSrtConsumer::enqueue(SrsSrtPacket* packet) +{ + srs_error_t err = srs_success; + + queue.push_back(packet); + + if (mw_waiting) { + if ((int)queue.size() > mw_min_msgs) { + srs_cond_signal(mw_wait); + mw_waiting = false; + return err; + } + } + + return err; +} + +srs_error_t SrsSrtConsumer::dump_packet(SrsSrtPacket** ppkt) +{ + srs_error_t err = srs_success; + + if (should_update_source_id) { + srs_trace("update source_id=%s/%s", source->source_id().c_str(), source->pre_source_id().c_str()); + should_update_source_id = false; + } + + // TODO: FIXME: Refine performance by ring buffer. + if (!queue.empty()) { + *ppkt = queue.front(); + queue.erase(queue.begin()); + } + + return err; +} + +void SrsSrtConsumer::wait(int nb_msgs) +{ + mw_min_msgs = nb_msgs; + + // when duration ok, signal to flush. + if ((int)queue.size() > mw_min_msgs) { + return; + } + + // the enqueue will notify this cond. + mw_waiting = true; + + // use cond block wait for high performance mode. + srs_cond_wait(mw_wait); +} + +ISrsTsSourceBridger::ISrsTsSourceBridger() +{ +} + +ISrsTsSourceBridger::~ISrsTsSourceBridger() +{ +} + +SrsRtmpFromTsBridge::SrsRtmpFromTsBridge(SrsLiveSource* source) +{ + ts_ctx_ = new SrsTsContext(); + + sps_pps_change_ = false; + sps_ = ""; + pps_ = ""; + + live_source_ = source; + req_ = NULL; +} + +SrsRtmpFromTsBridge::~SrsRtmpFromTsBridge() +{ + srs_freep(ts_ctx_); + srs_freep(req_); +} + +srs_error_t SrsRtmpFromTsBridge::on_publish() +{ + srs_error_t err = srs_success; + + if ((err = live_source_->on_publish()) != srs_success) { + return srs_error_wrap(err, "on publish"); + } + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_packet(SrsSrtPacket *pkt) +{ + srs_error_t err = srs_success; + + char* buf = pkt->data(); + int nb_buf = pkt->size(); + + // use stream to parse ts packet. + int nb_packet = nb_buf / SRS_TS_PACKET_SIZE; + for (int i = 0; i < nb_packet; i++) { + char* p = buf + (i * SRS_TS_PACKET_SIZE); + + SrsBuffer* stream = new SrsBuffer(p, SRS_TS_PACKET_SIZE); + SrsAutoFree(SrsBuffer, stream); + + // process each ts packet + if ((err = ts_ctx_->decode(stream, this)) != srs_success) { + srs_warn("parse ts packet err=%s", srs_error_desc(err).c_str()); + srs_error_reset(err); + continue; + } + } + + return err; +} + +void SrsRtmpFromTsBridge::on_unpublish() +{ + live_source_->on_unpublish(); +} + +srs_error_t SrsRtmpFromTsBridge::initialize(SrsRequest* req) +{ + srs_error_t err = srs_success; + + // TODO: FIXME: check srt2rtmp enable in config. + req_ = req->copy(); + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_ts_message(SrsTsMessage* msg) +{ + srs_error_t err = srs_success; + + // When the audio SID is private stream 1, we use common audio. + // @see https://github.com/ossrs/srs/issues/740 + if (msg->channel->apply == SrsTsPidApplyAudio && msg->sid == SrsTsPESStreamIdPrivateStream1) { + msg->sid = SrsTsPESStreamIdAudioCommon; + } + + // when not audio/video, or not adts/annexb format, donot support. + if (msg->stream_number() != 0) { + return srs_error_new(ERROR_STREAM_CASTER_TS_ES, "ts: unsupported stream format, sid=%#x(%s-%d)", + msg->sid, msg->is_audio()? "A":msg->is_video()? "V":"N", msg->stream_number()); + } + + // check supported codec + if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamAudioAAC) { + return srs_error_new(ERROR_STREAM_CASTER_TS_CODEC, "ts: unsupported stream codec=%d", msg->channel->stream); + } + + // parse the stream. + SrsBuffer avs(msg->payload->bytes(), msg->payload->length()); + + // publish audio or video. + if (msg->channel->stream == SrsTsStreamVideoH264) { + if ((err = on_ts_video(msg, &avs)) != srs_success) { + return srs_error_wrap(err, "ts: consume video"); + } + } + if (msg->channel->stream == SrsTsStreamAudioAAC) { + if ((err = on_ts_audio(msg, &avs)) != srs_success) { + return srs_error_wrap(err, "ts: consume audio"); + } + } + + // TODO: FIXME: implements other codec? + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) +{ + srs_error_t err = srs_success; + + vector > ipb_frames; + + SrsRawH264Stream* avc = new SrsRawH264Stream(); + SrsAutoFree(SrsRawH264Stream, avc); + + // send each frame. + while (!avs->empty()) { + char* frame = NULL; + int frame_size = 0; + if ((err = avc->annexb_demux(avs, &frame, &frame_size)) != srs_success) { + return srs_error_wrap(err, "demux annexb"); + } + + // 5bits, 7.3.1 NAL unit syntax, + // ISO_IEC_14496-10-AVC-2003.pdf, page 44. + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); + + // ignore the nalu type sps(7), pps(8), aud(9) + if (nal_unit_type == SrsAvcNaluTypeAccessUnitDelimiter) { + continue; + } + + // for sps + if (avc->is_sps(frame, frame_size)) { + std::string sps; + if ((err = avc->sps_demux(frame, frame_size, sps)) != srs_success) { + return srs_error_wrap(err, "demux sps"); + } + + if (! sps.empty() && sps_ != sps) { + sps_pps_change_ = true; + } + + sps_ = sps; + continue; + } + + // for pps + if (avc->is_pps(frame, frame_size)) { + std::string pps; + if ((err = avc->pps_demux(frame, frame_size, pps)) != srs_success) { + return srs_error_wrap(err, "demux pps"); + } + + if (! pps.empty() && pps_ != pps) { + sps_pps_change_ = true; + } + + pps_ = pps; + continue; + } + + ipb_frames.push_back(make_pair(frame, frame_size)); + } + + if ((err = check_sps_pps_change(msg)) != srs_success) { + return srs_error_wrap(err, "check sps pps"); + } + + return on_h264_frame(msg, ipb_frames); +} + +srs_error_t SrsRtmpFromTsBridge::check_sps_pps_change(SrsTsMessage* msg) +{ + srs_error_t err = srs_success; + + if (! sps_pps_change_) { + return err; + } + + // sps/pps changed, generate new video sh frame and dispatch it. + sps_pps_change_ = false; + + // ts tbn to flv tbn. + uint32_t dts = (uint32_t)(msg->dts / 90); + + //type_codec1 + avc_type + composition time + fix header + count of sps + len of sps + sps + count of pps + len of pps + pps + int nb_payload = 1 + 1 + 3 + 5 + 1 + 2 + sps_.size() + 1 + 2 + pps_.size(); + SrsCommonMessage rtmp; + rtmp.header.initialize_video(nb_payload, dts, 1); + rtmp.create_payload(nb_payload); + rtmp.size = nb_payload; + SrsBuffer payload(rtmp.payload, rtmp.size); + //TODO: call api + payload.write_1bytes(0x17);// type(4 bits): key frame; code(4bits): avc + payload.write_1bytes(0x0); // avc_type: sequence header + payload.write_1bytes(0x0); // composition time + payload.write_1bytes(0x0); + payload.write_1bytes(0x0); + payload.write_1bytes(0x01); // version + payload.write_1bytes(sps_[1]); + payload.write_1bytes(sps_[2]); + payload.write_1bytes(sps_[3]); + payload.write_1bytes(0xff); + payload.write_1bytes(0xe1); + payload.write_2bytes(sps_.size()); + payload.write_bytes((char*)sps_.data(), sps_.size()); + payload.write_1bytes(0x01); + payload.write_2bytes(pps_.size()); + payload.write_bytes((char*)pps_.data(), pps_.size()); + if ((err = live_source_->on_video(&rtmp)) != srs_success) { + return srs_error_wrap(err, "srt to rtmp sps/pps"); + } + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_h264_frame(SrsTsMessage* msg, vector >& ipb_frames) +{ + srs_error_t err = srs_success; + + if (ipb_frames.empty()) { + return srs_error_new(ERROR_SRT_CONN, "empty frame"); + } + + bool is_keyframe = false; + + // ts tbn to flv tbn. + uint32_t dts = (uint32_t)(msg->dts / 90); + uint32_t pts = (uint32_t)(msg->pts / 90); + int32_t cts = pts - dts; + + int frame_size = 5; // 5bytes video tag header + for (size_t i = 0; i != ipb_frames.size(); ++i) { + // 4 bytes for nalu length. + frame_size += 4 + ipb_frames[i].second; + if (((SrsAvcNaluType)(ipb_frames[i].first[0] & 0x1f)) == SrsAvcNaluTypeIDR) { + is_keyframe = true; + } + } + + SrsCommonMessage rtmp; + rtmp.header.initialize_video(frame_size, dts, 1/*streamid*/); + rtmp.create_payload(frame_size); + rtmp.size = frame_size; + SrsBuffer payload(rtmp.payload, rtmp.size); + // Write 5bytes video tag header. + if (is_keyframe) { + payload.write_1bytes(0x17); // type(4 bits): key frame; code(4bits): avc + } else { + payload.write_1bytes(0x27); // type(4 bits): inter frame; code(4bits): avc + } + payload.write_1bytes(0x01); // avc_type: nalu + payload.write_3bytes(cts); // composition time + + // Write video nalus. + for (size_t i = 0; i != ipb_frames.size(); ++i) { + char* nal = ipb_frames[i].first; + int nal_size = ipb_frames[i].second; + + // write 4 bytes of nalu length. + payload.write_4bytes(nal_size); + // write nalu + payload.write_bytes(nal, nal_size); + } + + if ((err = live_source_->on_video(&rtmp)) != srs_success) { + return srs_error_wrap(err ,"srt ts video to rtmp"); + } + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs) +{ + srs_error_t err = srs_success; + + SrsRawAacStream* aac = new SrsRawAacStream(); + SrsAutoFree(SrsRawAacStream, aac); + + // ts tbn to flv tbn. + uint32_t pts = (uint32_t)(msg->pts / 90); + + int frame_idx = 0; + + // send each frame. + while (!avs->empty()) { + char* frame = NULL; + int frame_size = 0; + SrsRawAacStreamCodec codec; + if ((err = aac->adts_demux(avs, &frame, &frame_size, codec)) != srs_success) { + return srs_error_wrap(err, "demux adts"); + } + + // ignore invalid frame, + // * atleast 1bytes for aac to decode the data. + if (frame_size <= 0) { + continue; + } + + std::string sh; + if ((err = aac->mux_sequence_header(&codec, sh)) != srs_success) { + return srs_error_wrap(err, "mux sequence header"); + } + + if (! sh.empty() && sh != audio_sh_) { + audio_sh_ = sh; + audio_sh_change_ = true; + } + + // May have more than one aac frame in PES packet, and shared same timestamp, + // so we must calculate each aac frame's timestamp. + int sample_rate = 44100; + switch (codec.sound_rate) { + case SrsAudioSampleRate5512: sample_rate = 5512; break; + case SrsAudioSampleRate11025: sample_rate = 11025; break; + case SrsAudioSampleRate22050: sample_rate = 22050; break; + case SrsAudioSampleRate44100: + default: sample_rate = 44100; break; + } + uint32_t frame_pts = (double)pts + (frame_idx * (1024.0 * 1000.0 / sample_rate)); + ++frame_idx; + + if ((err = check_audio_sh_change(msg, frame_pts)) != srs_success) { + return srs_error_wrap(err, "audio sh"); + } + + if ((err = on_aac_frame(msg, frame_pts, frame, frame_size)) != srs_success) { + return srs_error_wrap(err, "audio frame"); + } + } + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::check_audio_sh_change(SrsTsMessage* msg, uint32_t pts) +{ + srs_error_t err = srs_success; + + if (! audio_sh_change_) { + return err; + } + + // audio specific config changed, generate new audio sh and dispatch it. + audio_sh_change_ = false; + + int rtmp_len = audio_sh_.size() + 2; + + SrsCommonMessage rtmp; + rtmp.header.initialize_audio(rtmp_len, pts, 1); + rtmp.create_payload(rtmp_len); + rtmp.size = rtmp_len; + + SrsBuffer stream(rtmp.payload, rtmp_len); + uint8_t aac_flag = (SrsAudioCodecIdAAC << 4) | (SrsAudioSampleRate44100 << 2) | (SrsAudioSampleBits16bit << 1) | SrsAudioChannelsStereo; + stream.write_1bytes(aac_flag); + stream.write_1bytes(0); + stream.write_bytes((char*)audio_sh_.data(), audio_sh_.size()); + + if ((err = live_source_->on_audio(&rtmp)) != srs_success) { + return srs_error_wrap(err, "srt to rtmp audio sh"); + } + + return err; +} + +srs_error_t SrsRtmpFromTsBridge::on_aac_frame(SrsTsMessage* msg, uint32_t pts, char* frame, int frame_size) +{ + srs_error_t err = srs_success; + + int rtmp_len = frame_size + 2/* 2 bytes of flv audio tag header*/; + + SrsCommonMessage rtmp; + rtmp.header.initialize_audio(rtmp_len, pts, 2/*streamid*/); + rtmp.create_payload(rtmp_len); + rtmp.size = rtmp_len; + + SrsBuffer stream(rtmp.payload, rtmp_len); + uint8_t aac_flag = (SrsAudioCodecIdAAC << 4) | (SrsAudioSampleRate44100 << 2) | (SrsAudioSampleBits16bit << 1) | SrsAudioChannelsStereo; + // Write 2bytes audio tag header. + stream.write_1bytes(aac_flag); + stream.write_1bytes(1); + // Write audio frame. + stream.write_bytes(frame, frame_size); + + if ((err = live_source_->on_audio(&rtmp)) != srs_success) { + return srs_error_wrap(err, "srt to rtmp audio sh"); + } + + return err; +} + +SrsSrtSource::SrsSrtSource() +{ + req = NULL; + can_publish_ = true; + bridger_ = NULL; +} + +SrsSrtSource::~SrsSrtSource() +{ + // never free the consumers, + // for all consumers are auto free. + consumers.clear(); + + srs_freep(bridger_); +} + +srs_error_t SrsSrtSource::initialize(SrsRequest* r) +{ + srs_error_t err = srs_success; + + req = r->copy(); + + return err; +} + +srs_error_t SrsSrtSource::on_source_id_changed(SrsContextId id) +{ + srs_error_t err = srs_success; + + if (!_source_id.compare(id)) { + return err; + } + + if (_pre_source_id.empty()) { + _pre_source_id = id; + } + _source_id = id; + + // notice all consumer + std::vector::iterator it; + for (it = consumers.begin(); it != consumers.end(); ++it) { + SrsSrtConsumer* consumer = *it; + consumer->update_source_id(); + } + + return err; +} + +SrsContextId SrsSrtSource::source_id() +{ + return _source_id; +} + +SrsContextId SrsSrtSource::pre_source_id() +{ + return _pre_source_id; +} + +void SrsSrtSource::update_auth(SrsRequest* r) +{ + req->update_auth(r); +} + +void SrsSrtSource::set_bridger(ISrsTsSourceBridger *bridger) +{ + srs_freep(bridger_); + bridger_ = bridger; +} + +srs_error_t SrsSrtSource::create_consumer(SrsSrtConsumer*& consumer) +{ + srs_error_t err = srs_success; + + consumer = new SrsSrtConsumer(this); + consumers.push_back(consumer); + + return err; +} + +srs_error_t SrsSrtSource::consumer_dumps(SrsSrtConsumer* consumer) +{ + srs_error_t err = srs_success; + + // print status. + srs_trace("create ts consumer, no gop cache"); + + return err; +} + +void SrsSrtSource::on_consumer_destroy(SrsSrtConsumer* consumer) +{ + std::vector::iterator it; + it = std::find(consumers.begin(), consumers.end(), consumer); + if (it != consumers.end()) { + consumers.erase(it); + } +} + +bool SrsSrtSource::can_publish() +{ + return can_publish_; +} + +srs_error_t SrsSrtSource::on_publish() +{ + srs_error_t err = srs_success; + + can_publish_ = false; + + if ((err = on_source_id_changed(_srs_context->get_id())) != srs_success) { + return srs_error_wrap(err, "source id change"); + } + + if (bridger_) { + if ((err = bridger_->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridger on publish"); + } + } + + SrsStatistic* stat = SrsStatistic::instance(); + stat->on_stream_publish(req, _source_id.c_str()); + + return err; +} + +void SrsSrtSource::on_unpublish() +{ + // ignore when already unpublished. + if (can_publish_) { + return; + } + + can_publish_ = true; + + if (bridger_) { + bridger_->on_unpublish(); + srs_freep(bridger_); + } +} + +srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) +{ + srs_error_t err = srs_success; + + for (int i = 0; i < (int)consumers.size(); i++) { + SrsSrtConsumer* consumer = consumers.at(i); + if ((err = consumer->enqueue(packet->copy())) != srs_success) { + return srs_error_wrap(err, "consume ts packet"); + } + } + + if (bridger_ && (err = bridger_->on_packet(packet)) != srs_success) { + return srs_error_wrap(err, "bridger consume message"); + } + + return err; +} diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp new file mode 100644 index 00000000000..d285143c9c5 --- /dev/null +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -0,0 +1,205 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_APP_SRT_SOURCE_HPP +#define SRS_APP_SRT_SOURCE_HPP + +#include + +#include +#include + +#include +#include + +class SrsSharedPtrMessage; +class SrsRequest; +class SrsLiveSource; +class SrsSrtSource; + +// The SRT packet with shared message. +class SrsSrtPacket +{ +public: + SrsSrtPacket(); + virtual ~SrsSrtPacket(); +public: + // Wrap buffer to shared_message, which is managed by us. + char* wrap(int size); + char* wrap(char* data, int size); + // Wrap the shared message, we copy it. + char* wrap(SrsSharedPtrMessage* msg); + // Copy the SRT packet. + virtual SrsSrtPacket* copy(); +public: + char* data(); + int size(); +private: + SrsSharedPtrMessage* shared_buffer_; + // The size of SRT packet or SRT payload. + int actual_buffer_size_; +}; + +class SrsSrtSourceManager +{ +private: + srs_mutex_t lock; + std::map pool; +public: + SrsSrtSourceManager(); + virtual ~SrsSrtSourceManager(); +public: + // create source when fetch from cache failed. + // @param r the client request. + // @param pps the matched source, if success never be NULL. + virtual srs_error_t fetch_or_create(SrsRequest* r, SrsSrtSource** pps); +public: + // Get the exists source, NULL when not exists. + virtual SrsSrtSource* fetch(SrsRequest* r); +}; + +// Global singleton instance. +extern SrsSrtSourceManager* _srs_srt_sources; + +class SrsSrtConsumer +{ +public: + SrsSrtConsumer(SrsSrtSource* source); + virtual ~SrsSrtConsumer(); +private: + SrsSrtSource* source; + std::vector queue; + // when source id changed, notice all consumers + bool should_update_source_id; + // The cond wait for mw. + srs_cond_t mw_wait; + bool mw_waiting; + int mw_min_msgs; +public: + // When source id changed, notice client to print. + void update_source_id(); + // Put SRT packet into queue. + srs_error_t enqueue(SrsSrtPacket* packet); + // For SRT, we only got one packet, because there is not many packets in queue. + virtual srs_error_t dump_packet(SrsSrtPacket** ppkt); + // Wait for at-least some messages incoming in queue. + virtual void wait(int nb_msgs); +}; + +class ISrsTsSourceBridger +{ +public: + ISrsTsSourceBridger(); + virtual ~ISrsTsSourceBridger(); +public: + virtual srs_error_t on_publish() = 0; + virtual srs_error_t on_packet(SrsSrtPacket *pkt) = 0; + virtual void on_unpublish() = 0; +}; + +class SrsRtmpFromTsBridge : public ISrsTsSourceBridger, public ISrsTsHandler +{ +public: + SrsRtmpFromTsBridge(SrsLiveSource* source); + virtual ~SrsRtmpFromTsBridge(); +public: + virtual srs_error_t on_publish(); + virtual srs_error_t on_packet(SrsSrtPacket *pkt); + virtual void on_unpublish(); +public: + srs_error_t initialize(SrsRequest* req); +// Interface ISrsTsHandler +public: + virtual srs_error_t on_ts_message(SrsTsMessage* msg); +private: + srs_error_t on_ts_video(SrsTsMessage* msg, SrsBuffer* avs); + srs_error_t on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs); + srs_error_t check_sps_pps_change(SrsTsMessage* msg); + srs_error_t on_h264_frame(SrsTsMessage* msg, std::vector >& ipb_frames); + srs_error_t check_audio_sh_change(SrsTsMessage* msg, uint32_t pts); + srs_error_t on_aac_frame(SrsTsMessage* msg, uint32_t pts, char* frame, int frame_size); +private: + SrsTsContext* ts_ctx_; + + // Record sps/pps had changed, if change, need to generate new video sh frame. + bool sps_pps_change_; + std::string sps_; + std::string pps_; + + // Record audio sepcific config had changed, if change, need to generate new audio sh frame. + bool audio_sh_change_; + std::string audio_sh_; + + SrsRequest* req_; + SrsLiveSource* live_source_; +}; + +class SrsSrtSource +{ +public: + SrsSrtSource(); + virtual ~SrsSrtSource(); +public: + virtual srs_error_t initialize(SrsRequest* r); +public: + // The source id changed. + virtual srs_error_t on_source_id_changed(SrsContextId id); + // Get current source id. + virtual SrsContextId source_id(); + virtual SrsContextId pre_source_id(); + // Update the authentication information in request. + virtual void update_auth(SrsRequest* r); +public: + void set_bridger(ISrsTsSourceBridger *bridger); +public: + // Create consumer + // @param consumer, output the create consumer. + virtual srs_error_t create_consumer(SrsSrtConsumer*& consumer); + // Dumps packets in cache to consumer. + virtual srs_error_t consumer_dumps(SrsSrtConsumer* consumer); + virtual void on_consumer_destroy(SrsSrtConsumer* consumer); + // Whether we can publish stream to the source, return false if it exists. + virtual bool can_publish(); + // When start publish stream. + virtual srs_error_t on_publish(); + // When stop publish stream. + virtual void on_unpublish(); +public: + srs_error_t on_packet(SrsSrtPacket* packet); +private: + // Source id. + SrsContextId _source_id; + // previous source id. + SrsContextId _pre_source_id; + SrsRequest* req; + // To delivery packets to clients. + std::vector consumers; + bool can_publish_; + ISrsTsSourceBridger* bridger_; +}; + +/* +class SrsTsFromRtmpBridger : public ISrsLiveSourceBridger +{ +private: + SrsRequest* req; + SrsSrtSource* source_; +public: + SrsTsFromRtmpBridger(SrsSrtSource* source); + virtual ~SrsTsFromRtmpBridger(); +public: + virtual srs_error_t initialize(SrsRequest* r); +// Interface for ISrsLiveSourceBridger +public: + virtual srs_error_t on_publish(); + virtual void on_unpublish(); + virtual srs_error_t on_audio(SrsSharedPtrMessage* msg); + virtual srs_error_t on_video(SrsSharedPtrMessage* msg); +}; +*/ + +#endif + diff --git a/trunk/src/app/srs_app_srt_utility.cpp b/trunk/src/app/srs_app_srt_utility.cpp new file mode 100644 index 00000000000..5bb26ef2e1c --- /dev/null +++ b/trunk/src/app/srs_app_srt_utility.cpp @@ -0,0 +1,143 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include + +// See streamid of https://github.com/ossrs/srs/issues/2893 +// TODO: FIMXE: We should parse SRT streamid to URL object, rather than a HTTP url subpath. +bool srs_srt_streamid_info(const std::string& streamid, SrtMode& mode, std::string& vhost, std::string& url_subpath) +{ + mode = SrtModePull; + + size_t pos = streamid.find("#!::"); + if (pos != 0) { + pos = streamid.find("/"); + if (pos == streamid.npos) { + url_subpath = _srs_config->get_default_app_name() + "/" + streamid; + return true; + } + url_subpath = streamid; + return true; + } + + //SRT url supports multiple QueryStrings, which are passed to RTMP to realize authentication and other capabilities + //@see https://github.com/ossrs/srs/issues/2893 + std::string params; + std::string real_streamid; + real_streamid = streamid.substr(4); + + // Compatible with previous auth querystring, like this one: + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream?secret=xxx,m=publish + real_streamid = srs_string_replace(real_streamid, "?", ","); + + std::map query; + srs_parse_query_string(real_streamid, query); + for (std::map::iterator it = query.begin(); it != query.end(); ++it) { + if (it->first == "h") { + std::string host = it->second; + + size_t r0 = host.find("/"); + size_t r1 = host.rfind("/"); + if (r0 != std::string::npos && r0 != std::string::npos) { + // Compatible with previous style, see https://github.com/ossrs/srs/issues/2893#compatible + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=publish + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=request + // srt://127.0.0.1:10080?streamid=#!::h=srs.srt.com.cn/live/livestream,m=publish + if (r0 != r1) { + // We got vhost in host. + url_subpath = host.substr(r0 + 1); + host = host.substr(0, r0); + + params.append("vhost="); + params.append(host); + params.append("&"); + vhost = host; + } else { + // Only stream in host. + url_subpath = host; + } + } else { + // New URL style, see https://github.com/ossrs/srs/issues/2893#solution + // srt://host.com:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 + // srt://1.2.3.4:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 + // srt://1.2.3.4:10080?streamid=#!::r=app/stream,key1=value1,key2=value2 + params.append("vhost="); + params.append(host); + params.append("&"); + vhost = host; + } + } else if (it->first == "r") { + url_subpath = it->second; + } else if (it->first == "m") { + std::string mode_str = it->second; // support m=publish or m=request + std::transform(it->second.begin(), it->second.end(), mode_str.begin(), ::tolower); + if (mode_str == "publish") { + mode = SrtModePush; + } else if (mode_str == "request") { + mode = SrtModePull; + } else { + srs_warn("unknown mode_str:%s", mode_str.c_str()); + return false; + } + } else { + params.append(it->first); + params.append("="); + params.append(it->second); + params.append("&"); + } + } + + if (url_subpath.empty()) { + return false; + } + + if (!params.empty()) { + url_subpath.append("?"); + url_subpath.append(params); + url_subpath.pop_back(); // remove last '&' + } + + return true; +} + +bool srs_srt_streamid_to_request(const std::string& streamid, SrtMode& mode, SrsRequest* request) +{ + string url_subpath = ""; + bool ret = srs_srt_streamid_info(streamid, mode, request->vhost, url_subpath); + if (! ret) { + return ret; + } + + size_t pos = url_subpath.find("/"); + string stream_with_params = ""; + if (pos == string::npos) { + request->app = _srs_config->get_default_app_name(); + stream_with_params = url_subpath; + } else { + request->app = url_subpath.substr(0, pos); + stream_with_params = url_subpath.substr(pos + 1); + } + + pos = stream_with_params.find("?"); + if (pos == string::npos) { + request->stream = stream_with_params; + } else { + request->stream = stream_with_params.substr(0, pos); + request->param = stream_with_params.substr(pos + 1); + } + + return ret; +} diff --git a/trunk/src/app/srs_app_srt_utility.hpp b/trunk/src/app/srs_app_srt_utility.hpp new file mode 100644 index 00000000000..c542c04a282 --- /dev/null +++ b/trunk/src/app/srs_app_srt_utility.hpp @@ -0,0 +1,32 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_APP_SRT_UTILITY_HPP +#define SRS_APP_SRT_UTILITY_HPP + +#include + +#include + +#include +#include + +class SrsRequest; + +enum SrtMode +{ + SrtModePull = 1, + SrtModePush = 2, +}; + +// Get SRT streamid info. +extern bool srs_srt_streamid_info(const std::string& streamid, SrtMode& mode, std::string& vhost, std::string& url_subpath); + +// SRT streamid to request. +extern bool srs_srt_streamid_to_request(const std::string& streamid, SrtMode& mode, SrsRequest* request); + +#endif + diff --git a/trunk/src/app/srs_app_threads.cpp b/trunk/src/app/srs_app_threads.cpp index bcfd78c7380..594da79184d 100644 --- a/trunk/src/app/srs_app_threads.cpp +++ b/trunk/src/app/srs_app_threads.cpp @@ -22,6 +22,10 @@ #include #endif +#ifdef SRS_SRT +#include +#endif + #include using namespace std; @@ -298,6 +302,10 @@ srs_error_t srs_thread_initialize() _srs_stages = new SrsStageManager(); _srs_circuit_breaker = new SrsCircuitBreaker(); +#ifdef SRS_SRT + _srs_srt_sources = new SrsSrtSourceManager(); +#endif + #ifdef SRS_RTC _srs_rtc_sources = new SrsRtcSourceManager(); _srs_blackhole = new SrsRtcBlackhole(); diff --git a/trunk/src/kernel/srs_kernel_consts.hpp b/trunk/src/kernel/srs_kernel_consts.hpp index ed3b2fba5dd..48f590c734f 100644 --- a/trunk/src/kernel/srs_kernel_consts.hpp +++ b/trunk/src/kernel/srs_kernel_consts.hpp @@ -170,6 +170,10 @@ #define SRS_CONSTS_LOG_EXEC "EXE" // The rtc. #define SRS_CONSTS_LOG_RTC "RTC" +// Srt client play +#define SRS_CONSTS_LOG_SRT_PLAY "SRT_PLA" +// Srt client publish +#define SRS_CONSTS_LOG_SRT_PUBLISH "SRT_CPB" /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index c07bb84c801..94f8c9c5479 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -347,6 +347,18 @@ #define ERROR_RTC_NO_TRACK 5030 #define ERROR_RTC_RTCP_EMPTY_RR 5031 +/////////////////////////////////////////////////////// +// SRT protocol error. +/////////////////////////////////////////////////////// +#define ERROR_SRT_EPOLL 6000 +#define ERROR_SRT_IO 6001 +#define ERROR_SRT_TIMEOUT 6002 +#define ERROR_SRT_INTERRUPT 6003 +#define ERROR_SRT_LISTEN 6004 +#define ERROR_SRT_SOCKOPT 6005 +#define ERROR_SRT_CONN 6006 +#define ERROR_SRT_SOURCE_BUSY 6007 + /////////////////////////////////////////////////////// // HTTP API error. /////////////////////////////////////////////////////// diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index a9d51dfc5b2..025a53cab3c 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -44,7 +44,8 @@ using namespace std; #endif #ifdef SRS_SRT -#include +#include +#include #endif // pre-declare @@ -65,6 +66,10 @@ extern const char* _srs_version; // @global main SRS server, for debugging SrsServer* _srs_server = NULL; +#ifdef SRS_SRT +SrsSrtEventLoop* _srt_eventloop = NULL; +#endif + /** * main entrance. */ @@ -455,7 +460,14 @@ srs_error_t run_hybrid_server() _srs_hybrid->register_server(new SrsServerAdapter()); #ifdef SRS_SRT - _srs_hybrid->register_server(new SrtServerAdapter()); + _srt_eventloop = new SrsSrtEventLoop(); + if ((err = _srt_eventloop->initialize()) != srs_success) { + return srs_error_wrap(err, "srt poller initialize"); + } + if ((err = _srt_eventloop->start()) != srs_success) { + return srs_error_wrap(err, "srt poller start"); + } + _srs_hybrid->register_server(new SrsSrtServerAdapter()); #endif #ifdef SRS_RTC diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp index 88af17e7c7a..3934c11d2c4 100644 --- a/trunk/src/protocol/srs_protocol_utility.cpp +++ b/trunk/src/protocol/srs_protocol_utility.cpp @@ -533,3 +533,4 @@ string srs_get_cidr_ipv4(string network_address) { return ipv4_address; } + diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_service_st_srt.cpp new file mode 100644 index 00000000000..12daacb46ad --- /dev/null +++ b/trunk/src/protocol/srs_service_st_srt.cpp @@ -0,0 +1,789 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + +#include + +using namespace std; + +#include +#include +#include + +#define SET_SRT_OPT_STR(srtfd, optname, buf, size) \ + if (srt_setsockflag(srtfd, optname, buf, size) == SRT_ERROR) { \ + std::stringstream ss; \ + ss << "srtfd=" << srtfd << ",set " << #optname \ + << " failed,err=" << srt_getlasterror_str(); \ + return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \ + } + +#define SET_SRT_OPT(srtfd, optname, val) \ + if (srt_setsockflag(srtfd, optname, &val, sizeof(val)) == SRT_ERROR) { \ + std::stringstream ss; \ + ss << "srtfd=" << srtfd << ",set " << #optname << "=" << val \ + << " failed,err=" << srt_getlasterror_str(); \ + return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \ + } + +#define GET_SRT_OPT(srtfd, optname, val) \ + do { \ + int size = sizeof(val); \ + if (srt_getsockflag(srtfd, optname, &val, &size) == SRT_ERROR) { \ + std::stringstream ss; \ + ss << "srtfd=" << srtfd << ",get " << #optname \ + << " failed,err=" << srt_getlasterror_str(); \ + return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \ + } \ + } while (0) + +static srs_error_t do_srs_srt_listen(SRTSOCKET srt_fd, addrinfo* r) +{ + srs_error_t err = srs_success; + + if ((err = srs_srt_nonblock(srt_fd)) != srs_success) { + return srs_error_wrap(err, "nonblock"); + } + + if (srt_bind(srt_fd, r->ai_addr, r->ai_addrlen) == -1) { + return srs_error_new(ERROR_SOCKET_BIND, "bind"); + } + + if (srt_listen(srt_fd, 100) == -1) { + return srs_error_new(ERROR_SOCKET_LISTEN, "listen"); + } + + return err; +} + +static srs_error_t do_srs_srt_get_streamid(SRTSOCKET srt_fd, string& streamid) +{ + // SRT max streamid length is 512. + char sid[512]; + GET_SRT_OPT(srt_fd, SRTO_STREAMID, sid); + + streamid.assign(sid); + return srs_success; +} + +srs_error_t srs_srt_socket(SRTSOCKET* pfd) +{ + srs_error_t err = srs_success; + + SRTSOCKET srt_fd = 0; + if ((srt_fd = srt_create_socket()) < 0) { + return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket"); + } + + *pfd = srt_fd; + + return err; +} + +srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd) +{ + srs_error_t err = srs_success; + + SRTSOCKET srt_fd = 0; + if ((srt_fd = srt_create_socket()) < 0) { + return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket"); + } + + if ((err = srs_srt_nonblock(srt_fd)) != srs_success) { + return srs_error_wrap(err, "nonblock"); + } + + if ((err = srs_srt_set_tsbpdmode(srt_fd, false)) != srs_success) { + return srs_error_wrap(err, "set tsbpdmode"); + } + + if ((err = srs_srt_set_tlpktdrop(srt_fd, false)) != srs_success) { + return srs_error_wrap(err, "set tlpktdrop"); + } + + if ((err = srs_srt_set_latency(srt_fd, false)) != srs_success) { + return srs_error_wrap(err, "set latency"); + } + + *pfd = srt_fd; + + return err; +} + +srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port) +{ + srs_error_t err = srs_success; + + char sport[8]; + snprintf(sport, sizeof(sport), "%d", port); + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + + addrinfo* r = NULL; + SrsAutoFreeH(addrinfo, r, freeaddrinfo); + if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)", + hints.ai_family, hints.ai_socktype, hints.ai_flags); + } + + if ((err = do_srs_srt_listen(srt_fd, r)) != srs_success) { + srt_close(srt_fd); + return srs_error_wrap(err, "srt_fd=%d", srt_fd); + } + + return err; +} + +srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd) +{ + int sync = 0; + SET_SRT_OPT(srt_fd, SRTO_SNDSYN, sync); + SET_SRT_OPT(srt_fd, SRTO_RCVSYN, sync); + + return srs_success; +} + +srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw) +{ + SET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw); + return srs_success; +} + +srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss) +{ + SET_SRT_OPT(srt_fd, SRTO_MSS, mss); + return srs_success; +} + +srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size) +{ + SET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size); + return srs_success; +} + +srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout) +{ + SET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout); + return srs_success; +} + +srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout) +{ + SET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout); + return srs_success; +} + +srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode) +{ + SET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode); + return srs_success; +} + +srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf) +{ + SET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf); + return srs_success; +} + +srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf) +{ + SET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf); + return srs_success; +} + +srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop) +{ + SET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop); + return srs_success; +} + +srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency) +{ + SET_SRT_OPT(srt_fd, SRTO_LATENCY, latency); + return srs_success; +} + +srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency) +{ + SET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency); + return srs_success; +} + +srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency) +{ + SET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency); + return srs_success; +} + +srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid) +{ + SET_SRT_OPT_STR(srt_fd, SRTO_STREAMID, streamid.data(), streamid.size()); + return srs_success; +} + +srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw) +{ + GET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw); + return srs_success; +} + +srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss) +{ + GET_SRT_OPT(srt_fd, SRTO_MSS, mss); + return srs_success; +} + +srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size) +{ + GET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size); + return srs_success; +} + +srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout) +{ + GET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout); + return srs_success; +} + +srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout) +{ + GET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout); + return srs_success; +} + +srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode) +{ + GET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode); + return srs_success; +} + +srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf) +{ + GET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf); + return srs_success; +} + +srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf) +{ + GET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf); + return srs_success; +} + +srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop) +{ + GET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop); + return srs_success; +} + +srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency) +{ + GET_SRT_OPT(srt_fd, SRTO_LATENCY, latency); + return srs_success; +} + +srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency) +{ + GET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency); + return srs_success; +} + +srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency) +{ + GET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency); + return srs_success; +} + +srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid) +{ + srs_error_t err = srs_success; + + if ((err = do_srs_srt_get_streamid(srt_fd, streamid)) != srs_success) { + return srs_error_wrap(err, "srt get streamid"); + } + + return err; +} + +srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port) +{ + srs_error_t err = srs_success; + + // discovery client information + sockaddr_storage addr; + int addrlen = sizeof(addr); + if (srt_getsockname(srt_fd, (sockaddr*)&addr, &addrlen) == -1) { + return srs_error_new(ERROR_SRT_SOCKOPT, "srt_getsockname"); + } + + char saddr[64]; + char* h = (char*)saddr; + socklen_t nbh = (socklen_t)sizeof(saddr); + const int r0 = getnameinfo((const sockaddr*)&addr, addrlen, h, nbh,NULL, 0, NI_NUMERICHOST); + if (r0) { + return srs_error_new(ERROR_SRT_SOCKOPT, "getnameinfo"); + } + + switch(addr.ss_family) { + case AF_INET: + port = ntohs(((sockaddr_in*)&addr)->sin_port); + break; + case AF_INET6: + port = ntohs(((sockaddr_in6*)&addr)->sin6_port); + break; + } + + ip.assign(saddr); + return err; +} + +srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port) +{ + srs_error_t err = srs_success; + + // discovery client information + sockaddr_storage addr; + int addrlen = sizeof(addr); + if (srt_getpeername(srt_fd, (sockaddr*)&addr, &addrlen) == -1) { + return srs_error_new(ERROR_SRT_SOCKOPT, "srt_getpeername"); + } + + char saddr[64]; + char* h = (char*)saddr; + socklen_t nbh = (socklen_t)sizeof(saddr); + const int r0 = getnameinfo((const sockaddr*)&addr, addrlen, h, nbh,NULL, 0, NI_NUMERICHOST); + if (r0) { + return srs_error_new(ERROR_SRT_SOCKOPT, "getnameinfo"); + } + + switch(addr.ss_family) { + case AF_INET: + port = ntohs(((sockaddr_in*)&addr)->sin_port); + break; + case AF_INET6: + port = ntohs(((sockaddr_in6*)&addr)->sin6_port); + break; + } + + ip.assign(saddr); + return err; +} + +SrsSrtPoller::SrsSrtPoller() +{ + srt_epoller_fd_ = -1; +} + +SrsSrtPoller::~SrsSrtPoller() +{ + if (srt_epoller_fd_ > 0) { + srt_epoll_release(srt_epoller_fd_); + } +} + +srs_error_t SrsSrtPoller::initialize() +{ + srs_error_t err = srs_success; + + srt_epoller_fd_ = srt_epoll_create(); + events_.resize(1024); + + return err; +} + +srs_error_t SrsSrtPoller::add_socket(SrsSrtSocket* srt_skt) +{ + srs_error_t err = srs_success; + + int events = srt_skt->events(); + SRTSOCKET srtfd = srt_skt->fd(); + + int ret = srt_epoll_add_usock(srt_epoller_fd_, srtfd, &events); + + srs_info("srt poller %d add srt socket %d, events=%d", srt_epoller_fd_, srtfd, events); + if (ret == SRT_ERROR) { + return srs_error_new(ERROR_SRT_EPOLL, "srt epoll add socket=%lu failed, err=%s", srtfd, srt_getlasterror_str()); + } + + // record srtfd to SrsSrtSocket* + fd_sockets_[srtfd] = srt_skt; + + return err; +} + +srs_error_t SrsSrtPoller::del_socket(SrsSrtSocket* srt_skt) +{ + srs_error_t err = srs_success; + + SRTSOCKET srtfd = srt_skt->fd(); + + int ret = srt_epoll_remove_usock(srt_epoller_fd_, srtfd); + srs_info("srt poller %d remove srt socket %d", srt_epoller_fd_, srtfd); + if (ret == SRT_ERROR) { + return srs_error_new(ERROR_SRT_EPOLL, "srt epoll remove socket=%lu failed, err=%s", srtfd, srt_getlasterror_str()); + } + + fd_sockets_.erase(srtfd); + + return err; +} + +srs_error_t SrsSrtPoller::wait(int timeout_ms) +{ + srs_error_t err = srs_success; + + // wait srt event fired, will timeout after `timeout_ms` milliseconds. + int ret = srt_epoll_uwait(srt_epoller_fd_, events_.data(), events_.size(), timeout_ms); + if (ret < 0) { + return srs_error_new(ERROR_SRT_EPOLL, "srt_epoll_uwait, ret=%d", ret); + } + + for (int i = 0; i < ret; ++i) { + SRT_EPOLL_EVENT event = events_[i]; + map::iterator iter = fd_sockets_.find(event.fd); + if (iter == fd_sockets_.end()) { + srs_assert(false); + } + + SrsSrtSocket* srt_skt = iter->second; + srs_assert(srt_skt != NULL); + + // notify error, don't notify read/write event. + if (event.events & SRT_EPOLL_ERR) { + srt_skt->notify_error(); + } else { + if (event.events & SRT_EPOLL_IN) { + srt_skt->notify_readable(); + } + if (event.events & SRT_EPOLL_OUT) { + srt_skt->notify_writeable(); + } + } + } + + return err; +} + +srs_error_t SrsSrtPoller::mod_socket(SrsSrtSocket* srt_skt) +{ + srs_error_t err = srs_success; + + int events = srt_skt->events(); + SRTSOCKET srtfd = srt_skt->fd(); + + int ret = srt_epoll_update_usock(srt_epoller_fd_, srtfd, &events); + srs_info("srt poller %d update srt socket %d, events=%d", srt_epoller_fd_, srtfd, events); + + if (ret == SRT_ERROR) { + return srs_error_new(ERROR_SRT_EPOLL, "srt epoll update socket=%lu failed, err=%s", srtfd, srt_getlasterror_str()); + } + + return err; +} + +SrsSrtSocket::SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd) +{ + srt_poller_ = srt_poller; + srt_fd_ = srt_fd; + has_error_ = 0; + read_cond_ = srs_cond_new(); + write_cond_ = srs_cond_new(); + + recv_timeout_ = 5 * SRS_UTIME_SECONDS; + send_timeout_ = 5 * SRS_UTIME_SECONDS; + + recv_bytes_ = 0; + send_bytes_ = 0; + + events_ = 0; +} + +SrsSrtSocket::~SrsSrtSocket() +{ + srs_error_t err = srt_poller_->del_socket(this); + if (err != srs_success) { + srs_error("srt poller remove socket failed, err=%s", srs_error_desc(err).c_str()); + srs_error_reset(err); + } + + srs_cond_destroy(read_cond_); + srs_cond_destroy(write_cond_); + + srs_trace("close srt_fd=%d", srt_fd_); + srt_close(srt_fd_); +} + +srs_error_t SrsSrtSocket::connect(const string& ip, int port) +{ + srs_error_t err = srs_success; + + sockaddr_in inaddr; + inaddr.sin_family = AF_INET; + inaddr.sin_port = htons(port); + // TODO: FIXME: inet_addr is deprecated + inaddr.sin_addr.s_addr = inet_addr(ip.c_str()); + + int ret = srt_connect(srt_fd_, (const sockaddr*)&inaddr, sizeof(inaddr)); + + // TODO: FIXME: check return value. + SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_); + if (srt_status != SRTS_CONNECTED) { + // Connect is in progress, wait until it finish or error. + if ((err = wait_writeable()) != srs_success) { + return srs_error_wrap(err, "wait writeable"); + } + + // Double check if connect is established. + srt_status = srt_getsockstate(srt_fd_); + if (srt_status != SRTS_CONNECTED) { + return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); + } + } + + return err; +} + +srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd) +{ + srs_error_t err = srs_success; + + while (true) { + sockaddr_in inaddr; + int addrlen = sizeof(inaddr); + SRTSOCKET srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen); + if (srt_fd == SRT_INVALID_SOCK) { + if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { + // Accept would block, wait until new client connect or error. + if ((err = wait_readable()) != srs_success) { + return srs_error_wrap(err, "wait readable"); + } + continue; + } else { + return srs_error_new(ERROR_SRT_IO, "srt_accept, err=%s", srt_getlasterror_str()); + } + } else { + *client_srt_fd = srt_fd; + break; + } + } + + return err; +} + +srs_error_t SrsSrtSocket::recvmsg(void* buf, size_t size, ssize_t* nread) +{ + srs_error_t err = srs_success; + + while (true) { + int ret = srt_recvmsg(srt_fd_, (char*)buf, size); + if (ret < 0) { + if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { + if ((err = wait_readable()) != srs_success) { + return srs_error_wrap(err, "wait readable"); + } + continue; + } else { + return srs_error_new(ERROR_SRT_IO, "srt_recvmsg, err=%s", srt_getlasterror_str()); + } + } else { + recv_bytes_ += ret; + *nread = ret; + break; + } + } + + return err; +} + +srs_error_t SrsSrtSocket::sendmsg(void* buf, size_t size, ssize_t* nwrite) +{ + srs_error_t err = srs_success; + + while (true) { + int ret = srt_sendmsg(srt_fd_, (const char*)buf, size, -1, 1); + if (ret < 0) { + if (srt_getlasterror(NULL) == SRT_EASYNCSND) { + if ((err = wait_writeable()) != srs_success) { + return srs_error_wrap(err, "wait writeable"); + } + continue; + } else { + return srs_error_new(ERROR_SRT_IO, "srt_sendmsg, err=%s", srt_getlasterror_str()); + } + } else { + send_bytes_ += ret; + *nwrite = ret; + break; + } + } + + return err; +} + +srs_error_t SrsSrtSocket::wait_readable() +{ + srs_error_t err = srs_success; + + // Check if error occured. + if ((err = check_error()) != srs_success) { + return srs_error_wrap(err, "has error"); + } + + // Subscribe in and error event + if ((err = enable_read()) != srs_success) { + return srs_error_wrap(err, "enable read"); + } + + // Wait event fired or timeout. + int ret = srs_cond_timedwait(read_cond_, recv_timeout_); + // TODO: FIXME: need to disable it? + err = disable_read(); + if (err != srs_success) { + srs_freep(err); + } + + if (ret != 0) { + // Timeout and events no fired. + if (errno == ETIME) { + return srs_error_new(ERROR_SRT_TIMEOUT, "srt socket %d timeout", srt_fd_); + } + // Interrupted, maybe coroutine terminated. + if (errno == EINTR) { + return srs_error_new(ERROR_SRT_INTERRUPT, "srt socket %d interrupted", srt_fd_); + } + return srs_error_new(ERROR_SRT_IO, "srt socket %d wait read", srt_fd_); + } + + // Check if we are notify with error event. + if ((err = check_error()) != srs_success) { + return srs_error_wrap(err, "has error"); + } + + return err; +} + +srs_error_t SrsSrtSocket::wait_writeable() +{ + srs_error_t err = srs_success; + + if ((err = check_error()) != srs_success) { + return srs_error_wrap(err, "has error"); + } + + if ((err = enable_write()) != srs_success) { + return srs_error_wrap(err, "enable write"); + } + + int ret = srs_cond_timedwait(write_cond_, send_timeout_); + err = disable_write(); + if (err != srs_success) { + srs_freep(err); + } + + if (ret != 0) { + if (errno == ETIME) { + return srs_error_new(ERROR_SRT_TIMEOUT, "srt socket %d timeout", srt_fd_); + } + if (errno == EINTR) { + return srs_error_new(ERROR_SRT_INTERRUPT, "srt socket %d interrupted", srt_fd_); + } + return srs_error_new(ERROR_SRT_IO, "srt socket %d wait write", srt_fd_); + } + + if ((err = check_error()) != srs_success) { + return srs_error_wrap(err, "has error"); + } + + return err; +} + +void SrsSrtSocket::notify_readable() +{ + srs_cond_signal(read_cond_); +} + +void SrsSrtSocket::notify_writeable() +{ + srs_cond_signal(write_cond_); +} + +void SrsSrtSocket::notify_error() +{ + // mark error, and check when read/write + has_error_ = true; + srs_cond_signal(read_cond_); + srs_cond_signal(write_cond_); +} + +srs_error_t SrsSrtSocket::enable_read() +{ + return enable_event(SRT_EPOLL_IN | SRT_EPOLL_ERR); +} + +srs_error_t SrsSrtSocket::disable_read() +{ + return disable_event(SRT_EPOLL_IN); +} + +srs_error_t SrsSrtSocket::enable_write() +{ + return enable_event(SRT_EPOLL_OUT | SRT_EPOLL_ERR); +} + +srs_error_t SrsSrtSocket::disable_write() +{ + return disable_event(SRT_EPOLL_OUT); +} + +srs_error_t SrsSrtSocket::enable_event(int event) { + srs_error_t err = srs_success; + // Event has been subscribed. + if ((events_ & event) == event) { + return err; + } + + int old_events = events_; + events_ |= event; + + if (old_events == 0) { + err = srt_poller_->add_socket(this); + } else { + err = srt_poller_->mod_socket(this); + } + return err; +} + +srs_error_t SrsSrtSocket::disable_event(int event) { + srs_error_t err = srs_success; + // Event has been unsubscribed. + if ((events_ & event) == 0) { + return err; + } + + events_ &= (~event); + + if (events_ == 0) { + err = srt_poller_->del_socket(this); + } else { + err = srt_poller_->mod_socket(this); + } + return err; +} + +srs_error_t SrsSrtSocket::check_error() { + srs_error_t err = srs_success; + + if (has_error_) { + return srs_error_new(ERROR_SRT_IO, "has error"); + } + + return err; +} + diff --git a/trunk/src/protocol/srs_service_st_srt.hpp b/trunk/src/protocol/srs_service_st_srt.hpp new file mode 100644 index 00000000000..1e548b490da --- /dev/null +++ b/trunk/src/protocol/srs_service_st_srt.hpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_SERVICE_ST_SRT_HPP +#define SRS_SERVICE_ST_SRT_HPP + +#include +#include + +#include +#include + +#include + +// Create srt socket only, with libsrt's default option. +extern srs_error_t srs_srt_socket(SRTSOCKET* pfd); + +// Create srt socket with srs recommend default option(tsbpdmode=false,tlpktdrop=false,latency=0,sndsyn=0,rcvsyn=0) +extern srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd); + +// For server, listen at SRT endpoint. +extern srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port); + +// Set read/write no block. +extern srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd); + +// Set SRT options. +extern srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw); +extern srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss); +extern srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size); +extern srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout); +extern srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout); +extern srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode); +extern srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf); +extern srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf); +extern srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop); +extern srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency); +extern srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency); +extern srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency); +extern srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid); + +// Get SRT options. +extern srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw); +extern srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss); +extern srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size); +extern srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout); +extern srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout); +extern srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode); +extern srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf); +extern srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf); +extern srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop); +extern srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency); +extern srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency); +extern srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency); +extern srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid); + +// Get SRT socket info. +extern srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); +extern srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); + +class SrsSrtSocket; + +// Srt poller, subscribe/unsubscribed events and wait them fired. +class SrsSrtPoller +{ +public: + SrsSrtPoller(); + virtual ~SrsSrtPoller(); +public: + srs_error_t initialize(); + srs_error_t add_socket(SrsSrtSocket* srt_skt); + srs_error_t mod_socket(SrsSrtSocket* srt_skt); + srs_error_t del_socket(SrsSrtSocket* srt_skt); + srs_error_t wait(int timeout_ms); +private: + // Find SrsSrtSocket* context by SRTSOCKET. + std::map fd_sockets_; + int srt_epoller_fd_; + std::vector events_; +}; + +// Srt ST socket, wrap SRT io and make it adapt to ST-thread. +class SrsSrtSocket +{ +public: + SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd); + virtual ~SrsSrtSocket(); +public: // IO API + srs_error_t connect(const std::string& ip, int port); + srs_error_t accept(SRTSOCKET* client_srt_fd); + srs_error_t recvmsg(void* buf, size_t size, ssize_t* nread); + srs_error_t sendmsg(void* buf, size_t size, ssize_t* nwrite); +public: + SRTSOCKET fd() const { return srt_fd_; } + int events() const { return events_; } +public: + void set_recv_timeout(srs_utime_t tm) { recv_timeout_ = tm; } + void set_send_timeout(srs_utime_t tm) { send_timeout_ = tm; } + srs_utime_t get_send_timeout() { return send_timeout_; } + srs_utime_t get_recv_timeout() { return recv_timeout_; } + int64_t get_send_bytes() { return send_bytes_; } + int64_t get_recv_bytes() { return recv_bytes_; } + // Yiled coroutine and wait this socket readable. + srs_error_t wait_readable(); + // Yiled coroutine and wait this socket writeable. + srs_error_t wait_writeable(); + // Notify this socket readable, and resume coroutine later. + void notify_readable(); + // Notify this socket writeable, and resume coroutine later. + void notify_writeable(); + // Notify this socket error, resume coroutine later and error will return in all the operator of this socket. + void notify_error(); +public: + // Subscribed IN/ERR event to srt poller. + srs_error_t enable_read(); + // Unsubscribed IN event to srt poller. + srs_error_t disable_read(); + // Subscribed OUT/ERR event to srt poller. + srs_error_t enable_write(); + // Unsubscribed OUT event to srt poller. + srs_error_t disable_write(); +private: + srs_error_t enable_event(int event); + srs_error_t disable_event(int event); + srs_error_t check_error(); + +private: + SRTSOCKET srt_fd_; + // Mark if some error occured in srt socket. + bool has_error_; + // When read operator like recvmsg/accept would block, wait this condition timeout or notified, + // and the coroutine itself will be yiled and resume when condition be notified. + srs_cond_t read_cond_; + // When write operator like sendmsg/connectt would block, wait this condition timeout or notified, + // and the coroutine itself will be yiled and resume when condition be notified. + srs_cond_t write_cond_; + + srs_utime_t recv_timeout_; + srs_utime_t send_timeout_; + + int64_t recv_bytes_; + int64_t send_bytes_; + + // Event of this socket subscribed. + int events_; + // Srt poller which this socket attach to. + SrsSrtPoller* srt_poller_; +}; + +#endif + diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index 2b07563f6b7..f2478eb9f57 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -17,6 +17,10 @@ #include using namespace std; +#ifdef SRS_SRT +#include +#endif + // Temporary disk config. std::string _srs_tmp_file_prefix = "/tmp/srs-utest-"; // Temporary network config. @@ -32,6 +36,10 @@ SrsConfig* _srs_config = NULL; SrsServer* _srs_server = NULL; bool _srs_in_docker = false; +#ifdef SRS_SRT +SrsSrtEventLoop* _srt_eventloop = NULL; +#endif + #include // Initialize global settings. @@ -52,6 +60,16 @@ srs_error_t prepare_main() { srs_freep(_srs_context); _srs_context = new SrsThreadContext(); +#ifdef SRS_SRT + _srt_eventloop = new SrsSrtEventLoop(); + if ((err = _srt_eventloop->initialize()) != srs_success) { + return srs_error_wrap(err, "srt poller initialize"); + } + if ((err = _srt_eventloop->start()) != srs_success) { + return srs_error_wrap(err, "srt poller start"); + } +#endif + return err; } diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 7d420a22cac..8abba1288d1 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -6,84 +6,461 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include using namespace std; -VOID TEST(ProtocolSrtTest, SrtGetStreamInfoNormal) { +extern SrsSrtEventLoop* _srt_eventloop; + +// Test srt st service +VOID TEST(ServiceSrtPoller, SrtPollOperateSocket) +{ + srs_error_t err = srs_success; + + SrsSrtPoller* srt_poller = new SrsSrtPoller(); + HELPER_EXPECT_SUCCESS(srt_poller->initialize()); + + SRTSOCKET srt_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_fd)); + EXPECT_TRUE(srt_fd > 0); + + SrsSrtSocket* srt_socket = new SrsSrtSocket(srt_poller, srt_fd); + EXPECT_EQ(srt_socket->events(), 0); + + // Enable read, will subscribe SRT_EPOLL_IN and SRT_EPOLL_ERR event in srt poller. + HELPER_EXPECT_SUCCESS(srt_socket->enable_read()); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_IN); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_ERR); + + // Enable read, will subscribe SRT_EPOLL_OUT and SRT_EPOLL_ERR event in srt poller. + HELPER_EXPECT_SUCCESS(srt_socket->enable_write()); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_OUT); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_ERR); + + // Disable read, will unsubscribe SRT_EPOLL_IN event in srt poller. + HELPER_EXPECT_SUCCESS(srt_socket->disable_read()); + EXPECT_FALSE(srt_socket->events() & SRT_EPOLL_IN); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_ERR); + + // Disable write, will unsubscribe SRT_EPOLL_OUT event in srt poller. + HELPER_EXPECT_SUCCESS(srt_socket->disable_write()); + EXPECT_FALSE(srt_socket->events() & SRT_EPOLL_OUT); + EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_ERR); + + EXPECT_EQ(srt_poller->fd_sockets_.size(), 1); + // Delete socket, will remove in srt poller. + srs_freep(srt_socket); + EXPECT_EQ(srt_poller->fd_sockets_.size(), 0); + + srs_freep(srt_poller); +} + +VOID TEST(ServiceSrtPoller, SrtSetGetSocketOpt) +{ + srs_error_t err = srs_success; + + SRTSOCKET srt_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_nonblock(srt_fd)); + + int maxbw = 20000; + int mss = 1400; + int payload_size = 1316; + int connect_timeout = 5000; + int peer_idle_timeout = 10000; + bool tsbpdmode = false; + int sndbuf = 2 * 1024 * 1024; + int rcvbuf = 10 * 1024 * 1024; + bool tlpktdrop = false; + int latency = 0; + int rcv_latency = 120; + int peer_latency = 120; + std::string streamid = "SRS_SRT"; + + HELPER_EXPECT_SUCCESS(srs_srt_set_maxbw(srt_fd, maxbw)); + HELPER_EXPECT_SUCCESS(srs_srt_set_mss(srt_fd, mss)); + HELPER_EXPECT_SUCCESS(srs_srt_set_payload_size(srt_fd, payload_size)); + HELPER_EXPECT_SUCCESS(srs_srt_set_connect_timeout(srt_fd, connect_timeout)); + HELPER_EXPECT_SUCCESS(srs_srt_set_peer_idle_timeout(srt_fd, peer_idle_timeout)); + HELPER_EXPECT_SUCCESS(srs_srt_set_tsbpdmode(srt_fd, tsbpdmode)); + HELPER_EXPECT_SUCCESS(srs_srt_set_sndbuf(srt_fd, sndbuf)); + HELPER_EXPECT_SUCCESS(srs_srt_set_rcvbuf(srt_fd, rcvbuf)); + HELPER_EXPECT_SUCCESS(srs_srt_set_tlpktdrop(srt_fd, tlpktdrop)); + HELPER_EXPECT_SUCCESS(srs_srt_set_latency(srt_fd, latency)); + HELPER_EXPECT_SUCCESS(srs_srt_set_rcv_latency(srt_fd, rcv_latency)); + HELPER_EXPECT_SUCCESS(srs_srt_set_peer_latency(srt_fd, peer_latency)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_fd, streamid)); + + bool b; + int i = 0; + std::string s; + + HELPER_EXPECT_SUCCESS(srs_srt_get_maxbw(srt_fd, i)); + EXPECT_EQ(i, maxbw); + HELPER_EXPECT_SUCCESS(srs_srt_get_mss(srt_fd, i)); + EXPECT_EQ(i, mss); + HELPER_EXPECT_SUCCESS(srs_srt_get_payload_size(srt_fd, i)); + EXPECT_EQ(i, payload_size); + HELPER_EXPECT_SUCCESS(srs_srt_get_connect_timeout(srt_fd, i)); + EXPECT_EQ(i, connect_timeout); + HELPER_EXPECT_SUCCESS(srs_srt_get_peer_idle_timeout(srt_fd, i)); + EXPECT_EQ(i, peer_idle_timeout); + + // Don't check b equal to option blow, because some opt will deterimated after srt handshake done or change when set. + HELPER_EXPECT_SUCCESS(srs_srt_get_tsbpdmode(srt_fd, b)); + HELPER_EXPECT_SUCCESS(srs_srt_get_sndbuf(srt_fd, i)); + HELPER_EXPECT_SUCCESS(srs_srt_get_rcvbuf(srt_fd, i)); + HELPER_EXPECT_SUCCESS(srs_srt_get_tlpktdrop(srt_fd, b)); + HELPER_EXPECT_SUCCESS(srs_srt_get_latency(srt_fd, i)); + HELPER_EXPECT_SUCCESS(srs_srt_get_rcv_latency(srt_fd, i)); + HELPER_EXPECT_SUCCESS(srs_srt_get_peer_latency(srt_fd, i)); + + HELPER_EXPECT_SUCCESS(srs_srt_get_streamid(srt_fd, s)); + EXPECT_EQ(s, streamid); +} + +class MockSrtServer +{ +public: + SrsSrtSocket* srt_socket_; + SRTSOCKET srt_server_fd_; + + MockSrtServer() { + srt_server_fd_ = SRT_INVALID_SOCK; + srt_socket_ = NULL; + } + + srs_error_t create_socket() { + srs_error_t err = srs_success; + if ((err = srs_srt_socket_with_default_option(&srt_server_fd_)) != srs_success) { + return srs_error_wrap(err, "create srt socket"); + } + return err; + } + + srs_error_t listen(std::string ip, int port) { + srs_error_t err = srs_success; + + if ((err = srs_srt_listen(srt_server_fd_, ip, port)) != srs_success) { + return srs_error_wrap(err, "srt listen"); + } + + srt_socket_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_server_fd_); + + return err; + } + + virtual ~MockSrtServer() { + srs_freep(srt_socket_); + } + + virtual srs_error_t accept(SRTSOCKET* client_fd) { + srs_error_t err = srs_success; + + if ((err = srt_socket_->accept(client_fd)) != srs_success) { + return srs_error_wrap(err, "srt accept"); + } + + return err; + } +}; + +VOID TEST(ServiceStSRTTest, ListenConnectAccept) +{ + srs_error_t err = srs_success; + + std::string server_ip = "127.0.0.1"; + int server_port = 9000; + + MockSrtServer srt_server; + HELPER_EXPECT_SUCCESS(srt_server.create_socket()); + HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); + + SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_client_fd)); + + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + + // No client connected, accept will timeout. + SRTSOCKET srt_fd = SRT_INVALID_SOCK; + // Make utest fast timeout. + srt_server.srt_socket_->set_recv_timeout(50 * SRS_UTIME_MILLISECONDS); + err = srt_server.accept(&srt_fd); + EXPECT_EQ(srs_error_code(err), ERROR_SRT_TIMEOUT); + EXPECT_EQ(srt_fd, SRT_INVALID_SOCK); + + // Client connect to server + HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); + + // Server will accept one client. + HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_fd)); + EXPECT_NE(srt_fd, SRT_INVALID_SOCK); +} + +VOID TEST(ServiceStSRTTest, ConnectTimeout) +{ + srs_error_t err = srs_success; + + SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + + srt_client_socket->set_send_timeout(50 * SRS_UTIME_MILLISECONDS); + // Client connect to server which is no listening. + HELPER_EXPECT_FAILED(srt_client_socket->connect("127.0.0.1", 9099)); +} + +VOID TEST(ServiceStSRTTest, ConnectWithStreamid) +{ + srs_error_t err = srs_success; + + std::string server_ip = "127.0.0.1"; + int server_port = 9000; + + MockSrtServer srt_server; + HELPER_EXPECT_SUCCESS(srt_server.create_socket()); + HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); + + std::string streamid = "SRS_SRT_Streamid"; + SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + + HELPER_EXPECT_SUCCESS(srt_client_socket->connect("127.0.0.1", 9000)); + + SRTSOCKET srt_server_accepted_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); + EXPECT_NE(srt_server_accepted_fd, SRT_INVALID_SOCK); + std::string s; + HELPER_EXPECT_SUCCESS(srs_srt_get_streamid(srt_server_accepted_fd, s)); + EXPECT_EQ(s, streamid); +} + +VOID TEST(ServiceStSRTTest, ReadWrite) +{ + srs_error_t err = srs_success; + + std::string server_ip = "127.0.0.1"; + int server_port = 9000; + + MockSrtServer srt_server; + HELPER_EXPECT_SUCCESS(srt_server.create_socket()); + HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); + + SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + + // Client connect to server + HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); + + // Server will accept one client. + SRTSOCKET srt_server_accepted_fd = SRT_INVALID_SOCK; + HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); + EXPECT_NE(srt_server_accepted_fd, SRT_INVALID_SOCK); + SrsSrtSocket* srt_server_accepted_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_server_accepted_fd); + + if (true) { + std::string content = "Hello, SRS SRT!"; + + // Client send msg to server. + ssize_t nb_write = 0; + HELPER_EXPECT_SUCCESS(srt_client_socket->sendmsg((char*)content.data(), content.size(), &nb_write)); + EXPECT_EQ(nb_write, content.size()); + + // Server recv msg from client + char buf[1500]; + ssize_t nb_read = 0; + HELPER_EXPECT_SUCCESS(srt_server_accepted_socket->recvmsg(buf, sizeof(buf), &nb_read)); + EXPECT_EQ(nb_read, content.size()); + EXPECT_EQ(std::string(buf, nb_read), content); + + // Server echo msg back to client. + HELPER_EXPECT_SUCCESS(srt_server_accepted_socket->sendmsg(buf, nb_read, &nb_write)); + EXPECT_EQ(nb_write, content.size()); + + // Client recv echo msg from server. + HELPER_EXPECT_SUCCESS(srt_client_socket->recvmsg(buf, sizeof(buf), &nb_read)); + EXPECT_EQ(nb_read, content.size()); + EXPECT_EQ(std::string(buf, nb_read), content); + } + if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath)); - EXPECT_EQ(PULL_SRT_MODE, mode); + char buf[1500]; + ssize_t nb_read = 0; + // Make socket fast timeout in ustet. + srt_server_accepted_socket->set_recv_timeout(50 * SRS_UTIME_MILLISECONDS); + // Recv msg from client, but client no send any msg, so will be timeout. + err = srt_server_accepted_socket->recvmsg(buf, sizeof(buf), &nb_read); + EXPECT_EQ(srs_error_code(err), ERROR_SRT_TIMEOUT); + } +} + +// Test srt server +class MockSrtHandler : public ISrsSrtHandler +{ +private: + SRTSOCKET srt_fd; +public: + MockSrtHandler() { + srt_fd = SRT_INVALID_SOCK; + } + virtual ~MockSrtHandler() { + } +public: + virtual srs_error_t on_srt_client(SRTSOCKET fd) { + srt_fd = fd; + return srs_success; + } +}; + +VOID TEST(SrtServerTest, SrtListener) +{ + srs_error_t err = srs_success; + + if (true) { + MockSrtHandler h; + SrsSrtListener srt_listener(&h, "127.0.0.1", 9000); + HELPER_EXPECT_SUCCESS(srt_listener.create_socket()); + HELPER_EXPECT_SUCCESS(srt_listener.listen()); + EXPECT_TRUE(srt_listener.fd() > 0); + } +} + +// Test srt app +VOID TEST(ProtocolSrtTest, SrtGetStreamInfoNormal) +{ + if (true) { + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath)); + EXPECT_EQ(SrtModePull, mode); EXPECT_STREQ("", vhost.c_str()); EXPECT_STREQ("live/livestream?key1=value1&key2=value2", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=host.com,r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath)); - EXPECT_EQ(PULL_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=host.com,r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath)); + EXPECT_EQ(SrtModePull, mode); EXPECT_STREQ("host.com", vhost.c_str()); EXPECT_STREQ("live/livestream?vhost=host.com&key1=value1&key2=value2", subpath.c_str()); } } -VOID TEST(ProtocolSrtTest, SrtGetStreamInfoMethod) { +VOID TEST(ProtocolSrtTest, SrtGetStreamInfoMethod) +{ if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,m=request", mode, vhost, subpath)); - EXPECT_EQ(PULL_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::r=live/livestream,m=request", mode, vhost, subpath)); + EXPECT_EQ(SrtModePull, mode); EXPECT_STREQ("live/livestream", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,m=publish", mode, vhost, subpath)); - EXPECT_EQ(PUSH_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::r=live/livestream,m=publish", mode, vhost, subpath)); + EXPECT_EQ(SrtModePush, mode); EXPECT_STREQ("live/livestream", subpath.c_str()); } } -VOID TEST(ProtocolSrtTest, SrtGetStreamInfoCompatible) { +VOID TEST(ProtocolSrtTest, SrtGetStreamInfoCompatible) +{ if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=live/livestream,m=request", mode, vhost, subpath)); - EXPECT_EQ(PULL_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=live/livestream,m=request", mode, vhost, subpath)); + EXPECT_EQ(SrtModePull, mode); EXPECT_STREQ("", vhost.c_str()); EXPECT_STREQ("live/livestream", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=live/livestream,m=publish", mode, vhost, subpath)); - EXPECT_EQ(PUSH_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=live/livestream,m=publish", mode, vhost, subpath)); + EXPECT_EQ(SrtModePush, mode); EXPECT_STREQ("", vhost.c_str()); EXPECT_STREQ("live/livestream", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=request", mode, vhost, subpath)); - EXPECT_EQ(PULL_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=request", mode, vhost, subpath)); + EXPECT_EQ(SrtModePull, mode); EXPECT_STREQ("srs.srt.com.cn", vhost.c_str()); EXPECT_STREQ("live/livestream?vhost=srs.srt.com.cn", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=publish", mode, vhost, subpath)); - EXPECT_EQ(PUSH_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=publish", mode, vhost, subpath)); + EXPECT_EQ(SrtModePush, mode); EXPECT_STREQ("srs.srt.com.cn", vhost.c_str()); EXPECT_STREQ("live/livestream?vhost=srs.srt.com.cn", subpath.c_str()); } if (true) { - int mode; string vhost; string subpath; - EXPECT_TRUE(get_streamid_info("#!::h=live/livestream?secret=d6d2be37,m=publish", mode, vhost, subpath)); - EXPECT_EQ(PUSH_SRT_MODE, mode); + SrtMode mode; string vhost; string subpath; + EXPECT_TRUE(srs_srt_streamid_info("#!::h=live/livestream?secret=d6d2be37,m=publish", mode, vhost, subpath)); + EXPECT_EQ(SrtModePush, mode); EXPECT_STREQ("", vhost.c_str()); EXPECT_STREQ("live/livestream?secret=d6d2be37", subpath.c_str()); } } +VOID TEST(ProtocolSrtTest, SrtStreamIdToRequest) +{ + if (true) { + SrtMode mode; + SrsRequest req; + EXPECT_TRUE(srs_srt_streamid_to_request("#!::r=live/livestream?key1=val1,key2=val2", mode, &req)); + EXPECT_EQ(mode, SrtModePull); + EXPECT_STREQ(req.vhost.c_str(), ""); + EXPECT_STREQ(req.app.c_str(), "live"); + EXPECT_STREQ(req.stream.c_str(), "livestream"); + EXPECT_STREQ(req.param.c_str(), "key1=val1&key2=val2"); + } + + if (true) { + SrtMode mode; + SrsRequest req; + EXPECT_TRUE(srs_srt_streamid_to_request("#!::h=srs.srt.com.cn,r=live/livestream?key1=val1,key2=val2", mode, &req)); + EXPECT_EQ(mode, SrtModePull); + EXPECT_STREQ(req.vhost.c_str(), "srs.srt.com.cn"); + EXPECT_STREQ(req.app.c_str(), "live"); + EXPECT_STREQ(req.stream.c_str(), "livestream"); + EXPECT_STREQ(req.param.c_str(), "vhost=srs.srt.com.cn&key1=val1&key2=val2"); + } + + if (true) { + SrtMode mode; + SrsRequest req; + EXPECT_TRUE(srs_srt_streamid_to_request("#!::h=live/livestream?key1=val1,key2=val2", mode, &req)); + EXPECT_EQ(mode, SrtModePull); + EXPECT_STREQ(req.vhost.c_str(), ""); + EXPECT_STREQ(req.app.c_str(), "live"); + EXPECT_STREQ(req.stream.c_str(), "livestream"); + EXPECT_STREQ(req.param.c_str(), "key1=val1&key2=val2"); + } + + if (true) { + SrtMode mode; + SrsRequest req; + EXPECT_TRUE(srs_srt_streamid_to_request("#!::h=srs.srt.com.cn/live/livestream?key1=val1,key2=val2", mode, &req)); + EXPECT_EQ(mode, SrtModePull); + EXPECT_STREQ(req.vhost.c_str(), "srs.srt.com.cn"); + EXPECT_STREQ(req.app.c_str(), "live"); + EXPECT_STREQ(req.stream.c_str(), "livestream"); + EXPECT_STREQ(req.param.c_str(), "vhost=srs.srt.com.cn&key1=val1&key2=val2"); + } +} + +// TODO: FIXME: add mpegts conn test +// set srt option, recv srt client, get srt client opt and check. + From 193fcbdb8b4a91a17f379ac5b095dc92ff662454 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 16 Apr 2022 08:05:30 +0800 Subject: [PATCH 02/36] SRT: Support debugging with CLion. --- trunk/ide/srs_clion/CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/trunk/ide/srs_clion/CMakeLists.txt b/trunk/ide/srs_clion/CMakeLists.txt index f1d7b41040f..6503e37ee61 100755 --- a/trunk/ide/srs_clion/CMakeLists.txt +++ b/trunk/ide/srs_clion/CMakeLists.txt @@ -61,19 +61,13 @@ INCLUDE_DIRECTORIES(${SRS_DIR}/objs ${SRS_DIR}/src/kernel ${SRS_DIR}/src/protocol ${SRS_DIR}/src/app - ${SRS_DIR}/src/service - ${SRS_DIR}/src/srt) + ${SRS_DIR}/src/service) # Common used sources for SRS and utest. AUX_SOURCE_DIRECTORY(${SRS_DIR}/src/core SOURCE_FILES) AUX_SOURCE_DIRECTORY(${SRS_DIR}/src/kernel SOURCE_FILES) AUX_SOURCE_DIRECTORY(${SRS_DIR}/src/protocol SOURCE_FILES) AUX_SOURCE_DIRECTORY(${SRS_DIR}/src/app SOURCE_FILES) -AUX_SOURCE_DIRECTORY(${SRS_DIR}/src/srt SOURCE_FILES) - -# Remove the duplicated test main for srt. -# TODO: FIMXE: Remove the file directly, use utest or main or research. -list(REMOVE_ITEM SOURCE_FILES ${SRS_DIR}/src/srt/ts_demux_test.cpp) ADD_DEFINITIONS("-g -O0") From a499a8c221d46f63cedda43728419a1d2f32f03b Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 16 Apr 2022 08:10:42 +0800 Subject: [PATCH 03/36] SRT: Eliminate unused files for SRT. --- trunk/src/srt/srt_conn.cpp | 263 ----------- trunk/src/srt/srt_conn.hpp | 63 --- trunk/src/srt/srt_data.cpp | 71 --- trunk/src/srt/srt_data.hpp | 48 -- trunk/src/srt/srt_handle.cpp | 406 ----------------- trunk/src/srt/srt_handle.hpp | 70 --- trunk/src/srt/srt_log.cpp | 36 -- trunk/src/srt/srt_log.hpp | 52 --- trunk/src/srt/srt_server.cpp | 359 --------------- trunk/src/srt/srt_server.hpp | 67 --- trunk/src/srt/srt_to_rtmp.cpp | 779 -------------------------------- trunk/src/srt/srt_to_rtmp.hpp | 162 ------- trunk/src/srt/stringex.hpp | 48 -- trunk/src/srt/time_help.hpp | 19 - trunk/src/srt/ts_demux.cpp | 603 ------------------------ trunk/src/srt/ts_demux.hpp | 247 ---------- trunk/src/srt/ts_demux_test.cpp | 61 --- 17 files changed, 3354 deletions(-) delete mode 100644 trunk/src/srt/srt_conn.cpp delete mode 100644 trunk/src/srt/srt_conn.hpp delete mode 100644 trunk/src/srt/srt_data.cpp delete mode 100644 trunk/src/srt/srt_data.hpp delete mode 100644 trunk/src/srt/srt_handle.cpp delete mode 100644 trunk/src/srt/srt_handle.hpp delete mode 100644 trunk/src/srt/srt_log.cpp delete mode 100644 trunk/src/srt/srt_log.hpp delete mode 100644 trunk/src/srt/srt_server.cpp delete mode 100644 trunk/src/srt/srt_server.hpp delete mode 100644 trunk/src/srt/srt_to_rtmp.cpp delete mode 100644 trunk/src/srt/srt_to_rtmp.hpp delete mode 100644 trunk/src/srt/stringex.hpp delete mode 100644 trunk/src/srt/time_help.hpp delete mode 100644 trunk/src/srt/ts_demux.cpp delete mode 100644 trunk/src/srt/ts_demux.hpp delete mode 100644 trunk/src/srt/ts_demux_test.cpp diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp deleted file mode 100644 index 66267032458..00000000000 --- a/trunk/src/srt/srt_conn.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "srt_conn.hpp" -#include "time_help.hpp" -#include "stringex.hpp" -#include "srt_log.hpp" -#include - -#include -#include -#include - -bool is_streamid_valid(const std::string& streamid) { - if (streamid.empty()) { - return false; - } - - size_t pos = streamid.find(" "); - if (pos != streamid.npos) { - return false; - } - - int mode; - std::string subpath; - std::string vhost; - - // Parse the stream info from streamid, see https://github.com/ossrs/srs/issues/2893 - bool ret = get_streamid_info(streamid, mode, vhost, subpath); - if (!ret) { - return false; - } - - std::vector info_vec; - string_split(subpath, "/", info_vec); - - // TODO: FIXME: Should fail at parsing the original SRT URL. - if (info_vec.size() != 2) { - srt_log_warn("path format must be appname/stream?key=value..."); - return false; - } - - for (auto item : info_vec) { - if (item.empty()) { - return false; - } - pos = item.find(" "); - if (pos != item.npos) { - return false; - } - } - return true; -} - -bool get_key_value(const std::string& info, std::string& key, std::string& value) { - size_t pos = info.find("="); - - if (pos == info.npos) { - return false; - } - - key = info.substr(0, pos); - value = info.substr(pos+1); - - if (key.empty() || value.empty()) { - return false; - } - return true; -} - -// See streamid of https://github.com/ossrs/srs/issues/2893 -// TODO: FIMXE: We should parse SRT streamid to URL object, rather than a HTTP url subpath. -bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhost, std::string& url_subpath) -{ - mode = PULL_SRT_MODE; - - size_t pos = streamid.find("#!::"); - if (pos != 0) { - pos = streamid.find("/"); - if (pos == streamid.npos) { - url_subpath = _srs_config->get_default_app_name() + "/" + streamid; - return true; - } - url_subpath = streamid; - return true; - } - - //SRT url supports multiple QueryStrings, which are passed to RTMP to realize authentication and other capabilities - //@see https://github.com/ossrs/srs/issues/2893 - std::string params; - std::string real_streamid; - real_streamid = streamid.substr(4); - - // Compatible with previous auth querystring, like this one: - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream?secret=xxx,m=publish - real_streamid = srs_string_replace(real_streamid, "?", ","); - - std::map query; - srs_parse_query_string(real_streamid, query); - for (std::map::iterator it = query.begin(); it != query.end(); ++it) { - if (it->first == "h") { - std::string host = it->second; - - size_t r0 = host.find("/"); - size_t r1 = host.rfind("/"); - if (r0 != std::string::npos && r0 != std::string::npos) { - // Compatible with previous style, see https://github.com/ossrs/srs/issues/2893#compatible - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=publish - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=request - // srt://127.0.0.1:10080?streamid=#!::h=srs.srt.com.cn/live/livestream,m=publish - if (r0 != r1) { - // We got vhost in host. - url_subpath = host.substr(r0 + 1); - host = host.substr(0, r0); - - params.append("vhost="); - params.append(host); - params.append("&"); - vhost = host; - } else { - // Only stream in host. - url_subpath = host; - } - } else { - // New URL style, see https://github.com/ossrs/srs/issues/2893#solution - // srt://host.com:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 - // srt://1.2.3.4:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 - // srt://1.2.3.4:10080?streamid=#!::r=app/stream,key1=value1,key2=value2 - params.append("vhost="); - params.append(host); - params.append("&"); - vhost = host; - } - } else if (it->first == "r") { - url_subpath = it->second; - } else if (it->first == "m") { - std::string mode_str = it->second; // support m=publish or m=request - std::transform(it->second.begin(), it->second.end(), mode_str.begin(), ::tolower); - if (mode_str == "publish") { - mode = PUSH_SRT_MODE; - } else if (mode_str == "request") { - mode = PULL_SRT_MODE; - } else { - srt_log_warn("unknown mode_str:%s", mode_str.c_str()); - return false; - } - } else { - params.append(it->first); - params.append("="); - params.append(it->second); - params.append("&"); - } - } - - if (url_subpath.empty()) { - return false; - } - - if (!params.empty()) { - url_subpath.append("?"); - url_subpath.append(params); - url_subpath.pop_back(); // remove last '&' - } - - return true; -} - -srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd), - _streamid(streamid), - write_fail_cnt_(0) -{ - get_streamid_info(streamid, _mode, _vhost, _url_subpath); - - _update_timestamp = now_ms(); - - if (_vhost.empty()) { - _vhost = "__default_host__"; - } - - srt_log_trace("srt connect construct streamid:%s, mode:%d, subpath:%s, vhost:%s", - streamid.c_str(), _mode, _url_subpath.c_str(), _vhost.c_str()); -} - -srt_conn::~srt_conn() { - close(); -} - -std::string srt_conn::get_vhost() { - return _vhost; -} - -void srt_conn::update_timestamp(long long now_ts) { - _update_timestamp = now_ts; -} - -long long srt_conn::get_last_ts() { - return _update_timestamp; -} - -void srt_conn::close() { - if (_conn_fd == SRT_INVALID_SOCK) { - return; - } - srt_close(_conn_fd); - _conn_fd = SRT_INVALID_SOCK; -} - -SRTSOCKET srt_conn::get_conn() { - return _conn_fd; -} -int srt_conn::get_mode() { - return _mode; -} - -std::string srt_conn::get_streamid() { - return _streamid; -} - -std::string srt_conn::get_path() { - if (!_url_path.empty()) { - return _url_path; - } - - size_t pos = _url_subpath.find("?"); - _url_path = (pos != std::string::npos) ? _url_subpath.substr(0, pos) : _url_subpath; - - return _url_path; -} - -std::string srt_conn::get_subpath() { - return _url_subpath; -} - -int srt_conn::read(unsigned char* data, int len) { - int ret = 0; - - ret = srt_recv(_conn_fd, (char*)data, len); - if (ret <= 0) { - srt_log_error("srt read error:%d, socket fd:%d", ret, _conn_fd); - return ret; - } - return ret; -} - -int srt_conn::write(unsigned char* data, int len) { - int ret = 0; - - ret = srt_send(_conn_fd, (char*)data, len); - if (ret <= 0) { - srt_log_error("srt write error:%d, socket fd:%d", ret, _conn_fd); - write_fail_cnt_++; - return ret; - } - write_fail_cnt_ = 0; - return ret; -} - -int srt_conn::get_write_fail_count() { - return write_fail_cnt_; -} \ No newline at end of file diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp deleted file mode 100644 index 0608e230590..00000000000 --- a/trunk/src/srt/srt_conn.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRT_CONN_H -#define SRT_CONN_H - -#include - -#include "stringex.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ERR_SRT_MODE 0x00 -#define PULL_SRT_MODE 0x01 -#define PUSH_SRT_MODE 0x02 - -bool is_streamid_valid(const std::string& streamid); -bool get_key_value(const std::string& info, std::string& key, std::string& value); -bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhost, std::string& url_subpash); - -class srt_conn { -public: - srt_conn(SRTSOCKET conn_fd, const std::string& streamid); - ~srt_conn(); - - void close(); - SRTSOCKET get_conn(); - int get_mode(); - std::string get_streamid(); - std::string get_path(); - std::string get_subpath(); - std::string get_vhost(); - int read(unsigned char* data, int len); - int write(unsigned char* data, int len); - - void update_timestamp(long long now_ts); - long long get_last_ts(); - int get_write_fail_count(); - -private: - SRTSOCKET _conn_fd; - std::string _streamid; - std::string _url_path; - std::string _url_subpath; - std::string _vhost; - int _mode; - long long _update_timestamp; - int write_fail_cnt_; -}; - -typedef std::shared_ptr SRT_CONN_PTR; - -#endif //SRT_CONN_H diff --git a/trunk/src/srt/srt_data.cpp b/trunk/src/srt/srt_data.cpp deleted file mode 100644 index 2087b70d57d..00000000000 --- a/trunk/src/srt/srt_data.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "srt_data.hpp" -#include - -SRT_DATA_MSG::SRT_DATA_MSG(const std::string& path, unsigned int msg_type):_msg_type(msg_type) - ,_len(0) - ,_data_p(nullptr) - ,_key_path(path) { - -} - -SRT_DATA_MSG::SRT_DATA_MSG(unsigned int len, const std::string& path, unsigned int msg_type):_msg_type(msg_type) - ,_len(len) - ,_key_path(path) { - _data_p = new unsigned char[len]; - memset(_data_p, 0, len); -} - -SRT_DATA_MSG::SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path, unsigned int msg_type):_msg_type(msg_type) - ,_len(len) - ,_key_path(path) -{ - _data_p = new unsigned char[len]; - memcpy(_data_p, data_p, len); -} - -SRT_DATA_MSG::SRT_DATA_MSG(LOGGER_LEVEL log_level, const std::string& log_content): _msg_type(SRT_MSG_LOG_TYPE) - ,_log_content(log_content) - ,_log_level(log_level) -{ - -} - -SRT_DATA_MSG::~SRT_DATA_MSG() { - if (_data_p && (_len > 0)) { - delete[] _data_p; - } -} - -unsigned int SRT_DATA_MSG::msg_type() { - return _msg_type; -} - -void SRT_DATA_MSG::set_msg_type(unsigned int msg_type) { - _msg_type = msg_type; -} - -std::string SRT_DATA_MSG::get_path() { - return _key_path; -} - -unsigned int SRT_DATA_MSG::data_len() { - return _len; -} - -unsigned char* SRT_DATA_MSG::get_data() { - return _data_p; -} - -LOGGER_LEVEL SRT_DATA_MSG::get_log_level() { - return _log_level; -} - -const char* SRT_DATA_MSG::get_log_string() { - return _log_content.c_str(); -} diff --git a/trunk/src/srt/srt_data.hpp b/trunk/src/srt/srt_data.hpp deleted file mode 100644 index e7241fc90f0..00000000000 --- a/trunk/src/srt/srt_data.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRT_DATA_H -#define SRT_DATA_H - -#include "srt_log.hpp" -#include - -#include -#include - -#define SRT_MSG_DATA_TYPE 0x01 -#define SRT_MSG_CLOSE_TYPE 0x02 -#define SRT_MSG_LOG_TYPE 0x03 - -class SRT_DATA_MSG { -public: - SRT_DATA_MSG(const std::string& path, unsigned int msg_type=SRT_MSG_DATA_TYPE); - SRT_DATA_MSG(unsigned int len, const std::string& path, unsigned int msg_type=SRT_MSG_DATA_TYPE); - SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path, unsigned int msg_type=SRT_MSG_DATA_TYPE); - SRT_DATA_MSG(LOGGER_LEVEL log_level, const std::string& log_content); - ~SRT_DATA_MSG(); - - unsigned int msg_type(); - unsigned int data_len(); - unsigned char* get_data(); - std::string get_path(); - LOGGER_LEVEL get_log_level(); - const char* get_log_string(); - - void set_msg_type(unsigned int msg_type); - -private: - unsigned int _msg_type; - unsigned int _len = 0; - unsigned char* _data_p = nullptr; - std::string _key_path; - std::string _log_content; - LOGGER_LEVEL _log_level = SRT_LOGGER_TRACE_LEVEL; -}; - -typedef std::shared_ptr SRT_DATA_MSG_PTR; - -#endif diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp deleted file mode 100644 index fd1f951bb46..00000000000 --- a/trunk/src/srt/srt_handle.cpp +++ /dev/null @@ -1,406 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "srt_handle.hpp" -#include "time_help.hpp" -#include "srt_log.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static bool MONITOR_STATICS_ENABLE = false; -static long long MONITOR_TIMEOUT = 5000; -const unsigned int DEF_DATA_SIZE = 188*7; -const long long CHECK_ALIVE_INTERVAL = 5*1000; -const long long CHECK_ALIVE_TIMEOUT = 5*1000; -static const int SRT_WRTIE_FAIL_MAX = 10; - -long long srt_now_ms = 0; - -srt_handle::srt_handle(int pollid):_handle_pollid(pollid) - ,_last_timestamp(0) - ,_last_check_alive_ts(0) { -} - -srt_handle::~srt_handle() { - -} - -void srt_handle::debug_statics(SRTSOCKET srtsocket, const std::string& streamid) { - SRT_TRACEBSTATS mon; - srt_bstats(srtsocket, &mon, 1); - std::ostringstream output; - long long now_ul = now_ms(); - - if (!MONITOR_STATICS_ENABLE) { - return; - } - if (_last_timestamp == 0) { - _last_timestamp = now_ul; - return; - } - - if ((now_ul - _last_timestamp) < MONITOR_TIMEOUT) { - return; - } - _last_timestamp = now_ul; - output << "======= SRT STATS: sid=" << streamid << std::endl; - output << "PACKETS SENT: " << std::setw(11) << mon.pktSent << " RECEIVED: " << std::setw(11) << mon.pktRecv << std::endl; - output << "LOST PKT SENT: " << std::setw(11) << mon.pktSndLoss << " RECEIVED: " << std::setw(11) << mon.pktRcvLoss << std::endl; - output << "REXMIT SENT: " << std::setw(11) << mon.pktRetrans << " RECEIVED: " << std::setw(11) << mon.pktRcvRetrans << std::endl; - output << "DROP PKT SENT: " << std::setw(11) << mon.pktSndDrop << " RECEIVED: " << std::setw(11) << mon.pktRcvDrop << std::endl; - output << "RATE SENDING: " << std::setw(11) << mon.mbpsSendRate << " RECEIVING: " << std::setw(11) << mon.mbpsRecvRate << std::endl; - output << "BELATED RECEIVED: " << std::setw(11) << mon.pktRcvBelated << " AVG TIME: " << std::setw(11) << mon.pktRcvAvgBelatedTime << std::endl; - output << "REORDER DISTANCE: " << std::setw(11) << mon.pktReorderDistance << std::endl; - output << "WINDOW FLOW: " << std::setw(11) << mon.pktFlowWindow << " CONGESTION: " << std::setw(11) << mon.pktCongestionWindow << " FLIGHT: " << std::setw(11) << mon.pktFlightSize << std::endl; - output << "LINK RTT: " << std::setw(9) << mon.msRTT << "ms BANDWIDTH: " << std::setw(7) << mon.mbpsBandwidth << "Mb/s " << std::endl; - output << "BUFFERLEFT: SND: " << std::setw(11) << mon.byteAvailSndBuf << " RCV: " << std::setw(11) << mon.byteAvailRcvBuf << std::endl; - - srt_log_trace("\r\n%s", output.str().c_str()); - return; -} - -void srt_handle::add_new_puller(SRT_CONN_PTR conn_ptr, std::string stream_id) { - _conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); - - auto iter = _streamid_map.find(stream_id); - if (iter == _streamid_map.end()) { - std::unordered_map srtsocket_map; - srtsocket_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); - - _streamid_map.insert(std::make_pair(stream_id, srtsocket_map)); - srt_log_trace("add new puller fd:%d, streamid:%s", conn_ptr->get_conn(), stream_id.c_str()); - } else { - iter->second.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); - srt_log_trace("add new puller fd:%d, streamid:%s, size:%d", - conn_ptr->get_conn(), stream_id.c_str(), iter->second.size()); - } - - return; -} - -void srt_handle::close_pull_conn(SRTSOCKET srtsocket, std::string stream_id) { - srt_log_trace("close_pull_conn read_fd=%d, streamid=%s", srtsocket, stream_id.c_str()); - srt_epoll_remove_usock(_handle_pollid, srtsocket); - - auto streamid_iter = _streamid_map.find(stream_id); - if (streamid_iter != _streamid_map.end()) { - if (streamid_iter->second.size() == 0) { - _streamid_map.erase(stream_id); - } else if (streamid_iter->second.size() == 1) { - streamid_iter->second.erase(srtsocket); - _streamid_map.erase(stream_id); - } else { - streamid_iter->second.erase(srtsocket); - } - } else { - assert(0); - } - - auto conn_iter = _conn_map.find(srtsocket); - if (conn_iter != _conn_map.end()) { - _conn_map.erase(conn_iter); - return; - } else { - assert(0); - } - - return; -} - -SRT_CONN_PTR srt_handle::get_srt_conn(SRTSOCKET conn_srt_socket) { - SRT_CONN_PTR ret_conn; - - auto iter = _conn_map.find(conn_srt_socket); - if (iter == _conn_map.end()) { - return ret_conn; - } - - ret_conn = iter->second; - - return ret_conn; -} - -void srt_handle::add_newconn(SRT_CONN_PTR conn_ptr, int events) { - int val_i; - int opt_len = sizeof(int); - - int64_t val_i64; - int opt64_len = sizeof(int64_t); - - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_LATENCY, &val_i, &opt_len); - srt_log_trace("srto SRTO_LATENCY=%d", val_i); - - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_PEERLATENCY, &val_i, &opt_len); - srt_log_trace("srto SRTO_PEERLATENCY=%d", val_i); - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVLATENCY, &val_i, &opt_len); - srt_log_trace("srto SRTO_RCVLATENCY=%d", val_i); - - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_SNDBUF, &val_i, &opt_len); - srt_log_trace("srto SRTO_SNDBUF=%d", val_i); - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVBUF, &val_i, &opt_len); - srt_log_trace("srto SRTO_RCVBUF=%d", val_i); - srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_MAXBW, &val_i64, &opt64_len); - srt_log_trace("srto SRTO_MAXBW=%d", val_i64); - srt_log_trace("srt mix_correct is %s.", _srs_config->get_srt_mix_correct() ? "enable" : "disable"); - srt_log_trace("srt h264 sei filter is %s.", _srs_config->get_srt_sei_filter() ? "enable" : "disable"); - - if (conn_ptr->get_mode() == PULL_SRT_MODE) { - add_new_puller(conn_ptr, conn_ptr->get_path()); - } else { - if(add_new_pusher(conn_ptr) == false) { - srt_log_trace("push connection is repeated and rejected, fd:%d, streamid:%s", - conn_ptr->get_conn(), conn_ptr->get_streamid().c_str()); - conn_ptr->close(); - return; - } - } - srt_log_trace("new conn added fd:%d, event:0x%08x", conn_ptr->get_conn(), events); - int ret = srt_epoll_add_usock(_handle_pollid, conn_ptr->get_conn(), &events); - if (ret < 0) { - srt_log_error("srt handle run add epoll error:%d", ret); - return; - } - - return; -} - -void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& path, const std::string& subpath, SRTSOCKET conn_fd) { - SRT_CONN_PTR srt_conn_ptr; - unsigned char data[DEF_DATA_SIZE]; - int ret; - srt_conn_ptr = get_srt_conn(conn_fd); - - if (!srt_conn_ptr) { - srt_log_error("handle_push_data fd:%d fail to find srt connection.", conn_fd); - return; - } - - if (status != SRTS_CONNECTED) { - srt_log_error("handle_push_data error status:%d fd:%d", status, conn_fd); - close_push_conn(conn_fd); - return; - } - - ret = srt_conn_ptr->read(data, DEF_DATA_SIZE); - if (ret <= 0) { - srt_log_error("handle_push_data srt connect read error:%d, fd:%d", ret, conn_fd); - close_push_conn(conn_fd); - return; - } - - srt_conn_ptr->update_timestamp(srt_now_ms); - - srt2rtmp::get_instance()->insert_data_message(data, ret, subpath); - { - std::unique_lock locker(srt2rtmp::_srt_error_mutex); - if (srt2rtmp::_srt_error_map.count(subpath) == 1) { - int err_code = srt2rtmp::_srt_error_map[subpath]; - if (err_code != ERROR_SUCCESS) { - close_push_conn(conn_fd); - srt_log_error("handle_push_data srt to rtmp error:%d, fd:%d", err_code,conn_fd); - //todo: reset to next use, maybe update by srt2rtmp::cycle again - srt2rtmp::_srt_error_map[subpath] = ERROR_SUCCESS; - return; - } - } - } - - //send data to subscriber(players) - //streamid, play map - auto streamid_iter = _streamid_map.find(path); - if (streamid_iter == _streamid_map.end()) {//no puler - srt_log_info("receive data size(%d) from pusher(%d) but no puller", ret, conn_fd); - return; - } - srt_log_info("receive data size(%d) from pusher(%d) to pullers, count:%d", - ret, conn_fd, streamid_iter->second.size()); - - std::vector remove_vec; - for (auto puller_iter = streamid_iter->second.begin(); - puller_iter != streamid_iter->second.end(); - puller_iter++) { - auto player_conn = puller_iter->second; - if (!player_conn) { - srt_log_error("handle_push_data get srt connect error from fd:%d", puller_iter->first); - continue; - } - int write_ret = player_conn->write(data, ret); - srt_log_info("send data size(%d) to puller fd:%d", write_ret, puller_iter->first); - if (write_ret > 0) { - puller_iter->second->update_timestamp(srt_now_ms); - } else { - if (player_conn->get_write_fail_count() > SRT_WRTIE_FAIL_MAX) { - remove_vec.push_back(puller_iter->first); - } - } - } - - for (auto item : remove_vec) { - streamid_iter->second.erase(item); - if (streamid_iter->second.empty()) { - _streamid_map.erase(streamid_iter); - } - } - - return; -} - -void srt_handle::check_alive() { - long long diff_t; - std::list conn_list; - - if (_last_check_alive_ts == 0) { - _last_check_alive_ts = srt_now_ms; - return; - } - diff_t = srt_now_ms - _last_check_alive_ts; - if (diff_t < CHECK_ALIVE_INTERVAL) { - return; - } - - for (auto conn_iter = _conn_map.begin(); - conn_iter != _conn_map.end(); - conn_iter++) - { - long long timeout = srt_now_ms - conn_iter->second->get_last_ts(); - if (timeout > CHECK_ALIVE_TIMEOUT) { - conn_list.push_back(conn_iter->second); - } - } - - for (auto del_iter = conn_list.begin(); - del_iter != conn_list.end(); - del_iter++) - { - SRT_CONN_PTR conn_ptr = *del_iter; - if (conn_ptr->get_mode() == PUSH_SRT_MODE) { - srt_log_warn("check alive close pull connection fd:%d, streamid:%s", - conn_ptr->get_conn(), conn_ptr->get_subpath().c_str()); - close_push_conn(conn_ptr->get_conn()); - } else if (conn_ptr->get_mode() == PULL_SRT_MODE) { - srt_log_warn("check alive close pull connection fd:%d, streamid:%s", - conn_ptr->get_conn(), conn_ptr->get_path().c_str()); - close_pull_conn(conn_ptr->get_conn(), conn_ptr->get_path()); - } else { - srt_log_error("check_alive get unkown srt mode:%d, fd:%d", - conn_ptr->get_mode(), conn_ptr->get_conn()); - assert(0); - } - } -} - -void srt_handle::close_push_conn(SRTSOCKET srtsocket) { - auto iter = _conn_map.find(srtsocket); - - if (iter != _conn_map.end()) { - SRT_CONN_PTR conn_ptr = iter->second; - auto push_iter = _push_conn_map.find(conn_ptr->get_path()); - if (push_iter != _push_conn_map.end()) { - _push_conn_map.erase(push_iter); - } - _conn_map.erase(iter); - srt2rtmp::get_instance()->insert_ctrl_message(SRT_MSG_CLOSE_TYPE, conn_ptr->get_subpath()); - conn_ptr->close(); - } - - srt_epoll_remove_usock(_handle_pollid, srtsocket); - - return; -} - -bool srt_handle::add_new_pusher(SRT_CONN_PTR conn_ptr) { - auto push_iter = _push_conn_map.find(conn_ptr->get_path()); - if (push_iter != _push_conn_map.end()) { - return false; - } - _push_conn_map.insert(std::make_pair(conn_ptr->get_path(), conn_ptr)); - _conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); - srt_log_trace("srt_handle add new pusher streamid:%s, subpath:%s, sid:%s", - conn_ptr->get_streamid().c_str(), conn_ptr->get_subpath().c_str(), conn_ptr->get_path().c_str()); - return true; -} - -void srt_handle::handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) { - srt_log_info("handle_pull_data status:%d, subpath:%s, fd:%d", - status, subpath.c_str(), conn_fd); - auto conn_ptr = get_srt_conn(conn_fd); - if (!conn_ptr) { - srt_log_error("handle_pull_data fail to find fd(%d)", conn_fd); - assert(0); - return; - } - conn_ptr->update_timestamp(srt_now_ms); -} - -void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd) -{ - auto conn_ptr = get_srt_conn(conn_fd); - if (!conn_ptr) { - if (status != SRTS_CLOSED) { - srt_log_error("handle_srt_socket find srt connection error, fd:%d, status:%d", - conn_fd, status); - } - return; - } - - std::string path = conn_ptr->get_path(); - std::string subpath = conn_ptr->get_subpath(); - - int mode = conn_ptr->get_mode(); - if (mode == PUSH_SRT_MODE) { - switch (status) - { - case SRTS_CONNECTED: - { - handle_push_data(status, path, subpath, conn_fd); - break; - } - case SRTS_BROKEN: - { - srt_log_warn("srt push disconnected event fd:%d, streamid:%s", - conn_fd, conn_ptr->get_streamid().c_str()); - close_push_conn(conn_fd); - break; - } - default: - srt_log_error("push mode unkown status:%d, fd:%d", status, conn_fd); - break; - } - } else if (mode == PULL_SRT_MODE) { - switch (status) - { - case SRTS_CONNECTED: - { - handle_pull_data(status, subpath, conn_fd); - break; - } - case SRTS_BROKEN: - { - srt_log_warn("srt pull disconnected fd:%d, streamid:%s", - conn_fd, conn_ptr->get_streamid().c_str()); - close_pull_conn(conn_fd, path); - break; - } - default: - srt_log_error("pull mode unkown status:%d, fd:%d", status, conn_fd); - break; - } - } else { - assert(0); - } - return; -} diff --git a/trunk/src/srt/srt_handle.hpp b/trunk/src/srt/srt_handle.hpp deleted file mode 100644 index 052ac0f19a6..00000000000 --- a/trunk/src/srt/srt_handle.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRT_HANDLE_H -#define SRT_HANDLE_H - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "srt_conn.hpp" -#include "srt_to_rtmp.hpp" - -class srt_handle { -public: - srt_handle(int pollid); - ~srt_handle(); - - //add new srt connection into epoll event - void add_newconn(SRT_CONN_PTR conn_ptr, int events); - //handle recv/send srt socket - void handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd); - //check srt connection whether it's still alive. - void check_alive(); - -private: - //get srt conn object by srt socket - SRT_CONN_PTR get_srt_conn(SRTSOCKET conn_srt_socket); - - void handle_push_data(SRT_SOCKSTATUS status, const std::string& path, const std::string& subpath, SRTSOCKET conn_fd); - void handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd); - - //add new puller into puller list and conn_map - void add_new_puller(SRT_CONN_PTR, std::string stream_id); - //remove pull srt from play list - void close_pull_conn(SRTSOCKET srtsocket, std::string stream_id); - - //add new pusher into pusher map: - bool add_new_pusher(SRT_CONN_PTR conn_ptr); - //remove push connection and remove epoll - void close_push_conn(SRTSOCKET srtsocket); - - //debug statics - void debug_statics(SRTSOCKET srtsocket, const std::string& streamid); - -private: - int _handle_pollid; - - std::unordered_map _conn_map;//save all srt connection: pull or push - - //save push srt connection for prevent from repeat push connection - std::unordered_map _push_conn_map;//key:streamid, value:SRT_CONN_PTR - //streamid, play map - std::unordered_map> _streamid_map; - - long long _last_timestamp; - long long _last_check_alive_ts; -}; - -#endif //SRT_HANDLE_H diff --git a/trunk/src/srt/srt_log.cpp b/trunk/src/srt/srt_log.cpp deleted file mode 100644 index f850b720303..00000000000 --- a/trunk/src/srt/srt_log.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "srt_log.hpp" -#include "srt_to_rtmp.hpp" -#include -#include -#include - -LOGGER_LEVEL s_log_level = SRT_LOGGER_TRACE_LEVEL; -static char* srt_log_buffer = new char[LOGGER_BUFFER_SIZE]; - -void snprintbuffer(char* buffer, size_t size, const char* fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vsnprintf(buffer, size, fmt, ap); - va_end(ap); - - return; -} - -void set_srt_log_level(LOGGER_LEVEL level) { - s_log_level = level; -} - -LOGGER_LEVEL get_srt_log_level() { - return s_log_level; -} - -char* get_srt_log_buffer() { - return srt_log_buffer; -} - -void srt_log_output(LOGGER_LEVEL level, const char* buffer) { - std::string log_content(buffer); - srt2rtmp::get_instance()->insert_log_message(level, log_content); - return; -} diff --git a/trunk/src/srt/srt_log.hpp b/trunk/src/srt/srt_log.hpp deleted file mode 100644 index a7b2f5d348b..00000000000 --- a/trunk/src/srt/srt_log.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef SRT_LOG_HPP -#define SRT_LOG_HPP -#include -#include - -#define LOGGER_BUFFER_SIZE (10*1024) - -typedef enum { - SRT_LOGGER_INFO_LEVEL, - SRT_LOGGER_TRACE_LEVEL, - SRT_LOGGER_WARN_LEVEL, - SRT_LOGGER_ERROR_LEVEL -} LOGGER_LEVEL; - -void set_srt_log_level(LOGGER_LEVEL level); -LOGGER_LEVEL get_srt_log_level(); -char* get_srt_log_buffer(); -void srt_log_output(LOGGER_LEVEL level, const char* buffer); -void snprintbuffer(char* buffer, size_t size, const char* fmt, ...); - -#define srt_log_error(...) \ - if (get_srt_log_level() <= SRT_LOGGER_ERROR_LEVEL) \ - { \ - char* buffer = get_srt_log_buffer(); \ - snprintbuffer(buffer, LOGGER_BUFFER_SIZE, __VA_ARGS__); \ - srt_log_output(SRT_LOGGER_ERROR_LEVEL, buffer); \ - } - -#define srt_log_warn(...) \ - if (get_srt_log_level() <= SRT_LOGGER_WARN_LEVEL) \ - { \ - char* buffer = get_srt_log_buffer(); \ - snprintbuffer(buffer, LOGGER_BUFFER_SIZE, __VA_ARGS__); \ - srt_log_output(SRT_LOGGER_WARN_LEVEL, buffer); \ - } - -#define srt_log_trace(...) \ - if (get_srt_log_level() <= SRT_LOGGER_TRACE_LEVEL) \ - { \ - char* buffer = get_srt_log_buffer(); \ - snprintbuffer(buffer, LOGGER_BUFFER_SIZE, __VA_ARGS__); \ - srt_log_output(SRT_LOGGER_TRACE_LEVEL, buffer); \ - } - -#define srt_log_info(...) \ - if (get_srt_log_level() <= SRT_LOGGER_INFO_LEVEL) \ - { \ - char* buffer = get_srt_log_buffer(); \ - snprintbuffer(buffer, LOGGER_BUFFER_SIZE, __VA_ARGS__); \ - srt_log_output(SRT_LOGGER_INFO_LEVEL, buffer); \ - } -#endif //SRT_LOG_HPP \ No newline at end of file diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp deleted file mode 100644 index 10630efa3d7..00000000000 --- a/trunk/src/srt/srt_server.cpp +++ /dev/null @@ -1,359 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "srt_server.hpp" -#include "srt_handle.hpp" -#include "srt_log.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -srt_server::srt_server(unsigned short port):_listen_port(port) - ,_server_socket(-1) -{ -} - -srt_server::~srt_server() -{ - -} - -int srt_server::init_srt_parameter() { - const int DEF_RECV_LATENCY = 120; - const int DEF_PEER_LATENCY = 0; - - int opt_len = sizeof(int); - - if (_server_socket == -1) { - return -1; - } - int maxbw = _srs_config->get_srto_maxbw(); - srt_setsockopt(_server_socket, 0, SRTO_MAXBW, &maxbw, opt_len); - int mss = _srs_config->get_srto_mss(); - srt_setsockopt(_server_socket, 0, SRTO_MSS, &mss, opt_len); - - bool tlpkdrop = _srs_config->get_srto_tlpkdrop(); - int tlpkdrop_i = tlpkdrop ? 1 : 0; - srt_setsockopt(_server_socket, 0, SRTO_TLPKTDROP, &tlpkdrop_i, opt_len); - - int connection_timeout = _srs_config->get_srto_conntimeout(); - srt_setsockopt(_server_socket, 0, SRTO_CONNTIMEO, &connection_timeout, opt_len); - - int send_buff = _srs_config->get_srto_sendbuf(); - srt_setsockopt(_server_socket, 0, SRTO_SNDBUF, &send_buff, opt_len); - int recv_buff = _srs_config->get_srto_recvbuf(); - srt_setsockopt(_server_socket, 0, SRTO_RCVBUF, &recv_buff, opt_len); - int payload_size = _srs_config->get_srto_payloadsize(); - srt_setsockopt(_server_socket, 0, SRTO_PAYLOADSIZE, &payload_size, opt_len); - - int latency = _srs_config->get_srto_latency(); - if (DEF_RECV_LATENCY != latency) { - srt_setsockopt(_server_socket, 0, SRTO_LATENCY, &latency, opt_len); - } - - int recv_latency = _srs_config->get_srto_recv_latency(); - if (DEF_RECV_LATENCY != recv_latency) { - srt_setsockopt(_server_socket, 0, SRTO_RCVLATENCY, &recv_latency, opt_len); - } - - int peer_latency = _srs_config->get_srto_peer_latency(); - if (DEF_PEER_LATENCY != peer_latency) { - srt_setsockopt(_server_socket, 0, SRTO_PEERLATENCY, &recv_latency, opt_len); - } - - srt_log_trace("init srt parameter, maxbw:%d, mss:%d, tlpkdrop:%d, connect timeout:%d, \ -send buff:%d, recv buff:%d, payload size:%d, latency:%d, recv latency:%d, peer latency:%d", - maxbw, mss, tlpkdrop, connection_timeout, send_buff, recv_buff, payload_size, - latency, recv_latency, peer_latency); - return 0; -} - -void srt_server::init_srt_log() { - SrsLogLevel level = srs_get_log_level(_srs_config->get_log_level()); - switch (level) { - case SrsLogLevelInfo: - { - set_srt_log_level(SRT_LOGGER_INFO_LEVEL); - break; - } - case SrsLogLevelTrace: - { - set_srt_log_level(SRT_LOGGER_TRACE_LEVEL); - break; - } - case SrsLogLevelWarn: - { - set_srt_log_level(SRT_LOGGER_WARN_LEVEL); - break; - } - case SrsLogLevelError: - { - set_srt_log_level(SRT_LOGGER_ERROR_LEVEL); - break; - } - default: - { - set_srt_log_level(SRT_LOGGER_TRACE_LEVEL); - } - } - return; -} - -int srt_server::init_srt() { - if (_server_socket != -1) { - return -1; - } - - init_srt_log(); - - _server_socket = srt_create_socket(); - sockaddr_in sa; - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; - sa.sin_port = htons(_listen_port); - - sockaddr* psa = (sockaddr*)&sa; - - int ret = srt_bind(_server_socket, psa, sizeof(sa)); - if ( ret == SRT_ERROR ) - { - srt_close(_server_socket); - srt_log_error("srt bind error: %d", ret); - return -1; - } - - ret = srt_listen(_server_socket, 5); - if (ret == SRT_ERROR) - { - srt_close(_server_socket); - srt_log_error("srt listen error: %d", ret); - return -2; - } - - init_srt_parameter(); - - _pollid = srt_epoll_create(); - if (_pollid < -1) { - srt_log_error("srt server srt_epoll_create error, port=%d", _listen_port); - return -1; - } - _handle_ptr = std::make_shared(_pollid); - - int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; - ret = srt_epoll_add_usock(_pollid, _server_socket, &events); - if (ret < 0) { - srt_log_error("srt server run add epoll error:%d", ret); - return ret; - } - - srt_log_trace("srt server listen port=%d, server_fd=%d", _listen_port, _server_socket); - - return 0; -} - -int srt_server::start() -{ - int ret; - - if ((ret = init_srt()) < 0) { - return ret; - } - - run_flag = true; - srt_log_trace("srt server is starting... port(%d)", _listen_port); - thread_run_ptr = std::make_shared(&srt_server::on_work, this); - return 0; -} - -void srt_server::stop() -{ - run_flag = false; - if (!thread_run_ptr) { - return; - } - thread_run_ptr->join(); - - return; -} - -void srt_server::srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr) { - SRTSOCKET conn_fd = -1; - sockaddr_in scl; - int sclen = sizeof(scl); - int conn_event;// = SRT_EPOLL_IN |SRT_EPOLL_OUT| SRT_EPOLL_ERR; - - switch(status) { - case SRTS_LISTENING: - { - conn_fd = srt_accept(input_fd, (sockaddr*)&scl, &sclen); - if (conn_fd == -1) { - return; - } - //add new srt connect into srt handle - std::string streamid = UDT::getstreamid(conn_fd); - if (!is_streamid_valid(streamid)) { - srt_log_trace("srt streamid(%s) error, fd:%d", streamid.c_str(), conn_fd); - srt_close(conn_fd); - return; - } - SRT_CONN_PTR srt_conn_ptr = std::make_shared(conn_fd, streamid); - - std::string vhost_str = srt_conn_ptr->get_vhost(); - srt_log_trace("new srt connection streamid:%s, fd:%d, vhost:%s", - streamid.c_str(), conn_fd, vhost_str.c_str()); - SrsConfDirective* vhost_p = _srs_config->get_vhost(vhost_str, true); - if (!vhost_p) { - srt_log_trace("srt streamid(%s): no vhost %s, fd:%d", - streamid.c_str(), vhost_str.c_str(), conn_fd); - srt_conn_ptr->close(); - return; - } - if (srt_conn_ptr->get_mode() == PULL_SRT_MODE) { - //add SRT_EPOLL_IN for information notify - conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR;//not inlucde SRT_EPOLL_OUT for save cpu - } else if (srt_conn_ptr->get_mode() == PUSH_SRT_MODE) { - conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR; - } else { - srt_log_trace("stream mode error, it should be m=push or m=pull, streamid:%s", - srt_conn_ptr->get_streamid().c_str()); - srt_conn_ptr->close(); - return; - } - - _handle_ptr->add_newconn(srt_conn_ptr, conn_event); - break; - } - case SRTS_CONNECTED: - { - srt_log_trace("srt connected: socket=%d, mode:%s", input_fd, dscr.c_str()); - break; - } - case SRTS_BROKEN: - { - srt_epoll_remove_usock(_pollid, input_fd); - srt_close(input_fd); - srt_log_warn("srt close: socket=%d", input_fd); - break; - } - default: - { - srt_log_error("srt server unkown status:%d", status); - } - } -} - -void srt_server::srt_handle_data(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr) { - _handle_ptr->handle_srt_socket(status, input_fd); - return; -} - -void srt_server::on_work() -{ - const unsigned int SRT_FD_MAX = 100; - srt_log_trace("srt server is working port(%d)", _listen_port); - while (run_flag) - { - SRTSOCKET read_fds[SRT_FD_MAX]; - SRTSOCKET write_fds[SRT_FD_MAX]; - int rfd_num = SRT_FD_MAX; - int wfd_num = SRT_FD_MAX; - - int ret = srt_epoll_wait(_pollid, read_fds, &rfd_num, write_fds, &wfd_num, -1, - nullptr, nullptr, nullptr, nullptr); - if (ret < 0) { - continue; - } - _handle_ptr->check_alive(); - - for (int index = 0; index < rfd_num; index++) { - SRT_SOCKSTATUS status = srt_getsockstate(read_fds[index]); - if (_server_socket == read_fds[index]) { - srt_handle_connection(status, read_fds[index], "read fd"); - } else { - srt_handle_data(status, read_fds[index], "read fd"); - } - } - - for (int index = 0; index < wfd_num; index++) { - SRT_SOCKSTATUS status = srt_getsockstate(write_fds[index]); - if (_server_socket == write_fds[index]) { - srt_handle_connection(status, write_fds[index], "write fd"); - } else { - srt_handle_data(status, write_fds[index], "write fd"); - } - } - } - - // New API at 2020-01-28, >1.4.1 - // @see https://github.com/Haivision/srt/commit/b8c70ec801a56bea151ecce9c09c4ebb720c2f68#diff-fb66028e8746fea578788532533a296bR786 -#if (SRT_VERSION_MAJOR<<24 | SRT_VERSION_MINOR<<16 | SRT_VERSION_PATCH<<8) > 0x01040100 - srt_epoll_clear_usocks(_pollid); -#endif -} - -SrtServerAdapter::SrtServerAdapter() -{ -} - -SrtServerAdapter::~SrtServerAdapter() -{ -} - -srs_error_t SrtServerAdapter::initialize() -{ - srs_error_t err = srs_success; - - // TODO: FIXME: We could fork processes here, because here only ST is initialized. - - return err; -} - -srs_error_t SrtServerAdapter::run(SrsWaitGroup* wg) -{ - srs_error_t err = srs_success; - - // TODO: FIXME: We could start a coroutine to dispatch SRT task to processes. - - if(_srs_config->get_srt_enabled()) { - srt_log_trace("srt server is enabled..."); - unsigned short srt_port = _srs_config->get_srt_listen_port(); - srt_log_trace("srt server listen port:%d", srt_port); - err = srt2rtmp::get_instance()->init(); - if (err != srs_success) { - return srs_error_wrap(err, "srt start srt2rtmp error"); - } - - srt_ptr = std::make_shared(srt_port); - if (!srt_ptr) { - return srs_error_wrap(err, "srt listen %d", srt_port); - } - } else { - srt_log_trace("srt server is disabled..."); - } - - if(_srs_config->get_srt_enabled()) { - srt_ptr->start(); - } - - return err; -} - -void SrtServerAdapter::stop() -{ - // TODO: FIXME: If forked processes, we should do cleanup. -} diff --git a/trunk/src/srt/srt_server.hpp b/trunk/src/srt/srt_server.hpp deleted file mode 100644 index 6b86ee4c7a2..00000000000 --- a/trunk/src/srt/srt_server.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRT_SERVER_H -#define SRT_SERVER_H - -#include - -#include - -#include -#include - -#include - -class srt_handle; -class SrsWaitGroup; - -class srt_server { -public: - srt_server(unsigned short port); - ~srt_server(); - - int start();//init srt handl and create srt main thread loop - void stop();//stop srt main thread loop - -private: - //init srt socket and srt epoll - int init_srt(); - int init_srt_parameter(); - void init_srt_log(); - - //srt main epoll loop - void on_work(); - //accept new srt connection - void srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr); - //get srt data read/write - void srt_handle_data(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr); - -private: - unsigned short _listen_port; - SRTSOCKET _server_socket; - int _pollid; - bool run_flag; - std::shared_ptr thread_run_ptr; - std::shared_ptr _handle_ptr; -}; - -typedef std::shared_ptr SRT_SERVER_PTR; - -class SrtServerAdapter : public ISrsHybridServer -{ -private: - SRT_SERVER_PTR srt_ptr; -public: - SrtServerAdapter(); - virtual ~SrtServerAdapter(); -public: - virtual srs_error_t initialize(); - virtual srs_error_t run(SrsWaitGroup* wg); - virtual void stop(); -}; - -#endif//SRT_SERVER_H diff --git a/trunk/src/srt/srt_to_rtmp.cpp b/trunk/src/srt/srt_to_rtmp.cpp deleted file mode 100644 index f367201a462..00000000000 --- a/trunk/src/srt/srt_to_rtmp.cpp +++ /dev/null @@ -1,779 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "srt_to_rtmp.hpp" -#include "stringex.hpp" -#include "time_help.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -std::shared_ptr srt2rtmp::s_srt2rtmp_ptr; -std::mutex srt2rtmp::_srt_error_mutex; -std::map srt2rtmp::_srt_error_map; - -std::shared_ptr srt2rtmp::get_instance() { - if (!s_srt2rtmp_ptr) { - s_srt2rtmp_ptr = std::make_shared(); - } - return s_srt2rtmp_ptr; -} - -srt2rtmp::srt2rtmp():_lastcheck_ts(0) { - -} - -srt2rtmp::~srt2rtmp() { - release(); -} - -srs_error_t srt2rtmp::init() { - srs_error_t err = srs_success; - - if (_trd_ptr.get() != nullptr) { - return srs_error_wrap(err, "don't start thread again"); - } - - _trd_ptr = std::make_shared("srt2rtmp", this); - - if ((err = _trd_ptr->start()) != srs_success) { - return srs_error_wrap(err, "start thread"); - } - - srs_trace("srt2rtmp start coroutine..."); - - return err; -} - -void srt2rtmp::release() { - if (!_trd_ptr) { - return; - } - _trd_ptr->stop(); - _trd_ptr = nullptr; -} - -void srt2rtmp::insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path) { - std::unique_lock locker(_mutex); - - SRT_DATA_MSG_PTR msg_ptr = std::make_shared(data_p, len, key_path); - _msg_queue.push(msg_ptr); - //_notify_cond.notify_one(); - return; -} - -void srt2rtmp::insert_ctrl_message(unsigned int msg_type, const std::string& key_path) { - std::unique_lock locker(_mutex); - - SRT_DATA_MSG_PTR msg_ptr = std::make_shared(key_path, msg_type); - _msg_queue.push(msg_ptr); - //_notify_cond.notify_one(); - return; -} - -void srt2rtmp::insert_log_message(LOGGER_LEVEL level, const std::string& log_content) { - std::unique_lock locker(_mutex); - - SRT_DATA_MSG_PTR msg_ptr = std::make_shared(level, log_content); - msg_ptr->set_msg_type(SRT_MSG_LOG_TYPE); - _msg_queue.push(msg_ptr); - - return; -} - -SRT_DATA_MSG_PTR srt2rtmp::get_data_message() { - std::unique_lock locker(_mutex); - SRT_DATA_MSG_PTR msg_ptr; - - if (_msg_queue.empty()) - { - return msg_ptr; - } - //while (_msg_queue.empty()) { - // _notify_cond.wait(locker); - //} - - msg_ptr = _msg_queue.front(); - _msg_queue.pop(); - return msg_ptr; -} - -void srt2rtmp::check_rtmp_alive() { - const int64_t CHECK_INTERVAL = 5*1000; - const int64_t ALIVE_TIMEOUT_MAX = 5*1000; - - if (_lastcheck_ts == 0) { - _lastcheck_ts = now_ms(); - return; - } - int64_t timenow_ms = now_ms(); - - if ((timenow_ms - _lastcheck_ts) > CHECK_INTERVAL) { - _lastcheck_ts = timenow_ms; - - for (auto iter = _rtmp_client_map.begin(); - iter != _rtmp_client_map.end();) { - RTMP_CLIENT_PTR rtmp_ptr = iter->second; - - if ((timenow_ms - rtmp_ptr->get_last_live_ts()) >= ALIVE_TIMEOUT_MAX) { - srs_warn("srt2rtmp client is timeout, url:%s", - rtmp_ptr->get_url().c_str()); - _rtmp_client_map.erase(iter++); - rtmp_ptr->close(); - } else { - iter++; - } - } - } - return; -} - -void srt2rtmp::handle_close_rtmpsession(const std::string& key_path) { - RTMP_CLIENT_PTR rtmp_ptr; - auto iter = _rtmp_client_map.find(key_path); - if (iter == _rtmp_client_map.end()) { - srs_error("fail to close rtmp session fail, can't find session by key_path:%s", - key_path.c_str()); - return; - } - rtmp_ptr = iter->second; - _rtmp_client_map.erase(iter); - srs_trace("close rtmp session which key_path is %s", key_path.c_str()); - rtmp_ptr->close(); - - return; -} - -//the cycle is running in srs coroutine -srs_error_t srt2rtmp::cycle() { - srs_error_t err = srs_success; - _lastcheck_ts = 0; - int err_code = -1; - - while(true) { - SRT_DATA_MSG_PTR msg_ptr = get_data_message(); - - if (!msg_ptr) { - srs_usleep((30 * SRS_UTIME_MILLISECONDS)); - } else { - switch (msg_ptr->msg_type()) { - case SRT_MSG_DATA_TYPE: - { - err_code = handle_ts_data(msg_ptr); - if (err_code != ERROR_SUCCESS) { - std::unique_lock locker(_srt_error_mutex); - _srt_error_map[msg_ptr->get_path()] = err_code; - } - break; - } - case SRT_MSG_CLOSE_TYPE: - { - handle_close_rtmpsession(msg_ptr->get_path()); - break; - } - case SRT_MSG_LOG_TYPE: - { - handle_log_data(msg_ptr); - break; - } - default: - { - srs_error("srt to rtmp get wrong message type(%u), path:%s", - msg_ptr->msg_type(), msg_ptr->get_path().c_str()); - assert(0); - } - } - - } - check_rtmp_alive(); - if ((err = _trd_ptr->pull()) != srs_success) { - return srs_error_wrap(err, "forwarder"); - } - } -} - -int srt2rtmp::handle_ts_data(SRT_DATA_MSG_PTR data_ptr) { - RTMP_CLIENT_PTR rtmp_ptr; - auto iter = _rtmp_client_map.find(data_ptr->get_path()); - if (iter == _rtmp_client_map.end()) { - srs_trace("new rtmp client for srt upstream, key_path:%s", data_ptr->get_path().c_str()); - rtmp_ptr = std::make_shared(data_ptr->get_path()); - _rtmp_client_map.insert(std::make_pair(data_ptr->get_path(), rtmp_ptr)); - } else { - rtmp_ptr = iter->second; - } - - return rtmp_ptr->receive_ts_data(data_ptr); -} - -void srt2rtmp::handle_log_data(SRT_DATA_MSG_PTR data_ptr) { - switch (data_ptr->get_log_level()) { - case SRT_LOGGER_INFO_LEVEL: - { - srs_info(data_ptr->get_log_string()); - break; - } - case SRT_LOGGER_TRACE_LEVEL: - { - srs_trace(data_ptr->get_log_string()); - break; - } - case SRT_LOGGER_WARN_LEVEL: - { - srs_warn(data_ptr->get_log_string()); - break; - } - case SRT_LOGGER_ERROR_LEVEL: - { - srs_error(data_ptr->get_log_string()); - break; - } - default: - { - srs_trace(data_ptr->get_log_string()); - } - } - return; -} - -rtmp_client::rtmp_client(std::string key_path):_key_path(key_path) - , _connect_flag(false) { - const std::string DEF_VHOST = "DEFAULT_VHOST"; - _ts_demux_ptr = std::make_shared(); - _avc_ptr = std::make_shared(); - _aac_ptr = std::make_shared(); - std::vector ret_vec; - - string_split(key_path, "/", ret_vec); - - if (ret_vec.size() >= 3) { - _vhost = ret_vec[0]; - _appname = ret_vec[1]; - _streamname = ret_vec[2]; - } else { - _vhost = DEF_VHOST; - _appname = ret_vec[0]; - _streamname = ret_vec[1]; - } - std::stringstream url_ss; - - std::vector ip_ports = _srs_config->get_listens(); - int port = 0; - std::string ip; - - for (auto item : ip_ports) { - srs_parse_endpoint(item, ip, port); - if (port != 0) { - break; - } - } - - port = (port == 0) ? SRS_CONSTS_RTMP_DEFAULT_PORT : port; - - std::stringstream ss; - ss << "rtmp://" << SRS_CONSTS_LOCALHOST; - ss << ":" << port; - ss << "/" << _appname; - ss << "/" << _streamname; - ss << (_streamname.find("?") != std::string::npos ? "&" : "?") << "upstream=srt"; - if (_vhost != DEF_VHOST) { - ss << "&vhost=" << _vhost; - } - - _url = ss.str(); - - _h264_sps_changed = false; - _h264_pps_changed = false; - _h264_sps_pps_sent = false; - - _last_live_ts = now_ms(); - srs_trace("rtmp client construct url:%s", url_ss.str().c_str()); -} - -rtmp_client::~rtmp_client() { - -} - -void rtmp_client::close() { - _connect_flag = false; - if (!_rtmp_conn_ptr) { - return; - } - srs_trace("rtmp client close url:%s", _url.c_str()); - _rtmp_conn_ptr->close(); - _rtmp_conn_ptr = nullptr; - -} - -int64_t rtmp_client::get_last_live_ts() { - return _last_live_ts; -} - -std::string rtmp_client::get_url() { - return _url; -} - -srs_error_t rtmp_client::connect() { - srs_error_t err = srs_success; - srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT; - srs_utime_t sto = SRS_CONSTS_RTMP_PULSE; - - _last_live_ts = now_ms(); - if (_connect_flag) { - return srs_success; - } - - if (_rtmp_conn_ptr.get() != nullptr) { - return srs_error_wrap(err, "repeated connect %s failed, cto=%dms, sto=%dms.", - _url.c_str(), srsu2msi(cto), srsu2msi(sto)); - } - - _rtmp_conn_ptr = std::make_shared(_url, cto, sto); - - if ((err = _rtmp_conn_ptr->connect()) != srs_success) { - close(); - return srs_error_wrap(err, "connect %s failed, cto=%dms, sto=%dms.", - _url.c_str(), srsu2msi(cto), srsu2msi(sto)); - } - - if ((err = _rtmp_conn_ptr->publish(SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE)) != srs_success) { - close(); - return srs_error_wrap(err, "rtmp client in srt2rtmp publish fail url:%s", _url.c_str()); - } - _connect_flag = true; - return err; -} - -int rtmp_client::receive_ts_data(SRT_DATA_MSG_PTR data_ptr) { - return _ts_demux_ptr->decode(data_ptr, shared_from_this());//on_data_callback is the decode callback -} - -srs_error_t rtmp_client::write_h264_sps_pps(uint32_t dts, uint32_t pts) { - srs_error_t err = srs_success; - - // TODO: FIMXE: there exists bug, see following comments. - // when sps or pps changed, update the sequence header, - // for the pps maybe not changed while sps changed. - // so, we must check when each video ts message frame parsed. - if (!_h264_sps_changed || !_h264_pps_changed) { - return err; - } - - // h264 raw to h264 packet. - std::string sh; - if ((err = _avc_ptr->mux_sequence_header(_h264_sps, _h264_pps, dts, pts, sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - - // h264 packet to flv packet. - int8_t frame_type = SrsVideoAvcFrameTypeKeyFrame; - int8_t avc_packet_type = SrsVideoAvcFrameTraitSequenceHeader; - char* flv = NULL; - int nb_flv = 0; - if ((err = _avc_ptr->mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - return srs_error_wrap(err, "avc to flv"); - } - - if (_srs_config->get_srt_mix_correct()) { - _rtmp_queue.insert_rtmp_data((unsigned char*)flv, nb_flv, (int64_t)dts, SrsFrameTypeVideo); - err = rtmp_write_work(); - } else { - err = rtmp_write_packet(SrsFrameTypeVideo, dts, flv, nb_flv); - } - - // reset sps and pps. - _h264_sps_changed = false; - _h264_pps_changed = false; - _h264_sps_pps_sent = true; - - return err; -} - -srs_error_t rtmp_client::write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts) { - srs_error_t err = srs_success; - - // when sps or pps not sent, ignore the packet. - // @see https://github.com/ossrs/srs/issues/203 - if (!_h264_sps_pps_sent) { - return srs_error_new(ERROR_H264_DROP_BEFORE_SPS_PPS, "drop sps/pps"); - } - - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame - SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); - - // for IDR frame, the frame is keyframe. - SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame; - if (nal_unit_type == SrsAvcNaluTypeIDR) { - frame_type = SrsVideoAvcFrameTypeKeyFrame; - } - - std::string ibp; - if ((err = _avc_ptr->mux_ipb_frame(frame, frame_size, ibp)) != srs_success) { - return srs_error_wrap(err, "mux frame"); - } - - int8_t avc_packet_type = SrsVideoAvcFrameTraitNALU; - char* flv = NULL; - int nb_flv = 0; - if ((err = _avc_ptr->mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - return srs_error_wrap(err, "mux avc to flv"); - } - if (_srs_config->get_srt_mix_correct()) { - _rtmp_queue.insert_rtmp_data((unsigned char*)flv, nb_flv, (int64_t)dts, SrsFrameTypeVideo); - err = rtmp_write_work(); - } else { - err = rtmp_write_packet(SrsFrameTypeVideo, dts, flv, nb_flv); - } - - return err; -} - -srs_error_t rtmp_client::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts) { - srs_error_t err = srs_success; - - char* data = NULL; - int size = 0; - if ((err = _aac_ptr->mux_aac2flv(frame, frame_size, codec, dts, &data, &size)) != srs_success) { - return srs_error_wrap(err, "mux aac to flv"); - } - if (_srs_config->get_srt_mix_correct()) { - _rtmp_queue.insert_rtmp_data((unsigned char*)data, size, (int64_t)dts, SrsFrameTypeAudio); - err = rtmp_write_work(); - } else { - err = rtmp_write_packet(SrsFrameTypeAudio, dts, data, size); - } - - return err; -} - -srs_error_t rtmp_client::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) { - srs_error_t err = srs_success; - SrsSharedPtrMessage* msg = NULL; - - if (!_rtmp_conn_ptr) { - //when rtmp connection is closed, it's not error and just return; - srs_freepa(data); - return err; - } - - if ((err = srs_rtmp_create_msg(type, timestamp, data, size, _rtmp_conn_ptr->sid(), &msg)) != srs_success) { - return srs_error_wrap(err, "create message fail, url:%s", _url.c_str()); - } - srs_assert(msg); - - // send out encoded msg. - if ((err = _rtmp_conn_ptr->send_and_free_message(msg)) != srs_success) { - close(); - return srs_error_wrap(err, "rtmp client in srt2rtmp send message fail, url:%s", _url.c_str()); - } - - return err; -} - -srs_error_t rtmp_client::rtmp_write_work() { - srs_error_t err = srs_success; - rtmp_packet_info_s packet_info; - bool ret = false; - - do { - ret = _rtmp_queue.get_rtmp_data(packet_info); - if (ret) { - err = rtmp_write_packet(packet_info._type, packet_info._dts, (char*)packet_info._data, packet_info._len); - if (err != srs_success) { - break; - } - } - } while(ret); - - return err; -} - -srs_error_t rtmp_client::on_ts_video(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts) { - srs_error_t err = srs_success; - - // ensure rtmp connected. - if ((err = connect()) != srs_success) { - return err; - } - dts = dts / 90; - pts = pts / 90; - - if (dts == 0) { - dts = pts; - } - - // send each frame. - while (!avs_ptr->empty()) { - char* frame = NULL; - int frame_size = 0; - if ((err = _avc_ptr->annexb_demux(avs_ptr.get(), &frame, &frame_size)) != srs_success) { - return srs_error_wrap(err, "demux annexb"); - } - - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame - SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); - - // ignore the nalu type aud(9), pad(12) - if ((nal_unit_type == SrsAvcNaluTypeAccessUnitDelimiter) - || (nal_unit_type == SrsAvcNaluTypeFilterData)) { - continue; - } - - // TODO: FIXME: Should cache this config, it's better not to get it for each video frame. - if (_srs_config->get_srt_sei_filter()) { - if (nal_unit_type == SrsAvcNaluTypeSEI) { - continue; - } - } - - // for sps - if (_avc_ptr->is_sps(frame, frame_size)) { - std::string sps; - if ((err = _avc_ptr->sps_demux(frame, frame_size, sps)) != srs_success) { - return srs_error_wrap(err, "demux sps"); - } - - if (_h264_sps == sps) { - continue; - } - _h264_sps_changed = true; - _h264_sps = sps; - - if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { - return srs_error_wrap(err, "write sps/pps"); - } - continue; - } - - // for pps - if (_avc_ptr->is_pps(frame, frame_size)) { - std::string pps; - if ((err = _avc_ptr->pps_demux(frame, frame_size, pps)) != srs_success) { - return srs_error_wrap(err, "demux pps"); - } - - if (_h264_pps == pps) { - continue; - } - _h264_pps_changed = true; - _h264_pps = pps; - - if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { - return srs_error_wrap(err, "write sps/pps"); - } - continue; - } - - // ibp frame. - // for Issue: https://github.com/ossrs/srs/issues/2390 - // we only skip pps/sps frame and send left nalus. - srs_info("mpegts: demux avc ibp frame size=%d, dts=%d", avs_ptr->left() + frame_size, dts); - if ((err = write_h264_ipb_frame(avs_ptr->head() - frame_size, avs_ptr->left() + frame_size, dts, pts)) != srs_success) { - return srs_error_wrap(err, "write frame"); - } - _last_live_ts = now_ms(); - break; - } - - return err; -} - -int rtmp_client::get_sample_rate(char sample_index) { - int sample_rate = 44100; - - if ((sample_index >= 0) && (sample_index < SrsAAcSampleRateNumbers)) { - sample_rate = srs_aac_srates[(uint8_t)sample_index]; - } - - return sample_rate; -} - -srs_error_t rtmp_client::on_ts_audio(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts) { - srs_error_t err = srs_success; - uint64_t base_dts; - uint64_t real_dts; - uint64_t first_dts; - int index = 0; - int sample_size = 1024; - - // ensure rtmp connected. - if ((err = connect()) != srs_success) { - return srs_error_wrap(err, "connect"); - } - - base_dts = dts/90; - if (base_dts == 0) { - base_dts = pts/90; - } - - // send each frame. - while (!avs_ptr->empty()) { - char* frame = NULL; - int frame_size = 0; - SrsRawAacStreamCodec codec; - if ((err = _aac_ptr->adts_demux(avs_ptr.get(), &frame, &frame_size, codec)) != srs_success) { - return srs_error_wrap(err, "demux adts"); - } - - if (frame_size <= 0) { - continue; - } - int sample_rate = get_sample_rate(codec.sound_rate); - - if (codec.aac_packet_type > SrsAudioOpusFrameTraitRaw) { - sample_size = 2048; - } else { - sample_size = 1024; - } - - real_dts = base_dts + index * 1000.0 * sample_size / sample_rate; - if (index == 0) { - first_dts = real_dts; - } - index++; - - // generate sh. - if (_aac_specific_config.empty()) { - std::string sh; - if ((err = _aac_ptr->mux_sequence_header(&codec, sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - _aac_specific_config = sh; - - codec.aac_packet_type = 0; - - if ((err = write_audio_raw_frame((char*)sh.data(), (int)sh.length(), &codec, real_dts)) != srs_success) { - return srs_error_wrap(err, "write raw audio frame"); - } - } - - // audio raw data. - codec.aac_packet_type = 1; - if ((err = write_audio_raw_frame(frame, frame_size, &codec, real_dts)) != srs_success) { - return srs_error_wrap(err, "write audio raw frame"); - } - _last_live_ts = now_ms(); - } - - uint64_t diff_t = real_dts - first_dts; - diff_t += 100; - if ((diff_t > 200) && (diff_t < 600)) { - srs_info("set_queue_timeout timeout:%lu", diff_t); - _rtmp_queue.set_queue_timeout(diff_t); - } - return err; -} - -int rtmp_client::on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, - uint64_t dts, uint64_t pts) -{ - srs_error_t err = srs_success; - if (!data_ptr || (data_ptr->get_data() == nullptr) || (data_ptr->data_len() == 0)) { - assert(0); - return 0; - } - - auto avs_ptr = std::make_shared((char*)data_ptr->get_data(), data_ptr->data_len()); - - if (media_type == STREAM_TYPE_VIDEO_H264) { - err = on_ts_video(avs_ptr, dts, pts); - } else if (media_type == STREAM_TYPE_AUDIO_AAC) { - err = on_ts_audio(avs_ptr, dts, pts); - } else { - srs_error("mpegts demux unkown stream type:0x%02x, only support h264+aac", media_type); - return 0; - } - - if (err != srs_success) { - srs_error("send media data error:%s", srs_error_desc(err).c_str()); - int err_code = srs_error_code(err); - srs_freep(err); - return err_code; - } - return 0; -} - -rtmp_packet_queue::rtmp_packet_queue():_queue_timeout(QUEUE_DEF_TIMEOUT) - ,_queue_maxlen(QUEUE_LEN_MAX) - ,_first_packet_t(-1) - ,_first_local_t(-1) { - -} - -rtmp_packet_queue::~rtmp_packet_queue() { - for (auto item : _send_map) { - rtmp_packet_info_s info = item.second; - if (info._data) { - delete info._data; - } - } - _send_map.clear(); -} - -void rtmp_packet_queue::set_queue_timeout(int64_t queue_timeout) { - _queue_timeout = queue_timeout; -} - -void rtmp_packet_queue::insert_rtmp_data(unsigned char* data, int len, int64_t dts, char media_type) { - rtmp_packet_info_s packet_info; - - packet_info._data = data; - packet_info._len = len; - packet_info._dts = dts; - packet_info._type = media_type; - - if (_first_packet_t == -1) { - _first_packet_t = dts; - _first_local_t = (int64_t)now_ms(); - } - - _send_map.insert(std::make_pair(dts, packet_info)); - return; -} - -bool rtmp_packet_queue::is_ready() { - if (!_srs_config->get_srt_mix_correct() && !_send_map.empty()) { - return true; - } - if (_send_map.size() < 2) { - return false; - } - - if (_send_map.size() >= (size_t)_queue_maxlen) { - return true; - } - - auto first_item = _send_map.begin(); - int64_t now_t = (int64_t)now_ms(); - - int64_t diff_t = (now_t - _first_local_t) - (first_item->first - _first_packet_t); - - if (diff_t >= _queue_timeout) { - return true; - } - return false; -} - -bool rtmp_packet_queue::get_rtmp_data(rtmp_packet_info_s& packet_info) { - if (!is_ready()) { - return false; - } - auto iter = _send_map.begin(); - packet_info = iter->second; - _send_map.erase(iter); - - return true; -} diff --git a/trunk/src/srt/srt_to_rtmp.hpp b/trunk/src/srt/srt_to_rtmp.hpp deleted file mode 100644 index ff5b4e12fe2..00000000000 --- a/trunk/src/srt/srt_to_rtmp.hpp +++ /dev/null @@ -1,162 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRT_TO_RTMP_H -#define SRT_TO_RTMP_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "srt_data.hpp" -#include "ts_demux.hpp" -#include "srt_log.hpp" - -#define SRT_VIDEO_MSG_TYPE 0x01 -#define SRT_AUDIO_MSG_TYPE 0x02 - -typedef std::shared_ptr RTMP_CONN_PTR; -typedef std::shared_ptr AVC_PTR; -typedef std::shared_ptr AAC_PTR; - -#define DEFAULT_VHOST "__default_host__" - -#define QUEUE_DEF_TIMEOUT 500 -#define QUEUE_LEN_MAX 100 - -typedef struct { - unsigned char* _data; - int _len; - int64_t _dts; - char _type; - char reserve[3]; -} rtmp_packet_info_s; - -class rtmp_packet_queue { -public: - rtmp_packet_queue(); - ~rtmp_packet_queue(); - - void set_queue_timeout(int64_t queue_timeout); - void insert_rtmp_data(unsigned char* data, int len, int64_t dts, char media_type); - bool get_rtmp_data(rtmp_packet_info_s& packet_info); - -private: - bool is_ready(); - -private: - int64_t _queue_timeout; - int64_t _queue_maxlen; - int64_t _first_packet_t; - int64_t _first_local_t; - std::multimap _send_map;//key:dts, value:rtmp_packet_info -}; - -class rtmp_client : public ts_media_data_callback_I, public std::enable_shared_from_this { -public: - rtmp_client(std::string key_path); - virtual ~rtmp_client(); - - int receive_ts_data(SRT_DATA_MSG_PTR data_ptr); - int64_t get_last_live_ts(); - std::string get_url(); - - srs_error_t connect(); - void close(); - -private: - virtual int on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, uint64_t dts, uint64_t pts); - -private: - srs_error_t on_ts_video(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts); - srs_error_t on_ts_audio(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts); - virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts); - virtual srs_error_t write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts); - virtual srs_error_t write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts); - - int get_sample_rate(char sound_rate); - - srs_error_t rtmp_write_work(); - -private: - virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char* data, int size); - -private: - std::string _key_path; - std::string _url; - std::string _vhost; - std::string _appname; - std::string _streamname; - TS_DEMUX_PTR _ts_demux_ptr; - -private: - AVC_PTR _avc_ptr; - std::string _h264_sps; - bool _h264_sps_changed; - std::string _h264_pps; - bool _h264_pps_changed; - bool _h264_sps_pps_sent; -private: - std::string _aac_specific_config; - AAC_PTR _aac_ptr; -private: - RTMP_CONN_PTR _rtmp_conn_ptr; - bool _connect_flag; - int64_t _last_live_ts; - -private: - rtmp_packet_queue _rtmp_queue; -}; - -typedef std::shared_ptr RTMP_CLIENT_PTR; - -class srt2rtmp : public ISrsCoroutineHandler { -public: - static std::shared_ptr get_instance(); - srt2rtmp(); - virtual ~srt2rtmp(); - - srs_error_t init(); - void release(); - - void insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path); - void insert_ctrl_message(unsigned int msg_type, const std::string& key_path); - void insert_log_message(LOGGER_LEVEL level, const std::string& log_content); - -private: - SRT_DATA_MSG_PTR get_data_message(); - virtual srs_error_t cycle(); - int handle_ts_data(SRT_DATA_MSG_PTR data_ptr); - void handle_close_rtmpsession(const std::string& key_path); - void handle_log_data(SRT_DATA_MSG_PTR data_ptr); - void check_rtmp_alive(); - -private: - static std::shared_ptr s_srt2rtmp_ptr; - std::shared_ptr _trd_ptr; - std::mutex _mutex; - //std::condition_variable_any _notify_cond; - std::queue _msg_queue; - - std::unordered_map _rtmp_client_map; - int64_t _lastcheck_ts; -public: - static std::mutex _srt_error_mutex; - static std::map _srt_error_map; -}; - -#endif diff --git a/trunk/src/srt/stringex.hpp b/trunk/src/srt/stringex.hpp deleted file mode 100644 index 633e58ecf23..00000000000 --- a/trunk/src/srt/stringex.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef STRING_EX_H -#define STRING_EX_H - -#include - -#include -#include -#include -#include -#include -#include - -inline int string_split(const std::string& input_str, const std::string& split_str, std::vector& output_vec) { - if (input_str.length() == 0) { - return 0; - } - - std::string tempString(input_str); - do { - - size_t pos = tempString.find(split_str); - if (pos == tempString.npos) { - output_vec.push_back(tempString); - break; - } - std::string seg_str = tempString.substr(0, pos); - tempString = tempString.substr(pos+split_str.size()); - output_vec.push_back(seg_str); - } while(tempString.size() > 0); - - return output_vec.size(); -} - -inline std::string string_lower(const std::string input_str) { - std::string output_str(input_str); - - std::transform(input_str.begin(), input_str.end(), output_str.begin(), ::tolower); - - return output_str; -} - -#endif//STRING_EX_H diff --git a/trunk/src/srt/time_help.hpp b/trunk/src/srt/time_help.hpp deleted file mode 100644 index e58e5c0fd52..00000000000 --- a/trunk/src/srt/time_help.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef TIME_HELP_H -#define TIME_HELP_H - -#include - -#include - -inline long long now_ms() { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count(); -} - -#endif //TIME_HELP_H \ No newline at end of file diff --git a/trunk/src/srt/ts_demux.cpp b/trunk/src/srt/ts_demux.cpp deleted file mode 100644 index 6b919014e3c..00000000000 --- a/trunk/src/srt/ts_demux.cpp +++ /dev/null @@ -1,603 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "ts_demux.hpp" -#include "srt_log.hpp" -#include - -ts_demux::ts_demux():_data_total(0) - ,_last_pid(0) - ,_last_dts(0) - ,_last_pts(0) -{ - -} - -ts_demux::~ts_demux() { - -} - -int ts_demux::decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_CALLBACK_PTR callback) -{ - int pos = 0; - int npos = 0; - ts_header ts_header_info; - - ts_header_info._sync_byte = data_p[pos]; - pos++; - - ts_header_info._transport_error_indicator = (data_p[pos]&0x80)>>7; - ts_header_info._payload_unit_start_indicator = (data_p[pos]&0x40)>>6; - ts_header_info._transport_priority = (data_p[pos]&0x20)>>5; - ts_header_info._PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; - pos += 2; - - ts_header_info._transport_scrambling_control = (data_p[pos]&0xC0)>>6; - ts_header_info._adaptation_field_control = (data_p[pos]&0x30)>>4; - ts_header_info._continuity_counter = (data_p[pos]&0x0F); - pos++; - npos = pos; - - adaptation_field* field_p = &(ts_header_info._adaptation_field_info); - // adaptation field - // 0x01 No adaptation_field, payload only - // 0x02 Adaptation_field only, no payload - // 0x03 Adaptation_field followed by payload - if( ts_header_info._adaptation_field_control == 2 - || ts_header_info._adaptation_field_control == 3 ){ - // adaptation_field() - field_p->_adaptation_field_length = data_p[pos]; - pos++; - - if( field_p->_adaptation_field_length > 0 ){ - field_p->_discontinuity_indicator = (data_p[pos]&0x80)>>7; - field_p->_random_access_indicator = (data_p[pos]&0x40)>>6; - field_p->_elementary_stream_priority_indicator = (data_p[pos]&0x20)>>5; - field_p->_PCR_flag = (data_p[pos]&0x10)>>4; - field_p->_OPCR_flag = (data_p[pos]&0x08)>>3; - field_p->_splicing_point_flag = (data_p[pos]&0x04)>>2; - field_p->_transport_private_data_flag = (data_p[pos]&0x02)>>1; - field_p->_adaptation_field_extension_flag = (data_p[pos]&0x01); - pos++; - - if( field_p->_PCR_flag == 1 ) { // PCR info - //program_clock_reference_base 33 uimsbf - //reserved 6 bslbf - //program_clock_reference_extension 9 uimsbf - pos += 6; - } - if( field_p->_OPCR_flag == 1 ) { - //original_program_clock_reference_base 33 uimsbf - //reserved 6 bslbf - //original_program_clock_reference_extension 9 uimsbf - pos += 6; - } - if( field_p->_splicing_point_flag == 1 ) { - //splice_countdown 8 tcimsbf - pos++; - } - if( field_p->_transport_private_data_flag == 1 ) { - //transport_private_data_length 8 uimsbf - field_p->_transport_private_data_length = data_p[pos]; - pos++; - memcpy(field_p->_private_data_byte, data_p + pos, field_p->_transport_private_data_length); - pos += field_p->_transport_private_data_length; - } - if( field_p->_adaptation_field_extension_flag == 1 ) { - //adaptation_field_extension_length 8 uimsbf - field_p->_adaptation_field_extension_length = data_p[pos]; - pos++; - //ltw_flag 1 bslbf - field_p->_ltw_flag = (data_p[pos]&0x80)>>7; - //piecewise_rate_flag 1 bslbf - field_p->_piecewise_rate_flag = (data_p[pos]&0x40)>>6; - //seamless_splice_flag 1 bslbf - field_p->_seamless_splice_flag = (data_p[pos]&0x20)>>5; - //reserved 5 bslbf - pos++; - if (field_p->_ltw_flag == 1) { - //ltw_valid_flag 1 bslbf - //ltw_offset 15 uimsbf - pos += 2; - } - if (field_p->_piecewise_rate_flag == 1) { - //reserved 2 bslbf - //piecewise_rate 22 uimsbf - pos += 3; - } - if (field_p->_seamless_splice_flag == 1) { - //splice_type 4 bslbf - //DTS_next_AU[32..30] 3 bslbf - //marker_bit 1 bslbf - //DTS_next_AU[29..15] 15 bslbf - //marker_bit 1 bslbf - //DTS_next_AU[14..0] 15 bslbf - //marker_bit 1 bslbf - pos += 5; - } - } - } - npos += sizeof(field_p->_adaptation_field_length) + field_p->_adaptation_field_length; - pos = npos;//must consider the 'stuffing_byte' in adaptation field - } - - if(ts_header_info._adaptation_field_control == 1 - || ts_header_info._adaptation_field_control == 3 ) { - // data_byte with placeholder - // payload parser - if(ts_header_info._PID == 0x00){ - // PAT // program association table - if(ts_header_info._payload_unit_start_indicator) { - pos++; - } - _pat._table_id = data_p[pos]; - pos++; - _pat._section_syntax_indicator = (data_p[pos]>>7)&0x01; - // skip 3 bits of 1 zero and 2 reserved - _pat._section_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; - pos += 2; - _pat._transport_stream_id = (data_p[pos]<<8)|data_p[pos+1]; - pos += 2; - // reserved 2 bits - _pat._version_number = (data_p[pos]&0x3E)>>1; - _pat._current_next_indicator = data_p[pos]&0x01; - pos++; - _pat._section_number = data_p[pos]; - pos++; - _pat._last_section_number = data_p[pos]; - - if (_pat._table_id != 0x00) { - srt_log_error("pat table id(0x%02x) error, it must be 0x00", _pat._table_id); - return -1; - } - // PAT = section_length + 3 - if((188 - npos) <= (_pat._section_length + 3)) { - srt_log_error("pat _section_length(%d) error, the left len:%d", _pat._section_length, (188 - npos)); - return -1; - } - pos++; - _pat._pid_vec.clear(); - for (;pos+4 <= _pat._section_length-5-4+9 + npos;) { // 4:CRC, 5:follow section_length item rpos + 4(following unit length) section_length + 9(above field and unit_start_first_byte ) - PID_INFO pid_info; - //program_number 16 uimsbf - pid_info._program_number = data_p[pos]<<8|data_p[pos+1]; - pos += 2; -// reserved 3 bslbf - - if (pid_info._program_number == 0) { -// // network_PID 13 uimsbf - pid_info._network_id = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; - pos += 2; - } - else { -// // program_map_PID 13 uimsbf - pid_info._pid = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; - pos += 2; - } - _pat._pid_vec.push_back(pid_info); - // network_PID and program_map_PID save to list - } -// CRC_32 use pat to calc crc32, eq - pos += 4; - }else if(ts_header_info._PID == 0x01){ - // CAT // conditional access table - }else if(ts_header_info._PID == 0x02){ - //TSDT // transport stream description table - }else if(ts_header_info._PID == 0x03){ - //IPMP // IPMP control information table - // 0x0004-0x000F Reserved - // 0x0010-0x1FFE May be assigned as network_PID, Program_map_PID, elementary_PID, or for other purposes - }else if(ts_header_info._PID == 0x11){ - // SDT // https://en.wikipedia.org/wiki/Service_Description_Table / https://en.wikipedia.org/wiki/MPEG_transport_stream - }else if(is_pmt(ts_header_info._PID)) { - if(ts_header_info._payload_unit_start_indicator) - pos++; - _pmt._table_id = data_p[pos]; - pos++; - _pmt._section_syntax_indicator = (data_p[pos]>>7)&0x01; - // skip 3 bits of 1 zero and 2 reserved - _pmt._section_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; - pos += 2; - _pmt._program_number = (data_p[pos]<<8)|data_p[pos+1]; - pos += 2; - // reserved 2 bits - _pmt._version_number = (data_p[pos]&0x3E)>>1; - _pmt._current_next_indicator = data_p[pos]&0x01; - pos++; - _pmt._section_number = data_p[pos]; - pos++; - _pmt._last_section_number = data_p[pos]; - pos++; - // skip 3 bits for reserved 3 bslbf - _pmt._PCR_PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; //PCR_PID 13 uimsbf - pos += 2; - - //reserved 4 bslbf - _pmt._program_info_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF;//program_info_length 12 uimsbf - pos += 2; - - //0x02, // TS_program_map_section - if (_pmt._table_id != 0x02) { - srt_log_error("pmt tableid(0x%02x) error, it must be 0x02", _pmt._table_id) - return -1; - } - memcpy(_pmt._dscr, data_p+pos, _pmt._program_info_length); -// for (i = 0; i < N; i++) { -// descriptor() -// } - pos += _pmt._program_info_length; - _pmt._stream_pid_vec.clear(); - _pmt._pid2steamtype.clear(); - - for (; pos + 5 <= _pmt._section_length + 4 - 4 + npos; ) { // pos(above field length) i+5(following unit length) section_length +3(PMT begin three bytes)+1(payload_unit_start_indicator) -4(crc32) - STREAM_PID_INFO pid_info; - pid_info._stream_type = data_p[pos];//stream_type 8 uimsbf 0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video - pos++; - //reserved 3 bslbf - pid_info._elementary_PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; //elementary_PID 13 uimsbf - pos += 2; - //reserved 4 bslbf - pid_info._ES_info_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; //ES_info_length 12 uimsbf - pos += 2; - if( pos + pid_info._ES_info_length > _pmt._section_length + 4 - 4 + npos ) - break; - int absES_info_length = pos + pid_info._ES_info_length; - for (; pos< absES_info_length; ) { - //descriptor() - int descriptor_tag = data_p[pos]; - (void)descriptor_tag; - pos++; - int descriptor_length = data_p[pos]; - pos++; - memcpy(pid_info._dscr, data_p + pos, descriptor_length); - pos += descriptor_length; - } - // save program_number(stream num) elementary_PID(PES PID) stream_type(stream codec) - _pmt._stream_pid_vec.push_back(pid_info); - _pmt._pid2steamtype.insert(std::make_pair((unsigned short)pid_info._elementary_PID, pid_info._stream_type)); - } - pos += 4;//CRC_32 - }else if(ts_header_info._PID == 0x0042){ - // USER - }else if(ts_header_info._PID == 0x1FFF){ - // Null packet - }else{//pes packet or pure data packet - //bool isFound = false; - for (size_t i = 0; i < _pmt._stream_pid_vec.size(); i++) { - if(ts_header_info._PID == _pmt._stream_pid_vec[i]._elementary_PID){ - //isFound = true; - if(ts_header_info._payload_unit_start_indicator){ - unsigned char* ret_data_p = nullptr; - size_t ret_size = 0; - uint64_t dts = 0; - uint64_t pts = 0; - - //callback last media data in data buffer - int err_code = on_callback(callback, _last_pid, key_path, _last_dts, _last_pts); - if (err_code != 0) - return err_code; - - int ret = pes_parse(data_p+npos, npos, &ret_data_p, ret_size, dts, pts); - if (ret > 188) { - srt_log_error("pes length(%d) error", ret); - return -1; - } - - _last_pts = pts; - _last_dts = (dts == 0) ? pts : dts; - - if ((ret_data_p != nullptr) && (ret_size > 0)) { - insert_into_databuf(ret_data_p, ret_size, key_path, ts_header_info._PID); - } - }else{ - //fwrite(p, 1, 188-(npos+pos), pes_info[i].fd); - insert_into_databuf(data_p + npos, 188-npos, key_path, ts_header_info._PID); - } - } - } - } - } - - return 0; -} -int ts_demux::decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback) -{ - int ret = -1; - std::string path; - - if (!data_ptr || (data_ptr->data_len() < 188) || (data_ptr->data_len()%188 != 0)) - { - return -1; - } - - unsigned int count = data_ptr->data_len()/188; - path = data_ptr->get_path(); - for (unsigned int index = 0; index < count; index++) - { - unsigned char* data = data_ptr->get_data() + 188*index; - if (data[0] != 0x47) { - continue; - } - ret = decode_unit(data, path, callback); - if (ret != 0) // srs_error_code is positive - { - break; - } - } - return ret; -} - -void ts_demux::insert_into_databuf(unsigned char* data_p, size_t data_size, std::string key_path, unsigned short pid) { - _last_pid = pid; - _data_total += data_size; - _data_buffer_vec.push_back(std::make_shared(data_p, data_size, key_path)); - return; -} - -int ts_demux::on_callback(TS_DATA_CALLBACK_PTR callback, unsigned short pid, std::string key_path, - uint64_t dts, uint64_t pts) { - if ((_data_total <=0 ) || (_data_buffer_vec.empty())) { - return 0; - } - - auto iter = _pmt._pid2steamtype.find(pid); - if (iter == _pmt._pid2steamtype.end()) { - return 0; - } - unsigned char stream_type = iter->second; - auto total_data_ptr = std::make_shared(_data_total, key_path); - size_t pos = 0; - - for (size_t index = 0; index < _data_buffer_vec.size(); index++) { - memcpy(total_data_ptr->get_data() + pos, - _data_buffer_vec[index]->get_data(), - _data_buffer_vec[index]->data_len()); - pos += _data_buffer_vec[index]->data_len(); - } - _data_buffer_vec.clear(); - _data_total = 0; - - return callback->on_data_callback(total_data_ptr, stream_type, dts, pts); -} - -bool ts_demux::is_pmt(unsigned short pid) { - for (size_t index = 0; index < _pat._pid_vec.size(); index++) { - if (_pat._pid_vec[index]._program_number != 0) { - if (_pat._pid_vec[index]._pid == pid) { - return true; - } - } - } - return false; -} - - -int ts_demux::pes_parse(unsigned char* p, size_t npos, - unsigned char** ret_pp, size_t& ret_size, - uint64_t& dts, uint64_t& pts) { - int pos = 0; - int packet_start_code_prefix = (p[pos]<<16)|(p[pos+1]<<8)|p[pos+2]; //packet_start_code_prefix 24 bslbf - pos += 3; - int stream_id = p[pos]; //stream_id 8 uimsbf - pos++; - - int PES_packet_length = ((unsigned int)p[pos]<<8)|p[pos+1]; //PES_packet_length 16 uimsbf - (void)PES_packet_length; - pos += 2; - - if (0x00000001 != packet_start_code_prefix) { - srt_log_error("pes packet start code prefix(%06x) error, it must be 0x00 00 01", packet_start_code_prefix); - return 255; - } - if (stream_id != 188//program_stream_map 1011 1100 - && stream_id != 190//padding_stream 1011 1110 - && stream_id != 191//private_stream_2 1011 1111 - && stream_id != 240//ECM 1111 0000 - && stream_id != 241//EMM 1111 0001 - && stream_id != 255//program_stream_directory 1111 1111 - && stream_id != 242//DSMCC_stream 1111 0010 - && stream_id != 248//ITU-T Rec. H.222.1 type E stream 1111 1000 - ) - { - if (0x80 != (p[pos] & 0xc0)) { - srt_log_error("the first 2 bits:0x%02x error, it must be 0x80.", (p[pos] & 0xc0)); - return 255; - } - //skip 2bits//'10' 2 bslbf - int PES_scrambling_control = (p[pos]&30)>>4; //PES_scrambling_control 2 bslbf - (void)PES_scrambling_control; - int PES_priority = (p[pos]&0x08)>>3; //PES_priority 1 bslbf - (void)PES_priority; - int data_alignment_indicator = (p[pos]&0x04)>>2;//data_alignment_indicator 1 bslbf - (void)data_alignment_indicator; - int copyright = (p[pos]&0x02)>>1; //copyright 1 bslbf - (void)copyright; - int original_or_copy = (p[pos]&0x01);//original_or_copy 1 bslbf - (void)original_or_copy; - pos++; - int PTS_DTS_flags = (p[pos]&0xC0)>>6; //PTS_DTS_flags 2 bslbf - int ESCR_flag = (p[pos]&0x20)>>5; // ESCR_flag 1 bslbf - int ES_rate_flag = (p[pos]&0x10)>>4;//ES_rate_flag 1 bslbf - int DSM_trick_mode_flag = (p[pos]&0x08)>>3;//DSM_trick_mode_flag 1 bslbf - int additional_copy_info_flag = (p[pos]&0x04)>>2; //additional_copy_info_flag 1 bslbf - int PES_CRC_flag = (p[pos]&0x02)>>1; //PES_CRC_flag 1 bslbf - int PES_extension_flag = (p[pos]&0x01);//PES_extension_flag 1 bslbf - pos++; - int PES_header_data_length = p[pos]; //PES_header_data_length 8 uimsbf - (void)PES_header_data_length; - pos++; - - if (PTS_DTS_flags == 2) { - // skip 4 bits '0010' 4 bslbf - // PTS [32..30] 3 bslbf - // marker_bit 1 bslbf - // PTS [29..15] 15 bslbf - // marker_bit 1 bslbf - // PTS [14..0] 15 bslbf - // marker_bit 1 bslbf - pts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); - pos += 5; - } - if (PTS_DTS_flags == 3) { - // '0011' 4 bslbf - // PTS [32..30] 3 bslbf - // marker_bit 1 bslbf - //PTS [29..15] 15 bslbf - //marker_bit 1 bslbf - // PTS [14..0] 15 bslbf - // marker_bit 1 bslbf - pts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); - pos += 5; - // '0001' 4 bslbf - // DTS [32..30] 3 bslbf - // marker_bit 1 bslbf - // DTS [29..15] 15 bslbf - // marker_bit 1 bslbf - // DTS [14..0] 15 bslbf - // marker_bit 1 bslbf - dts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); - pos += 5; - } - if (ESCR_flag == 1) { - // reserved 2 bslbf - // ESCR_base[32..30] 3 bslbf - // marker_bit 1 bslbf - // ESCR_base[29..15] 15 bslbf - // marker_bit 1 bslbf - // ESCR_base[14..0] 15 bslbf - // marker_bit 1 bslbf - // ESCR_extension 9 uimsbf - // marker_bit 1 bslbf - uint64_t ESCR_base = ((((uint64_t)p[pos] >> 3) & 0x07) << 30) | (((uint64_t)p[pos] & 0x03) << 28) | ((uint64_t)p[pos + 1] << 20) | ((((uint64_t)p[pos + 2] >> 3) & 0x1F) << 15) | (((uint64_t)p[pos + 2] & 0x3) << 13) | ((uint64_t)p[pos + 3] << 5) | ((p[pos + 4] >> 3) & 0x1F); - int ESCR_extension = ((p[pos + 4] & 0x03) << 7) | ((p[pos + 5] >> 1) & 0x7F); - (void)ESCR_base; - (void)ESCR_extension; - pos += 6; - } - if (ES_rate_flag == 1) { - // marker_bit 1 bslbf - // ES_rate 22 uimsbf - // marker_bit 1 bslbf - int ES_rate = (p[pos]&0x7F)<<15 | (p[pos+1])<<7 | (p[pos+2]&0x7F)>>1; - (void)ES_rate; - pos += 3; - } - if (DSM_trick_mode_flag == 1) { // ignore - int trick_mode_control = (p[pos]&0xE0)>>5;//trick_mode_control 3 uimsbf - if ( trick_mode_control == 0/*fast_forward*/ ) { - // field_id 2 bslbf - // intra_slice_refresh 1 bslbf - // frequency_truncation 2 bslbf - } - else if ( trick_mode_control == 1/*slow_motion*/ ) { - //rep_cntrl 5 uimsbf - } - else if ( trick_mode_control == 2/*freeze_frame*/ ) { - // field_id 2 uimsbf - // reserved 3 bslbf - } - else if ( trick_mode_control == 3/*fast_reverse*/ ) { - // field_id 2 bslbf - // intra_slice_refresh 1 bslbf - // frequency_truncation 2 bslbf - }else if ( trick_mode_control == 4/*slow_reverse*/ ) { - // rep_cntrl 5 uimsbf - } - else{ - //reserved 5 bslbf - } - pos++; - } - if ( additional_copy_info_flag == 1) { // ignore - // marker_bit 1 bslbf - // additional_copy_info 7 bslbf - pos++; - } - if ( PES_CRC_flag == 1) { // ignore - // previous_PES_packet_CRC 16 bslbf - pos += 2; - } - if ( PES_extension_flag == 1) { // ignore - int PES_private_data_flag = (p[pos]&0x80)>>7;// PES_private_data_flag 1 bslbf - int pack_header_field_flag = (p[pos]&0x40)>>6;// pack_header_field_flag 1 bslbf - int program_packet_sequence_counter_flag = (p[pos]&0x20)>>5;// program_packet_sequence_counter_flag 1 bslbf - int P_STD_buffer_flag = (p[pos]&0x10)>>4; // P-STD_buffer_flag 1 bslbf - // reserved 3 bslbf - int PES_extension_flag_2 = (p[pos]&0x01);// PES_extension_flag_2 1 bslbf - pos++; - - if ( PES_private_data_flag == 1) { - // PES_private_data 128 bslbf - pos += 16; - } - if (pack_header_field_flag == 1) { - // pack_field_length 8 uimsbf - // pack_header() - } - if (program_packet_sequence_counter_flag == 1) { - // marker_bit 1 bslbf - // program_packet_sequence_counter 7 uimsbf - // marker_bit 1 bslbf - // MPEG1_MPEG2_identifier 1 bslbf - // original_stuff_length 6 uimsbf - pos += 2; - } - if ( P_STD_buffer_flag == 1) { - // '01' 2 bslbf - // P-STD_buffer_scale 1 bslbf - // P-STD_buffer_size 13 uimsbf - pos += 2; - } - if ( PES_extension_flag_2 == 1) { - // marker_bit 1 bslbf - int PES_extension_field_length = (p[pos]&0x7F);// PES_extension_field_length 7 uimsbf - pos++; - for (int i = 0; i < PES_extension_field_length; i++) { - // reserved 8 bslbf - pos++; - } - } - } - -// for (int i = 0; i < N1; i++) { - //stuffing_byte 8 bslbf -// rpos++; -// } -// for (int i = 0; i < N2; i++) { - //PES_packet_data_byte 8 bslbf -// rpos++; -// } - *ret_pp = p+pos; - ret_size = 188-(npos+pos); - } - else if ( stream_id == 188//program_stream_map 1011 1100 BC - || stream_id == 191//private_stream_2 1011 1111 BF - || stream_id == 240//ECM 1111 0000 F0 - || stream_id == 241//EMM 1111 0001 F1 - || stream_id == 255//program_stream_directory 1111 1111 FF - || stream_id == 242//DSMCC_stream 1111 0010 F2 - || stream_id == 248//ITU-T Rec. H.222.1 type E stream 1111 1000 F8 - ) { -// for (i = 0; i < PES_packet_length; i++) { - //PES_packet_data_byte 8 bslbf -// rpos++; -// } - *ret_pp = p+pos; - ret_size = 188-(npos+pos); - //fwrite(p, 1, 188-(npos+rpos), fd); - } - else if ( stream_id == 190//padding_stream 1011 1110 - ) { -// for (i = 0; i < PES_packet_length; i++) { - // padding_byte 8 bslbf -// rpos++; - *ret_pp = p+pos; - ret_size = 188-(npos+pos); -// } - } - - return pos; -} diff --git a/trunk/src/srt/ts_demux.hpp b/trunk/src/srt/ts_demux.hpp deleted file mode 100644 index 06a888c6c1e..00000000000 --- a/trunk/src/srt/ts_demux.hpp +++ /dev/null @@ -1,247 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef TS_DEMUX_H -#define TS_DEMUX_H - -#include - -#include "srt_data.hpp" -#include -#include -#include -#include - -/* mpegts stream type in ts pmt -Value Description -0x00 ITU-T | ISO/IEC Reserved -0x01 ISO/IEC 11172-2 Video (mpeg video v1) -0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video(mpeg video v2)or ISO/IEC 11172-2 constrained parameter video stream -0x03 ISO/IEC 11172-3 Audio (MPEG 1 Audio codec Layer I, Layer II and Layer III audio specifications) -0x04 ISO/IEC 13818-3 Audio (BC Audio Codec) -0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections -0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data -0x07 ISO/IEC 13522 MHEG -0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC -0x09 ITU-T Rec. H.222.1 -0x0A ISO/IEC 13818-6 type A -0x0B ISO/IEC 13818-6 type B -0x0C ISO/IEC 13818-6 type C -0x0D ISO/IEC 13818-6 type D -0x0E ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary -0x0F ISO/IEC 13818-7 Audio with ADTS transport syntax -0x10 ISO/IEC 14496-2 Visual -0x11 ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3/Amd.1 -0x12 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets -0x13 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC 14496_sections -0x14 ISO/IEC 13818-6 Synchronized Download Protocol -0x15 Metadata carried in PES packets -0x16 Metadata carried in metadata_sections -0x17 Metadata carried in ISO/IEC 13818-6 Data Carousel -0x18 Metadata carried in ISO/IEC 13818-6 Object Carousel -0x19 Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol -0x1A IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) -0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video (h.264) -0x1C ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS -0x1D ISO/IEC 14496-17 Text -0x1E Auxiliary video stream as defined in ISO/IEC 23002-3 (AVS) -0x1F-0x7E ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved -0x7F IPMP stream 0x80-0xFF User Private -*/ -#define STREAM_TYPE_VIDEO_MPEG1 0x01 -#define STREAM_TYPE_VIDEO_MPEG2 0x02 -#define STREAM_TYPE_AUDIO_MPEG1 0x03 -#define STREAM_TYPE_AUDIO_MPEG2 0x04 -#define STREAM_TYPE_PRIVATE_SECTION 0x05 -#define STREAM_TYPE_PRIVATE_DATA 0x06 -#define STREAM_TYPE_AUDIO_AAC 0x0f -#define STREAM_TYPE_AUDIO_AAC_LATM 0x11 -#define STREAM_TYPE_VIDEO_MPEG4 0x10 -#define STREAM_TYPE_METADATA 0x15 -#define STREAM_TYPE_VIDEO_H264 0x1b -#define STREAM_TYPE_VIDEO_HEVC 0x24 -#define STREAM_TYPE_VIDEO_CAVS 0x42 -#define STREAM_TYPE_VIDEO_VC1 0xea -#define STREAM_TYPE_VIDEO_DIRAC 0xd1 - -#define STREAM_TYPE_AUDIO_AC3 0x81 -#define STREAM_TYPE_AUDIO_DTS 0x82 -#define STREAM_TYPE_AUDIO_TRUEHD 0x83 -#define STREAM_TYPE_AUDIO_EAC3 0x87 - -class ts_media_data_callback_I { -public: - virtual int on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, uint64_t dts, uint64_t pts) = 0; -}; - -typedef std::shared_ptr TS_DATA_CALLBACK_PTR; - -class adaptation_field { -public: - adaptation_field(){}; - ~adaptation_field(){}; - -public: - unsigned char _adaptation_field_length; - - unsigned char _discontinuity_indicator:1; - unsigned char _random_access_indicator:1; - unsigned char _elementary_stream_priority_indicator:1; - unsigned char _PCR_flag:1; - unsigned char _OPCR_flag:1; - unsigned char _splicing_point_flag:1; - unsigned char _transport_private_data_flag:1; - unsigned char _adaptation_field_extension_flag:1; - - //if(PCR_flag == '1') - unsigned long _program_clock_reference_base;//33 bits - unsigned short _program_clock_reference_extension;//9bits - //if (OPCR_flag == '1') - unsigned long _original_program_clock_reference_base;//33 bits - unsigned short _original_program_clock_reference_extension;//9bits - //if (splicing_point_flag == '1') - unsigned char _splice_countdown; - //if (transport_private_data_flag == '1') - unsigned char _transport_private_data_length; - unsigned char _private_data_byte[256]; - //if (adaptation_field_extension_flag == '1') - unsigned char _adaptation_field_extension_length; - unsigned char _ltw_flag; - unsigned char _piecewise_rate_flag; - unsigned char _seamless_splice_flag; - unsigned char _reserved0; - //if (ltw_flag == '1') - unsigned short _ltw_valid_flag:1; - unsigned short _ltw_offset:15; - //if (piecewise_rate_flag == '1') - unsigned int _piecewise_rate;//22bits - //if (seamless_splice_flag == '1') - unsigned char _splice_type;//4bits - unsigned char _DTS_next_AU1;//3bits - unsigned char _marker_bit1;//1bit - unsigned short _DTS_next_AU2;//15bit - unsigned char _marker_bit2;//1bit - unsigned short _DTS_next_AU3;//15bit - unsigned char _marker_bit3;//1bit -}; - -class ts_header { -public: - ts_header(){} - ~ts_header(){} - -public: - unsigned char _sync_byte; - - unsigned short _transport_error_indicator:1; - unsigned short _payload_unit_start_indicator:1; - unsigned short _transport_priority:1; - unsigned short _PID:13; - - unsigned char _transport_scrambling_control:2; - unsigned char _adaptation_field_control:2; - unsigned char _continuity_counter:4; - - adaptation_field _adaptation_field_info; -}; - -typedef struct { - unsigned short _program_number; - unsigned short _pid; - unsigned short _network_id; -} PID_INFO; - -class pat_info { -public: - pat_info(){}; - ~pat_info(){}; - -public: - unsigned char _table_id; - - unsigned short _section_syntax_indicator:1; - unsigned short _reserved0:1; - unsigned short _reserved1:2; - unsigned short _section_length:12; - - unsigned short _transport_stream_id; - - unsigned char _reserved3:2; - unsigned char _version_number:5; - unsigned char _current_next_indicator:1; - - unsigned char _section_number; - unsigned char _last_section_number; - std::vector _pid_vec; -}; - -typedef struct { - unsigned char _stream_type; - unsigned short _reserved1:3; - unsigned short _elementary_PID:13; - unsigned short _reserved:4; - unsigned short _ES_info_length; - unsigned char _dscr[4096]; - unsigned int _crc_32; -} STREAM_PID_INFO; - -class pmt_info { -public: - pmt_info(){}; - ~pmt_info(){}; -public: - unsigned char _table_id; - unsigned short _section_syntax_indicator:1; - unsigned short _reserved1:1; - unsigned short _reserved2:2; - unsigned short _section_length:12; - unsigned short _program_number:16; - unsigned char _reserved:2; - unsigned char _version_number:5; - unsigned char _current_next_indicator:5; - unsigned char _section_number; - unsigned char _last_section_number; - unsigned short _reserved3:3; - unsigned short _PCR_PID:13; - unsigned short _reserved4:4; - unsigned short _program_info_length:12; - unsigned char _dscr[4096]; - - std::unordered_map _pid2steamtype; - std::vector _stream_pid_vec; -}; - -class ts_demux { -public: - ts_demux(); - ~ts_demux(); - - int decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback); - -private: - int decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_CALLBACK_PTR callback); - bool is_pmt(unsigned short pmt_id); - int pes_parse(unsigned char* p, size_t npos, unsigned char** ret_pp, size_t& ret_size, - uint64_t& dts, uint64_t& pts); - void insert_into_databuf(unsigned char* data_p, size_t data_size, std::string key_path, unsigned short pid); - int on_callback(TS_DATA_CALLBACK_PTR callback, unsigned short pid, - std::string key_path, uint64_t dts, uint64_t pts); - -private: - std::string _key_path;//only for srt - - pat_info _pat; - pmt_info _pmt; - std::vector _data_buffer_vec; - size_t _data_total; - unsigned short _last_pid; - uint64_t _last_dts; - uint64_t _last_pts; -}; - -typedef std::shared_ptr TS_DEMUX_PTR; - -#endif diff --git a/trunk/src/srt/ts_demux_test.cpp b/trunk/src/srt/ts_demux_test.cpp deleted file mode 100644 index e3867964099..00000000000 --- a/trunk/src/srt/ts_demux_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2013-2021 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include "ts_demux.hpp" -#include -#include - -#define TS_MAX 188 - -class media_data_get : public ts_media_data_callback_I { -public: - media_data_get() {}; - virtual ~media_data_get() {}; - -public: - virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type - , uint64_t dts, uint64_t pts) { - printf("media type:%d, data len:%d, key_path:%s, dts:%lu(%lu), pts:%lu(%lu)\r\n", - media_type, data_ptr->data_len(), data_ptr->get_path().c_str(), dts, dts/90, pts, pts/90); - FILE* file_p; - char filename[80]; - - sprintf(filename, "%u.media", media_type); - file_p = fopen(filename, "ab+"); - if (file_p) { - fwrite(data_ptr->get_data(), data_ptr->data_len(), 1, file_p); - fclose(file_p); - } - return; - } -}; - -int main(int argn, char** argv) { - unsigned char data[TS_MAX]; - ts_demux demux_obj; - auto callback_ptr = std::make_shared(); - FILE* file_p; - if (argn < 2) { - printf("please input ts name.\r\n"); - return 0; - } - - const char* file_name = argv[1]; - printf("input ts name:%s.\r\n", file_name); - - file_p = fopen(file_name, "r"); - fseek(file_p, 0L, SEEK_END); /* 定位到文件末尾 */ - size_t flen = ftell(file_p); /* 得到文件大小 */ - fseek(file_p, 0L, SEEK_SET); /* 定位到文件开头 */ - - do { - fread(data, TS_MAX, 1, file_p); - auto input_ptr = std::make_shared((unsigned char*)data, (unsigned int)TS_MAX, std::string("live/shiwei")); - demux_obj.decode(input_ptr, callback_ptr); - flen -= TS_MAX; - } while(flen > 0); - return 1; -} From 85e958139294cbbabe21898e74ce8466d2813d54 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Sat, 16 Apr 2022 15:05:24 +0800 Subject: [PATCH 04/36] SRT: check srt_connect return value --- trunk/src/protocol/srs_service_st_srt.cpp | 32 +++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_service_st_srt.cpp index 12daacb46ad..99e9146c62f 100644 --- a/trunk/src/protocol/srs_service_st_srt.cpp +++ b/trunk/src/protocol/srs_service_st_srt.cpp @@ -530,21 +530,28 @@ srs_error_t SrsSrtSocket::connect(const string& ip, int port) // TODO: FIXME: inet_addr is deprecated inaddr.sin_addr.s_addr = inet_addr(ip.c_str()); + // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_connect int ret = srt_connect(srt_fd_, (const sockaddr*)&inaddr, sizeof(inaddr)); - // TODO: FIXME: check return value. - SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_); - if (srt_status != SRTS_CONNECTED) { - // Connect is in progress, wait until it finish or error. - if ((err = wait_writeable()) != srs_success) { - return srs_error_wrap(err, "wait writeable"); - } - - // Double check if connect is established. - srt_status = srt_getsockstate(srt_fd_); + if (ret == 0) { + // Connect succuess, in async mode, means SRT API succuess and return directly, + // and the connection is in progress, like tcp socket API connect errno EINPROGRESS, + // and the SRT IO threads will do the real handshake step to finish srt connect. + SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_); if (srt_status != SRTS_CONNECTED) { - return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); + // Connect is in progress, wait until it finish or error. + if ((err = wait_writeable()) != srs_success) { + return srs_error_wrap(err, "wait writeable"); + } + + // Double check if connect is established. + srt_status = srt_getsockstate(srt_fd_); + if (srt_status != SRTS_CONNECTED) { + return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); + } } + } else { + return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); } return err; @@ -557,6 +564,7 @@ srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd) while (true) { sockaddr_in inaddr; int addrlen = sizeof(inaddr); + // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_accept SRTSOCKET srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen); if (srt_fd == SRT_INVALID_SOCK) { if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { @@ -582,6 +590,7 @@ srs_error_t SrsSrtSocket::recvmsg(void* buf, size_t size, ssize_t* nread) srs_error_t err = srs_success; while (true) { + // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_recvmsg int ret = srt_recvmsg(srt_fd_, (char*)buf, size); if (ret < 0) { if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { @@ -607,6 +616,7 @@ srs_error_t SrsSrtSocket::sendmsg(void* buf, size_t size, ssize_t* nwrite) srs_error_t err = srs_success; while (true) { + // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_sendmsg int ret = srt_sendmsg(srt_fd_, (const char*)buf, size, -1, 1); if (ret < 0) { if (srt_getlasterror(NULL) == SRT_EASYNCSND) { From 7352bfee73f8c2facbe9dfa58efdb36746774fc8 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Wed, 20 Apr 2022 22:23:46 +0800 Subject: [PATCH 05/36] SRT: support rtmp to srt --- trunk/src/app/srs_app_config.cpp | 96 +++++++++-- trunk/src/app/srs_app_config.hpp | 5 + trunk/src/app/srs_app_rtc_source.cpp | 54 ++++-- trunk/src/app/srs_app_rtc_source.hpp | 6 +- trunk/src/app/srs_app_rtmp_conn.cpp | 26 +++ trunk/src/app/srs_app_source.cpp | 66 ++++++-- trunk/src/app/srs_app_source.hpp | 23 ++- trunk/src/app/srs_app_srt_conn.cpp | 197 ++++++++++++---------- trunk/src/app/srs_app_srt_conn.hpp | 19 +++ trunk/src/app/srs_app_srt_server.cpp | 4 +- trunk/src/app/srs_app_srt_source.cpp | 171 +++++++++++++++---- trunk/src/app/srs_app_srt_source.hpp | 39 +++-- trunk/src/kernel/srs_kernel_error.hpp | 2 + trunk/src/protocol/srs_service_st_srt.cpp | 17 +- trunk/src/protocol/srs_service_st_srt.hpp | 3 + 15 files changed, 539 insertions(+), 189 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f15296933fb..2d4c5470fa1 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2723,7 +2723,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "play" && n != "publish" && n != "cluster" && n != "security" && n != "http_remux" && n != "dash" && n != "http_static" && n != "hds" && n != "exec" - && n != "in_ack_size" && n != "out_ack_size" && n != "rtc") { + && n != "in_ack_size" && n != "out_ack_size" && n != "rtc" && n != "srt") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.%s", n.c_str()); } // for each sub directives of vhost. @@ -2880,6 +2880,13 @@ srs_error_t SrsConfig::check_normal_config() return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } + } else if (n == "srt") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name; + if (m != "enabled" && m != "rtmp_to_srt" && m != "srt_to_rtmp") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.srt.%s of %s", m.c_str(), vhost->arg0().c_str()); + } + } } } } @@ -6757,20 +6764,6 @@ unsigned short SrsConfig::get_srt_listen_port() return (unsigned short)atoi(conf->arg0().c_str()); } -bool SrsConfig::get_srt_mix_correct() { - static bool DEFAULT = true; - SrsConfDirective* conf = root->get("srt_server"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("mix_correct"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - return SRS_CONF_PERFER_TRUE(conf->arg0()); -} - int SrsConfig::get_srto_maxbw() { static int64_t DEFAULT = -1; SrsConfDirective* conf = root->get("srt_server"); @@ -6971,6 +6964,79 @@ string SrsConfig::get_default_app_name() { return conf->arg0(); } +bool SrsConfig::get_srt_mix_correct() { + static bool DEFAULT = true; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("mix_correct"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + +SrsConfDirective* SrsConfig::get_srt(std::string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + return conf? conf->get("srt") : NULL; +} + +bool SrsConfig::get_srt_enabled(std::string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_srt(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +bool SrsConfig::get_srt_to_rtmp(std::string vhost) +{ + static bool DEFAULT = true; + + SrsConfDirective* conf = get_srt(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("srt_to_rtmp"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +bool SrsConfig::get_srt_from_rtmp(std::string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_srt(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("rtmp_to_srt"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + bool SrsConfig::get_http_stream_enabled() { SrsConfDirective* conf = root->get("http_server"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 7cebd5c8023..78a815111b2 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -662,6 +662,11 @@ class SrsConfig virtual std::string get_default_app_name(); // Get the mix_correct virtual bool get_srt_mix_correct(); +public: + SrsConfDirective* get_srt(std::string vhost); + bool get_srt_enabled(std::string vhost); + bool get_srt_to_rtmp(std::string vhost); + bool get_srt_from_rtmp(std::string vhost); // http_hooks section private: diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index d4145eb3d3e..af4ee133781 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -270,7 +270,7 @@ srs_error_t SrsRtcSourceManager::fetch_or_create(SrsRequest* r, SrsRtcSource** p // should always not exists for create a source. srs_assert (pool.find(stream_url) == pool.end()); - srs_trace("new source, stream_url=%s", stream_url.c_str()); + srs_trace("new rtc source, stream_url=%s", stream_url.c_str()); source = new SrsRtcSource(); if ((err = source->initialize(r)) != srs_success) { @@ -316,7 +316,7 @@ ISrsRtcSourceEventHandler::~ISrsRtcSourceEventHandler() { } -ISrsRtcSourceBridger::ISrsRtcSourceBridger() +ISrsRtcSourceBridger::ISrsRtcSourceBridger(SrsBridgeDestType type) : ISrsBridge(type) { } @@ -333,7 +333,6 @@ SrsRtcSource::SrsRtcSource() stream_desc_ = NULL; req = NULL; - bridger_ = NULL; pli_for_rtmp_ = pli_elapsed_ = 0; } @@ -345,7 +344,11 @@ SrsRtcSource::~SrsRtcSource() consumers.clear(); srs_freep(req); - srs_freep(bridger_); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsRtcSourceBridger* bridge = *iter; + srs_freep(bridge); + } + bridgers_.clear(); srs_freep(stream_desc_); } @@ -459,8 +462,16 @@ SrsContextId SrsRtcSource::pre_source_id() void SrsRtcSource::set_bridger(ISrsRtcSourceBridger *bridger) { - srs_freep(bridger_); - bridger_ = bridger; + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsRtcSourceBridger* b = *iter; + if (b->get_type() == bridger->get_type()) { + srs_freep(b); + *iter = bridger; + return; + } + } + + bridgers_.push_back(bridger); } srs_error_t SrsRtcSource::create_consumer(SrsRtcConsumer*& consumer) @@ -533,9 +544,12 @@ srs_error_t SrsRtcSource::on_publish() } // If bridge to other source, handle event and start timer to request PLI. - if (bridger_) { - if ((err = bridger_->on_publish()) != srs_success) { - return srs_error_wrap(err, "bridger on publish"); + if (! bridgers_.empty()) { + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsRtcSourceBridger* bridge = *iter; + if ((err = bridge->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridger on publish"); + } } // The PLI interval for RTC2RTMP. @@ -574,12 +588,16 @@ void SrsRtcSource::on_unpublish() } //free bridger resource - if (bridger_) { + if (! bridgers_.empty()) { // For SrsRtcSource::on_timer() _srs_hybrid->timer100ms()->unsubscribe(this); - bridger_->on_unpublish(); - srs_freep(bridger_); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsRtcSourceBridger* bridge = *iter; + bridge->on_unpublish(); + srs_freep(bridge); + } + bridgers_.clear(); } SrsStatistic* stat = SrsStatistic::instance(); @@ -629,8 +647,11 @@ srs_error_t SrsRtcSource::on_rtp(SrsRtpPacket* pkt) } } - if (bridger_ && (err = bridger_->on_rtp(pkt)) != srs_success) { - return srs_error_wrap(err, "bridger consume message"); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsRtcSourceBridger* bridge = *iter; + if ((err = bridge->on_rtp(pkt)) != srs_success) { + return srs_error_wrap(err, "bridger consume message"); + } } return err; @@ -703,7 +724,8 @@ srs_error_t SrsRtcSource::on_timer(srs_utime_t interval) } #ifdef SRS_FFMPEG_FIT -SrsRtcFromRtmpBridger::SrsRtcFromRtmpBridger(SrsRtcSource* source) +SrsRtcFromRtmpBridger::SrsRtcFromRtmpBridger(SrsRtcSource* source) + : ISrsLiveSourceBridger(SrsBridgeDestTypeRTC) { req = NULL; source_ = source; @@ -1270,7 +1292,7 @@ srs_error_t SrsRtcFromRtmpBridger::consume_packets(vector& pkts) return err; } -SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger(SrsLiveSource *src) +SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger(SrsLiveSource *src) : ISrsRtcSourceBridger(SrsBridgeDestTypeRtmp) { source_ = src; codec_ = NULL; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 8b5a9d78659..e8c04cb4a1a 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -144,10 +144,10 @@ class ISrsRtcSourceEventHandler }; // SrsRtcSource bridge to SrsLiveSource -class ISrsRtcSourceBridger +class ISrsRtcSourceBridger : public ISrsBridge { public: - ISrsRtcSourceBridger(); + ISrsRtcSourceBridger(SrsBridgeDestType type); virtual ~ISrsRtcSourceBridger(); public: virtual srs_error_t on_publish() = 0; @@ -171,7 +171,7 @@ class SrsRtcSource : public ISrsFastTimer // Steam description for this steam. SrsRtcSourceDescription* stream_desc_; // The Source bridger, bridger stream to other source. - ISrsRtcSourceBridger* bridger_; + std::vector bridgers_; private: // To delivery stream to clients. std::vector consumers; diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 6be2b6862a3..729babd83b6 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -39,6 +39,7 @@ using namespace std; #include #include #include +#include // the timeout in srs_utime_t to wait encoder to republish // if timeout, close the connection. @@ -950,6 +951,31 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsLiveSource* source) if (!source->can_publish(info->edge)) { return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "rtmp: stream %s is busy", req->get_stream_url().c_str()); } + +#ifdef SRS_SRT + if (_srs_config->get_rtc_from_rtmp(req->vhost)) { + SrsSrtSource *srt = NULL; + if (!info->edge) { + if ((err = _srs_srt_sources->fetch_or_create(req, &srt)) != srs_success) { + return srs_error_wrap(err, "create source"); + } + + if (!srt->can_publish()) { + return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "srt stream %s busy", req->get_stream_url().c_str()); + } + } + + if (srt) { + SrsSrtFromRtmpBridge *bridger = new SrsSrtFromRtmpBridge(srt); + if ((err = bridger->initialize(req)) != srs_success) { + srs_freep(bridger); + return srs_error_wrap(err, "bridger init"); + } + + source->set_bridger(bridger); + } + } +#endif // Check whether RTC stream is busy. #ifdef SRS_RTC diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f7156103307..fc08cf47e5e 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1802,7 +1802,7 @@ srs_error_t SrsLiveSourceManager::fetch_or_create(SrsRequest* r, ISrsLiveSourceH // should always not exists for create a source. srs_assert (pool.find(stream_url) == pool.end()); - srs_trace("new source, stream_url=%s", stream_url.c_str()); + srs_trace("new live source, stream_url=%s", stream_url.c_str()); source = new SrsLiveSource(); if ((err = source->initialize(r, h)) != srs_success) { @@ -1909,7 +1909,21 @@ void SrsLiveSourceManager::destroy() pool.clear(); } -ISrsLiveSourceBridger::ISrsLiveSourceBridger() +ISrsBridge::ISrsBridge(SrsBridgeDestType type) +{ + type_ = type; +} + +ISrsBridge::~ISrsBridge() +{ +} + +SrsBridgeDestType ISrsBridge::get_type() const +{ + return type_; +} + +ISrsLiveSourceBridger::ISrsLiveSourceBridger(SrsBridgeDestType type) : ISrsBridge(type) { } @@ -1928,7 +1942,6 @@ SrsLiveSource::SrsLiveSource() die_at = 0; handler = NULL; - bridger_ = NULL; play_edge = new SrsPlayEdge(); publish_edge = new SrsPublishEdge(); @@ -1960,7 +1973,11 @@ SrsLiveSource::~SrsLiveSource() srs_freep(gop_cache); srs_freep(req); - srs_freep(bridger_); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + srs_freep(bridge); + } + bridgers_.clear(); } void SrsLiveSource::dispose() @@ -2038,8 +2055,16 @@ srs_error_t SrsLiveSource::initialize(SrsRequest* r, ISrsLiveSourceHandler* h) void SrsLiveSource::set_bridger(ISrsLiveSourceBridger* v) { - srs_freep(bridger_); - bridger_ = v; + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + if (v->get_type() == bridge->get_type()) { + srs_freep(bridge); + *iter = v; + return; + } + } + + bridgers_.push_back(v); } srs_error_t SrsLiveSource::on_reload_vhost_play(string vhost) @@ -2292,8 +2317,11 @@ srs_error_t SrsLiveSource::on_audio_imp(SrsSharedPtrMessage* msg) } // For bridger to consume the message. - if (bridger_ && (err = bridger_->on_audio(msg)) != srs_success) { - return srs_error_wrap(err, "bridger consume audio"); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + if ((err = bridge->on_audio(msg)) != srs_success) { + return srs_error_wrap(err, "bridger consume audio"); + } } // copy to all consumer @@ -2422,8 +2450,11 @@ srs_error_t SrsLiveSource::on_video_imp(SrsSharedPtrMessage* msg) } // For bridger to consume the message. - if (bridger_ && (err = bridger_->on_video(msg)) != srs_success) { - return srs_error_wrap(err, "bridger consume video"); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + if ((err = bridge->on_video(msg)) != srs_success) { + return srs_error_wrap(err, "bridger consume video"); + } } // copy to all consumer @@ -2586,8 +2617,11 @@ srs_error_t SrsLiveSource::on_publish() return srs_error_wrap(err, "handle publish"); } - if (bridger_ && (err = bridger_->on_publish()) != srs_success) { - return srs_error_wrap(err, "bridger publish"); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + if ((err = bridge->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridger publish"); + } } SrsStatistic* stat = SrsStatistic::instance(); @@ -2631,10 +2665,12 @@ void SrsLiveSource::on_unpublish() handler->on_unpublish(this, req); - if (bridger_) { - bridger_->on_unpublish(); - srs_freep(bridger_); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsLiveSourceBridger* bridge = *iter; + bridge->on_unpublish(); + srs_freep(bridge); } + bridgers_.clear(); // no consumer, stream is die. if (consumers.empty()) { diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 065deba0145..6da6de3bad4 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -468,11 +468,28 @@ class SrsLiveSourceManager : public ISrsHourGlass // Global singleton instance. extern SrsLiveSourceManager* _srs_sources; +// Destination type. +enum SrsBridgeDestType { + SrsBridgeDestTypeRtmp = 1, + SrsBridgeDestTypeRTC = 2, + SrsBridgeDestTypeSRT = 3, +}; + +class ISrsBridge { +public: + ISrsBridge(SrsBridgeDestType type); + virtual ~ISrsBridge(); +public: + SrsBridgeDestType get_type() const; +protected: + SrsBridgeDestType type_; +}; + // For RTMP2RTC, bridge SrsLiveSource to SrsRtcSource -class ISrsLiveSourceBridger +class ISrsLiveSourceBridger : public ISrsBridge { public: - ISrsLiveSourceBridger(); + ISrsLiveSourceBridger(SrsBridgeDestType type); virtual ~ISrsLiveSourceBridger(); public: virtual srs_error_t on_publish() = 0; @@ -515,7 +532,7 @@ class SrsLiveSource : public ISrsReloadHandler // The event handler. ISrsLiveSourceHandler* handler; // The source bridger for other source. - ISrsLiveSourceBridger* bridger_; + std::vector bridgers_; // The edge control service SrsPlayEdge* play_edge; SrsPublishEdge* publish_edge; diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index a0a279c0700..8986128ed1e 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -87,6 +87,67 @@ srs_error_t SrsSrtConnection::writev(const iovec *iov, int iov_size, ssize_t* nw return srs_error_new(ERROR_SRT_CONN, "unsupport method"); } +SrsSrtRecvThread::SrsSrtRecvThread(SrsSrtConnection* srt_conn) +{ + srt_conn_ = srt_conn; + trd_ = new SrsSTCoroutine("srt-recv", this, _srs_context->get_id()); + recv_err_ = srs_success; +} + +SrsSrtRecvThread::~SrsSrtRecvThread() +{ + srs_freep(trd_); + srs_error_reset(recv_err_); +} + +srs_error_t SrsSrtRecvThread::cycle() +{ + srs_error_t err = srs_success; + + if ((err = do_cycle()) != srs_success) { + recv_err_ = srs_error_copy(err); + } + + return err; +} + +srs_error_t SrsSrtRecvThread::do_cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt: thread quit"); + } + + char buf[1316]; + ssize_t nb = 0; + if ((err = srt_conn_->read(buf, sizeof(buf), &nb)) != srs_success) { + if (srs_error_code(err) != ERROR_SRT_TIMEOUT) { + return srs_error_wrap(err, "srt read"); + } + } + } + + return err; +} + +srs_error_t SrsSrtRecvThread::start() +{ + srs_error_t err = srs_success; + + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "start srt recv thread"); + } + + return err; +} + +srs_error_t SrsSrtRecvThread::get_recv_err() +{ + return srs_error_copy(recv_err_); +} + SrsMpegtsSrtConn::SrsMpegtsSrtConn(SrsSrtServer* srt_server, SRTSOCKET srt_fd, std::string ip, int port) { // Create a identify for this client. @@ -178,7 +239,7 @@ srs_error_t SrsMpegtsSrtConn::do_cycle() { srs_error_t err = srs_success; - if ((err != fetch_or_create_source()) != srs_success) { + if ((err = fetch_or_create_source()) != srs_success) { return srs_error_wrap(err, "fetch or create srt source"); } @@ -216,6 +277,10 @@ srs_error_t SrsMpegtsSrtConn::fetch_or_create_source() return srs_error_new(ERROR_SRT_CONN, "invalid srt streamid=%s", streamid.c_str()); } + if (! _srs_config->get_srt_enabled(req_->vhost)) { + return srs_error_new(ERROR_SRT_CONN, "srt disabled, vhost=%s", req_->vhost.c_str()); + } + srs_trace("@srt, streamid=%s, stream_url=%s, vhost=%s, app=%s, stream=%s, param=%s", streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); @@ -267,72 +332,8 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish() return srs_error_new(ERROR_SRT_SOURCE_BUSY, "srt stream %s busy", req_->get_stream_url().c_str()); } - // Check rtmp stream is busy. - SrsLiveSource *live_source = _srs_sources->fetch(req_); - if (live_source && !live_source->can_publish(false)) { - return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str()); - } - - if ((err = _srs_sources->fetch_or_create(req_, _srs_hybrid->srs()->instance(), &live_source)) != srs_success) { - return srs_error_wrap(err, "create source"); - } - - SrsRtmpFromTsBridge *bridger = new SrsRtmpFromTsBridge(live_source); - if ((err = bridger->initialize(req_)) != srs_success) { - srs_freep(bridger); - return srs_error_wrap(err, "create bridger"); - } - - srt_source_->set_bridger(bridger); - - if ((err = srt_source_->on_publish()) != srs_success) { - return srs_error_wrap(err, "srt source publish"); - } - - return err; -} - -void SrsMpegtsSrtConn::release_publish() -{ - srt_source_->on_unpublish(); -} - -/* -srs_error_t SrsMpegtsSrtConn::do_cycle() -{ - srs_error_t err = srs_success; - - string streamid = ""; - if ((err = srs_srt_get_streamid(srt_fd_, streamid)) != srs_success) { - return srs_error_wrap(err, "get srt streamid"); - } - - // Must have streamid, because srt ts packet will convert to rtmp or rtc. - if (streamid.empty()) { - return srs_error_new(ERROR_SRT_CONN, "empty srt streamid"); - } - - // Detect streamid of srt to request. - if (! srs_srt_streamid_to_request(streamid, mode_, req_)) { - return srs_error_new(ERROR_SRT_CONN, "invalid srt streamid=%s", streamid.c_str()); - } - - srs_trace("@srt, streamid=%s, stream_url=%s, vhost=%s, app=%s, stream=%s, param=%s", - streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); - - if ((err = _srs_srt_sources->fetch_or_create(req_, &srt_source_)) != srs_success) { - return srs_error_wrap(err, "fetch srt source"); - } - - if (mode_ == SrtModePush) { - if ((err = http_hooks_on_publish()) != srs_success) { - return srs_error_wrap(err, "srt: callback on publish"); - } - // Do srt publish. - if (! srt_source_->can_publish()) { - return srs_error_new(ERROR_SRT_SOURCE_BUSY, "srt stream %s busy", req_->get_stream_url().c_str()); - } - + if (_srs_config->get_srt_to_rtmp(req_->vhost)) { + // Check rtmp stream is busy. SrsLiveSource *live_source = _srs_sources->fetch(req_); if (live_source && !live_source->can_publish(false)) { return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str()); @@ -342,37 +343,26 @@ srs_error_t SrsMpegtsSrtConn::do_cycle() return srs_error_wrap(err, "create source"); } - SrsRtmpFromTsBridge *bridger = new SrsRtmpFromTsBridge(live_source); + SrsRtmpFromSrtBridge *bridger = new SrsRtmpFromSrtBridge(live_source); if ((err = bridger->initialize(req_)) != srs_success) { srs_freep(bridger); return srs_error_wrap(err, "create bridger"); } srt_source_->set_bridger(bridger); + } - if ((err = srt_source_->on_publish()) != srs_success) { - return srs_error_wrap(err, "srt source publish"); - } - - err = do_publish_cycle(); - - srt_source_->on_unpublish(); - http_hooks_on_unpublish(); - } else if (mode_ == SrtModePull) { - if ((err = http_hooks_on_play()) != srs_success) { - return srs_error_wrap(err, "srt: callback on play"); - } - // Do srt play. - err = do_play_cycle(); - - http_hooks_on_stop(); - } else { - srs_assert(false); + if ((err = srt_source_->on_publish()) != srs_success) { + return srs_error_wrap(err, "srt source publish"); } return err; } -*/ + +void SrsMpegtsSrtConn::release_publish() +{ + srt_source_->on_unpublish(); +} srs_error_t SrsMpegtsSrtConn::do_publishing() { @@ -394,7 +384,18 @@ srs_error_t SrsMpegtsSrtConn::do_publishing() // reportable if (pprint->can_print()) { + SRT_TRACEBSTATS srt_stats; + srs_error_t err_tmp = srs_srt_get_stats(srt_fd_, &srt_stats, true); + if (err_tmp != srs_success) { + srs_freep(err_tmp); + } else { + srs_trace("<- " SRS_CONSTS_LOG_SRT_PUBLISH " Transport Stats # " + "pktRecv=%ld, pktRcvLoss=%d, pktRcvRetrans=%d, pktRcvDrop=%d", + srt_stats.pktRecv, srt_stats.pktRcvLoss, srt_stats.pktRcvRetrans, srt_stats.pktRcvDrop); + } + kbps_->sample(); + srs_trace("<- " SRS_CONSTS_LOG_SRT_PUBLISH " time=%d, packets=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", (int)pprint->age(), nb_packets, kbps_->get_send_kbps(), kbps_->get_send_kbps_30s(), kbps_->get_send_kbps_5m(), kbps_->get_recv_kbps(), kbps_->get_recv_kbps_30s(), kbps_->get_recv_kbps_5m()); @@ -436,6 +437,11 @@ srs_error_t SrsMpegtsSrtConn::do_playing() SrsPithyPrint* pprint = SrsPithyPrint::create_srt_play(); SrsAutoFree(SrsPithyPrint, pprint); + SrsSrtRecvThread srt_recv_trd(srt_conn_); + if ((err = srt_recv_trd.start()) != srs_success) { + return srs_error_wrap(err, "start srt recv trd"); + } + int nb_packets = 0; while (true) { @@ -443,6 +449,10 @@ srs_error_t SrsMpegtsSrtConn::do_playing() return srs_error_wrap(err, "srt play thread"); } + if ((err = srt_recv_trd.get_recv_err()) != srs_success) { + return srs_error_wrap(err, "srt play recv thread"); + } + pprint->elapse(); // Wait for amount of packets. @@ -451,13 +461,24 @@ srs_error_t SrsMpegtsSrtConn::do_playing() consumer->dump_packet(&pkt); if (!pkt) { // TODO: FIXME: We should check the quit event. - consumer->wait(1); + consumer->wait(1, 1000 * SRS_UTIME_MILLISECONDS); continue; } // reportable if (pprint->can_print()) { + SRT_TRACEBSTATS srt_stats; + srs_error_t err_tmp = srs_srt_get_stats(srt_fd_, &srt_stats, true); + if (err_tmp != srs_success) { + srs_freep(err_tmp); + } else { + srs_trace("-> " SRS_CONSTS_LOG_SRT_PLAY " Transport Stats # " + "pktSent=%ld, pktSndLoss=%d, pktRetrans=%d, pktSndDrop=%d", + srt_stats.pktSent, srt_stats.pktSndLoss, srt_stats.pktRetrans, srt_stats.pktSndDrop); + } + kbps_->sample(); + srs_trace("-> " SRS_CONSTS_LOG_SRT_PLAY " time=%d, packets=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", (int)pprint->age(), nb_packets, kbps_->get_send_kbps(), kbps_->get_send_kbps_30s(), kbps_->get_send_kbps_5m(), kbps_->get_recv_kbps(), kbps_->get_recv_kbps_30s(), kbps_->get_recv_kbps_5m()); diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index 351894f7087..40bf9974335 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -51,6 +51,25 @@ class SrsSrtConnection : public ISrsProtocolReadWriter SrsSrtSocket* srt_skt_; }; +class SrsSrtRecvThread : public ISrsCoroutineHandler +{ +public: + SrsSrtRecvThread(SrsSrtConnection* srt_conn); + ~SrsSrtRecvThread(); +// Interface ISrsCoroutineHandler +public: + virtual srs_error_t cycle(); +private: + srs_error_t do_cycle(); +public: + srs_error_t start(); + srs_error_t get_recv_err(); +private: + SrsSrtConnection* srt_conn_; + SrsCoroutine* trd_; + srs_error_t recv_err_; +}; + class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHandler { public: diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 7e709706d15..a550fe35720 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -380,12 +380,14 @@ srs_error_t SrsSrtEventLoop::cycle() return srs_error_wrap(err, "srt listener"); } + // Check events fired, return directly. if ((err = srt_poller_->wait(0)) != srs_success) { srs_error("srt poll wait failed, err=%s", srs_error_desc(err).c_str()); srs_error_reset(err); } - srs_usleep(10 * SRS_UTIME_MILLISECONDS); + // Schedule srt event by state-thread. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); } return err; diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index f3025ca4a45..0f03ac82020 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -125,7 +125,7 @@ srs_error_t SrsSrtSourceManager::fetch_or_create(SrsRequest* r, SrsSrtSource** p // should always not exists for create a source. srs_assert (pool.find(stream_url) == pool.end()); - srs_trace("new ts source, stream_url=%s", stream_url.c_str()); + srs_trace("new srt source, stream_url=%s", stream_url.c_str()); source = new SrsSrtSource(); if ((err = source->initialize(r)) != srs_success) { @@ -218,7 +218,7 @@ srs_error_t SrsSrtConsumer::dump_packet(SrsSrtPacket** ppkt) return err; } -void SrsSrtConsumer::wait(int nb_msgs) +void SrsSrtConsumer::wait(int nb_msgs, srs_utime_t timeout) { mw_min_msgs = nb_msgs; @@ -231,18 +231,19 @@ void SrsSrtConsumer::wait(int nb_msgs) mw_waiting = true; // use cond block wait for high performance mode. - srs_cond_wait(mw_wait); + srs_cond_timedwait(mw_wait, timeout); } -ISrsTsSourceBridger::ISrsTsSourceBridger() +ISrsSrtSourceBridge::ISrsSrtSourceBridge(SrsBridgeDestType type) : ISrsBridge(type) { } -ISrsTsSourceBridger::~ISrsTsSourceBridger() +ISrsSrtSourceBridge::~ISrsSrtSourceBridge() { } -SrsRtmpFromTsBridge::SrsRtmpFromTsBridge(SrsLiveSource* source) +SrsRtmpFromSrtBridge::SrsRtmpFromSrtBridge(SrsLiveSource* source) + : ISrsSrtSourceBridge(SrsBridgeDestTypeRtmp) { ts_ctx_ = new SrsTsContext(); @@ -254,13 +255,13 @@ SrsRtmpFromTsBridge::SrsRtmpFromTsBridge(SrsLiveSource* source) req_ = NULL; } -SrsRtmpFromTsBridge::~SrsRtmpFromTsBridge() +SrsRtmpFromSrtBridge::~SrsRtmpFromSrtBridge() { srs_freep(ts_ctx_); srs_freep(req_); } -srs_error_t SrsRtmpFromTsBridge::on_publish() +srs_error_t SrsRtmpFromSrtBridge::on_publish() { srs_error_t err = srs_success; @@ -271,7 +272,7 @@ srs_error_t SrsRtmpFromTsBridge::on_publish() return err; } -srs_error_t SrsRtmpFromTsBridge::on_packet(SrsSrtPacket *pkt) +srs_error_t SrsRtmpFromSrtBridge::on_packet(SrsSrtPacket *pkt) { srs_error_t err = srs_success; @@ -297,12 +298,12 @@ srs_error_t SrsRtmpFromTsBridge::on_packet(SrsSrtPacket *pkt) return err; } -void SrsRtmpFromTsBridge::on_unpublish() +void SrsRtmpFromSrtBridge::on_unpublish() { live_source_->on_unpublish(); } -srs_error_t SrsRtmpFromTsBridge::initialize(SrsRequest* req) +srs_error_t SrsRtmpFromSrtBridge::initialize(SrsRequest* req) { srs_error_t err = srs_success; @@ -312,7 +313,7 @@ srs_error_t SrsRtmpFromTsBridge::initialize(SrsRequest* req) return err; } -srs_error_t SrsRtmpFromTsBridge::on_ts_message(SrsTsMessage* msg) +srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg) { srs_error_t err = srs_success; @@ -352,7 +353,7 @@ srs_error_t SrsRtmpFromTsBridge::on_ts_message(SrsTsMessage* msg) return err; } -srs_error_t SrsRtmpFromTsBridge::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) +srs_error_t SrsRtmpFromSrtBridge::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) { srs_error_t err = srs_success; @@ -419,7 +420,7 @@ srs_error_t SrsRtmpFromTsBridge::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) return on_h264_frame(msg, ipb_frames); } -srs_error_t SrsRtmpFromTsBridge::check_sps_pps_change(SrsTsMessage* msg) +srs_error_t SrsRtmpFromSrtBridge::check_sps_pps_change(SrsTsMessage* msg) { srs_error_t err = srs_success; @@ -464,7 +465,7 @@ srs_error_t SrsRtmpFromTsBridge::check_sps_pps_change(SrsTsMessage* msg) return err; } -srs_error_t SrsRtmpFromTsBridge::on_h264_frame(SrsTsMessage* msg, vector >& ipb_frames) +srs_error_t SrsRtmpFromSrtBridge::on_h264_frame(SrsTsMessage* msg, vector >& ipb_frames) { srs_error_t err = srs_success; @@ -520,7 +521,7 @@ srs_error_t SrsRtmpFromTsBridge::on_h264_frame(SrsTsMessage* msg, vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsSrtSourceBridge* bridge = *iter; + srs_freep(bridge); + } + bridgers_.clear(); } srs_error_t SrsSrtSource::initialize(SrsRequest* r) @@ -702,10 +706,18 @@ void SrsSrtSource::update_auth(SrsRequest* r) req->update_auth(r); } -void SrsSrtSource::set_bridger(ISrsTsSourceBridger *bridger) +void SrsSrtSource::set_bridger(ISrsSrtSourceBridge *bridger) { - srs_freep(bridger_); - bridger_ = bridger; + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsSrtSourceBridge* b = *iter; + if (b->get_type() == bridger->get_type()) { + srs_freep(b); + *iter = bridger; + return; + } + } + + bridgers_.push_back(bridger); } srs_error_t SrsSrtSource::create_consumer(SrsSrtConsumer*& consumer) @@ -752,8 +764,9 @@ srs_error_t SrsSrtSource::on_publish() return srs_error_wrap(err, "source id change"); } - if (bridger_) { - if ((err = bridger_->on_publish()) != srs_success) { + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsSrtSourceBridge* bridge = *iter; + if ((err = bridge->on_publish()) != srs_success) { return srs_error_wrap(err, "bridger on publish"); } } @@ -773,10 +786,12 @@ void SrsSrtSource::on_unpublish() can_publish_ = true; - if (bridger_) { - bridger_->on_unpublish(); - srs_freep(bridger_); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsSrtSourceBridge* bridge = *iter; + bridge->on_unpublish(); + srs_freep(bridge); } + bridgers_.clear(); } srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) @@ -790,8 +805,104 @@ srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) } } - if (bridger_ && (err = bridger_->on_packet(packet)) != srs_success) { - return srs_error_wrap(err, "bridger consume message"); + for (vector::iterator iter = bridgers_.begin(); iter != bridgers_.end(); ++iter) { + ISrsSrtSourceBridge* bridge = *iter; + if ((err = bridge->on_packet(packet)) != srs_success) { + return srs_error_wrap(err, "bridger consume message"); + } + } + + return err; +} + +SrsSrtFromRtmpBridge::SrsSrtFromRtmpBridge(SrsSrtSource* source) + : ISrsLiveSourceBridger(SrsBridgeDestTypeSRT) +{ + srt_source_ = source; + ts_muxer_ = NULL; + offset_ = 0; +} + +SrsSrtFromRtmpBridge::~SrsSrtFromRtmpBridge() +{ + srs_freep(ts_muxer_); +} + +srs_error_t SrsSrtFromRtmpBridge::initialize(SrsRequest* r) +{ + srs_error_t err = srs_success; + + // TODO: FIXME: check config. + req_ = r; + + ts_muxer_ = new SrsTsTransmuxer(); + if ((err = ts_muxer_->initialize(this)) != srs_success) { + return srs_error_wrap(err, "init ts muxer"); + } + + return err; +} + +srs_error_t SrsSrtFromRtmpBridge::on_publish() +{ + srs_error_t err = srs_success; + + // TODO: FIXME: check if enable rtmp_to_srt + + if ((err = srt_source_->on_publish()) != srs_success) { + return srs_error_wrap(err, "source publish"); + } + + return err; +} + +void SrsSrtFromRtmpBridge::on_unpublish() +{ + // TODO: FIXME: check if enable rtmp_to_srt + srt_source_->on_unpublish(); +} + +srs_error_t SrsSrtFromRtmpBridge::on_audio(SrsSharedPtrMessage* msg) +{ + srs_error_t err = srs_success; + + if ((err = ts_muxer_->write_audio(msg->timestamp, msg->payload, msg->size)) != srs_success) { + return srs_error_wrap(err, "rtmp to srt, ts mux audio"); + } + + return err; +} + +srs_error_t SrsSrtFromRtmpBridge::on_video(SrsSharedPtrMessage* msg) +{ + srs_error_t err = srs_success; + + if ((err = ts_muxer_->write_video(msg->timestamp, msg->payload, msg->size)) != srs_success) { + return srs_error_wrap(err, "rtmp to srt, ts mux video"); + } + + return err; +} + +srs_error_t SrsSrtFromRtmpBridge::write(void* buf, size_t size, ssize_t* nwrite) +{ + srs_error_t err = srs_success; + + if (size % SRS_TS_PACKET_SIZE != 0) { + return srs_error_new(ERROR_RTMP_TO_SRT, "invalid ts size=%u", size); + } + + for (int i = 0; i < size; i += SRS_TS_PACKET_SIZE) { + memcpy(ts_buf_ + offset_, (const char*)buf + i, SRS_TS_PACKET_SIZE); + offset_ += SRS_TS_PACKET_SIZE; + if (offset_ >= 1316) { + offset_ = 0; + SrsSrtPacket* packet = new SrsSrtPacket(); + SrsAutoFree(SrsSrtPacket, packet); + packet->wrap(ts_buf_, 1316); + + srt_source_->on_packet(packet); + } } return err; diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp index d285143c9c5..14c2a55176d 100644 --- a/trunk/src/app/srs_app_srt_source.hpp +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -14,6 +14,7 @@ #include #include +#include class SrsSharedPtrMessage; class SrsRequest; @@ -86,25 +87,25 @@ class SrsSrtConsumer // For SRT, we only got one packet, because there is not many packets in queue. virtual srs_error_t dump_packet(SrsSrtPacket** ppkt); // Wait for at-least some messages incoming in queue. - virtual void wait(int nb_msgs); + virtual void wait(int nb_msgs, srs_utime_t timeout); }; -class ISrsTsSourceBridger +class ISrsSrtSourceBridge : public ISrsBridge { public: - ISrsTsSourceBridger(); - virtual ~ISrsTsSourceBridger(); + ISrsSrtSourceBridge(SrsBridgeDestType type); + virtual ~ISrsSrtSourceBridge(); public: virtual srs_error_t on_publish() = 0; virtual srs_error_t on_packet(SrsSrtPacket *pkt) = 0; virtual void on_unpublish() = 0; }; -class SrsRtmpFromTsBridge : public ISrsTsSourceBridger, public ISrsTsHandler +class SrsRtmpFromSrtBridge : public ISrsSrtSourceBridge, public ISrsTsHandler { public: - SrsRtmpFromTsBridge(SrsLiveSource* source); - virtual ~SrsRtmpFromTsBridge(); + SrsRtmpFromSrtBridge(SrsLiveSource* source); + virtual ~SrsRtmpFromSrtBridge(); public: virtual srs_error_t on_publish(); virtual srs_error_t on_packet(SrsSrtPacket *pkt); @@ -153,7 +154,7 @@ class SrsSrtSource // Update the authentication information in request. virtual void update_auth(SrsRequest* r); public: - void set_bridger(ISrsTsSourceBridger *bridger); + void set_bridger(ISrsSrtSourceBridge *bridger); public: // Create consumer // @param consumer, output the create consumer. @@ -178,18 +179,14 @@ class SrsSrtSource // To delivery packets to clients. std::vector consumers; bool can_publish_; - ISrsTsSourceBridger* bridger_; + std::vector bridgers_; }; -/* -class SrsTsFromRtmpBridger : public ISrsLiveSourceBridger +class SrsSrtFromRtmpBridge : public ISrsLiveSourceBridger, public ISrsStreamWriter { -private: - SrsRequest* req; - SrsSrtSource* source_; public: - SrsTsFromRtmpBridger(SrsSrtSource* source); - virtual ~SrsTsFromRtmpBridger(); + SrsSrtFromRtmpBridge(SrsSrtSource* source); + virtual ~SrsSrtFromRtmpBridge(); public: virtual srs_error_t initialize(SrsRequest* r); // Interface for ISrsLiveSourceBridger @@ -198,8 +195,16 @@ class SrsTsFromRtmpBridger : public ISrsLiveSourceBridger virtual void on_unpublish(); virtual srs_error_t on_audio(SrsSharedPtrMessage* msg); virtual srs_error_t on_video(SrsSharedPtrMessage* msg); +// Interface for ISrsStreamWriter +public: + virtual srs_error_t write(void* buf, size_t size, ssize_t* nwrite); +private: + SrsRequest* req_; + SrsSrtSource* srt_source_; + SrsTsTransmuxer* ts_muxer_; + char ts_buf_[1316]; + int offset_; }; -*/ #endif diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 94f8c9c5479..457afb346fd 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -358,6 +358,8 @@ #define ERROR_SRT_SOCKOPT 6005 #define ERROR_SRT_CONN 6006 #define ERROR_SRT_SOURCE_BUSY 6007 +#define ERROR_RTMP_TO_SRT 6008 +#define ERROR_SRT_STATS 6009 /////////////////////////////////////////////////////// // HTTP API error. diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_service_st_srt.cpp index 99e9146c62f..5809ddecb2d 100644 --- a/trunk/src/protocol/srs_service_st_srt.cpp +++ b/trunk/src/protocol/srs_service_st_srt.cpp @@ -376,6 +376,18 @@ srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& p return err; } +srs_error_t srs_srt_get_stats(SRTSOCKET srt_fd, SRT_TRACEBSTATS* srt_stats, bool clear) +{ + srs_error_t err = srs_success; + + int ret = srt_bstats(srt_fd, srt_stats, clear); + if (ret != 0) { + return srs_error_new(ERROR_SRT_STATS, "srt_bstats"); + } + + return err; +} + SrsSrtPoller::SrsSrtPoller() { srt_epoller_fd_ = -1; @@ -395,6 +407,9 @@ srs_error_t SrsSrtPoller::initialize() srt_epoller_fd_ = srt_epoll_create(); events_.resize(1024); + // Enable srt empty poller, avoid warning. + srt_epoll_set(srt_epoller_fd_, SRT_EPOLL_ENABLE_EMPTY); + return err; } @@ -442,7 +457,7 @@ srs_error_t SrsSrtPoller::wait(int timeout_ms) // wait srt event fired, will timeout after `timeout_ms` milliseconds. int ret = srt_epoll_uwait(srt_epoller_fd_, events_.data(), events_.size(), timeout_ms); if (ret < 0) { - return srs_error_new(ERROR_SRT_EPOLL, "srt_epoll_uwait, ret=%d", ret); + return srs_error_new(ERROR_SRT_EPOLL, "srt_epoll_uwait, ret=%d, err=%s", ret, srt_getlasterror_str()); } for (int i = 0; i < ret; ++i) { diff --git a/trunk/src/protocol/srs_service_st_srt.hpp b/trunk/src/protocol/srs_service_st_srt.hpp index 1e548b490da..f2d1f775511 100644 --- a/trunk/src/protocol/srs_service_st_srt.hpp +++ b/trunk/src/protocol/srs_service_st_srt.hpp @@ -61,6 +61,9 @@ extern srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid) extern srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); extern srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); +// Get SRT stats. +extern srs_error_t srs_srt_get_stats(SRTSOCKET srt_fd, SRT_TRACEBSTATS* srt_stats, bool clear); + class SrsSrtSocket; // Srt poller, subscribe/unsubscribed events and wait them fired. From 5d33eec2aae2e488b90b430bc378fa8a95a84902 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Fri, 22 Apr 2022 19:46:52 +0800 Subject: [PATCH 06/36] SRT: fix utest failed --- trunk/conf/srt.conf | 10 ++++++++-- trunk/src/utest/srs_utest_config.cpp | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index ed1c57f0b16..bcb1f9de401 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -26,12 +26,18 @@ srt_server { listen 10080; maxbw 1000000000; connect_timeout 4000; - peerlatency 300; - recvlatency 300; + peerlatency 0; + recvlatency 0; } # @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577607026 vhost __defaultVhost__ { + srt { + enabled on; + srt_to_rtmp on; + rtmp_to_srt on; + } + http_remux { enabled on; mount [vhost]/[app]/[stream].flv; diff --git a/trunk/src/utest/srs_utest_config.cpp b/trunk/src/utest/srs_utest_config.cpp index b36700b69bd..ebce274fe81 100644 --- a/trunk/src/utest/srs_utest_config.cpp +++ b/trunk/src/utest/srs_utest_config.cpp @@ -2115,6 +2115,9 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost) VOID TEST(ConfigUnitTest, CheckDefaultValuesGlobal) { if (true) { + // Schedule thread once, to update last_clock in state-thread. + srs_usleep(1); + srs_utime_t t0 = srs_update_system_time(); srs_usleep(10 * SRS_UTIME_MILLISECONDS); srs_utime_t t1 = srs_update_system_time(); From 8cea168c0471a18a56112f14aa0d485c0ad3e3db Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 23 May 2022 08:31:57 +0800 Subject: [PATCH 07/36] SRT: Fix cmake bug, quit if error. --- trunk/auto/depends.sh | 8 +++----- trunk/ide/srs_clion/CMakeLists.txt | 11 +++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 87bf940fb59..f40bd645614 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -253,11 +253,9 @@ function OSX_prepare() echo "OSX detected, install tools if needed" - brew --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then - echo "install brew" - echo "ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"" - ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi - echo "install brew success" + brew --version >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Please install brew at https://brew.sh/" + exit $ret fi gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then diff --git a/trunk/ide/srs_clion/CMakeLists.txt b/trunk/ide/srs_clion/CMakeLists.txt index 6503e37ee61..d5c4cd7507c 100755 --- a/trunk/ide/srs_clion/CMakeLists.txt +++ b/trunk/ide/srs_clion/CMakeLists.txt @@ -26,10 +26,17 @@ ProcessorCount(JOBS) # We should always configure SRS for switching between branches. IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - EXEC_PROGRAM("cd ${SRS_DIR} && ./configure --osx --srt=on --utest=on --jobs=${JOBS}") + EXECUTE_PROCESS( + COMMAND ./configure --osx --srt=on --utest=on --jobs=${JOBS} + WORKING_DIRECTORY ${SRS_DIR} RESULT_VARIABLE ret) ELSE () - EXEC_PROGRAM("cd ${SRS_DIR} && ./configure --srt=on --utest=on --jobs=${JOBS}") + EXECUTE_PROCESS( + COMMAND ./configure --srt=on --utest=on --jobs=${JOBS} + WORKING_DIRECTORY ${SRS_DIR} RESULT_VARIABLE ret) ENDIF () +if(NOT ret EQUAL 0) + message(FATAL_ERROR "FAILED: ${ret}") +endif() set(DEPS_LIBS ${SRS_DIR}/objs/st/libst.a ${SRS_DIR}/objs/openssl/lib/libssl.a From 05d3d963d0893a45df310ad60fbb70765d25fd4f Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 23 May 2022 08:44:16 +0800 Subject: [PATCH 08/36] SRT: Update full.conf for new configs. --- trunk/conf/full.conf | 15 +++++++++------ trunk/conf/srt.conf | 10 +++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 1e975ade8fe..15765eb1e14 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -352,7 +352,7 @@ stream_caster { ############################################################################################# # SRT server section ############################################################################################# -# @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577607026 +# @doc https://github.com/ossrs/srs/issues/1147#usage srt_server { # whether SRT server is enabled. # default: off @@ -364,11 +364,14 @@ srt_server { # https://github.com/ossrs/srs/wiki/v4_EN_SRTParams maxbw 1000000000; connect_timeout 4000; - peerlatency 300; - recvlatency 300; - # Default app for vmix, see https://github.com/ossrs/srs/pull/1615 - # default: live - default_app live; + peerlatency 0; + recvlatency 0; + # TODO: FIXME: Add comments. + latency 0; + tsbpdmode off; + tlpktdrop off; + sendbuf 2000000; + recvbuf 2000000; } ############################################################################################# diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index bcb1f9de401..f9cc63f5071 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -18,16 +18,16 @@ http_server { srt_server { enabled on; - tsbpdmode off; - tlpktdrop off; - latency 0; - sendbuf 2000000; - recvbuf 2000000; listen 10080; maxbw 1000000000; connect_timeout 4000; peerlatency 0; recvlatency 0; + latency 0; + tsbpdmode off; + tlpktdrop off; + sendbuf 2000000; + recvbuf 2000000; } # @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577607026 From 4ce091e219379261fb0412b10757597bcbd9ac3b Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 23 May 2022 08:51:42 +0800 Subject: [PATCH 09/36] SRT: Update full.conf for review. --- trunk/conf/full.conf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 15765eb1e14..a84b3f3bc45 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -360,13 +360,15 @@ srt_server { # The UDP listen port for SRT. listen 10080; # For detail parameters, please read wiki: - # https://github.com/ossrs/srs/wiki/v4_CN_SRTParams - # https://github.com/ossrs/srs/wiki/v4_EN_SRTParams + # https://github.com/ossrs/srs/wiki/v5_CN_SRTParams + # https://github.com/ossrs/srs/wiki/v5_EN_SRTParams maxbw 1000000000; connect_timeout 4000; + # Default app for vmix, see https://github.com/ossrs/srs/pull/1615 + # default: live + default_app live; peerlatency 0; recvlatency 0; - # TODO: FIXME: Add comments. latency 0; tsbpdmode off; tlpktdrop off; From 86d48c46769b15903648001ca6becea37c20a99c Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 25 May 2022 08:35:44 +0800 Subject: [PATCH 10/36] SRT: Add srt vhost section to full.conf. --- trunk/conf/full.conf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index a84b3f3bc45..0dcdbc46f58 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -376,6 +376,14 @@ srt_server { recvbuf 2000000; } +vhost srt.vhost.srs.com { + srt { + enabled on; + srt_to_rtmp on; + rtmp_to_srt on; + } +} + ############################################################################################# # WebRTC server section ############################################################################################# From 738e110b79ff822d0ac136f81378de23d8e8d2fd Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 28 May 2022 09:16:24 +0800 Subject: [PATCH 11/36] SRT: Refine parse SRT listen ip and port. --- trunk/src/app/srs_app_srt_server.cpp | 30 +++++++++++----------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index a550fe35720..eaea6b286f8 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -188,27 +188,21 @@ srs_error_t SrsSrtServer::listen_srt_mpegts() if (! _srs_config->get_srt_enabled()) { return err; } - - // TODO: FIXME: bad code, refine it. - std::vector ip_ports; - std::stringstream ss; - ss << _srs_config->get_srt_listen_port(); - ip_ports.push_back(ss.str()); - + + // Close all listener for SRT if exists. close_listeners(SrsSrtListenerMpegts); - - for (int i = 0; i < (int)ip_ports.size(); i++) { - SrsSrtAcceptor* acceptor = new SrsSrtMessageAcceptor(this, SrsSrtListenerMpegts); - acceptors_.push_back(acceptor); - int port; string ip; - srs_parse_endpoint(ip_ports[i], ip, port); - - if ((err = acceptor->listen(ip, port)) != srs_success) { - return srs_error_wrap(err, "srt listen %s:%d", ip.c_str(), port); - } + // Start a listener for SRT, we might need multiple listeners in the future. + SrsSrtAcceptor* acceptor = new SrsSrtMessageAcceptor(this, SrsSrtListenerMpegts); + acceptors_.push_back(acceptor); + + int port; string ip; + srs_parse_endpoint(srs_int2str(_srs_config->get_srt_listen_port()), ip, port); + + if ((err = acceptor->listen(ip, port)) != srs_success) { + return srs_error_wrap(err, "srt listen %s:%d", ip.c_str(), port); } - + return err; } From bc59917c738ddb2a918930c3cc3cf14c87d71878 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 28 May 2022 10:46:05 +0800 Subject: [PATCH 12/36] SRT: Refine the schedule resolution to 10ms if idle. --- trunk/src/app/srs_app_srt_server.cpp | 16 +++++++++++----- trunk/src/protocol/srs_service_st_srt.cpp | 4 +++- trunk/src/protocol/srs_service_st_srt.hpp | 4 +++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index eaea6b286f8..bfaef1f8eb4 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -374,15 +374,21 @@ srs_error_t SrsSrtEventLoop::cycle() return srs_error_wrap(err, "srt listener"); } - // Check events fired, return directly. - if ((err = srt_poller_->wait(0)) != srs_success) { - srs_error("srt poll wait failed, err=%s", srs_error_desc(err).c_str()); + // Check and notify fired SRT events by epoll. + // + // Note that the SRT poller use a dedicated and isolated epoll, which is not the same as the one of SRS, in + // short, the wait won't switch to other coroutines when no fd is active, so we must use timeout(0) to make sure + // to return directly, then use srs_usleep to do the coroutine switch. + int n_fds = 0; + if ((err = srt_poller_->wait(0, &n_fds)) != srs_success) { + srs_warn("srt poll wait failed, n_fds=%d, err=%s", n_fds, srs_error_desc(err).c_str()); srs_error_reset(err); } - // Schedule srt event by state-thread. - srs_usleep(1 * SRS_UTIME_MILLISECONDS); + // We use sleep to switch to other coroutines, because the SRT poller is not possible to do this. + srs_usleep((n_fds ? 1 : 10) * SRS_UTIME_MILLISECONDS); } return err; } + diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_service_st_srt.cpp index 5809ddecb2d..d2f5809116b 100644 --- a/trunk/src/protocol/srs_service_st_srt.cpp +++ b/trunk/src/protocol/srs_service_st_srt.cpp @@ -450,12 +450,14 @@ srs_error_t SrsSrtPoller::del_socket(SrsSrtSocket* srt_skt) return err; } -srs_error_t SrsSrtPoller::wait(int timeout_ms) +srs_error_t SrsSrtPoller::wait(int timeout_ms, int* pn_fds) { srs_error_t err = srs_success; // wait srt event fired, will timeout after `timeout_ms` milliseconds. int ret = srt_epoll_uwait(srt_epoller_fd_, events_.data(), events_.size(), timeout_ms); + *pn_fds = ret; + if (ret < 0) { return srs_error_new(ERROR_SRT_EPOLL, "srt_epoll_uwait, ret=%d, err=%s", ret, srt_getlasterror_str()); } diff --git a/trunk/src/protocol/srs_service_st_srt.hpp b/trunk/src/protocol/srs_service_st_srt.hpp index f2d1f775511..c96d0711041 100644 --- a/trunk/src/protocol/srs_service_st_srt.hpp +++ b/trunk/src/protocol/srs_service_st_srt.hpp @@ -77,7 +77,9 @@ class SrsSrtPoller srs_error_t add_socket(SrsSrtSocket* srt_skt); srs_error_t mod_socket(SrsSrtSocket* srt_skt); srs_error_t del_socket(SrsSrtSocket* srt_skt); - srs_error_t wait(int timeout_ms); + // Wait for the fds in its epoll to be fired in specified timeout_ms, where the pn_fds is the number of active fds. + // Note that for ST, please always use timeout_ms(0) and switch coroutine by yourself. + srs_error_t wait(int timeout_ms, int* pn_fds); private: // Find SrsSrtSocket* context by SRTSOCKET. std::map fd_sockets_; From f5101ae977095318cf2af888fdc6291a803f11ca Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 28 May 2022 12:07:36 +0800 Subject: [PATCH 13/36] SRT: Initialize SRT eventloop in adapter. --- trunk/src/app/srs_app_srt_server.cpp | 15 +++++++++++++++ trunk/src/main/srs_main_server.cpp | 11 ----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index bfaef1f8eb4..e77896ea35f 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -14,6 +14,10 @@ using namespace std; #include #include +#ifdef SRS_SRT +SrsSrtEventLoop* _srt_eventloop = NULL; +#endif + std::string srs_srt_listener_type2string(SrsSrtListenerType type) { switch (type) { @@ -300,6 +304,17 @@ SrsSrtServerAdapter::~SrsSrtServerAdapter() srs_error_t SrsSrtServerAdapter::initialize() { srs_error_t err = srs_success; + + _srt_eventloop = new SrsSrtEventLoop(); + + if ((err = _srt_eventloop->initialize()) != srs_success) { + return srs_error_wrap(err, "srt poller initialize"); + } + + if ((err = _srt_eventloop->start()) != srs_success) { + return srs_error_wrap(err, "srt poller start"); + } + return err; } diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 025a53cab3c..e02ef786e4c 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -66,10 +66,6 @@ extern const char* _srs_version; // @global main SRS server, for debugging SrsServer* _srs_server = NULL; -#ifdef SRS_SRT -SrsSrtEventLoop* _srt_eventloop = NULL; -#endif - /** * main entrance. */ @@ -460,13 +456,6 @@ srs_error_t run_hybrid_server() _srs_hybrid->register_server(new SrsServerAdapter()); #ifdef SRS_SRT - _srt_eventloop = new SrsSrtEventLoop(); - if ((err = _srt_eventloop->initialize()) != srs_success) { - return srs_error_wrap(err, "srt poller initialize"); - } - if ((err = _srt_eventloop->start()) != srs_success) { - return srs_error_wrap(err, "srt poller start"); - } _srs_hybrid->register_server(new SrsSrtServerAdapter()); #endif From 16063d1467cf975976014e3c6df14c1efab898a3 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 28 May 2022 16:53:40 +0800 Subject: [PATCH 14/36] SRT: Refine get_srt_poller to poller. --- trunk/src/app/srs_app_srt_conn.cpp | 2 +- trunk/src/app/srs_app_srt_listener.cpp | 2 +- trunk/src/app/srs_app_srt_server.hpp | 4 ++-- trunk/src/utest/srs_utest_srt.cpp | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 8986128ed1e..6cf2fe779c8 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -23,7 +23,7 @@ using namespace std; SrsSrtConnection::SrsSrtConnection(SRTSOCKET srt_fd) { srt_fd_ = srt_fd; - srt_skt_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_fd_); + srt_skt_ = new SrsSrtSocket(_srt_eventloop->poller(), srt_fd_); } SrsSrtConnection::~SrsSrtConnection() diff --git a/trunk/src/app/srs_app_srt_listener.cpp b/trunk/src/app/srs_app_srt_listener.cpp index f3b9951f4b9..5931ca93d5c 100644 --- a/trunk/src/app/srs_app_srt_listener.cpp +++ b/trunk/src/app/srs_app_srt_listener.cpp @@ -61,7 +61,7 @@ srs_error_t SrsSrtListener::listen() return srs_error_wrap(err, "srs_srt_listen"); } - srt_skt_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), lfd_); + srt_skt_ = new SrsSrtSocket(_srt_eventloop->poller(), lfd_); // Accept never timeout. srt_skt_->set_recv_timeout(ST_UTIME_NO_TIMEOUT); srt_skt_->set_send_timeout(ST_UTIME_NO_TIMEOUT); diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index e3311a77ac3..577638acac5 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -104,14 +104,14 @@ class SrsSrtServerAdapter : public ISrsHybridServer virtual SrsSrtServer* instance(); }; -// The srt event loop, run srt poller and wait event happeed. +// Start a coroutine to drive the SRT events with state-threads. class SrsSrtEventLoop : public ISrsCoroutineHandler { public: SrsSrtEventLoop(); virtual ~SrsSrtEventLoop(); public: - SrsSrtPoller* get_srt_poller() { return srt_poller_; } + SrsSrtPoller* poller() { return srt_poller_; } public: srs_error_t initialize(); srs_error_t start(); diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 8abba1288d1..3b17debb6c4 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -151,7 +151,7 @@ class MockSrtServer return srs_error_wrap(err, "srt listen"); } - srt_socket_ = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_server_fd_); + srt_socket_ = new SrsSrtSocket(_srt_eventloop->poller(), srt_server_fd_); return err; } @@ -185,7 +185,7 @@ VOID TEST(ServiceStSRTTest, ListenConnectAccept) SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_client_fd)); - SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); // No client connected, accept will timeout. SRTSOCKET srt_fd = SRT_INVALID_SOCK; @@ -209,7 +209,7 @@ VOID TEST(ServiceStSRTTest, ConnectTimeout) SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); - SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); srt_client_socket->set_send_timeout(50 * SRS_UTIME_MILLISECONDS); // Client connect to server which is no listening. @@ -231,7 +231,7 @@ VOID TEST(ServiceStSRTTest, ConnectWithStreamid) SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); - SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); HELPER_EXPECT_SUCCESS(srt_client_socket->connect("127.0.0.1", 9000)); @@ -256,7 +256,7 @@ VOID TEST(ServiceStSRTTest, ReadWrite) SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); - SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_client_fd); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); // Client connect to server HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); @@ -265,7 +265,7 @@ VOID TEST(ServiceStSRTTest, ReadWrite) SRTSOCKET srt_server_accepted_fd = SRT_INVALID_SOCK; HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); EXPECT_NE(srt_server_accepted_fd, SRT_INVALID_SOCK); - SrsSrtSocket* srt_server_accepted_socket = new SrsSrtSocket(_srt_eventloop->get_srt_poller(), srt_server_accepted_fd); + SrsSrtSocket* srt_server_accepted_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_server_accepted_fd); if (true) { std::string content = "Hello, SRS SRT!"; From a7725f6cd3a4899faeb0acd616a8220b0593a06a Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 28 May 2022 17:18:39 +0800 Subject: [PATCH 15/36] SRT: Refine the SRT socket code. --- trunk/src/protocol/srs_service_st_srt.cpp | 130 ++++++++++++---------- trunk/src/utest/srs_utest.cpp | 4 - 2 files changed, 72 insertions(+), 62 deletions(-) diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_service_st_srt.cpp index d2f5809116b..9aed09fddef 100644 --- a/trunk/src/protocol/srs_service_st_srt.cpp +++ b/trunk/src/protocol/srs_service_st_srt.cpp @@ -549,25 +549,26 @@ srs_error_t SrsSrtSocket::connect(const string& ip, int port) // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_connect int ret = srt_connect(srt_fd_, (const sockaddr*)&inaddr, sizeof(inaddr)); + if (ret != 0) { + return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); + } - if (ret == 0) { - // Connect succuess, in async mode, means SRT API succuess and return directly, - // and the connection is in progress, like tcp socket API connect errno EINPROGRESS, - // and the SRT IO threads will do the real handshake step to finish srt connect. - SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_); - if (srt_status != SRTS_CONNECTED) { - // Connect is in progress, wait until it finish or error. - if ((err = wait_writeable()) != srs_success) { - return srs_error_wrap(err, "wait writeable"); - } + // Connect succeed, in async mode, means SRT API succeed and return directly, + // and the connection is in progress, like tcp socket API connect errno EINPROGRESS, + // and the SRT IO threads will do the real handshake step to finish srt connect. + SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_); + if (srt_status == SRTS_CONNECTED) { + return err; + } - // Double check if connect is established. - srt_status = srt_getsockstate(srt_fd_); - if (srt_status != SRTS_CONNECTED) { - return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); - } - } - } else { + // Connect is in progress, wait until it finish or error. + if ((err = wait_writeable()) != srs_success) { + return srs_error_wrap(err, "wait writeable"); + } + + // Double check if connect is established. + srt_status = srt_getsockstate(srt_fd_); + if (srt_status != SRTS_CONNECTED) { return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str()); } @@ -583,19 +584,21 @@ srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd) int addrlen = sizeof(inaddr); // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_accept SRTSOCKET srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen); - if (srt_fd == SRT_INVALID_SOCK) { - if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { - // Accept would block, wait until new client connect or error. - if ((err = wait_readable()) != srs_success) { - return srs_error_wrap(err, "wait readable"); - } - continue; - } else { - return srs_error_new(ERROR_SRT_IO, "srt_accept, err=%s", srt_getlasterror_str()); - } - } else { + + // Accept ok, return with the SRT client fd. + if (srt_fd != SRT_INVALID_SOCK) { *client_srt_fd = srt_fd; - break; + return err; + } + + // Got something error, return immediately. + if (srt_getlasterror(NULL) != SRT_EASYNCRCV) { + return srs_error_new(ERROR_SRT_IO, "srt_accept, err=%s", srt_getlasterror_str()); + } + + // Accept would block, wait until new client connect or error. + if ((err = wait_readable()) != srs_success) { + return srs_error_wrap(err, "wait readable"); } } @@ -609,19 +612,22 @@ srs_error_t SrsSrtSocket::recvmsg(void* buf, size_t size, ssize_t* nread) while (true) { // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_recvmsg int ret = srt_recvmsg(srt_fd_, (char*)buf, size); - if (ret < 0) { - if (srt_getlasterror(NULL) == SRT_EASYNCRCV) { - if ((err = wait_readable()) != srs_success) { - return srs_error_wrap(err, "wait readable"); - } - continue; - } else { - return srs_error_new(ERROR_SRT_IO, "srt_recvmsg, err=%s", srt_getlasterror_str()); - } - } else { + + // Receive message ok. + if (ret >= 0) { recv_bytes_ += ret; *nread = ret; - break; + return err; + } + + // Got something error, return immediately. + if (srt_getlasterror(NULL) != SRT_EASYNCRCV) { + return srs_error_new(ERROR_SRT_IO, "srt_recvmsg, err=%s", srt_getlasterror_str()); + } + + // Wait for the fd ready or error, switch to other coroutines. + if ((err = wait_readable()) != srs_success) { + return srs_error_wrap(err, "wait readable"); } } @@ -635,19 +641,22 @@ srs_error_t SrsSrtSocket::sendmsg(void* buf, size_t size, ssize_t* nwrite) while (true) { // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_sendmsg int ret = srt_sendmsg(srt_fd_, (const char*)buf, size, -1, 1); - if (ret < 0) { - if (srt_getlasterror(NULL) == SRT_EASYNCSND) { - if ((err = wait_writeable()) != srs_success) { - return srs_error_wrap(err, "wait writeable"); - } - continue; - } else { - return srs_error_new(ERROR_SRT_IO, "srt_sendmsg, err=%s", srt_getlasterror_str()); - } - } else { + + // Send message ok. + if (ret >= 0) { send_bytes_ += ret; *nwrite = ret; - break; + return err; + } + + // Got something error, return immediately. + if (srt_getlasterror(NULL) != SRT_EASYNCSND) { + return srs_error_new(ERROR_SRT_IO, "srt_sendmsg, err=%s", srt_getlasterror_str()); + } + + // Wait for the fd ready or error, switch to other coroutines. + if ((err = wait_writeable()) != srs_success) { + return srs_error_wrap(err, "wait writeable"); } } @@ -671,8 +680,7 @@ srs_error_t SrsSrtSocket::wait_readable() // Wait event fired or timeout. int ret = srs_cond_timedwait(read_cond_, recv_timeout_); // TODO: FIXME: need to disable it? - err = disable_read(); - if (err != srs_success) { + if ((err = disable_read()) != srs_success) { srs_freep(err); } @@ -709,8 +717,7 @@ srs_error_t SrsSrtSocket::wait_writeable() } int ret = srs_cond_timedwait(write_cond_, send_timeout_); - err = disable_write(); - if (err != srs_success) { + if ((err = disable_write()) != srs_success) { srs_freep(err); } @@ -769,8 +776,10 @@ srs_error_t SrsSrtSocket::disable_write() return disable_event(SRT_EPOLL_OUT); } -srs_error_t SrsSrtSocket::enable_event(int event) { +srs_error_t SrsSrtSocket::enable_event(int event) +{ srs_error_t err = srs_success; + // Event has been subscribed. if ((events_ & event) == event) { return err; @@ -784,11 +793,14 @@ srs_error_t SrsSrtSocket::enable_event(int event) { } else { err = srt_poller_->mod_socket(this); } + return err; } -srs_error_t SrsSrtSocket::disable_event(int event) { +srs_error_t SrsSrtSocket::disable_event(int event) +{ srs_error_t err = srs_success; + // Event has been unsubscribed. if ((events_ & event) == 0) { return err; @@ -801,10 +813,12 @@ srs_error_t SrsSrtSocket::disable_event(int event) { } else { err = srt_poller_->mod_socket(this); } + return err; } -srs_error_t SrsSrtSocket::check_error() { +srs_error_t SrsSrtSocket::check_error() +{ srs_error_t err = srs_success; if (has_error_) { diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index f2478eb9f57..52365b942a5 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -36,10 +36,6 @@ SrsConfig* _srs_config = NULL; SrsServer* _srs_server = NULL; bool _srs_in_docker = false; -#ifdef SRS_SRT -SrsSrtEventLoop* _srt_eventloop = NULL; -#endif - #include // Initialize global settings. From 14fb187dedfc7f398f7eb34da6f70f47250ee744 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:23:57 +0800 Subject: [PATCH 16/36] SRT: Add SRT option annotation in full.conf --- trunk/conf/full.conf | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 0dcdbc46f58..a6c77c6787b 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -362,17 +362,44 @@ srt_server { # For detail parameters, please read wiki: # https://github.com/ossrs/srs/wiki/v5_CN_SRTParams # https://github.com/ossrs/srs/wiki/v5_EN_SRTParams + + # The maxbw is the max bandwidth of the sender side. + # -1: Means the biggest bandwidth is infinity. + # 0: Means the bandwidth is determined by SRTO_INPUTBW. + # >0: Means the bandwidth is the configuration value. + # default: -1 maxbw 1000000000; + # The timeout time of SRT connection. When the SRT connection is idle more than this config, it will be close. + # default: 3000 connect_timeout 4000; # Default app for vmix, see https://github.com/ossrs/srs/pull/1615 # default: live default_app live; + # The peerlatency is set by the sender side and will notify the receiver side. + # default: 0 peerlatency 0; + # The recvlatency means latency from sender to receiver. + # default: 120 recvlatency 0; + # This latency configuration configures both recvlatency and peerlatency to the same value. + # default: 120 latency 0; + # The tsbpd mode means timestamp based packet delivery. + # SRT sender side will pack timestamp in each packet. If this config is true, + # the receiver will read the packet according to the timestamp in the head of the packet. + # default: on tsbpdmode off; + # The tlpkdrop means too-late Packet Drop + # SRT sender side will pack timestamp in each packet, When the network is congested, + # the packet will drop if latency is bigger than the configuration in both sender side and receiver side. + # And on the sender side, it also will be dropped because latency is bigger than configuration. + # default: on tlpktdrop off; + # The send buffer size of SRT. + # default: 8192 * (1500-28) sendbuf 2000000; + # The recv buffer size of SRT. + # default: 8192 * (1500-28) recvbuf 2000000; } From 8558fb944762fa8278189cc45cb982fbff63d618 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:24:23 +0800 Subject: [PATCH 17/36] SRT: Tsbpdmode default on --- trunk/src/app/srs_app_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 2d4c5470fa1..efed819fb8b 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -6793,7 +6793,7 @@ int SrsConfig::get_srto_mss() { } bool SrsConfig::get_srto_tsbpdmode() { - static bool DEFAULT = false; + static bool DEFAULT = true; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { return DEFAULT; From a3e0a3ced203c09d27bd9dee7a9f0aa565498b1a Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:50:51 +0800 Subject: [PATCH 18/36] SRT: refine int to srs_utime_t in srt timeout config --- trunk/src/app/srs_app_config.cpp | 12 ++++++------ trunk/src/app/srs_app_config.hpp | 4 ++-- trunk/src/app/srs_app_srt_server.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index efed819fb8b..7a212dad6db 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -6880,8 +6880,8 @@ bool SrsConfig::get_srto_tlpktdrop() { return SRS_CONF_PERFER_TRUE(conf->arg0()); } -int SrsConfig::get_srto_conntimeout() { - static int DEFAULT = 3000; +srs_utime_t SrsConfig::get_srto_conntimeout() { + static srs_utime_t DEFAULT = 3 * SRS_UTIME_SECONDS; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { return DEFAULT; @@ -6891,11 +6891,11 @@ int SrsConfig::get_srto_conntimeout() { if (!conf || conf->arg0().empty()) { return DEFAULT; } - return atoi(conf->arg0().c_str()); + return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); } -int SrsConfig::get_srto_peeridletimeout() { - static int DEFAULT = 10000; +srs_utime_t SrsConfig::get_srto_peeridletimeout() { + static srs_utime_t DEFAULT = 10 * SRS_UTIME_SECONDS; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { return DEFAULT; @@ -6905,7 +6905,7 @@ int SrsConfig::get_srto_peeridletimeout() { if (!conf || conf->arg0().empty()) { return DEFAULT; } - return atoi(conf->arg0().c_str()); + return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); } int SrsConfig::get_srto_sendbuf() { diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 78a815111b2..51616261833 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -649,9 +649,9 @@ class SrsConfig // Get the srt SRTO_TLPKTDROP, Too-late Packet Drop, default is true. virtual bool get_srto_tlpktdrop(); // Get the srt SRTO_CONNTIMEO, connection timeout, default is 3000ms. - virtual int get_srto_conntimeout(); + virtual srs_utime_t get_srto_conntimeout(); // Get the srt SRTO_PEERIDLETIMEO, peer idle timeout, default is 10000ms. - virtual int get_srto_peeridletimeout(); + virtual srs_utime_t get_srto_peeridletimeout(); // Get the srt SRTO_SNDBUF, send buffer, default is 8192 × (1500-28). virtual int get_srto_sendbuf(); // Get the srt SRTO_RCVBUF, recv buffer, default is 8192 × (1500-28). diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index e77896ea35f..0a23fcc610a 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -118,11 +118,11 @@ srs_error_t SrsSrtMessageAcceptor::set_srt_opt() return srs_error_wrap(err, "set opt"); } - if ((err = srs_srt_set_connect_timeout(listener_->fd(), _srs_config->get_srto_conntimeout())) != srs_success) { + if ((err = srs_srt_set_connect_timeout(listener_->fd(), srsu2msi(_srs_config->get_srto_conntimeout()))) != srs_success) { return srs_error_wrap(err, "set opt"); } - if ((err = srs_srt_set_peer_idle_timeout(listener_->fd(), _srs_config->get_srto_peeridletimeout())) != srs_success) { + if ((err = srs_srt_set_peer_idle_timeout(listener_->fd(), srsu2msi(_srs_config->get_srto_peeridletimeout()))) != srs_success) { return srs_error_wrap(err, "set opt"); } From c096dfa12c0d20f03382671c66d5c1aeac073449 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:51:11 +0800 Subject: [PATCH 19/36] SRT: add option peer_idle_timeout in full.conf --- trunk/conf/full.conf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index a6c77c6787b..d62004ff476 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -369,9 +369,14 @@ srt_server { # >0: Means the bandwidth is the configuration value. # default: -1 maxbw 1000000000; - # The timeout time of SRT connection. When the SRT connection is idle more than this config, it will be close. + # The timeout time of the SRT connection on the sender side in ms. When SRT connects to a peer costs time + # more than this config, it will be close. # default: 3000 connect_timeout 4000; + # The timeout time of SRT connection on the receiver side in ms. When the SRT connection is idle + # more than this config, it will be close. + # default: 10000 + peer_idle_timeout 8000; # Default app for vmix, see https://github.com/ossrs/srs/pull/1615 # default: live default_app live; From 40725ab2e120c6160170b2ab4875a9243f656101 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:56:15 +0800 Subject: [PATCH 20/36] SRT: use srs code style in function defination --- trunk/src/app/srs_app_config.cpp | 49 +++++++++++++++++++++----------- trunk/src/app/srs_app_config.hpp | 3 +- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7a212dad6db..d96e53aa116 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -6764,7 +6764,8 @@ unsigned short SrsConfig::get_srt_listen_port() return (unsigned short)atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_maxbw() { +int SrsConfig::get_srto_maxbw() +{ static int64_t DEFAULT = -1; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6778,7 +6779,8 @@ int SrsConfig::get_srto_maxbw() { return atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_mss() { +int SrsConfig::get_srto_mss() +{ static int DEFAULT = 1500; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6792,7 +6794,8 @@ int SrsConfig::get_srto_mss() { return atoi(conf->arg0().c_str()); } -bool SrsConfig::get_srto_tsbpdmode() { +bool SrsConfig::get_srto_tsbpdmode() +{ static bool DEFAULT = true; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6806,7 +6809,8 @@ bool SrsConfig::get_srto_tsbpdmode() { return SRS_CONF_PERFER_TRUE(conf->arg0()); } -int SrsConfig::get_srto_latency() { +int SrsConfig::get_srto_latency() +{ static int DEFAULT = 120; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6820,7 +6824,8 @@ int SrsConfig::get_srto_latency() { return atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_recv_latency() { +int SrsConfig::get_srto_recv_latency() +{ static int DEFAULT = 120; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6834,7 +6839,8 @@ int SrsConfig::get_srto_recv_latency() { return atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_peer_latency() { +int SrsConfig::get_srto_peer_latency() +{ static int DEFAULT = 0; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6848,7 +6854,8 @@ int SrsConfig::get_srto_peer_latency() { return atoi(conf->arg0().c_str()); } -bool SrsConfig::get_srt_sei_filter() { +bool SrsConfig::get_srt_sei_filter() +{ static bool DEFAULT = true; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6862,7 +6869,8 @@ bool SrsConfig::get_srt_sei_filter() { return SRS_CONF_PERFER_TRUE(conf->arg0()); } -bool SrsConfig::get_srto_tlpktdrop() { +bool SrsConfig::get_srto_tlpktdrop() +{ static bool DEFAULT = true; SrsConfDirective* srt_server_conf = root->get("srt_server"); if (!srt_server_conf) { @@ -6880,7 +6888,8 @@ bool SrsConfig::get_srto_tlpktdrop() { return SRS_CONF_PERFER_TRUE(conf->arg0()); } -srs_utime_t SrsConfig::get_srto_conntimeout() { +srs_utime_t SrsConfig::get_srto_conntimeout() +{ static srs_utime_t DEFAULT = 3 * SRS_UTIME_SECONDS; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6894,7 +6903,8 @@ srs_utime_t SrsConfig::get_srto_conntimeout() { return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); } -srs_utime_t SrsConfig::get_srto_peeridletimeout() { +srs_utime_t SrsConfig::get_srto_peeridletimeout() +{ static srs_utime_t DEFAULT = 10 * SRS_UTIME_SECONDS; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6908,8 +6918,9 @@ srs_utime_t SrsConfig::get_srto_peeridletimeout() { return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS); } -int SrsConfig::get_srto_sendbuf() { - static int64_t DEFAULT = 8192 * (1500-28); +int SrsConfig::get_srto_sendbuf() +{ + static int DEFAULT = 8192 * (1500-28); SrsConfDirective* conf = root->get("srt_server"); if (!conf) { return DEFAULT; @@ -6922,8 +6933,9 @@ int SrsConfig::get_srto_sendbuf() { return atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_recvbuf() { - static int64_t DEFAULT = 8192 * (1500-28); +int SrsConfig::get_srto_recvbuf() +{ + static int DEFAULT = 8192 * (1500-28); SrsConfDirective* conf = root->get("srt_server"); if (!conf) { return DEFAULT; @@ -6936,7 +6948,8 @@ int SrsConfig::get_srto_recvbuf() { return atoi(conf->arg0().c_str()); } -int SrsConfig::get_srto_payloadsize() { +int SrsConfig::get_srto_payloadsize() +{ static int DEFAULT = 1316; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6950,7 +6963,8 @@ int SrsConfig::get_srto_payloadsize() { return atoi(conf->arg0().c_str()); } -string SrsConfig::get_default_app_name() { +string SrsConfig::get_default_app_name() +{ static string DEFAULT = "live"; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { @@ -6964,7 +6978,8 @@ string SrsConfig::get_default_app_name() { return conf->arg0(); } -bool SrsConfig::get_srt_mix_correct() { +bool SrsConfig::get_srt_mix_correct() +{ static bool DEFAULT = true; SrsConfDirective* conf = root->get("srt_server"); if (!conf) { diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 51616261833..e514ec6b8d6 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -662,8 +662,9 @@ class SrsConfig virtual std::string get_default_app_name(); // Get the mix_correct virtual bool get_srt_mix_correct(); -public: +private: SrsConfDirective* get_srt(std::string vhost); +public: bool get_srt_enabled(std::string vhost); bool get_srt_to_rtmp(std::string vhost); bool get_srt_from_rtmp(std::string vhost); From b217eaf034897a2e03848871dd3a188c2b0b46bc Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 19:58:16 +0800 Subject: [PATCH 21/36] SRT: remove mix_correct --- trunk/src/app/srs_app_config.cpp | 17 +---------------- trunk/src/app/srs_app_config.hpp | 2 -- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index d96e53aa116..38025e56ffd 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2546,7 +2546,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "mss" && n != "latency" && n != "recvlatency" && n != "peerlatency" && n != "tlpkdrop" && n != "connect_timeout" && n != "sendbuf" && n != "recvbuf" && n != "payloadsize" - && n != "default_app" && n != "mix_correct" && n != "sei_filter" + && n != "default_app" && n != "sei_filter" && n != "tlpktdrop" && n != "tsbpdmode") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_server.%s", n.c_str()); } @@ -6978,21 +6978,6 @@ string SrsConfig::get_default_app_name() return conf->arg0(); } -bool SrsConfig::get_srt_mix_correct() -{ - static bool DEFAULT = true; - SrsConfDirective* conf = root->get("srt_server"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("mix_correct"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - return SRS_CONF_PERFER_TRUE(conf->arg0()); -} - SrsConfDirective* SrsConfig::get_srt(std::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 e514ec6b8d6..d9bd6b47c6e 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -660,8 +660,6 @@ class SrsConfig virtual int get_srto_payloadsize(); // Get the default app. virtual std::string get_default_app_name(); - // Get the mix_correct - virtual bool get_srt_mix_correct(); private: SrsConfDirective* get_srt(std::string vhost); public: From c4abac8163b3cd0bfc16116ee271822fe2c35cf8 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Mon, 30 May 2022 20:03:11 +0800 Subject: [PATCH 22/36] SRT: remove rtmp_to_srt --- trunk/conf/full.conf | 1 - trunk/conf/srt.conf | 1 - trunk/src/app/srs_app_config.cpp | 20 +----- trunk/src/app/srs_app_config.hpp | 1 - trunk/src/app/srs_app_rtmp_conn.cpp | 25 -------- trunk/src/app/srs_app_srt_source.cpp | 92 ---------------------------- trunk/src/app/srs_app_srt_source.hpp | 24 -------- 7 files changed, 1 insertion(+), 163 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index d62004ff476..7d45cc7e580 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -412,7 +412,6 @@ vhost srt.vhost.srs.com { srt { enabled on; srt_to_rtmp on; - rtmp_to_srt on; } } diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index f9cc63f5071..582bc005639 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -35,7 +35,6 @@ vhost __defaultVhost__ { srt { enabled on; srt_to_rtmp on; - rtmp_to_srt on; } http_remux { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 38025e56ffd..7aa18bb2539 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2883,7 +2883,7 @@ srs_error_t SrsConfig::check_normal_config() } else if (n == "srt") { for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; - if (m != "enabled" && m != "rtmp_to_srt" && m != "srt_to_rtmp") { + if (m != "enabled" && m != "srt_to_rtmp") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.srt.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -7019,24 +7019,6 @@ bool SrsConfig::get_srt_to_rtmp(std::string vhost) return SRS_CONF_PERFER_FALSE(conf->arg0()); } -bool SrsConfig::get_srt_from_rtmp(std::string vhost) -{ - static bool DEFAULT = false; - - SrsConfDirective* conf = get_srt(vhost); - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("rtmp_to_srt"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - bool SrsConfig::get_http_stream_enabled() { SrsConfDirective* conf = root->get("http_server"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index d9bd6b47c6e..1f59332c94d 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -665,7 +665,6 @@ class SrsConfig public: bool get_srt_enabled(std::string vhost); bool get_srt_to_rtmp(std::string vhost); - bool get_srt_from_rtmp(std::string vhost); // http_hooks section private: diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 729babd83b6..fffae492cad 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -952,31 +952,6 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsLiveSource* source) return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "rtmp: stream %s is busy", req->get_stream_url().c_str()); } -#ifdef SRS_SRT - if (_srs_config->get_rtc_from_rtmp(req->vhost)) { - SrsSrtSource *srt = NULL; - if (!info->edge) { - if ((err = _srs_srt_sources->fetch_or_create(req, &srt)) != srs_success) { - return srs_error_wrap(err, "create source"); - } - - if (!srt->can_publish()) { - return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "srt stream %s busy", req->get_stream_url().c_str()); - } - } - - if (srt) { - SrsSrtFromRtmpBridge *bridger = new SrsSrtFromRtmpBridge(srt); - if ((err = bridger->initialize(req)) != srs_success) { - srs_freep(bridger); - return srs_error_wrap(err, "bridger init"); - } - - source->set_bridger(bridger); - } - } -#endif - // Check whether RTC stream is busy. #ifdef SRS_RTC SrsRtcSource *rtc = NULL; diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 0f03ac82020..78b1d7054f8 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -815,95 +815,3 @@ srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) return err; } -SrsSrtFromRtmpBridge::SrsSrtFromRtmpBridge(SrsSrtSource* source) - : ISrsLiveSourceBridger(SrsBridgeDestTypeSRT) -{ - srt_source_ = source; - ts_muxer_ = NULL; - offset_ = 0; -} - -SrsSrtFromRtmpBridge::~SrsSrtFromRtmpBridge() -{ - srs_freep(ts_muxer_); -} - -srs_error_t SrsSrtFromRtmpBridge::initialize(SrsRequest* r) -{ - srs_error_t err = srs_success; - - // TODO: FIXME: check config. - req_ = r; - - ts_muxer_ = new SrsTsTransmuxer(); - if ((err = ts_muxer_->initialize(this)) != srs_success) { - return srs_error_wrap(err, "init ts muxer"); - } - - return err; -} - -srs_error_t SrsSrtFromRtmpBridge::on_publish() -{ - srs_error_t err = srs_success; - - // TODO: FIXME: check if enable rtmp_to_srt - - if ((err = srt_source_->on_publish()) != srs_success) { - return srs_error_wrap(err, "source publish"); - } - - return err; -} - -void SrsSrtFromRtmpBridge::on_unpublish() -{ - // TODO: FIXME: check if enable rtmp_to_srt - srt_source_->on_unpublish(); -} - -srs_error_t SrsSrtFromRtmpBridge::on_audio(SrsSharedPtrMessage* msg) -{ - srs_error_t err = srs_success; - - if ((err = ts_muxer_->write_audio(msg->timestamp, msg->payload, msg->size)) != srs_success) { - return srs_error_wrap(err, "rtmp to srt, ts mux audio"); - } - - return err; -} - -srs_error_t SrsSrtFromRtmpBridge::on_video(SrsSharedPtrMessage* msg) -{ - srs_error_t err = srs_success; - - if ((err = ts_muxer_->write_video(msg->timestamp, msg->payload, msg->size)) != srs_success) { - return srs_error_wrap(err, "rtmp to srt, ts mux video"); - } - - return err; -} - -srs_error_t SrsSrtFromRtmpBridge::write(void* buf, size_t size, ssize_t* nwrite) -{ - srs_error_t err = srs_success; - - if (size % SRS_TS_PACKET_SIZE != 0) { - return srs_error_new(ERROR_RTMP_TO_SRT, "invalid ts size=%u", size); - } - - for (int i = 0; i < size; i += SRS_TS_PACKET_SIZE) { - memcpy(ts_buf_ + offset_, (const char*)buf + i, SRS_TS_PACKET_SIZE); - offset_ += SRS_TS_PACKET_SIZE; - if (offset_ >= 1316) { - offset_ = 0; - SrsSrtPacket* packet = new SrsSrtPacket(); - SrsAutoFree(SrsSrtPacket, packet); - packet->wrap(ts_buf_, 1316); - - srt_source_->on_packet(packet); - } - } - - return err; -} diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp index 14c2a55176d..7a4b06b3bf9 100644 --- a/trunk/src/app/srs_app_srt_source.hpp +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -182,29 +182,5 @@ class SrsSrtSource std::vector bridgers_; }; -class SrsSrtFromRtmpBridge : public ISrsLiveSourceBridger, public ISrsStreamWriter -{ -public: - SrsSrtFromRtmpBridge(SrsSrtSource* source); - virtual ~SrsSrtFromRtmpBridge(); -public: - virtual srs_error_t initialize(SrsRequest* r); -// Interface for ISrsLiveSourceBridger -public: - virtual srs_error_t on_publish(); - virtual void on_unpublish(); - virtual srs_error_t on_audio(SrsSharedPtrMessage* msg); - virtual srs_error_t on_video(SrsSharedPtrMessage* msg); -// Interface for ISrsStreamWriter -public: - virtual srs_error_t write(void* buf, size_t size, ssize_t* nwrite); -private: - SrsRequest* req_; - SrsSrtSource* srt_source_; - SrsTsTransmuxer* ts_muxer_; - char ts_buf_[1316]; - int offset_; -}; - #endif From 563cb816c2355c1bc59b7be8f6590cb8e60ec7a0 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 7 Jun 2022 19:44:26 +0800 Subject: [PATCH 23/36] SRT: Rename srs_service_st_srt to srs_protocol_srt --- trunk/configure | 2 +- trunk/src/app/srs_app_srt_conn.cpp | 2 +- trunk/src/app/srs_app_srt_conn.hpp | 2 +- trunk/src/app/srs_app_srt_listener.hpp | 2 +- trunk/src/app/srs_app_srt_server.hpp | 2 +- trunk/src/main/srs_main_server.cpp | 2 +- .../protocol/{srs_service_st_srt.cpp => srs_protocol_srt.cpp} | 2 +- .../protocol/{srs_service_st_srt.hpp => srs_protocol_srt.hpp} | 4 ++-- trunk/src/utest/srs_utest_srt.cpp | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) rename trunk/src/protocol/{srs_service_st_srt.cpp => srs_protocol_srt.cpp} (99%) rename trunk/src/protocol/{srs_service_st_srt.hpp => srs_protocol_srt.hpp} (99%) diff --git a/trunk/configure b/trunk/configure index c28404154fe..eb5fa8b1910 100755 --- a/trunk/configure +++ b/trunk/configure @@ -228,7 +228,7 @@ MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_protocol_format" "srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") if [[ $SRS_SRT == YES ]]; then - MODULE_FILES+=("srs_service_st_srt") + MODULE_FILES+=("srs_protocol_srt") ModuleLibIncs+=(${LibSRTRoot}) fi if [[ $SRS_RTC == YES ]]; then diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 6cf2fe779c8..4b44fba3364 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -13,7 +13,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index 40bf9974335..84a1cf79d7c 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_srt_listener.hpp b/trunk/src/app/srs_app_srt_listener.hpp index 6bd3e2501a3..fe9f9466b72 100644 --- a/trunk/src/app/srs_app_srt_listener.hpp +++ b/trunk/src/app/srs_app_srt_listener.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index 577638acac5..886ac21f97a 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index e02ef786e4c..dd16864d89e 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -44,7 +44,7 @@ using namespace std; #endif #ifdef SRS_SRT -#include +#include #include #endif diff --git a/trunk/src/protocol/srs_service_st_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp similarity index 99% rename from trunk/src/protocol/srs_service_st_srt.cpp rename to trunk/src/protocol/srs_protocol_srt.cpp index 9aed09fddef..76520c3d7fa 100644 --- a/trunk/src/protocol/srs_service_st_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT or MulanPSL-2.0 // -#include +#include #include diff --git a/trunk/src/protocol/srs_service_st_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp similarity index 99% rename from trunk/src/protocol/srs_service_st_srt.hpp rename to trunk/src/protocol/srs_protocol_srt.hpp index c96d0711041..64116892fa7 100644 --- a/trunk/src/protocol/srs_service_st_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: MIT or MulanPSL-2.0 // -#ifndef SRS_SERVICE_ST_SRT_HPP -#define SRS_SERVICE_ST_SRT_HPP +#ifndef SRS_PROTOCOL_SRT_HPP +#define SRS_PROTOCOL_SRT_HPP #include #include diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 3b17debb6c4..1fd5d966d78 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include From 083b8ce2952de9f88cce41cce84f901cdf8f7acd Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 7 Jun 2022 20:24:43 +0800 Subject: [PATCH 24/36] SRT: Wrap SRT stat object. --- trunk/src/app/srs_app_srt_conn.cpp | 24 +++++----- trunk/src/protocol/srs_protocol_srt.cpp | 59 +++++++++++++++++++++++-- trunk/src/protocol/srs_protocol_srt.hpp | 25 +++++++++-- 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 4b44fba3364..a524605f448 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -384,14 +384,12 @@ srs_error_t SrsMpegtsSrtConn::do_publishing() // reportable if (pprint->can_print()) { - SRT_TRACEBSTATS srt_stats; - srs_error_t err_tmp = srs_srt_get_stats(srt_fd_, &srt_stats, true); - if (err_tmp != srs_success) { - srs_freep(err_tmp); + SrsSrtStat s; + if ((err = s.fetch(srt_fd_, true)) != srs_success) { + srs_freep(err); } else { - srs_trace("<- " SRS_CONSTS_LOG_SRT_PUBLISH " Transport Stats # " - "pktRecv=%ld, pktRcvLoss=%d, pktRcvRetrans=%d, pktRcvDrop=%d", - srt_stats.pktRecv, srt_stats.pktRcvLoss, srt_stats.pktRcvRetrans, srt_stats.pktRcvDrop); + srs_trace("<- " SRS_CONSTS_LOG_SRT_PUBLISH " Transport Stats # pktRecv=%" PRId64 ", pktRcvLoss=%d, pktRcvRetrans=%d, pktRcvDrop=%d", + s.pktRecv(), s.pktRcvLoss(), s.pktRcvRetrans(), s.pktRcvDrop()); } kbps_->sample(); @@ -467,14 +465,12 @@ srs_error_t SrsMpegtsSrtConn::do_playing() // reportable if (pprint->can_print()) { - SRT_TRACEBSTATS srt_stats; - srs_error_t err_tmp = srs_srt_get_stats(srt_fd_, &srt_stats, true); - if (err_tmp != srs_success) { - srs_freep(err_tmp); + SrsSrtStat s; + if ((err = s.fetch(srt_fd_, true)) != srs_success) { + srs_freep(err); } else { - srs_trace("-> " SRS_CONSTS_LOG_SRT_PLAY " Transport Stats # " - "pktSent=%ld, pktSndLoss=%d, pktRetrans=%d, pktSndDrop=%d", - srt_stats.pktSent, srt_stats.pktSndLoss, srt_stats.pktRetrans, srt_stats.pktSndDrop); + srs_trace("-> " SRS_CONSTS_LOG_SRT_PLAY " Transport Stats # pktSent=%" PRId64 ", pktSndLoss=%d, pktRetrans=%d, pktSndDrop=%d", + s.pktSent(), s.pktSndLoss(), s.pktRetrans(), s.pktSndDrop()); } kbps_->sample(); diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index 76520c3d7fa..6892a483949 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -376,13 +376,64 @@ srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& p return err; } -srs_error_t srs_srt_get_stats(SRTSOCKET srt_fd, SRT_TRACEBSTATS* srt_stats, bool clear) +SrsSrtStat::SrsSrtStat() +{ + stat_ = new SRT_TRACEBSTATS(); +} + +SrsSrtStat::~SrsSrtStat() +{ + SRT_TRACEBSTATS* p = (SRT_TRACEBSTATS*)stat_; + srs_freep(p); +} + +int64_t SrsSrtStat::pktRecv() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktRecv; +} + +int SrsSrtStat::pktRcvLoss() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktRcvLoss; +} + +int SrsSrtStat::pktRcvRetrans() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktRcvRetrans; +} + +int SrsSrtStat::pktRcvDrop() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktRcvDrop; +} + +int64_t SrsSrtStat::pktSent() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktSent; +} + +int SrsSrtStat::pktSndLoss() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktSndLoss; +} + +int SrsSrtStat::pktRetrans() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktRetrans; +} + +int SrsSrtStat::pktSndDrop() +{ + return ((SRT_TRACEBSTATS*)stat_)->pktSndDrop; +} + +srs_error_t SrsSrtStat::fetch(SRTSOCKET srt_fd, bool clear) { srs_error_t err = srs_success; - int ret = srt_bstats(srt_fd, srt_stats, clear); - if (ret != 0) { - return srs_error_new(ERROR_SRT_STATS, "srt_bstats"); + int r0 = srt_bstats(srt_fd, (SRT_TRACEBSTATS*)stat_, clear); + if (r0) { + return srs_error_new(ERROR_SRT_STATS, "srt_bstats r0=%d", r0); } return err; diff --git a/trunk/src/protocol/srs_protocol_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp index 64116892fa7..4cbb5a7f875 100644 --- a/trunk/src/protocol/srs_protocol_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -15,6 +15,8 @@ #include +class SrsSrtSocket; + // Create srt socket only, with libsrt's default option. extern srs_error_t srs_srt_socket(SRTSOCKET* pfd); @@ -62,9 +64,26 @@ extern srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, extern srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); // Get SRT stats. -extern srs_error_t srs_srt_get_stats(SRTSOCKET srt_fd, SRT_TRACEBSTATS* srt_stats, bool clear); - -class SrsSrtSocket; +class SrsSrtStat +{ +private: + void* stat_; +public: + SrsSrtStat(); + virtual ~SrsSrtStat(); +public: + int64_t pktRecv(); + int pktRcvLoss(); + int pktRcvRetrans(); + int pktRcvDrop(); +public: + int64_t pktSent(); + int pktSndLoss(); + int pktRetrans(); + int pktSndDrop(); +public: + srs_error_t fetch(SRTSOCKET srt_fd, bool clear); +}; // Srt poller, subscribe/unsubscribed events and wait them fired. class SrsSrtPoller From 031ea9672e1cd9268e0332595ef7d6e6d7d6f7ef Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 7 Jun 2022 20:40:31 +0800 Subject: [PATCH 25/36] SRT: Extract ISrsSrtPoller to hide SRT_EPOLL_EVENT --- trunk/src/app/srs_app_srt_server.cpp | 2 +- trunk/src/app/srs_app_srt_server.hpp | 4 +-- trunk/src/protocol/srs_protocol_srt.cpp | 33 ++++++++++++++++++++++++- trunk/src/protocol/srs_protocol_srt.hpp | 26 +++++++++---------- trunk/src/utest/srs_utest_srt.cpp | 2 +- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 0a23fcc610a..38baab9ab78 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -359,7 +359,7 @@ srs_error_t SrsSrtEventLoop::initialize() { srs_error_t err = srs_success; - srt_poller_ = new SrsSrtPoller(); + srt_poller_ = srs_srt_poller_new(); if ((err = srt_poller_->initialize()) != srs_success) { return srs_error_wrap(err, "srt poller initialize"); diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index 886ac21f97a..386806cf8c1 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -111,7 +111,7 @@ class SrsSrtEventLoop : public ISrsCoroutineHandler SrsSrtEventLoop(); virtual ~SrsSrtEventLoop(); public: - SrsSrtPoller* poller() { return srt_poller_; } + ISrsSrtPoller* poller() { return srt_poller_; } public: srs_error_t initialize(); srs_error_t start(); @@ -119,7 +119,7 @@ class SrsSrtEventLoop : public ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: - SrsSrtPoller* srt_poller_; + ISrsSrtPoller* srt_poller_; SrsCoroutine* trd_; }; diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index 6892a483949..0e61aadfcd5 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -439,6 +439,24 @@ srs_error_t SrsSrtStat::fetch(SRTSOCKET srt_fd, bool clear) return err; } +class SrsSrtPoller : public ISrsSrtPoller +{ +public: + SrsSrtPoller(); + virtual ~SrsSrtPoller(); +public: + srs_error_t initialize(); + srs_error_t add_socket(SrsSrtSocket* srt_skt); + srs_error_t mod_socket(SrsSrtSocket* srt_skt); + srs_error_t del_socket(SrsSrtSocket* srt_skt); + srs_error_t wait(int timeout_ms, int* pn_fds); +private: + // Find SrsSrtSocket* context by SRTSOCKET. + std::map fd_sockets_; + int srt_epoller_fd_; + std::vector events_; +}; + SrsSrtPoller::SrsSrtPoller() { srt_epoller_fd_ = -1; @@ -556,7 +574,20 @@ srs_error_t SrsSrtPoller::mod_socket(SrsSrtSocket* srt_skt) return err; } -SrsSrtSocket::SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd) +ISrsSrtPoller::ISrsSrtPoller() +{ +} + +ISrsSrtPoller::~ISrsSrtPoller() +{ +} + +ISrsSrtPoller* srs_srt_poller_new() +{ + return new SrsSrtPoller(); +} + +SrsSrtSocket::SrsSrtSocket(ISrsSrtPoller* srt_poller, SRTSOCKET srt_fd) { srt_poller_ = srt_poller; srt_fd_ = srt_fd; diff --git a/trunk/src/protocol/srs_protocol_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp index 4cbb5a7f875..df2cb309b27 100644 --- a/trunk/src/protocol/srs_protocol_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -86,31 +86,27 @@ class SrsSrtStat }; // Srt poller, subscribe/unsubscribed events and wait them fired. -class SrsSrtPoller +class ISrsSrtPoller { public: - SrsSrtPoller(); - virtual ~SrsSrtPoller(); + ISrsSrtPoller(); + virtual ~ISrsSrtPoller(); public: - srs_error_t initialize(); - srs_error_t add_socket(SrsSrtSocket* srt_skt); - srs_error_t mod_socket(SrsSrtSocket* srt_skt); - srs_error_t del_socket(SrsSrtSocket* srt_skt); + virtual srs_error_t initialize() = 0; + virtual srs_error_t add_socket(SrsSrtSocket* srt_skt) = 0; + virtual srs_error_t mod_socket(SrsSrtSocket* srt_skt) = 0; + virtual srs_error_t del_socket(SrsSrtSocket* srt_skt) = 0; // Wait for the fds in its epoll to be fired in specified timeout_ms, where the pn_fds is the number of active fds. // Note that for ST, please always use timeout_ms(0) and switch coroutine by yourself. - srs_error_t wait(int timeout_ms, int* pn_fds); -private: - // Find SrsSrtSocket* context by SRTSOCKET. - std::map fd_sockets_; - int srt_epoller_fd_; - std::vector events_; + virtual srs_error_t wait(int timeout_ms, int* pn_fds) = 0; }; +ISrsSrtPoller* srs_srt_poller_new(); // Srt ST socket, wrap SRT io and make it adapt to ST-thread. class SrsSrtSocket { public: - SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd); + SrsSrtSocket(ISrsSrtPoller* srt_poller, SRTSOCKET srt_fd); virtual ~SrsSrtSocket(); public: // IO API srs_error_t connect(const std::string& ip, int port); @@ -171,7 +167,7 @@ class SrsSrtSocket // Event of this socket subscribed. int events_; // Srt poller which this socket attach to. - SrsSrtPoller* srt_poller_; + ISrsSrtPoller* srt_poller_; }; #endif diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 1fd5d966d78..bd3dd49a111 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -23,7 +23,7 @@ VOID TEST(ServiceSrtPoller, SrtPollOperateSocket) { srs_error_t err = srs_success; - SrsSrtPoller* srt_poller = new SrsSrtPoller(); + ISrsSrtPoller* srt_poller = srs_srt_poller_new(); HELPER_EXPECT_SUCCESS(srt_poller->initialize()); SRTSOCKET srt_fd = SRT_INVALID_SOCK; From 248ce936e33d4bb0f1db0e476df4e517e3ae9cad Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 7 Jun 2022 21:04:04 +0800 Subject: [PATCH 26/36] SRT: Hide srt implements from API. --- trunk/src/app/srs_app_srt_conn.cpp | 4 +- trunk/src/app/srs_app_srt_conn.hpp | 8 +- trunk/src/app/srs_app_srt_listener.cpp | 7 +- trunk/src/app/srs_app_srt_listener.hpp | 6 +- trunk/src/app/srs_app_srt_server.cpp | 12 +-- trunk/src/app/srs_app_srt_server.hpp | 6 +- trunk/src/protocol/srs_protocol_srt.cpp | 115 ++++++++++++++---------- trunk/src/protocol/srs_protocol_srt.hpp | 82 +++++++++-------- trunk/src/utest/srs_utest_srt.cpp | 44 ++++----- 9 files changed, 157 insertions(+), 127 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index a524605f448..6071918b8a7 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -20,7 +20,7 @@ using namespace std; #include #include -SrsSrtConnection::SrsSrtConnection(SRTSOCKET srt_fd) +SrsSrtConnection::SrsSrtConnection(srs_srt_t srt_fd) { srt_fd_ = srt_fd; srt_skt_ = new SrsSrtSocket(_srt_eventloop->poller(), srt_fd_); @@ -148,7 +148,7 @@ srs_error_t SrsSrtRecvThread::get_recv_err() return srs_error_copy(recv_err_); } -SrsMpegtsSrtConn::SrsMpegtsSrtConn(SrsSrtServer* srt_server, SRTSOCKET srt_fd, std::string ip, int port) +SrsMpegtsSrtConn::SrsMpegtsSrtConn(SrsSrtServer* srt_server, srs_srt_t srt_fd, std::string ip, int port) { // Create a identify for this client. _srs_context->set_id(_srs_context->generate_id()); diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index 84a1cf79d7c..c1d54edf283 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -28,7 +28,7 @@ class SrsSrtServer; class SrsSrtConnection : public ISrsProtocolReadWriter { public: - SrsSrtConnection(SRTSOCKET srt_fd); + SrsSrtConnection(srs_srt_t srt_fd); virtual ~SrsSrtConnection(); public: virtual srs_error_t initialize(); @@ -46,7 +46,7 @@ class SrsSrtConnection : public ISrsProtocolReadWriter virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t* nwrite); private: // The underlayer srt fd handler. - SRTSOCKET srt_fd_; + srs_srt_t srt_fd_; // The underlayer srt socket. SrsSrtSocket* srt_skt_; }; @@ -73,7 +73,7 @@ class SrsSrtRecvThread : public ISrsCoroutineHandler class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHandler { public: - SrsMpegtsSrtConn(SrsSrtServer* srt_server, SRTSOCKET srt_fd, std::string ip, int port); + SrsMpegtsSrtConn(SrsSrtServer* srt_server, srs_srt_t srt_fd, std::string ip, int port); virtual ~SrsMpegtsSrtConn(); // Interface ISrsResource. public: @@ -111,7 +111,7 @@ class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHan void http_hooks_on_stop(); private: SrsSrtServer* srt_server_; - SRTSOCKET srt_fd_; + srs_srt_t srt_fd_; SrsSrtConnection* srt_conn_; SrsWallClock* clock_; SrsKbps* kbps_; diff --git a/trunk/src/app/srs_app_srt_listener.cpp b/trunk/src/app/srs_app_srt_listener.cpp index 5931ca93d5c..4f223957c4f 100644 --- a/trunk/src/app/srs_app_srt_listener.cpp +++ b/trunk/src/app/srs_app_srt_listener.cpp @@ -26,7 +26,7 @@ SrsSrtListener::SrsSrtListener(ISrsSrtHandler* h, std::string i, int p) ip_ = i; port_ = p; - lfd_ = SRT_INVALID_SOCK; + lfd_ = srs_srt_socket_invalid(); srt_skt_ = NULL; trd_ = new SrsDummyCoroutine(); @@ -36,7 +36,8 @@ SrsSrtListener::~SrsSrtListener() { srs_freep(trd_); srs_freep(srt_skt_); - srt_close(lfd_); + // TODO: FIXME: Handle error. + srs_srt_close(lfd_); } int SrsSrtListener::fd() @@ -84,7 +85,7 @@ srs_error_t SrsSrtListener::cycle() return srs_error_wrap(err, "srt listener"); } - SRTSOCKET client_srt_fd = SRT_INVALID_SOCK; + srs_srt_t client_srt_fd = srs_srt_socket_invalid(); if ((err = srt_skt_->accept(&client_srt_fd)) != srs_success) { return srs_error_wrap(err, "srt accept"); } diff --git a/trunk/src/app/srs_app_srt_listener.hpp b/trunk/src/app/srs_app_srt_listener.hpp index fe9f9466b72..86a3a7ae059 100644 --- a/trunk/src/app/srs_app_srt_listener.hpp +++ b/trunk/src/app/srs_app_srt_listener.hpp @@ -21,14 +21,14 @@ class ISrsSrtHandler virtual ~ISrsSrtHandler(); public: // When got srt client. - virtual srs_error_t on_srt_client(SRTSOCKET srt_fd) = 0; + virtual srs_error_t on_srt_client(srs_srt_t srt_fd) = 0; }; // Bind and listen SRT(udp) port, use handler to process the client. class SrsSrtListener : public ISrsCoroutineHandler { private: - SRTSOCKET lfd_; + srs_srt_t lfd_; SrsSrtSocket* srt_skt_; SrsCoroutine* trd_; private: @@ -39,7 +39,7 @@ class SrsSrtListener : public ISrsCoroutineHandler SrsSrtListener(ISrsSrtHandler* h, std::string i, int p); virtual ~SrsSrtListener(); public: - virtual SRTSOCKET fd(); + virtual srs_srt_t fd(); public: // Create srt socket, separate this step because of srt have some option must set before listen. virtual srs_error_t create_socket(); diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 38baab9ab78..b8443d8e664 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -141,7 +141,7 @@ srs_error_t SrsSrtMessageAcceptor::set_srt_opt() return err; } -srs_error_t SrsSrtMessageAcceptor::on_srt_client(SRTSOCKET srt_fd) +srs_error_t SrsSrtMessageAcceptor::on_srt_client(srs_srt_t srt_fd) { // Notify srt server to accept srt client, and create new SrsSrtConn on it. srs_error_t err = srt_server_->accept_srt_client(type_, srt_fd); @@ -226,7 +226,7 @@ void SrsSrtServer::close_listeners(SrsSrtListenerType type) } } -srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, SRTSOCKET srt_fd) +srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, srs_srt_t srt_fd) { srs_error_t err = srs_success; @@ -234,7 +234,8 @@ srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, SRTSOCKET s if ((err = fd_to_resource(type, srt_fd, &conn)) != srs_success) { //close fd on conn error, otherwise will lead to fd leak -gs - srt_close(srt_fd); + // TODO: FIXME: Handle error. + srs_srt_close(srt_fd); return srs_error_wrap(err, "srt fd to resource"); } srs_assert(conn); @@ -249,7 +250,7 @@ srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, SRTSOCKET s return err; } -srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, SRTSOCKET srt_fd, ISrsStartableConneciton** pr) +srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, srs_srt_t srt_fd, ISrsStartableConneciton** pr) { srs_error_t err = srs_success; @@ -271,7 +272,8 @@ srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, SRTSOCKET srt_ *pr = new SrsMpegtsSrtConn(this, srt_fd, ip, port); } else { srs_warn("close for no service handler. srtfd=%d, ip=%s:%d", srt_fd, ip.c_str(), port); - srt_close(srt_fd); + // TODO: FIXME: Handle error. + srs_srt_close(srt_fd); return err; } diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index 386806cf8c1..11d56a5f7aa 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -50,7 +50,7 @@ class SrsSrtMessageAcceptor : public SrsSrtAcceptor, public ISrsSrtHandler virtual srs_error_t set_srt_opt(); // Interface ISrsSrtHandler public: - virtual srs_error_t on_srt_client(SRTSOCKET srt_fd); + virtual srs_error_t on_srt_client(srs_srt_t srt_fd); }; // SRS SRT server, initialize and listen, start connection service thread, destroy client. @@ -78,9 +78,9 @@ class SrsSrtServer : public ISrsResourceManager // @param type, the client type, used to create concrete connection, // for instance SRT connection to serve client. // @param srt_fd, the client fd in srt boxed, the underlayer fd. - virtual srs_error_t accept_srt_client(SrsSrtListenerType type, SRTSOCKET srt_fd); + virtual srs_error_t accept_srt_client(SrsSrtListenerType type, srs_srt_t srt_fd); private: - virtual srs_error_t fd_to_resource(SrsSrtListenerType type, SRTSOCKET srt_fd, ISrsStartableConneciton** pr); + virtual srs_error_t fd_to_resource(SrsSrtListenerType type, srs_srt_t srt_fd, ISrsStartableConneciton** pr); // Interface ISrsResourceManager public: // A callback for connection to remove itself. diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index 0e61aadfcd5..53b77c2c999 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -14,6 +14,8 @@ using namespace std; #include #include +#include + #define SET_SRT_OPT_STR(srtfd, optname, buf, size) \ if (srt_setsockflag(srtfd, optname, buf, size) == SRT_ERROR) { \ std::stringstream ss; \ @@ -41,7 +43,7 @@ using namespace std; } \ } while (0) -static srs_error_t do_srs_srt_listen(SRTSOCKET srt_fd, addrinfo* r) +static srs_error_t do_srs_srt_listen(srs_srt_t srt_fd, addrinfo* r) { srs_error_t err = srs_success; @@ -60,7 +62,7 @@ static srs_error_t do_srs_srt_listen(SRTSOCKET srt_fd, addrinfo* r) return err; } -static srs_error_t do_srs_srt_get_streamid(SRTSOCKET srt_fd, string& streamid) +static srs_error_t do_srs_srt_get_streamid(srs_srt_t srt_fd, string& streamid) { // SRT max streamid length is 512. char sid[512]; @@ -70,11 +72,16 @@ static srs_error_t do_srs_srt_get_streamid(SRTSOCKET srt_fd, string& streamid) return srs_success; } -srs_error_t srs_srt_socket(SRTSOCKET* pfd) +srs_srt_t srs_srt_socket_invalid() +{ + return SRT_INVALID_SOCK; +} + +srs_error_t srs_srt_socket(srs_srt_t* pfd) { srs_error_t err = srs_success; - SRTSOCKET srt_fd = 0; + srs_srt_t srt_fd = 0; if ((srt_fd = srt_create_socket()) < 0) { return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket"); } @@ -84,11 +91,18 @@ srs_error_t srs_srt_socket(SRTSOCKET* pfd) return err; } -srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd) +srs_error_t srs_srt_close(srs_srt_t fd) +{ + // TODO: FIXME: Handle error. + srt_close(fd); + return srs_success; +} + +srs_error_t srs_srt_socket_with_default_option(srs_srt_t* pfd) { srs_error_t err = srs_success; - SRTSOCKET srt_fd = 0; + srs_srt_t srt_fd = 0; if ((srt_fd = srt_create_socket()) < 0) { return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket"); } @@ -114,7 +128,7 @@ srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd) return err; } -srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port) +srs_error_t srs_srt_listen(srs_srt_t srt_fd, std::string ip, int port) { srs_error_t err = srs_success; @@ -142,7 +156,7 @@ srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port) return err; } -srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd) +srs_error_t srs_srt_nonblock(srs_srt_t srt_fd) { int sync = 0; SET_SRT_OPT(srt_fd, SRTO_SNDSYN, sync); @@ -151,157 +165,157 @@ srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd) return srs_success; } -srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw) +srs_error_t srs_srt_set_maxbw(srs_srt_t srt_fd, int maxbw) { SET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw); return srs_success; } -srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss) +srs_error_t srs_srt_set_mss(srs_srt_t srt_fd, int mss) { SET_SRT_OPT(srt_fd, SRTO_MSS, mss); return srs_success; } -srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size) +srs_error_t srs_srt_set_payload_size(srs_srt_t srt_fd, int payload_size) { SET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size); return srs_success; } -srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout) +srs_error_t srs_srt_set_connect_timeout(srs_srt_t srt_fd, int timeout) { SET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout); return srs_success; } -srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout) +srs_error_t srs_srt_set_peer_idle_timeout(srs_srt_t srt_fd, int timeout) { SET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout); return srs_success; } -srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode) +srs_error_t srs_srt_set_tsbpdmode(srs_srt_t srt_fd, bool tsbpdmode) { SET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode); return srs_success; } -srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf) +srs_error_t srs_srt_set_sndbuf(srs_srt_t srt_fd, int sndbuf) { SET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf); return srs_success; } -srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf) +srs_error_t srs_srt_set_rcvbuf(srs_srt_t srt_fd, int rcvbuf) { SET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf); return srs_success; } -srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop) +srs_error_t srs_srt_set_tlpktdrop(srs_srt_t srt_fd, bool tlpktdrop) { SET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop); return srs_success; } -srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency) +srs_error_t srs_srt_set_latency(srs_srt_t srt_fd, int latency) { SET_SRT_OPT(srt_fd, SRTO_LATENCY, latency); return srs_success; } -srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency) +srs_error_t srs_srt_set_rcv_latency(srs_srt_t srt_fd, int rcv_latency) { SET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency); return srs_success; } -srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency) +srs_error_t srs_srt_set_peer_latency(srs_srt_t srt_fd, int peer_latency) { SET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency); return srs_success; } -srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid) +srs_error_t srs_srt_set_streamid(srs_srt_t srt_fd, const std::string& streamid) { SET_SRT_OPT_STR(srt_fd, SRTO_STREAMID, streamid.data(), streamid.size()); return srs_success; } -srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw) +srs_error_t srs_srt_get_maxbw(srs_srt_t srt_fd, int& maxbw) { GET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw); return srs_success; } -srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss) +srs_error_t srs_srt_get_mss(srs_srt_t srt_fd, int& mss) { GET_SRT_OPT(srt_fd, SRTO_MSS, mss); return srs_success; } -srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size) +srs_error_t srs_srt_get_payload_size(srs_srt_t srt_fd, int& payload_size) { GET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size); return srs_success; } -srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout) +srs_error_t srs_srt_get_connect_timeout(srs_srt_t srt_fd, int& timeout) { GET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout); return srs_success; } -srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout) +srs_error_t srs_srt_get_peer_idle_timeout(srs_srt_t srt_fd, int& timeout) { GET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout); return srs_success; } -srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode) +srs_error_t srs_srt_get_tsbpdmode(srs_srt_t srt_fd, bool& tsbpdmode) { GET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode); return srs_success; } -srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf) +srs_error_t srs_srt_get_sndbuf(srs_srt_t srt_fd, int& sndbuf) { GET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf); return srs_success; } -srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf) +srs_error_t srs_srt_get_rcvbuf(srs_srt_t srt_fd, int& rcvbuf) { GET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf); return srs_success; } -srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop) +srs_error_t srs_srt_get_tlpktdrop(srs_srt_t srt_fd, bool& tlpktdrop) { GET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop); return srs_success; } -srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency) +srs_error_t srs_srt_get_latency(srs_srt_t srt_fd, int& latency) { GET_SRT_OPT(srt_fd, SRTO_LATENCY, latency); return srs_success; } -srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency) +srs_error_t srs_srt_get_rcv_latency(srs_srt_t srt_fd, int& rcv_latency) { GET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency); return srs_success; } -srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency) +srs_error_t srs_srt_get_peer_latency(srs_srt_t srt_fd, int& peer_latency) { GET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency); return srs_success; } -srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid) +srs_error_t srs_srt_get_streamid(srs_srt_t srt_fd, std::string& streamid) { srs_error_t err = srs_success; @@ -312,7 +326,7 @@ srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid) return err; } -srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port) +srs_error_t srs_srt_get_local_ip_port(srs_srt_t srt_fd, std::string& ip, int& port) { srs_error_t err = srs_success; @@ -344,7 +358,7 @@ srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& po return err; } -srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port) +srs_error_t srs_srt_get_remote_ip_port(srs_srt_t srt_fd, std::string& ip, int& port) { srs_error_t err = srs_success; @@ -427,7 +441,7 @@ int SrsSrtStat::pktSndDrop() return ((SRT_TRACEBSTATS*)stat_)->pktSndDrop; } -srs_error_t SrsSrtStat::fetch(SRTSOCKET srt_fd, bool clear) +srs_error_t SrsSrtStat::fetch(srs_srt_t srt_fd, bool clear) { srs_error_t err = srs_success; @@ -450,9 +464,11 @@ class SrsSrtPoller : public ISrsSrtPoller srs_error_t mod_socket(SrsSrtSocket* srt_skt); srs_error_t del_socket(SrsSrtSocket* srt_skt); srs_error_t wait(int timeout_ms, int* pn_fds); +public: + virtual int size(); private: - // Find SrsSrtSocket* context by SRTSOCKET. - std::map fd_sockets_; + // Find SrsSrtSocket* context by srs_srt_t. + std::map fd_sockets_; int srt_epoller_fd_; std::vector events_; }; @@ -487,7 +503,7 @@ srs_error_t SrsSrtPoller::add_socket(SrsSrtSocket* srt_skt) srs_error_t err = srs_success; int events = srt_skt->events(); - SRTSOCKET srtfd = srt_skt->fd(); + srs_srt_t srtfd = srt_skt->fd(); int ret = srt_epoll_add_usock(srt_epoller_fd_, srtfd, &events); @@ -506,7 +522,7 @@ srs_error_t SrsSrtPoller::del_socket(SrsSrtSocket* srt_skt) { srs_error_t err = srs_success; - SRTSOCKET srtfd = srt_skt->fd(); + srs_srt_t srtfd = srt_skt->fd(); int ret = srt_epoll_remove_usock(srt_epoller_fd_, srtfd); srs_info("srt poller %d remove srt socket %d", srt_epoller_fd_, srtfd); @@ -533,7 +549,7 @@ srs_error_t SrsSrtPoller::wait(int timeout_ms, int* pn_fds) for (int i = 0; i < ret; ++i) { SRT_EPOLL_EVENT event = events_[i]; - map::iterator iter = fd_sockets_.find(event.fd); + map::iterator iter = fd_sockets_.find(event.fd); if (iter == fd_sockets_.end()) { srs_assert(false); } @@ -557,12 +573,17 @@ srs_error_t SrsSrtPoller::wait(int timeout_ms, int* pn_fds) return err; } +int SrsSrtPoller::size() +{ + return (int)fd_sockets_.size(); +} + srs_error_t SrsSrtPoller::mod_socket(SrsSrtSocket* srt_skt) { srs_error_t err = srs_success; int events = srt_skt->events(); - SRTSOCKET srtfd = srt_skt->fd(); + srs_srt_t srtfd = srt_skt->fd(); int ret = srt_epoll_update_usock(srt_epoller_fd_, srtfd, &events); srs_info("srt poller %d update srt socket %d, events=%d", srt_epoller_fd_, srtfd, events); @@ -587,7 +608,7 @@ ISrsSrtPoller* srs_srt_poller_new() return new SrsSrtPoller(); } -SrsSrtSocket::SrsSrtSocket(ISrsSrtPoller* srt_poller, SRTSOCKET srt_fd) +SrsSrtSocket::SrsSrtSocket(ISrsSrtPoller* srt_poller, srs_srt_t srt_fd) { srt_poller_ = srt_poller; srt_fd_ = srt_fd; @@ -657,7 +678,7 @@ srs_error_t SrsSrtSocket::connect(const string& ip, int port) return err; } -srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd) +srs_error_t SrsSrtSocket::accept(srs_srt_t* client_srt_fd) { srs_error_t err = srs_success; @@ -665,10 +686,10 @@ srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd) sockaddr_in inaddr; int addrlen = sizeof(inaddr); // @see https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_accept - SRTSOCKET srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen); + srs_srt_t srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen); // Accept ok, return with the SRT client fd. - if (srt_fd != SRT_INVALID_SOCK) { + if (srt_fd != srs_srt_socket_invalid()) { *client_srt_fd = srt_fd; return err; } diff --git a/trunk/src/protocol/srs_protocol_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp index df2cb309b27..a2f4189fef3 100644 --- a/trunk/src/protocol/srs_protocol_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -13,55 +13,57 @@ #include #include -#include - class SrsSrtSocket; +typedef int srs_srt_t; +extern srs_srt_t srs_srt_socket_invalid(); + // Create srt socket only, with libsrt's default option. -extern srs_error_t srs_srt_socket(SRTSOCKET* pfd); +extern srs_error_t srs_srt_socket(srs_srt_t* pfd); +extern srs_error_t srs_srt_close(srs_srt_t fd); // Create srt socket with srs recommend default option(tsbpdmode=false,tlpktdrop=false,latency=0,sndsyn=0,rcvsyn=0) -extern srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd); +extern srs_error_t srs_srt_socket_with_default_option(srs_srt_t* pfd); // For server, listen at SRT endpoint. -extern srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port); +extern srs_error_t srs_srt_listen(srs_srt_t srt_fd, std::string ip, int port); // Set read/write no block. -extern srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd); +extern srs_error_t srs_srt_nonblock(srs_srt_t srt_fd); // Set SRT options. -extern srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw); -extern srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss); -extern srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size); -extern srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout); -extern srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout); -extern srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode); -extern srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf); -extern srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf); -extern srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop); -extern srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency); -extern srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency); -extern srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency); -extern srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid); +extern srs_error_t srs_srt_set_maxbw(srs_srt_t srt_fd, int maxbw); +extern srs_error_t srs_srt_set_mss(srs_srt_t srt_fd, int mss); +extern srs_error_t srs_srt_set_payload_size(srs_srt_t srt_fd, int payload_size); +extern srs_error_t srs_srt_set_connect_timeout(srs_srt_t srt_fd, int timeout); +extern srs_error_t srs_srt_set_peer_idle_timeout(srs_srt_t srt_fd, int timeout); +extern srs_error_t srs_srt_set_tsbpdmode(srs_srt_t srt_fd, bool tsbpdmode); +extern srs_error_t srs_srt_set_sndbuf(srs_srt_t srt_fd, int sndbuf); +extern srs_error_t srs_srt_set_rcvbuf(srs_srt_t srt_fd, int rcvbuf); +extern srs_error_t srs_srt_set_tlpktdrop(srs_srt_t srt_fd, bool tlpktdrop); +extern srs_error_t srs_srt_set_latency(srs_srt_t srt_fd, int latency); +extern srs_error_t srs_srt_set_rcv_latency(srs_srt_t srt_fd, int rcv_latency); +extern srs_error_t srs_srt_set_peer_latency(srs_srt_t srt_fd, int peer_latency); +extern srs_error_t srs_srt_set_streamid(srs_srt_t srt_fd, const std::string& streamid); // Get SRT options. -extern srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw); -extern srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss); -extern srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size); -extern srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout); -extern srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout); -extern srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode); -extern srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf); -extern srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf); -extern srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop); -extern srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency); -extern srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency); -extern srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency); -extern srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid); +extern srs_error_t srs_srt_get_maxbw(srs_srt_t srt_fd, int& maxbw); +extern srs_error_t srs_srt_get_mss(srs_srt_t srt_fd, int& mss); +extern srs_error_t srs_srt_get_payload_size(srs_srt_t srt_fd, int& payload_size); +extern srs_error_t srs_srt_get_connect_timeout(srs_srt_t srt_fd, int& timeout); +extern srs_error_t srs_srt_get_peer_idle_timeout(srs_srt_t srt_fd, int& timeout); +extern srs_error_t srs_srt_get_tsbpdmode(srs_srt_t srt_fd, bool& tsbpdmode); +extern srs_error_t srs_srt_get_sndbuf(srs_srt_t srt_fd, int& sndbuf); +extern srs_error_t srs_srt_get_rcvbuf(srs_srt_t srt_fd, int& rcvbuf); +extern srs_error_t srs_srt_get_tlpktdrop(srs_srt_t srt_fd, bool& tlpktdrop); +extern srs_error_t srs_srt_get_latency(srs_srt_t srt_fd, int& latency); +extern srs_error_t srs_srt_get_rcv_latency(srs_srt_t srt_fd, int& rcv_latency); +extern srs_error_t srs_srt_get_peer_latency(srs_srt_t srt_fd, int& peer_latency); +extern srs_error_t srs_srt_get_streamid(srs_srt_t srt_fd, std::string& streamid); // Get SRT socket info. -extern srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); -extern srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port); +extern srs_error_t srs_srt_get_local_ip_port(srs_srt_t srt_fd, std::string& ip, int& port); +extern srs_error_t srs_srt_get_remote_ip_port(srs_srt_t srt_fd, std::string& ip, int& port); // Get SRT stats. class SrsSrtStat @@ -82,7 +84,7 @@ class SrsSrtStat int pktRetrans(); int pktSndDrop(); public: - srs_error_t fetch(SRTSOCKET srt_fd, bool clear); + srs_error_t fetch(srs_srt_t srt_fd, bool clear); }; // Srt poller, subscribe/unsubscribed events and wait them fired. @@ -99,6 +101,8 @@ class ISrsSrtPoller // Wait for the fds in its epoll to be fired in specified timeout_ms, where the pn_fds is the number of active fds. // Note that for ST, please always use timeout_ms(0) and switch coroutine by yourself. virtual srs_error_t wait(int timeout_ms, int* pn_fds) = 0; +public: + virtual int size() = 0; }; ISrsSrtPoller* srs_srt_poller_new(); @@ -106,15 +110,15 @@ ISrsSrtPoller* srs_srt_poller_new(); class SrsSrtSocket { public: - SrsSrtSocket(ISrsSrtPoller* srt_poller, SRTSOCKET srt_fd); + SrsSrtSocket(ISrsSrtPoller* srt_poller, srs_srt_t srt_fd); virtual ~SrsSrtSocket(); public: // IO API srs_error_t connect(const std::string& ip, int port); - srs_error_t accept(SRTSOCKET* client_srt_fd); + srs_error_t accept(srs_srt_t* client_srt_fd); srs_error_t recvmsg(void* buf, size_t size, ssize_t* nread); srs_error_t sendmsg(void* buf, size_t size, ssize_t* nwrite); public: - SRTSOCKET fd() const { return srt_fd_; } + srs_srt_t fd() const { return srt_fd_; } int events() const { return events_; } public: void set_recv_timeout(srs_utime_t tm) { recv_timeout_ = tm; } @@ -148,7 +152,7 @@ class SrsSrtSocket srs_error_t check_error(); private: - SRTSOCKET srt_fd_; + srs_srt_t srt_fd_; // Mark if some error occured in srt socket. bool has_error_; // When read operator like recvmsg/accept would block, wait this condition timeout or notified, diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index bd3dd49a111..f01cfd76381 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -16,6 +16,8 @@ #include using namespace std; +#include + extern SrsSrtEventLoop* _srt_eventloop; // Test srt st service @@ -26,7 +28,7 @@ VOID TEST(ServiceSrtPoller, SrtPollOperateSocket) ISrsSrtPoller* srt_poller = srs_srt_poller_new(); HELPER_EXPECT_SUCCESS(srt_poller->initialize()); - SRTSOCKET srt_fd = SRT_INVALID_SOCK; + srs_srt_t srt_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_fd)); EXPECT_TRUE(srt_fd > 0); @@ -53,10 +55,10 @@ VOID TEST(ServiceSrtPoller, SrtPollOperateSocket) EXPECT_FALSE(srt_socket->events() & SRT_EPOLL_OUT); EXPECT_TRUE(srt_socket->events() & SRT_EPOLL_ERR); - EXPECT_EQ(srt_poller->fd_sockets_.size(), 1); + EXPECT_EQ(srt_poller->size(), 1); // Delete socket, will remove in srt poller. srs_freep(srt_socket); - EXPECT_EQ(srt_poller->fd_sockets_.size(), 0); + EXPECT_EQ(srt_poller->size(), 0); srs_freep(srt_poller); } @@ -65,7 +67,7 @@ VOID TEST(ServiceSrtPoller, SrtSetGetSocketOpt) { srs_error_t err = srs_success; - SRTSOCKET srt_fd = SRT_INVALID_SOCK; + srs_srt_t srt_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_fd)); HELPER_EXPECT_SUCCESS(srs_srt_nonblock(srt_fd)); @@ -129,10 +131,10 @@ class MockSrtServer { public: SrsSrtSocket* srt_socket_; - SRTSOCKET srt_server_fd_; + srs_srt_t srt_server_fd_; MockSrtServer() { - srt_server_fd_ = SRT_INVALID_SOCK; + srt_server_fd_ = srs_srt_socket_invalid(); srt_socket_ = NULL; } @@ -160,7 +162,7 @@ class MockSrtServer srs_freep(srt_socket_); } - virtual srs_error_t accept(SRTSOCKET* client_fd) { + virtual srs_error_t accept(srs_srt_t* client_fd) { srs_error_t err = srs_success; if ((err = srt_socket_->accept(client_fd)) != srs_success) { @@ -182,32 +184,32 @@ VOID TEST(ServiceStSRTTest, ListenConnectAccept) HELPER_EXPECT_SUCCESS(srt_server.create_socket()); HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); - SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket(&srt_client_fd)); SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); // No client connected, accept will timeout. - SRTSOCKET srt_fd = SRT_INVALID_SOCK; + srs_srt_t srt_fd = srs_srt_socket_invalid(); // Make utest fast timeout. srt_server.srt_socket_->set_recv_timeout(50 * SRS_UTIME_MILLISECONDS); err = srt_server.accept(&srt_fd); EXPECT_EQ(srs_error_code(err), ERROR_SRT_TIMEOUT); - EXPECT_EQ(srt_fd, SRT_INVALID_SOCK); + EXPECT_EQ(srt_fd, srs_srt_socket_invalid()); // Client connect to server HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); // Server will accept one client. HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_fd)); - EXPECT_NE(srt_fd, SRT_INVALID_SOCK); + EXPECT_NE(srt_fd, srs_srt_socket_invalid()); } VOID TEST(ServiceStSRTTest, ConnectTimeout) { srs_error_t err = srs_success; - SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); @@ -228,16 +230,16 @@ VOID TEST(ServiceStSRTTest, ConnectWithStreamid) HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); std::string streamid = "SRS_SRT_Streamid"; - SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); HELPER_EXPECT_SUCCESS(srt_client_socket->connect("127.0.0.1", 9000)); - SRTSOCKET srt_server_accepted_fd = SRT_INVALID_SOCK; + srs_srt_t srt_server_accepted_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); - EXPECT_NE(srt_server_accepted_fd, SRT_INVALID_SOCK); + EXPECT_NE(srt_server_accepted_fd, srs_srt_socket_invalid()); std::string s; HELPER_EXPECT_SUCCESS(srs_srt_get_streamid(srt_server_accepted_fd, s)); EXPECT_EQ(s, streamid); @@ -254,7 +256,7 @@ VOID TEST(ServiceStSRTTest, ReadWrite) HELPER_EXPECT_SUCCESS(srt_server.create_socket()); HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); - SRTSOCKET srt_client_fd = SRT_INVALID_SOCK; + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); @@ -262,9 +264,9 @@ VOID TEST(ServiceStSRTTest, ReadWrite) HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); // Server will accept one client. - SRTSOCKET srt_server_accepted_fd = SRT_INVALID_SOCK; + srs_srt_t srt_server_accepted_fd = srs_srt_socket_invalid(); HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); - EXPECT_NE(srt_server_accepted_fd, SRT_INVALID_SOCK); + EXPECT_NE(srt_server_accepted_fd, srs_srt_socket_invalid()); SrsSrtSocket* srt_server_accepted_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_server_accepted_fd); if (true) { @@ -307,15 +309,15 @@ VOID TEST(ServiceStSRTTest, ReadWrite) class MockSrtHandler : public ISrsSrtHandler { private: - SRTSOCKET srt_fd; + srs_srt_t srt_fd; public: MockSrtHandler() { - srt_fd = SRT_INVALID_SOCK; + srt_fd = srs_srt_socket_invalid(); } virtual ~MockSrtHandler() { } public: - virtual srs_error_t on_srt_client(SRTSOCKET fd) { + virtual srs_error_t on_srt_client(srs_srt_t fd) { srt_fd = fd; return srs_success; } From 99a6d722dcbc28716865b5740e21ec151a30b0eb Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 8 Jun 2022 20:03:39 +0800 Subject: [PATCH 27/36] SRT: Undo extract of fetch_or_create_source and change mode_ to local. --- trunk/src/app/srs_app_srt_conn.cpp | 41 +++++++++++------------------- trunk/src/app/srs_app_srt_conn.hpp | 2 -- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 6071918b8a7..8c024978f9c 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -167,7 +167,6 @@ SrsMpegtsSrtConn::SrsMpegtsSrtConn(SrsSrtServer* srt_server, srs_srt_t srt_fd, s srt_source_ = NULL; req_ = new SrsRequest(); - mode_ = SrtModePull; } SrsMpegtsSrtConn::~SrsMpegtsSrtConn() @@ -239,29 +238,6 @@ srs_error_t SrsMpegtsSrtConn::do_cycle() { srs_error_t err = srs_success; - if ((err = fetch_or_create_source()) != srs_success) { - return srs_error_wrap(err, "fetch or create srt source"); - } - - if ((err = http_hooks_on_connect()) != srs_success) { - return srs_error_wrap(err, "on connect"); - } - - if (mode_ == SrtModePush) { - err = publishing(); - } else if (mode_ == SrtModePull) { - err = playing(); - } - - http_hooks_on_close(); - - return err; -} - -srs_error_t SrsMpegtsSrtConn::fetch_or_create_source() -{ - srs_error_t err = srs_success; - string streamid = ""; if ((err = srs_srt_get_streamid(srt_fd_, streamid)) != srs_success) { return srs_error_wrap(err, "get srt streamid"); @@ -273,7 +249,8 @@ srs_error_t SrsMpegtsSrtConn::fetch_or_create_source() } // Detect streamid of srt to request. - if (! srs_srt_streamid_to_request(streamid, mode_, req_)) { + SrtMode mode = SrtModePull; + if (! srs_srt_streamid_to_request(streamid, mode, req_)) { return srs_error_new(ERROR_SRT_CONN, "invalid srt streamid=%s", streamid.c_str()); } @@ -282,12 +259,24 @@ srs_error_t SrsMpegtsSrtConn::fetch_or_create_source() } srs_trace("@srt, streamid=%s, stream_url=%s, vhost=%s, app=%s, stream=%s, param=%s", - streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); + streamid.c_str(), req_->get_stream_url().c_str(), req_->vhost.c_str(), req_->app.c_str(), req_->stream.c_str(), req_->param.c_str()); if ((err = _srs_srt_sources->fetch_or_create(req_, &srt_source_)) != srs_success) { return srs_error_wrap(err, "fetch srt source"); } + if ((err = http_hooks_on_connect()) != srs_success) { + return srs_error_wrap(err, "on connect"); + } + + if (mode == SrtModePush) { + err = publishing(); + } else if (mode == SrtModePull) { + err = playing(); + } + + http_hooks_on_close(); + return err; } diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index c1d54edf283..76eaa53b08e 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -93,7 +93,6 @@ class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHan protected: virtual srs_error_t do_cycle(); private: - srs_error_t fetch_or_create_source(); srs_error_t publishing(); srs_error_t playing(); srs_error_t acquire_publish(); @@ -120,7 +119,6 @@ class SrsMpegtsSrtConn : public ISrsStartableConneciton, public ISrsCoroutineHan SrsCoroutine* trd_; SrsRequest* req_; - SrtMode mode_; SrsSrtSource* srt_source_; }; From b2b60873067ef10297b6452bd41ea00cfaee535c Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 8 Jun 2022 20:38:07 +0800 Subject: [PATCH 28/36] SRT: Refine packet error handler. --- trunk/src/app/srs_app_srt_conn.cpp | 19 ++++++++++++++----- trunk/src/app/srs_app_srt_source.cpp | 3 ++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 8c024978f9c..144410ad90f 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -312,6 +312,7 @@ srs_error_t SrsMpegtsSrtConn::playing() return err; } +// TODO: FIXME: It's not atomic and has risk between multiple source checking. srs_error_t SrsMpegtsSrtConn::acquire_publish() { srs_error_t err = srs_success; @@ -370,8 +371,6 @@ srs_error_t SrsMpegtsSrtConn::do_publishing() } pprint->elapse(); - - // reportable if (pprint->can_print()) { SrsSrtStat s; if ((err = s.fetch(srt_fd_, true)) != srs_success) { @@ -485,9 +484,19 @@ srs_error_t SrsMpegtsSrtConn::on_srt_packet(char* buf, int nb_buf) { srs_error_t err = srs_success; - // Check srt payload, mpegts must be N times of SRS_TS_PACKET_SIZE, and the first byte must be 0x47 - if ((nb_buf <= 0) || (nb_buf % SRS_TS_PACKET_SIZE != 0) || (buf[0] != 0x47)) { - return srs_error_new(ERROR_SRT_CONN, "invalid ts packet"); + // Ignore if invalid length. + if (nb_buf <= 0) { + return err; + } + + // Check srt payload, mpegts must be N times of SRS_TS_PACKET_SIZE + if ((nb_buf % SRS_TS_PACKET_SIZE) != 0) { + return srs_error_new(ERROR_SRT_CONN, "invalid ts packet len=%d", nb_buf); + } + + // Check srt payload, the first byte must be 0x47 + if (buf[0] != 0x47) { + return srs_error_new(ERROR_SRT_CONN, "invalid ts packet first=%#x", (uint8_t)buf[0]); } SrsSrtPacket* packet = new SrsSrtPacket(); diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 78b1d7054f8..4d4f68a31ad 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -287,7 +287,8 @@ srs_error_t SrsRtmpFromSrtBridge::on_packet(SrsSrtPacket *pkt) SrsBuffer* stream = new SrsBuffer(p, SRS_TS_PACKET_SIZE); SrsAutoFree(SrsBuffer, stream); - // process each ts packet + // Process each ts packet. Note that the jitter of UDP may cause video glitch when packet loss or wrong seq. We + // don't handle it because SRT will, see tlpkdrop at https://github.com/ossrs/srs/wiki/v5_EN_SRTParams if ((err = ts_ctx_->decode(stream, this)) != srs_success) { srs_warn("parse ts packet err=%s", srs_error_desc(err).c_str()); srs_error_reset(err); From a89c725ec0d1629d03b698ad9da877625bb13f29 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 9 Jun 2022 19:28:08 +0800 Subject: [PATCH 29/36] SRT: Add todo for coroutine yield. --- trunk/src/app/srs_app_srt_conn.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 144410ad90f..70d3c722e34 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -412,7 +412,6 @@ srs_error_t SrsMpegtsSrtConn::do_playing() if ((err = srt_source_->create_consumer(consumer)) != srs_success) { return srs_error_wrap(err, "create consumer, ts source=%s", req_->get_stream_url().c_str()); } - srs_assert(consumer); // TODO: FIXME: Dumps the SPS/PPS from gop cache, without other frames. @@ -439,8 +438,6 @@ srs_error_t SrsMpegtsSrtConn::do_playing() return srs_error_wrap(err, "srt play recv thread"); } - pprint->elapse(); - // Wait for amount of packets. SrsSrtPacket* pkt = NULL; SrsAutoFree(SrsSrtPacket, pkt); @@ -451,7 +448,10 @@ srs_error_t SrsMpegtsSrtConn::do_playing() continue; } + ++nb_packets; + // reportable + pprint->elapse(); if (pprint->can_print()) { SrsSrtStat s; if ((err = s.fetch(srt_fd_, true)) != srs_success) { @@ -468,13 +468,15 @@ srs_error_t SrsMpegtsSrtConn::do_playing() kbps_->get_recv_kbps(), kbps_->get_recv_kbps_30s(), kbps_->get_recv_kbps_5m()); nb_packets = 0; } - - ++nb_packets; ssize_t nb_write = 0; if ((err = srt_conn_->write(pkt->data(), pkt->size(), &nb_write)) != srs_success) { return srs_error_wrap(err, "srt send, size=%d", pkt->size()); } + + // Yield to another coroutines. + // @see https://github.com/ossrs/srs/issues/2194#issuecomment-777542162 + // TODO: FIXME: Please check whether SRT sendmsg causing clock deviation, see srs_thread_yield of SrsUdpMuxSocket::sendto } return err; From 93d0cfbe2dd3c9861349509b502af733e8103ec4 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 9 Jun 2022 20:53:10 +0800 Subject: [PATCH 30/36] SRT: Merge develop, fix build fail. --- trunk/src/utest/srs_utest_srt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index f01cfd76381..be03e82c337 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include From 4c32b52891528e641cb98a7b4ab01348b3f3c26f Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 10 Jun 2022 19:27:44 +0800 Subject: [PATCH 31/36] SRT: Refine code, remove SrsSrtListenerType --- trunk/src/app/srs_app_srt_server.cpp | 86 ++++++++-------------------- trunk/src/app/srs_app_srt_server.hpp | 40 ++++--------- 2 files changed, 34 insertions(+), 92 deletions(-) diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 80c4b684849..5b6444c14de 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -18,50 +18,25 @@ using namespace std; SrsSrtEventLoop* _srt_eventloop = NULL; #endif -std::string srs_srt_listener_type2string(SrsSrtListenerType type) -{ - switch (type) { - case SrsSrtListenerMpegts: - return "SRT-MPEGTS"; - default: - return "UNKONWN"; - } -} - -SrsSrtAcceptor::SrsSrtAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType t) +SrsSrtAcceptor::SrsSrtAcceptor(SrsSrtServer* srt_server) { port_ = 0; srt_server_ = srt_server; - type_ = t; -} - -SrsSrtAcceptor::~SrsSrtAcceptor() -{ -} - -SrsSrtListenerType SrsSrtAcceptor::listen_type() -{ - return type_; -} - -SrsSrtMessageAcceptor::SrsSrtMessageAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type) - : SrsSrtAcceptor(srt_server, listen_type) -{ listener_ = NULL; } -SrsSrtMessageAcceptor::~SrsSrtMessageAcceptor() +SrsSrtAcceptor::~SrsSrtAcceptor() { srs_freep(listener_); } -srs_error_t SrsSrtMessageAcceptor::listen(std::string ip, int port) +srs_error_t SrsSrtAcceptor::listen(std::string ip, int port) { srs_error_t err = srs_success; - + ip_ = ip; port_ = port; - + srs_freep(listener_); listener_ = new SrsSrtListener(this, ip_, port_); @@ -79,14 +54,13 @@ srs_error_t SrsSrtMessageAcceptor::listen(std::string ip, int port) if ((err = listener_->listen()) != srs_success) { return srs_error_wrap(err, "message srt acceptor"); } - - string v = srs_srt_listener_type2string(type_); - srs_trace("%s listen at srt://%s:%d, fd=%d", v.c_str(), ip_.c_str(), port_, listener_->fd()); - + + srs_trace("srt listen at udp://%s:%d, fd=%d", ip_.c_str(), port_, listener_->fd()); + return err; } -srs_error_t SrsSrtMessageAcceptor::set_srt_opt() +srs_error_t SrsSrtAcceptor::set_srt_opt() { srs_error_t err = srs_success; @@ -141,16 +115,17 @@ srs_error_t SrsSrtMessageAcceptor::set_srt_opt() return err; } -srs_error_t SrsSrtMessageAcceptor::on_srt_client(srs_srt_t srt_fd) +srs_error_t SrsSrtAcceptor::on_srt_client(srs_srt_t srt_fd) { + srs_error_t err = srs_success; + // Notify srt server to accept srt client, and create new SrsSrtConn on it. - srs_error_t err = srt_server_->accept_srt_client(type_, srt_fd); - if (err != srs_success) { + if ((err = srt_server_->accept_srt_client(srt_fd)) != srs_success) { srs_warn("accept srt client failed, err is %s", srs_error_desc(err).c_str()); srs_freep(err); } - return srs_success; + return err; } SrsSrtServer::SrsSrtServer() @@ -194,10 +169,10 @@ srs_error_t SrsSrtServer::listen_srt_mpegts() } // Close all listener for SRT if exists. - close_listeners(SrsSrtListenerMpegts); + close_listeners(); // Start a listener for SRT, we might need multiple listeners in the future. - SrsSrtAcceptor* acceptor = new SrsSrtMessageAcceptor(this, SrsSrtListenerMpegts); + SrsSrtAcceptor* acceptor = new SrsSrtAcceptor(this); acceptors_.push_back(acceptor); int port; string ip; @@ -210,29 +185,23 @@ srs_error_t SrsSrtServer::listen_srt_mpegts() return err; } -void SrsSrtServer::close_listeners(SrsSrtListenerType type) +void SrsSrtServer::close_listeners() { std::vector::iterator it; for (it = acceptors_.begin(); it != acceptors_.end();) { SrsSrtAcceptor* acceptor = *it; - - if (acceptor->listen_type() != type) { - ++it; - continue; - } - srs_freep(acceptor); + it = acceptors_.erase(it); } } -srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, srs_srt_t srt_fd) +srs_error_t SrsSrtServer::accept_srt_client(srs_srt_t srt_fd) { srs_error_t err = srs_success; ISrsStartableConneciton* conn = NULL; - - if ((err = fd_to_resource(type, srt_fd, &conn)) != srs_success) { + if ((err = fd_to_resource(srt_fd, &conn)) != srs_success) { //close fd on conn error, otherwise will lead to fd leak -gs // TODO: FIXME: Handle error. srs_srt_close(srt_fd); @@ -250,13 +219,12 @@ srs_error_t SrsSrtServer::accept_srt_client(SrsSrtListenerType type, srs_srt_t s return err; } -srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, srs_srt_t srt_fd, ISrsStartableConneciton** pr) +srs_error_t SrsSrtServer::fd_to_resource(srs_srt_t srt_fd, ISrsStartableConneciton** pr) { srs_error_t err = srs_success; string ip = ""; int port = 0; - if ((err = srs_srt_get_remote_ip_port(srt_fd, ip, port)) != srs_success) { return srs_error_wrap(err, "get srt ip port"); } @@ -267,15 +235,9 @@ srs_error_t SrsSrtServer::fd_to_resource(SrsSrtListenerType type, srs_srt_t srt_ // The context id may change during creating the bellow objects. SrsContextRestore(_srs_context->get_id()); - - if (type == SrsSrtListenerMpegts) { - *pr = new SrsMpegtsSrtConn(this, srt_fd, ip, port); - } else { - srs_warn("close for no service handler. srtfd=%d, ip=%s:%d", srt_fd, ip.c_str(), port); - // TODO: FIXME: Handle error. - srs_srt_close(srt_fd); - return err; - } + + // Covert to SRT conection. + *pr = new SrsMpegtsSrtConn(this, srt_fd, ip, port); return err; } diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index 11d56a5f7aa..9c266c09f3d 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -15,38 +15,21 @@ class SrsSrtServer; -enum SrsSrtListenerType -{ - SrsSrtListenerMpegts = 1, -}; - // A common srt acceptor, for SRT server. -class SrsSrtAcceptor +class SrsSrtAcceptor : public ISrsSrtHandler { -protected: - SrsSrtListenerType type_; -protected: +private: std::string ip_; int port_; SrsSrtServer* srt_server_; -public: - SrsSrtAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type); - virtual ~SrsSrtAcceptor(); -public: - virtual SrsSrtListenerType listen_type(); - virtual srs_error_t listen(std::string ip, int port) = 0; -}; - -// A srt messge acceptor. -class SrsSrtMessageAcceptor : public SrsSrtAcceptor, public ISrsSrtHandler -{ private: SrsSrtListener* listener_; public: - SrsSrtMessageAcceptor(SrsSrtServer* srt_server, SrsSrtListenerType listen_type); - virtual ~SrsSrtMessageAcceptor(); + SrsSrtAcceptor(SrsSrtServer* srt_server); + virtual ~SrsSrtAcceptor(); public: - virtual srs_error_t listen(std::string i, int p); + virtual srs_error_t listen(std::string ip, int port); +private: virtual srs_error_t set_srt_opt(); // Interface ISrsSrtHandler public: @@ -69,18 +52,15 @@ class SrsSrtServer : public ISrsResourceManager private: // listen at specified srt protocol. virtual srs_error_t listen_srt_mpegts(); - // Close the listeners for specified type, - // Remove the listen object from manager. - virtual void close_listeners(SrsSrtListenerType type); + // Close the listeners and remove the listen object from manager. + virtual void close_listeners(); // For internal only public: // When listener got a fd, notice server to accept it. - // @param type, the client type, used to create concrete connection, - // for instance SRT connection to serve client. // @param srt_fd, the client fd in srt boxed, the underlayer fd. - virtual srs_error_t accept_srt_client(SrsSrtListenerType type, srs_srt_t srt_fd); + virtual srs_error_t accept_srt_client(srs_srt_t srt_fd); private: - virtual srs_error_t fd_to_resource(SrsSrtListenerType type, srs_srt_t srt_fd, ISrsStartableConneciton** pr); + virtual srs_error_t fd_to_resource(srs_srt_t srt_fd, ISrsStartableConneciton** pr); // Interface ISrsResourceManager public: // A callback for connection to remove itself. From 424f5ec7d801d2278e7e58143bcdc69edfd69b76 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 10 Jun 2022 19:52:18 +0800 Subject: [PATCH 32/36] SRT: Change bridges to bridge. --- trunk/src/app/srs_app_rtc_source.cpp | 51 +++++++-------------- trunk/src/app/srs_app_rtc_source.hpp | 6 +-- trunk/src/app/srs_app_rtmp_conn.cpp | 1 - trunk/src/app/srs_app_source.cpp | 66 +++++++--------------------- trunk/src/app/srs_app_source.hpp | 23 ++-------- trunk/src/app/srs_app_srt_source.cpp | 48 ++++++-------------- trunk/src/app/srs_app_srt_source.hpp | 6 +-- 7 files changed, 52 insertions(+), 149 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 17ed9fc61fb..acf0d8875b5 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -316,7 +316,7 @@ ISrsRtcSourceEventHandler::~ISrsRtcSourceEventHandler() { } -ISrsRtcSourceBridge::ISrsRtcSourceBridge(SrsBridgeDestType type) : ISrsBridge(type) +ISrsRtcSourceBridge::ISrsRtcSourceBridge() { } @@ -333,6 +333,7 @@ SrsRtcSource::SrsRtcSource() stream_desc_ = NULL; req = NULL; + bridge_ = NULL; pli_for_rtmp_ = pli_elapsed_ = 0; } @@ -343,11 +344,7 @@ SrsRtcSource::~SrsRtcSource() // for all consumers are auto free. consumers.clear(); - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsRtcSourceBridge* bridge = *iter; - srs_freep(bridge); - } - bridges_.clear(); + srs_freep(bridge_); srs_freep(stream_desc_); srs_freep(req); @@ -463,16 +460,8 @@ SrsContextId SrsRtcSource::pre_source_id() void SrsRtcSource::set_bridge(ISrsRtcSourceBridge *bridge) { - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsRtcSourceBridge* b = *iter; - if (b->get_type() == bridge->get_type()) { - srs_freep(b); - *iter = bridge; - return; - } - } - - bridges_.push_back(bridge); + srs_freep(bridge_); + bridge_ = bridge; } srs_error_t SrsRtcSource::create_consumer(SrsRtcConsumer*& consumer) @@ -545,12 +534,9 @@ srs_error_t SrsRtcSource::on_publish() } // If bridge to other source, handle event and start timer to request PLI. - if (! bridges_.empty()) { - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsRtcSourceBridge* bridge = *iter; - if ((err = bridge->on_publish()) != srs_success) { - return srs_error_wrap(err, "bridge on publish"); - } + if (bridge_) { + if ((err = bridge_->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridge on publish"); } // The PLI interval for RTC2RTMP. @@ -589,16 +575,12 @@ void SrsRtcSource::on_unpublish() } //free bridge resource - if (! bridges_.empty()) { + if (bridge_) { // For SrsRtcSource::on_timer() _srs_hybrid->timer100ms()->unsubscribe(this); - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsRtcSourceBridge* bridge = *iter; - bridge->on_unpublish(); - srs_freep(bridge); - } - bridges_.clear(); + bridge_->on_unpublish(); + srs_freep(bridge_); } SrsStatistic* stat = SrsStatistic::instance(); @@ -648,11 +630,8 @@ srs_error_t SrsRtcSource::on_rtp(SrsRtpPacket* pkt) } } - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsRtcSourceBridge* bridge = *iter; - if ((err = bridge->on_rtp(pkt)) != srs_success) { - return srs_error_wrap(err, "bridge consume message"); - } + if (bridge_ && (err = bridge_->on_rtp(pkt)) != srs_success) { + return srs_error_wrap(err, "bridge consume message"); } return err; @@ -725,7 +704,7 @@ srs_error_t SrsRtcSource::on_timer(srs_utime_t interval) } #ifdef SRS_FFMPEG_FIT -SrsRtcFromRtmpBridge::SrsRtcFromRtmpBridge(SrsRtcSource* source) : ISrsLiveSourceBridge(SrsBridgeDestTypeRTC) +SrsRtcFromRtmpBridge::SrsRtcFromRtmpBridge(SrsRtcSource* source) { req = NULL; source_ = source; @@ -1292,7 +1271,7 @@ srs_error_t SrsRtcFromRtmpBridge::consume_packets(vector& pkts) return err; } -SrsRtmpFromRtcBridge::SrsRtmpFromRtcBridge(SrsLiveSource *src) : ISrsRtcSourceBridge(SrsBridgeDestTypeRtmp) +SrsRtmpFromRtcBridge::SrsRtmpFromRtcBridge(SrsLiveSource *src) { source_ = src; codec_ = NULL; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 01f2e24867f..f261ed41045 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -144,10 +144,10 @@ class ISrsRtcSourceEventHandler }; // SrsRtcSource bridge to SrsLiveSource -class ISrsRtcSourceBridge : public ISrsBridge +class ISrsRtcSourceBridge { public: - ISrsRtcSourceBridge(SrsBridgeDestType type); + ISrsRtcSourceBridge(); virtual ~ISrsRtcSourceBridge(); public: virtual srs_error_t on_publish() = 0; @@ -171,7 +171,7 @@ class SrsRtcSource : public ISrsFastTimer // Steam description for this steam. SrsRtcSourceDescription* stream_desc_; // The Source bridge, bridge stream to other source. - std::vector bridges_; + ISrsRtcSourceBridge* bridge_; private: // To delivery stream to clients. std::vector consumers; diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 68764496803..e3d9901bfea 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -39,7 +39,6 @@ using namespace std; #include #include #include -#include // the timeout in srs_utime_t to wait encoder to republish // if timeout, close the connection. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 8532adbf61f..409eddffb8f 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1909,21 +1909,7 @@ void SrsLiveSourceManager::destroy() pool.clear(); } -ISrsBridge::ISrsBridge(SrsBridgeDestType type) -{ - type_ = type; -} - -ISrsBridge::~ISrsBridge() -{ -} - -SrsBridgeDestType ISrsBridge::get_type() const -{ - return type_; -} - -ISrsLiveSourceBridge::ISrsLiveSourceBridge(SrsBridgeDestType type) : ISrsBridge(type) +ISrsLiveSourceBridge::ISrsLiveSourceBridge() { } @@ -1942,6 +1928,7 @@ SrsLiveSource::SrsLiveSource() die_at = 0; handler = NULL; + bridge_ = NULL; play_edge = new SrsPlayEdge(); publish_edge = new SrsPublishEdge(); @@ -1973,11 +1960,7 @@ SrsLiveSource::~SrsLiveSource() srs_freep(gop_cache); srs_freep(req); - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - srs_freep(bridge); - } - bridges_.clear(); + srs_freep(bridge_); } void SrsLiveSource::dispose() @@ -2055,16 +2038,8 @@ srs_error_t SrsLiveSource::initialize(SrsRequest* r, ISrsLiveSourceHandler* h) void SrsLiveSource::set_bridge(ISrsLiveSourceBridge* v) { - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - if (v->get_type() == bridge->get_type()) { - srs_freep(bridge); - *iter = v; - return; - } - } - - bridges_.push_back(v); + srs_freep(bridge_); + bridge_ = v; } srs_error_t SrsLiveSource::on_reload_vhost_play(string vhost) @@ -2317,11 +2292,8 @@ srs_error_t SrsLiveSource::on_audio_imp(SrsSharedPtrMessage* msg) } // For bridge to consume the message. - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - if ((err = bridge->on_audio(msg)) != srs_success) { - return srs_error_wrap(err, "bridge consume audio"); - } + if (bridge_ && (err = bridge_->on_audio(msg)) != srs_success) { + return srs_error_wrap(err, "bridge consume audio"); } // copy to all consumer @@ -2450,11 +2422,8 @@ srs_error_t SrsLiveSource::on_video_imp(SrsSharedPtrMessage* msg) } // For bridge to consume the message. - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - if ((err = bridge->on_video(msg)) != srs_success) { - return srs_error_wrap(err, "bridge consume video"); - } + if (bridge_ && (err = bridge_->on_video(msg)) != srs_success) { + return srs_error_wrap(err, "bridge consume video"); } // copy to all consumer @@ -2617,11 +2586,8 @@ srs_error_t SrsLiveSource::on_publish() return srs_error_wrap(err, "handle publish"); } - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - if ((err = bridge->on_publish()) != srs_success) { - return srs_error_wrap(err, "bridge publish"); - } + if (bridge_ && (err = bridge_->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridge publish"); } SrsStatistic* stat = SrsStatistic::instance(); @@ -2665,13 +2631,11 @@ void SrsLiveSource::on_unpublish() handler->on_unpublish(this, req); - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsLiveSourceBridge* bridge = *iter; - bridge->on_unpublish(); - srs_freep(bridge); + if (bridge_) { + bridge_->on_unpublish(); + srs_freep(bridge_); } - bridges_.clear(); - + // no consumer, stream is die. if (consumers.empty()) { die_at = srs_get_system_time(); diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 00729768431..5ebdb461429 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -468,28 +468,11 @@ class SrsLiveSourceManager : public ISrsHourGlass // Global singleton instance. extern SrsLiveSourceManager* _srs_sources; -// Destination type. -enum SrsBridgeDestType { - SrsBridgeDestTypeRtmp = 1, - SrsBridgeDestTypeRTC = 2, - SrsBridgeDestTypeSRT = 3, -}; - -class ISrsBridge { -public: - ISrsBridge(SrsBridgeDestType type); - virtual ~ISrsBridge(); -public: - SrsBridgeDestType get_type() const; -protected: - SrsBridgeDestType type_; -}; - // For RTMP2RTC, bridge SrsLiveSource to SrsRtcSource -class ISrsLiveSourceBridge : public ISrsBridge +class ISrsLiveSourceBridge { public: - ISrsLiveSourceBridge(SrsBridgeDestType type); + ISrsLiveSourceBridge(); virtual ~ISrsLiveSourceBridge(); public: virtual srs_error_t on_publish() = 0; @@ -532,7 +515,7 @@ class SrsLiveSource : public ISrsReloadHandler // The event handler. ISrsLiveSourceHandler* handler; // The source bridge for other source. - std::vector bridges_; + ISrsLiveSourceBridge* bridge_; // The edge control service SrsPlayEdge* play_edge; SrsPublishEdge* publish_edge; diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index b066b3d7acd..ca13fb9dfa1 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -234,7 +234,7 @@ void SrsSrtConsumer::wait(int nb_msgs, srs_utime_t timeout) srs_cond_timedwait(mw_wait, timeout); } -ISrsSrtSourceBridge::ISrsSrtSourceBridge(SrsBridgeDestType type) : ISrsBridge(type) +ISrsSrtSourceBridge::ISrsSrtSourceBridge() { } @@ -242,8 +242,7 @@ ISrsSrtSourceBridge::~ISrsSrtSourceBridge() { } -SrsRtmpFromSrtBridge::SrsRtmpFromSrtBridge(SrsLiveSource* source) - : ISrsSrtSourceBridge(SrsBridgeDestTypeRtmp) +SrsRtmpFromSrtBridge::SrsRtmpFromSrtBridge(SrsLiveSource* source) : ISrsSrtSourceBridge() { ts_ctx_ = new SrsTsContext(); @@ -645,6 +644,7 @@ SrsSrtSource::SrsSrtSource() { req = NULL; can_publish_ = true; + bridge_ = NULL; } SrsSrtSource::~SrsSrtSource() @@ -653,11 +653,7 @@ SrsSrtSource::~SrsSrtSource() // for all consumers are auto free. consumers.clear(); - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsSrtSourceBridge* bridge = *iter; - srs_freep(bridge); - } - bridges_.clear(); + srs_freep(bridge_); } srs_error_t SrsSrtSource::initialize(SrsRequest* r) @@ -707,18 +703,10 @@ void SrsSrtSource::update_auth(SrsRequest* r) req->update_auth(r); } -void SrsSrtSource::set_bridge(ISrsSrtSourceBridge *bridge) +void SrsSrtSource::set_bridge(ISrsSrtSourceBridge* bridge) { - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsSrtSourceBridge* b = *iter; - if (b->get_type() == bridge->get_type()) { - srs_freep(b); - *iter = bridge; - return; - } - } - - bridges_.push_back(bridge); + srs_freep(bridge_); + bridge_ = bridge; } srs_error_t SrsSrtSource::create_consumer(SrsSrtConsumer*& consumer) @@ -765,11 +753,8 @@ srs_error_t SrsSrtSource::on_publish() return srs_error_wrap(err, "source id change"); } - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsSrtSourceBridge* bridge = *iter; - if ((err = bridge->on_publish()) != srs_success) { - return srs_error_wrap(err, "bridge on publish"); - } + if ((err = bridge_->on_publish()) != srs_success) { + return srs_error_wrap(err, "bridge on publish"); } SrsStatistic* stat = SrsStatistic::instance(); @@ -787,12 +772,8 @@ void SrsSrtSource::on_unpublish() can_publish_ = true; - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsSrtSourceBridge* bridge = *iter; - bridge->on_unpublish(); - srs_freep(bridge); - } - bridges_.clear(); + bridge_->on_unpublish(); + srs_freep(bridge_); } srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) @@ -806,11 +787,8 @@ srs_error_t SrsSrtSource::on_packet(SrsSrtPacket* packet) } } - for (vector::iterator iter = bridges_.begin(); iter != bridges_.end(); ++iter) { - ISrsSrtSourceBridge* bridge = *iter; - if ((err = bridge->on_packet(packet)) != srs_success) { - return srs_error_wrap(err, "bridge consume message"); - } + if ((err = bridge_->on_packet(packet)) != srs_success) { + return srs_error_wrap(err, "bridge consume message"); } return err; diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp index 5ba5eef3190..f3cdd6af3f5 100644 --- a/trunk/src/app/srs_app_srt_source.hpp +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -90,10 +90,10 @@ class SrsSrtConsumer virtual void wait(int nb_msgs, srs_utime_t timeout); }; -class ISrsSrtSourceBridge : public ISrsBridge +class ISrsSrtSourceBridge { public: - ISrsSrtSourceBridge(SrsBridgeDestType type); + ISrsSrtSourceBridge(); virtual ~ISrsSrtSourceBridge(); public: virtual srs_error_t on_publish() = 0; @@ -179,7 +179,7 @@ class SrsSrtSource // To delivery packets to clients. std::vector consumers; bool can_publish_; - std::vector bridges_; + ISrsSrtSourceBridge* bridge_; }; #endif From f933e7f213261c2dd9f2fbd779c5634d73f2013f Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Sun, 12 Jun 2022 14:39:34 +0800 Subject: [PATCH 33/36] SRT: move accept log into srt conn cycle --- trunk/src/app/srs_app_srt_conn.cpp | 2 ++ trunk/src/app/srs_app_srt_server.cpp | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index ae888896d8e..b49c03008ed 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -238,6 +238,8 @@ srs_error_t SrsMpegtsSrtConn::do_cycle() { srs_error_t err = srs_success; + srs_trace("SRT client ip=%s:%d, fd=%d", ip_.c_str(), port_, srt_fd_); + string streamid = ""; if ((err = srs_srt_get_streamid(srt_fd_, streamid)) != srs_success) { return srs_error_wrap(err, "get srt streamid"); diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 5b6444c14de..3d4f19f5f32 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -229,8 +229,6 @@ srs_error_t SrsSrtServer::fd_to_resource(srs_srt_t srt_fd, ISrsStartableConnecit return srs_error_wrap(err, "get srt ip port"); } - srs_trace("accept srt client from %s:%d, fd=%d", ip.c_str(), port, srt_fd); - // TODO: FIXME: need to check max connection? // The context id may change during creating the bellow objects. From 9d974028079853a504089e8edb30caf3ced11430 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Sun, 12 Jun 2022 14:41:18 +0800 Subject: [PATCH 34/36] SRT: readd mix_correct, compatible old srt conf --- trunk/src/app/srs_app_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 96afd544c76..1d59503b8a3 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2546,7 +2546,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "mss" && n != "latency" && n != "recvlatency" && n != "peerlatency" && n != "tlpkdrop" && n != "connect_timeout" && n != "sendbuf" && n != "recvbuf" && n != "payloadsize" - && n != "default_app" && n != "sei_filter" + && n != "default_app" && n != "sei_filter" && n != "mix_correct" && n != "tlpktdrop" && n != "tsbpdmode") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_server.%s", n.c_str()); } From b7aad030d324a7c83848c3343905b103dca33508 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Sun, 12 Jun 2022 23:17:17 +0800 Subject: [PATCH 35/36] SRT: add srs_core_lock, support scope lock guard --- trunk/configure | 2 +- trunk/src/core/srs_core_lock.cpp | 8 +++++ trunk/src/core/srs_core_lock.hpp | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 trunk/src/core/srs_core_lock.cpp create mode 100644 trunk/src/core/srs_core_lock.hpp diff --git a/trunk/configure b/trunk/configure index 86cf95eed2b..5be1d5f3e47 100755 --- a/trunk/configure +++ b/trunk/configure @@ -199,7 +199,7 @@ MODULE_ID="CORE" MODULE_DEPENDS=() ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srs_core" "srs_core_version5" "srs_core_autofree" "srs_core_performance" - "srs_core_time" "srs_core_platform") + "srs_core_time" "srs_core_platform" "srs_core_lock") CORE_INCS="src/core"; MODULE_DIR=${CORE_INCS} . auto/modules.sh CORE_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/core/srs_core_lock.cpp b/trunk/src/core/srs_core_lock.cpp new file mode 100644 index 00000000000..a2da00e24ca --- /dev/null +++ b/trunk/src/core/srs_core_lock.cpp @@ -0,0 +1,8 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#include + diff --git a/trunk/src/core/srs_core_lock.hpp b/trunk/src/core/srs_core_lock.hpp new file mode 100644 index 00000000000..3eb1c1d3c16 --- /dev/null +++ b/trunk/src/core/srs_core_lock.hpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2013-2021 The SRS Authors +// +// SPDX-License-Identifier: MIT or MulanPSL-2.0 +// + +#ifndef SRS_CORE_LOCK_HPP +#define SRS_CORE_LOCK_HPP + +#include + +#include + +#include + +class SrsScopeLock +{ +private: + pthread_mutex_t* mutex_; + bool locked_; + +public: + explicit SrsScopeLock(pthread_mutex_t* mutex) + { + mutex_ = mutex; + locked_ = false; + + lock(); + } + + ~SrsScopeLock() + { + unlock(); + } + + void lock() + { + if (locked_) { + return; + } + + locked_ = true; + pthread_mutex_lock(mutex_); + } + + void unlock() + { + if (! locked_) { + return; + } + + locked_ = false; + pthread_mutex_unlock(mutex_); + } +}; + +#endif From edc291a8e1edea5a1b71de20083c9cbf8a93b23b Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Sun, 12 Jun 2022 23:18:18 +0800 Subject: [PATCH 36/36] SRT: add srt log handle, srs log supoort multithread --- trunk/src/app/srs_app_log.cpp | 15 ++++++++++ trunk/src/app/srs_app_log.hpp | 3 ++ trunk/src/app/srs_app_srt_server.cpp | 4 +++ trunk/src/protocol/srs_protocol_srt.cpp | 37 +++++++++++++++++++++++++ trunk/src/protocol/srs_protocol_srt.hpp | 2 ++ 5 files changed, 61 insertions(+) diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index 89885cd6a44..38c10c4ff3b 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -18,6 +18,7 @@ #include #include #include +#include // the max size of a line of log. #define LOG_MAX_SIZE 8192 @@ -35,6 +36,8 @@ SrsFileLog::SrsFileLog() fd = -1; log_to_file_tank = false; utc = false; + + pthread_mutex_init(&mutex_, NULL); } SrsFileLog::~SrsFileLog() @@ -49,6 +52,8 @@ SrsFileLog::~SrsFileLog() if (_srs_config) { _srs_config->unsubscribe(this); } + + pthread_mutex_destroy(&mutex_); } srs_error_t SrsFileLog::initialize() @@ -79,6 +84,8 @@ void SrsFileLog::reopen() void SrsFileLog::verbose(const char* tag, SrsContextId context_id, const char* fmt, ...) { + SrsScopeLock sl(&mutex_); + if (level > SrsLogLevelVerbose) { return; } @@ -99,6 +106,8 @@ void SrsFileLog::verbose(const char* tag, SrsContextId context_id, const char* f void SrsFileLog::info(const char* tag, SrsContextId context_id, const char* fmt, ...) { + SrsScopeLock sl(&mutex_); + if (level > SrsLogLevelInfo) { return; } @@ -119,6 +128,8 @@ void SrsFileLog::info(const char* tag, SrsContextId context_id, const char* fmt, void SrsFileLog::trace(const char* tag, SrsContextId context_id, const char* fmt, ...) { + SrsScopeLock sl(&mutex_); + if (level > SrsLogLevelTrace) { return; } @@ -139,6 +150,8 @@ void SrsFileLog::trace(const char* tag, SrsContextId context_id, const char* fmt void SrsFileLog::warn(const char* tag, SrsContextId context_id, const char* fmt, ...) { + SrsScopeLock sl(&mutex_); + if (level > SrsLogLevelWarn) { return; } @@ -159,6 +172,8 @@ void SrsFileLog::warn(const char* tag, SrsContextId context_id, const char* fmt, void SrsFileLog::error(const char* tag, SrsContextId context_id, const char* fmt, ...) { + SrsScopeLock sl(&mutex_); + if (level > SrsLogLevelError) { return; } diff --git a/trunk/src/app/srs_app_log.hpp b/trunk/src/app/srs_app_log.hpp index a1866283423..fc0cbcccde7 100644 --- a/trunk/src/app/srs_app_log.hpp +++ b/trunk/src/app/srs_app_log.hpp @@ -39,6 +39,9 @@ class SrsFileLog : public ISrsLog, public ISrsReloadHandler bool log_to_file_tank; // Whether use utc time. bool utc; + // TODO: FIXME: use macro define like SRS_MULTI_THREAD_LOG to switch enable log mutex or not. + // Mutex for multithread log. + pthread_mutex_t mutex_; public: SrsFileLog(); virtual ~SrsFileLog(); diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 3d4f19f5f32..59524383264 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -267,6 +267,10 @@ srs_error_t SrsSrtServerAdapter::initialize() { srs_error_t err = srs_success; + if ((err = srs_srt_log_initialie()) != srs_success) { + return srs_error_wrap(err, "srt log initialize"); + } + _srt_eventloop = new SrsSrtEventLoop(); if ((err = _srt_eventloop->initialize()) != srs_success) { diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index 53b77c2c999..d92adfb3af7 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -16,6 +16,9 @@ using namespace std; #include +// TODO: FIXME: protocol could no include app's header file, so define TAG_SRT in this file. +#define TAG_SRT "SRT" + #define SET_SRT_OPT_STR(srtfd, optname, buf, size) \ if (srt_setsockflag(srtfd, optname, buf, size) == SRT_ERROR) { \ std::stringstream ss; \ @@ -43,6 +46,7 @@ using namespace std; } \ } while (0) + static srs_error_t do_srs_srt_listen(srs_srt_t srt_fd, addrinfo* r) { srs_error_t err = srs_success; @@ -72,6 +76,39 @@ static srs_error_t do_srs_srt_get_streamid(srs_srt_t srt_fd, string& streamid) return srs_success; } +static void srs_srt_log_handler(void* opaque, int level, const char* file, int line, const char* area, const char* message) +{ + switch (level) { + case srt_logging::LogLevel::debug: + srs_info2(TAG_SRT, "%s:%d(%s) # %s", file, line, area, message); + break; + case srt_logging::LogLevel::note: + srs_trace2(TAG_SRT, "%s:%d(%s) # %s", file, line, area, message); + break; + case srt_logging::LogLevel::warning: + srs_warn2(TAG_SRT, "%s:%d(%s) # %s", file, line, area, message); + break; + case srt_logging::LogLevel::error: + case srt_logging::LogLevel::fatal: + srs_error2(TAG_SRT, "%s:%d(%s) # %s", file, line, area, message); + break; + default: + srs_trace2(TAG_SRT, "%s:%d(%s) # %s", file, line, area, message); + break; + } +} + +srs_error_t srs_srt_log_initialie() +{ + srs_error_t err = srs_success; + + srt_setlogflags(0 | SRT_LOGF_DISABLE_TIME | SRT_LOGF_DISABLE_SEVERITY | + SRT_LOGF_DISABLE_THREADNAME | SRT_LOGF_DISABLE_EOL); + srt_setloghandler(NULL, srs_srt_log_handler); + + return err; +} + srs_srt_t srs_srt_socket_invalid() { return SRT_INVALID_SOCK; diff --git a/trunk/src/protocol/srs_protocol_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp index dacba1fbd78..e1fd2e7680e 100644 --- a/trunk/src/protocol/srs_protocol_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -15,6 +15,8 @@ class SrsSrtSocket; +extern srs_error_t srs_srt_log_initialie(); + typedef int srs_srt_t; extern srs_srt_t srs_srt_socket_invalid();