From ef048b0d656bf7378cc75c99255707210074f657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haibo=20Chen=28=E9=99=88=E6=B5=B7=E5=8D=9A=29?= <495810242@qq.com> Date: Tue, 28 Oct 2025 21:33:40 +0800 Subject: [PATCH] RTC: Fix DVR missing first 4-6 seconds by initializing rate from SDP (#4541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for issue #4418, #4151, #4076 .DVR Missing First Few Seconds of Audio/Video ### Root Cause When recording WebRTC streams to FLV files using DVR, the first 4-6 seconds of audio/video are missing. This occurs because: 1. **Packets are discarded before A/V sync is available**: The RTC-to-RTMP conversion pipeline actively discards all RTP packets when avsync_time <= 0. 2. **Original algorithm requires 2 RTCP SR packets**: The previous implementation needed to receive two RTCP Sender Report (SR) packets before it could calculate the rate for audio/video synchronization timestamp conversion. 3. **Delay causes packet loss**: Since RTCP SR packets typically arrive every 2-3 seconds, waiting for 2 SRs means 4-6 seconds of packets are discarded before A/V sync becomes available. 4. **Audio SR arrives slower than video SR**: As reported in the issue, video RTCP SR packets arrive much faster than audio SR packets. This asymmetry causes audio packets to be discarded for a longer period, resulting in the audio loss observed in DVR recordings. ### Solution 1. **Initialize rate from SDP**: Use the sample rate from SDP (Session Description Protocol) to calculate the initial rate immediately when the track is created. Audio (Opus): 48000 Hz → rate = 48 (RTP units per millisecond) Video (H.264/H.265): 90000 Hz → rate = 90 (RTP units per millisecond) 2. **Enable immediate A/V sync:** With the SDP rate available, cal_avsync_time() can calculate valid timestamps from the very first RTP packet, eliminating packet loss. 3. **Smooth transition to precise rate**: After receiving the 2nd RTCP SR, update to the precisely calculated rate based on actual RTP/NTP timestamp mapping. ## Configuration Added new configuration option `init_rate_from_sdp` in the RTC vhost section: ```nginx vhost rtc.vhost.srs.com { rtc { # Whether initialize RTP rate from SDP sample rate for immediate A/V sync. # When enabled, the RTP rate (units per millisecond) is initialized from the SDP # sample rate (e.g., 90 for video 90kHz, 48 for audio 48kHz) before receiving # 2 RTCP SR packets. This allows immediate audio/video synchronization. # The rate will be updated to a more precise value after receiving the 2nd SR. # Overwrite by env SRS_VHOST_RTC_INIT_RATE_FROM_SDP for all vhosts. # Default: off init_rate_from_sdp off; } } ``` **⚠️ Important Note**: This config defaults to **off** because: - ✅ When **enabled**: Fixes the audio loss problem (no missing first 4-6 seconds) - ❌ When **enabled**: VLC on macOS cannot play the video properly - ✅ Other platforms work fine (Windows, Linux) - ✅ FFplay works fine on all platforms Users experiencing audio loss in DVR recordings can enable this option if they don't need VLC macOS compatibility. We're investigating the VLC macOS issue to make this feature safe to enable by default in the future. --------- Co-authored-by: winlin Co-authored-by: OSSRS-AI --- trunk/conf/full.conf | 9 + trunk/configure | 8 +- trunk/src/app/srs_app_config.cpp | 21 +- trunk/src/app/srs_app_config.hpp | 2 + trunk/src/app/srs_app_dash.cpp | 2 +- trunk/src/app/srs_app_factory.cpp | 19 + trunk/src/app/srs_app_factory.hpp | 14 + trunk/src/app/srs_app_hls.cpp | 2 +- trunk/src/app/srs_app_rtc_codec.cpp | 84 +-- trunk/src/app/srs_app_rtc_codec.hpp | 16 + trunk/src/app/srs_app_rtc_conn.cpp | 11 +- trunk/src/app/srs_app_rtc_conn.hpp | 15 +- trunk/src/app/srs_app_rtc_source.cpp | 91 ++- trunk/src/app/srs_app_rtc_source.hpp | 83 ++- trunk/src/app/srs_app_rtmp_conn.cpp | 5 +- trunk/src/app/srs_app_rtmp_conn.hpp | 2 + trunk/src/app/srs_app_srt_conn.cpp | 12 +- trunk/src/app/srs_app_stream_bridge.cpp | 25 +- trunk/src/app/srs_app_stream_bridge.hpp | 19 +- trunk/src/kernel/srs_kernel_packet.cpp | 44 ++ trunk/src/kernel/srs_kernel_packet.hpp | 14 + trunk/src/main/srs_main_server.cpp | 6 + .../src/protocol/srs_protocol_http_stack.cpp | 2 +- trunk/src/utest/srs_utest.cpp | 11 + trunk/src/utest/srs_utest_ai08.cpp | 198 +++--- trunk/src/utest/srs_utest_ai09.cpp | 255 ++++---- trunk/src/utest/srs_utest_ai09.hpp | 6 +- trunk/src/utest/srs_utest_ai10.cpp | 102 +-- trunk/src/utest/srs_utest_ai11.cpp | 18 +- trunk/src/utest/srs_utest_ai12.cpp | 22 +- trunk/src/utest/srs_utest_ai24.cpp | 305 +++++++++ trunk/src/utest/srs_utest_ai24.hpp | 11 + .../utest/srs_utest_manual_app_rtc2rtmp.cpp | 40 +- trunk/src/utest/srs_utest_manual_mock.cpp | 609 ++++-------------- trunk/src/utest/srs_utest_manual_mock.hpp | 306 ++++++--- trunk/src/utest/srs_utest_manual_rtc.cpp | 12 +- .../utest/srs_utest_manual_rtc_recv_track.cpp | 2 +- trunk/src/utest/srs_utest_manual_st.cpp | 4 +- .../src/utest/srs_utest_workflow_rtc2rtmp.cpp | 190 ++++++ .../src/utest/srs_utest_workflow_rtc2rtmp.hpp | 32 + .../src/utest/srs_utest_workflow_rtc_conn.hpp | 6 +- .../srs_utest_workflow_rtc_playstream.cpp | 5 - .../srs_utest_workflow_rtc_publishstream.cpp | 5 - .../src/utest/srs_utest_workflow_rtmp2rtc.cpp | 250 +++++++ .../src/utest/srs_utest_workflow_rtmp2rtc.hpp | 32 + .../utest/srs_utest_workflow_rtmp_conn.cpp | 11 +- .../src/utest/srs_utest_workflow_srt_conn.cpp | 1 + 47 files changed, 1913 insertions(+), 1026 deletions(-) create mode 100644 trunk/src/utest/srs_utest_ai24.cpp create mode 100644 trunk/src/utest/srs_utest_ai24.hpp create mode 100644 trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp create mode 100644 trunk/src/utest/srs_utest_workflow_rtc2rtmp.hpp create mode 100644 trunk/src/utest/srs_utest_workflow_rtmp2rtc.cpp create mode 100644 trunk/src/utest/srs_utest_workflow_rtmp2rtc.hpp diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 7d4de2a11..7a8729e67 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -951,6 +951,15 @@ vhost rtc.vhost.srs.com { # [8000, 320000] # default: 48000 aac_bitrate 48000; + ############################################################### + # Whether initialize RTP rate from SDP sample rate for immediate A/V sync. + # When enabled, the RTP rate (units per millisecond) is initialized from the SDP + # sample rate (e.g., 90 for video 90kHz, 48 for audio 48kHz) before receiving + # 2 RTCP SR packets. This allows immediate audio/video synchronization. + # The rate will be updated to a more precise value after receiving the 2nd SR. + # Overwrite by env SRS_VHOST_RTC_INIT_RATE_FROM_SDP for all vhosts. + # Default: off + init_rate_from_sdp off; } ############################################################### # For transmuxing RTMP to RTC, it will impact the default values if RTC is on. diff --git a/trunk/configure b/trunk/configure index 5fb52bbc3..f9100c909 100755 --- a/trunk/configure +++ b/trunk/configure @@ -381,12 +381,14 @@ if [[ $SRS_UTEST == YES ]]; then "srs_utest_manual_protocol" "srs_utest_manual_protocol2" "srs_utest_manual_kernel2" "srs_utest_manual_st" "srs_utest_manual_fmp4" "srs_utest_manual_source_lock" "srs_utest_manual_stream_token" "srs_utest_manual_rtc_recv_track" "srs_utest_manual_st2" "srs_utest_manual_hevc_structs" "srs_utest_manual_coworkers" "srs_utest_manual_pithy_print" "srs_utest_manual_protocol3" - "srs_utest_manual_app" "srs_utest_manual_mock" "srs_utest_workflow_rtc_playstream" "srs_utest_workflow_rtc_publishstream" - "srs_utest_workflow_rtc_conn" "srs_utest_workflow_rtmp_conn" "srs_utest_workflow_srt_conn" "srs_utest_workflow_http_conn") + "srs_utest_manual_app" "srs_utest_manual_mock") + MODULE_FILES+=("srs_utest_workflow_rtc_playstream" "srs_utest_workflow_rtc_publishstream" + "srs_utest_workflow_rtc_conn" "srs_utest_workflow_rtmp_conn" "srs_utest_workflow_srt_conn" "srs_utest_workflow_http_conn" + "srs_utest_workflow_forward" "srs_utest_workflow_rtc2rtmp" "srs_utest_workflow_rtmp2rtc") MODULE_FILES+=("srs_utest_ai01" "srs_utest_ai02" "srs_utest_ai03" "srs_utest_ai04" "srs_utest_ai05" "srs_utest_ai06" "srs_utest_ai07" "srs_utest_ai08" "srs_utest_ai09" "srs_utest_ai10" "srs_utest_ai11" "srs_utest_ai12" "srs_utest_ai13" "srs_utest_ai14" "srs_utest_ai15" "srs_utest_ai16" "srs_utest_ai17" - "srs_utest_ai18" "srs_utest_ai19" "srs_utest_ai20" "srs_utest_workflow_forward") + "srs_utest_ai18" "srs_utest_ai19" "srs_utest_ai20" "srs_utest_ai24") if [[ $SRS_GB28181 == YES ]]; then MODULE_FILES+=("srs_utest_manual_gb28181" "srs_utest_ai23") fi diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7a353826a..faf0155a3 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2340,7 +2340,7 @@ srs_error_t SrsConfig::check_normal_config() } else if (n == "rtc") { for (int j = 0; j < (int)conf->directives_.size(); j++) { string m = conf->at(j)->name_; - if (m != "enabled" && m != "nack" && m != "twcc" && m != "nack_no_copy" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check" && m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt" && m != "rtc_to_rtmp" && m != "pli_for_rtmp" && m != "rtmp_to_rtc" && m != "keep_bframe" && m != "opus_bitrate" && m != "aac_bitrate" && m != "keep_avc_nalu_sei") { + if (m != "enabled" && m != "nack" && m != "twcc" && m != "nack_no_copy" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check" && m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt" && m != "rtc_to_rtmp" && m != "pli_for_rtmp" && m != "rtmp_to_rtc" && m != "keep_bframe" && m != "opus_bitrate" && m != "aac_bitrate" && m != "keep_avc_nalu_sei" && m != "init_rate_from_sdp") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -4065,6 +4065,25 @@ int SrsConfig::get_rtc_aac_bitrate(string vhost) return v; } +bool SrsConfig::get_rtc_init_rate_from_sdp(string vhost) +{ + SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.rtc.init_rate_from_sdp"); // SRS_VHOST_RTC_INIT_RATE_FROM_SDP + + static bool DEFAULT = false; + + SrsConfDirective *conf = get_rtc(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("init_rate_from_sdp"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PREFER_FALSE(conf->arg0()); +} + SrsConfDirective *SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root_); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index d72dd1b69..b294692ef 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -481,6 +481,7 @@ public: virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost) = 0; virtual int get_rtc_drop_for_pt(std::string vhost) = 0; virtual bool get_rtc_twcc_enabled(std::string vhost) = 0; + virtual bool get_rtc_init_rate_from_sdp(std::string vhost) = 0; virtual bool get_srt_enabled() = 0; virtual bool get_srt_enabled(std::string vhost) = 0; virtual std::string get_srt_default_streamid() = 0; @@ -909,6 +910,7 @@ public: bool get_rtc_twcc_enabled(std::string vhost); int get_rtc_opus_bitrate(std::string vhost); int get_rtc_aac_bitrate(std::string vhost); + bool get_rtc_init_rate_from_sdp(std::string vhost); // vhost specified section public: diff --git a/trunk/src/app/srs_app_dash.cpp b/trunk/src/app/srs_app_dash.cpp index 0e04e314d..349dbef8c 100644 --- a/trunk/src/app/srs_app_dash.cpp +++ b/trunk/src/app/srs_app_dash.cpp @@ -878,7 +878,7 @@ SrsDash::~SrsDash() void SrsDash::dispose() { - // We disabled the reload, so DASH will not be enabled by reloading. + // We disabled the reload, so DASH will not be enabled by reloading. // As a result, if DASH is disabled, we don't need to dispose. if (!enabled_) { return; diff --git a/trunk/src/app/srs_app_factory.cpp b/trunk/src/app/srs_app_factory.cpp index 7322d521d..0c6325def 100644 --- a/trunk/src/app/srs_app_factory.cpp +++ b/trunk/src/app/srs_app_factory.cpp @@ -23,7 +23,9 @@ #ifdef SRS_RTSP #include #endif +#include #include +#include #include #include #include @@ -212,6 +214,23 @@ ISrsHttpResponseWriter *SrsAppFactory::create_http_response_writer(ISrsProtocolR return new SrsHttpResponseWriter(io); } +#ifdef SRS_FFMPEG_FIT +SrsRtcFrameBuilder *SrsAppFactory::create_rtc_frame_builder(ISrsFrameTarget *target) +{ + return new SrsRtcFrameBuilder(this, target); +} + +ISrsRtcFrameBuilderAudioPacketCache *SrsAppFactory::create_rtc_frame_builder_audio_packet_cache() +{ + return new SrsRtcFrameBuilderAudioPacketCache(); +} + +ISrsAudioTranscoder *SrsAppFactory::create_audio_transcoder() +{ + return new SrsAudioTranscoder(); +} +#endif + ISrsCoroutine *SrsAppFactory::create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid) { return kernel_factory_->create_coroutine(name, handler, cid); diff --git a/trunk/src/app/srs_app_factory.hpp b/trunk/src/app/srs_app_factory.hpp index 852a7c4bb..208bc6fdd 100644 --- a/trunk/src/app/srs_app_factory.hpp +++ b/trunk/src/app/srs_app_factory.hpp @@ -50,6 +50,10 @@ class ISrsRtcPlayStream; class ISrsRtcPacketSender; class ISrsHttpResponseWriter; class ISrsProtocolReadWriter; +class SrsRtcFrameBuilder; +class ISrsFrameTarget; +class ISrsRtcFrameBuilderAudioPacketCache; +class ISrsAudioTranscoder; // The factory to create app objects. class ISrsAppFactory : public ISrsKernelFactory @@ -93,6 +97,11 @@ public: virtual ISrsRtcPublishStream *create_rtc_publish_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid) = 0; virtual ISrsRtcPlayStream *create_rtc_play_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid) = 0; virtual ISrsHttpResponseWriter *create_http_response_writer(ISrsProtocolReadWriter *io) = 0; +#ifdef SRS_FFMPEG_FIT + virtual SrsRtcFrameBuilder *create_rtc_frame_builder(ISrsFrameTarget *target) = 0; + virtual ISrsRtcFrameBuilderAudioPacketCache *create_rtc_frame_builder_audio_packet_cache() = 0; + virtual ISrsAudioTranscoder *create_audio_transcoder() = 0; +#endif }; // The factory to create app objects. @@ -141,6 +150,11 @@ public: virtual ISrsRtcPublishStream *create_rtc_publish_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid); virtual ISrsRtcPlayStream *create_rtc_play_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid); virtual ISrsHttpResponseWriter *create_http_response_writer(ISrsProtocolReadWriter *io); +#ifdef SRS_FFMPEG_FIT + virtual SrsRtcFrameBuilder *create_rtc_frame_builder(ISrsFrameTarget *target); + virtual ISrsRtcFrameBuilderAudioPacketCache *create_rtc_frame_builder_audio_packet_cache(); + virtual ISrsAudioTranscoder *create_audio_transcoder(); +#endif public: virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid); diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 0c8fef9cc..5394256d8 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -2549,7 +2549,7 @@ srs_error_t SrsHls::do_reload(int *reloading, int *reloaded, int *refreshed) void SrsHls::dispose() { - // We disabled the reload, so HLS will not be enabled by reloading. + // We disabled the reload, so HLS will not be enabled by reloading. // As a result, if HLS is disabled, we don't need to dispose. if (!enabled_) { return; diff --git a/trunk/src/app/srs_app_rtc_codec.cpp b/trunk/src/app/srs_app_rtc_codec.cpp index cd99181ff..c4409b03f 100644 --- a/trunk/src/app/srs_app_rtc_codec.cpp +++ b/trunk/src/app/srs_app_rtc_codec.cpp @@ -42,49 +42,57 @@ static const AVCodec *srs_find_encoder_by_id(SrsAudioCodecId id) return NULL; } -class SrsFFmpegLogHelper +SrsFFmpegLogHelper::SrsFFmpegLogHelper() { -public: - SrsFFmpegLogHelper() - { - av_log_set_callback(ffmpeg_log_callback); - av_log_set_level(AV_LOG_TRACE); + av_log_set_callback(ffmpeg_log_callback); + av_log_set_level(AV_LOG_TRACE); +} +SrsFFmpegLogHelper::~SrsFFmpegLogHelper() +{ + av_log_set_callback(NULL); +} + +bool SrsFFmpegLogHelper::disabled_ = false; + +void SrsFFmpegLogHelper::disable_ffmpeg_log() +{ + disabled_ = true; +} + +void SrsFFmpegLogHelper::ffmpeg_log_callback(void *, int level, const char *fmt, va_list vl) +{ + if (disabled_) { + return; } - static void ffmpeg_log_callback(void *, int level, const char *fmt, va_list vl) - { - static char buf[4096] = {0}; - int nbytes = vsnprintf(buf, sizeof(buf), fmt, vl); - if (nbytes > 0 && nbytes < (int)sizeof(buf)) { - // Srs log is always start with new line, replcae '\n' to '\0', make log easy to read. - if (buf[nbytes - 1] == '\n') { - buf[nbytes - 1] = '\0'; - } - switch (level) { - case AV_LOG_PANIC: - case AV_LOG_FATAL: - case AV_LOG_ERROR: - srs_error("%s", buf); - break; - case AV_LOG_WARNING: - srs_warn("%s", buf); - break; - case AV_LOG_INFO: - srs_trace("%s", buf); - break; - case AV_LOG_VERBOSE: - case AV_LOG_DEBUG: - case AV_LOG_TRACE: - default: - srs_verbose("%s", buf); - break; - } + static char buf[4096] = {0}; + int nbytes = vsnprintf(buf, sizeof(buf), fmt, vl); + if (nbytes > 0 && nbytes < (int)sizeof(buf)) { + // Srs log is always start with new line, replcae '\n' to '\0', make log easy to read. + if (buf[nbytes - 1] == '\n') { + buf[nbytes - 1] = '\0'; + } + switch (level) { + case AV_LOG_PANIC: + case AV_LOG_FATAL: + case AV_LOG_ERROR: + srs_error("%s", buf); + break; + case AV_LOG_WARNING: + srs_warn("%s", buf); + break; + case AV_LOG_INFO: + srs_trace("%s", buf); + break; + case AV_LOG_VERBOSE: + case AV_LOG_DEBUG: + case AV_LOG_TRACE: + default: + srs_verbose("%s", buf); + break; } } -}; - -// Register FFmpeg log callback funciton. -SrsFFmpegLogHelper _srs_ffmpeg_log_helper; +} ISrsAudioTranscoder::ISrsAudioTranscoder() { diff --git a/trunk/src/app/srs_app_rtc_codec.hpp b/trunk/src/app/srs_app_rtc_codec.hpp index a754dca49..6fa571385 100644 --- a/trunk/src/app/srs_app_rtc_codec.hpp +++ b/trunk/src/app/srs_app_rtc_codec.hpp @@ -31,6 +31,22 @@ extern "C" { } #endif +// Register FFmpeg log callback funciton. +class SrsFFmpegLogHelper +{ +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + static bool disabled_; + +public: + SrsFFmpegLogHelper(); + virtual ~SrsFFmpegLogHelper(); + +public: + static void disable_ffmpeg_log(); + static void ffmpeg_log_callback(void *, int level, const char *fmt, va_list vl); +}; + // The interface for audio transcoder. class ISrsAudioTranscoder { diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 216b757d5..04d76df4e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1223,6 +1223,7 @@ SrsRtcPublishStream::SrsRtcPublishStream(ISrsExecRtcAsyncTask *exec, ISrsExpire live_sources_ = _srs_sources; srt_sources_ = _srs_srt_sources; circuit_breaker_ = _srs_circuit_breaker; + app_factory_ = _srs_app_factory; } SrsRtcPublishStream::~SrsRtcPublishStream() @@ -1268,6 +1269,7 @@ SrsRtcPublishStream::~SrsRtcPublishStream() live_sources_ = NULL; srt_sources_ = NULL; circuit_breaker_ = NULL; + app_factory_ = NULL; } srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescription *stream_desc) @@ -1289,13 +1291,16 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript return srs_error_wrap(err, "rtc: stat client"); } + // Use SDP sample rate to initialize track rate for A/V sync. + bool init_rate_from_sdp = config_->get_rtc_init_rate_from_sdp(req_->vhost_); + if (stream_desc->audio_track_desc_) { - audio_tracks_.push_back(new SrsRtcAudioRecvTrack(receiver_, stream_desc->audio_track_desc_)); + audio_tracks_.push_back(new SrsRtcAudioRecvTrack(receiver_, stream_desc->audio_track_desc_, init_rate_from_sdp)); } for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) { SrsRtcTrackDescription *desc = stream_desc->video_track_descs_.at(i); - video_tracks_.push_back(new SrsRtcVideoRecvTrack(receiver_, desc)); + video_tracks_.push_back(new SrsRtcVideoRecvTrack(receiver_, desc, init_rate_from_sdp)); } int twcc_id = -1; @@ -1367,7 +1372,7 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript } // Create the bridge for RTC. - SrsRtcBridge *bridge = new SrsRtcBridge(); + SrsRtcBridge *bridge = new SrsRtcBridge(app_factory_); // Bridge to RTMP. // TODO: Support bridge to RTSP. diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 288481084..ccaa41c9d 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -515,13 +515,6 @@ public: // A RTC publish stream, client push and publish stream to SRS. class SrsRtcPublishStream : public ISrsRtcPublishStream { -// clang-format off -SRS_DECLARE_PRIVATE: // clang-format on - ISrsExecRtcAsyncTask *exec_; - ISrsExpire *expire_; - ISrsRtcPacketReceiver *receiver_; - ISrsCircuitBreaker *circuit_breaker_; - // clang-format off SRS_DECLARE_PRIVATE: // clang-format on ISrsStatistic *stat_; @@ -529,6 +522,14 @@ SRS_DECLARE_PRIVATE: // clang-format on ISrsRtcSourceManager *rtc_sources_; ISrsLiveSourceManager *live_sources_; ISrsSrtSourceManager *srt_sources_; + ISrsAppFactory *app_factory_; + +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsExecRtcAsyncTask *exec_; + ISrsExpire *expire_; + ISrsRtcPacketReceiver *receiver_; + ISrsCircuitBreaker *circuit_breaker_; // clang-format off SRS_DECLARE_PRIVATE: // clang-format on diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 6ba964878..71fe59dec 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -32,11 +32,10 @@ #include #include #include - #ifdef SRS_FFMPEG_FIT #include #endif - +#include #include #include #include @@ -401,6 +400,8 @@ SrsRtcSource::SrsRtcSource() pli_for_rtmp_ = pli_elapsed_ = 0; stream_die_at_ = 0; + + app_factory_ = _srs_app_factory; } SrsRtcSource::~SrsRtcSource() @@ -417,6 +418,8 @@ SrsRtcSource::~SrsRtcSource() if (cid.empty()) cid = _pre_source_id; srs_trace("free rtc source id=[%s]", cid.c_str()); + + app_factory_ = NULL; } // CRITICAL: This method is called AFTER the source has been added to the source pool @@ -879,14 +882,14 @@ srs_error_t SrsRtcSource::on_timer(srs_utime_t interval) #ifdef SRS_FFMPEG_FIT -SrsRtcRtpBuilder::SrsRtcRtpBuilder(ISrsRtpTarget *target, SrsSharedPtr source) +SrsRtcRtpBuilder::SrsRtcRtpBuilder(ISrsAppFactory *factory, ISrsRtpTarget *target, SrsSharedPtr source) { rtp_target_ = target; source_ = source; req_ = NULL; format_ = new SrsRtmpFormat(); - codec_ = new SrsAudioTranscoder(); + codec_ = factory->create_audio_transcoder(); latest_codec_ = SrsAudioCodecIdForbidden; keep_bframe_ = false; keep_avc_nalu_sei_ = true; @@ -902,6 +905,8 @@ SrsRtcRtpBuilder::SrsRtcRtpBuilder(ISrsRtpTarget *target, SrsSharedPtrcreate_audio_transcoder(); // Initialize the codec according to the codec in stream. int bitrate = _srs_config->get_rtc_opus_bitrate(req_->vhost_); // The output bitrate in bps. @@ -1377,6 +1384,14 @@ srs_error_t SrsRtcRtpBuilder::consume_packets(vector &pkts) return err; } +ISrsRtcFrameBuilderVideoPacketCache::ISrsRtcFrameBuilderVideoPacketCache() +{ +} + +ISrsRtcFrameBuilderVideoPacketCache::~ISrsRtcFrameBuilderVideoPacketCache() +{ +} + SrsRtcFrameBuilderVideoPacketCache::SrsRtcFrameBuilderVideoPacketCache() { memset(cache_pkts_, 0, sizeof(cache_pkts_)); @@ -1496,7 +1511,7 @@ int32_t SrsRtcFrameBuilderVideoPacketCache::find_next_lost_sn(uint16_t current_s } } - srs_error("cache overflow. the packet count of video frame is more than %u", cache_size_); + srs_warn("cache overflow. the packet count of video frame is more than %u", cache_size_); return -2; } @@ -1536,7 +1551,15 @@ bool SrsRtcFrameBuilderVideoPacketCache::check_frame_complete(const uint16_t sta return nn_fu_start == nn_fu_end; } -SrsRtcFrameBuilderVideoFrameDetector::SrsRtcFrameBuilderVideoFrameDetector(SrsRtcFrameBuilderVideoPacketCache *cache) +ISrsRtcFrameBuilderVideoFrameDetector::ISrsRtcFrameBuilderVideoFrameDetector() +{ +} + +ISrsRtcFrameBuilderVideoFrameDetector::~ISrsRtcFrameBuilderVideoFrameDetector() +{ +} + +SrsRtcFrameBuilderVideoFrameDetector::SrsRtcFrameBuilderVideoFrameDetector(ISrsRtcFrameBuilderVideoPacketCache *cache) { video_cache_ = cache; header_sn_ = 0; @@ -1640,6 +1663,14 @@ bool SrsRtcFrameBuilderVideoFrameDetector::is_lost_sn(uint16_t received) return lost_sn_ == received; } +ISrsRtcFrameBuilderAudioPacketCache::ISrsRtcFrameBuilderAudioPacketCache() +{ +} + +ISrsRtcFrameBuilderAudioPacketCache::~ISrsRtcFrameBuilderAudioPacketCache() +{ +} + SrsRtcFrameBuilderAudioPacketCache::SrsRtcFrameBuilderAudioPacketCache() { last_audio_seq_num_ = 0; @@ -1752,17 +1783,19 @@ void SrsRtcFrameBuilderAudioPacketCache::clear_all() audio_buffer_.clear(); } -SrsRtcFrameBuilder::SrsRtcFrameBuilder(ISrsFrameTarget *target) +SrsRtcFrameBuilder::SrsRtcFrameBuilder(ISrsAppFactory *factory, ISrsFrameTarget *target) { frame_target_ = target; is_first_audio_ = true; audio_transcoder_ = NULL; video_codec_ = SrsVideoCodecIdAVC; - audio_cache_ = new SrsRtcFrameBuilderAudioPacketCache(); + audio_cache_ = factory->create_rtc_frame_builder_audio_packet_cache(); video_cache_ = new SrsRtcFrameBuilderVideoPacketCache(); frame_detector_ = new SrsRtcFrameBuilderVideoFrameDetector(video_cache_); sync_state_ = -1; obs_whip_vps_ = obs_whip_sps_ = obs_whip_pps_ = NULL; + + app_factory_ = factory; } SrsRtcFrameBuilder::~SrsRtcFrameBuilder() @@ -1774,6 +1807,8 @@ SrsRtcFrameBuilder::~SrsRtcFrameBuilder() srs_freep(obs_whip_vps_); srs_freep(obs_whip_sps_); srs_freep(obs_whip_pps_); + + app_factory_ = NULL; } srs_error_t SrsRtcFrameBuilder::initialize(ISrsRequest *r, SrsAudioCodecId audio_codec, SrsVideoCodecId video_codec) @@ -1781,7 +1816,7 @@ srs_error_t SrsRtcFrameBuilder::initialize(ISrsRequest *r, SrsAudioCodecId audio srs_error_t err = srs_success; srs_freep(audio_transcoder_); - audio_transcoder_ = new SrsAudioTranscoder(); + audio_transcoder_ = app_factory_->create_audio_transcoder(); SrsAudioCodecId to = SrsAudioCodecIdAAC; // The output audio codec. int channels = 2; // The output audio channels. @@ -1820,8 +1855,9 @@ srs_error_t SrsRtcFrameBuilder::on_rtp(SrsRtpPacket *pkt) return err; } - // Have no received any sender report, can't calculate avsync_time, - // discard it to avoid timestamp problem in live source + // Check if avsync_time is valid (> 0). + // NOTE: This check should NEVER fail unless SDP has no sample rate, in which case packets are discarded + // to avoid timestamp problems in live source. const SrsRtpHeader &h = pkt->header_; if (pkt->get_avsync_time() <= 0) { if (sync_state_ < 0) { @@ -1879,6 +1915,9 @@ srs_error_t SrsRtcFrameBuilder::transcode_audio(SrsRtpPacket *pkt) int header_len = 0; uint8_t *header = NULL; audio_transcoder_->aac_codec_header(&header, &header_len); + if (header_len <= 0) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "no aac header"); + } SrsRtmpCommonMessage out_rtmp; packet_aac(&out_rtmp, (char *)header, header_len, ts, is_first_audio_); @@ -3089,7 +3128,7 @@ ISrsRtcPacketReceiver::~ISrsRtcPacketReceiver() { } -SrsRtcRecvTrack::SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool is_audio) +SrsRtcRecvTrack::SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool is_audio, bool init_rate_from_sdp) { receiver_ = receiver; track_desc_ = track_desc->copy(); @@ -3105,7 +3144,17 @@ SrsRtcRecvTrack::SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDes last_sender_report_rtp_time_ = 0; last_sender_report_rtp_time1_ = 0; + + // Initialize rate from SDP sample rate + // rate_ is RTP units per millisecond (e.g., 90 for video 90kHz, 48 for audio 48kHz) + // This allows immediate A/V sync before receiving 2 RTCP SR packets + // Will be updated to precise rate after receiving 2nd SR rate_ = 0.0; + if (init_rate_from_sdp && track_desc_->media_) { + rate_ = static_cast(track_desc_->media_->sample_) / 1000.0; + srs_trace("RTC: Init %s track, ssrc=%u, rate from SDP=%.0f (RTP units per ms, will be updated after 2nd SR)", + track_desc_->type_.c_str(), track_desc_->ssrc_, rate_); + } last_sender_report_sys_time_ = 0; } @@ -3163,8 +3212,14 @@ void SrsRtcRecvTrack::update_send_report_time(const SrsNtp &ntp, uint32_t rtp_ti double rtp_time_elpased = static_cast(last_sender_report_rtp_time_) - static_cast(last_sender_report_rtp_time1_); double rate = round(rtp_time_elpased / sys_time_elapsed); - // TODO: FIXME: use the sample rate from sdp. if (rate > 0) { + if (rate_ != rate) { + srs_warn("RTC: SR update %s, ssrc=%u, ntp_ms=%u->%u (delta=%.0fms), rtp_time=%u->%u (delta=%.0f), rate %.0f->%.0f", + track_desc_->type_.c_str(), track_desc_->ssrc_, + last_sender_report_ntp1_.system_ms_, last_sender_report_ntp_.system_ms_, sys_time_elapsed, + (uint32_t)last_sender_report_rtp_time1_, (uint32_t)last_sender_report_rtp_time_, rtp_time_elpased, + rate_, rate); + } rate_ = rate; } } @@ -3282,8 +3337,8 @@ srs_error_t SrsRtcRecvTrack::do_check_send_nacks(uint32_t &timeout_nacks) return err; } -SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc) - : SrsRtcRecvTrack(receiver, track_desc, true) +SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool init_rate_from_sdp) + : SrsRtcRecvTrack(receiver, track_desc, true, init_rate_from_sdp) { } @@ -3330,8 +3385,8 @@ srs_error_t SrsRtcAudioRecvTrack::check_send_nacks() return err; } -SrsRtcVideoRecvTrack::SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc) - : SrsRtcRecvTrack(receiver, track_desc, false) +SrsRtcVideoRecvTrack::SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool init_rate_from_sdp) + : SrsRtcRecvTrack(receiver, track_desc, false, init_rate_from_sdp) { } diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 3021562ee..dba5e8b03 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -44,6 +44,7 @@ class SrsRtpVideoBuilder; class ISrsRtcConsumer; class ISrsCircuitBreaker; class ISrsRtcPublishStream; +class ISrsAppFactory; // Firefox defaults as 109, Chrome is 111. const int kAudioPayloadType = 111; @@ -227,11 +228,12 @@ class SrsRtcSource : public ISrsRtpTarget, public ISrsFastTimerHandler, public I { // clang-format off SRS_DECLARE_PRIVATE: // clang-format on - // The RTP bridge, convert RTP packets to other protocols. - ISrsRtcBridge *rtc_bridge_; + ISrsAppFactory *app_factory_; // clang-format off SRS_DECLARE_PRIVATE: // clang-format on + // The RTP bridge, convert RTP packets to other protocols. + ISrsRtcBridge *rtc_bridge_; // Circuit breaker for protecting server resources. ISrsCircuitBreaker *circuit_breaker_; // For publish, it's the publish client id. @@ -347,6 +349,10 @@ SRS_DECLARE_PRIVATE: // clang-format on // Convert AV frame to RTC RTP packets. class SrsRtcRtpBuilder { +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; + // clang-format off SRS_DECLARE_PRIVATE: // clang-format on ISrsRequest *req_; @@ -380,7 +386,7 @@ SRS_DECLARE_PRIVATE: // clang-format on bool video_initialized_; public: - SrsRtcRtpBuilder(ISrsRtpTarget *target, SrsSharedPtr source); + SrsRtcRtpBuilder(ISrsAppFactory *factory, ISrsRtpTarget *target, SrsSharedPtr source); virtual ~SrsRtcRtpBuilder(); // clang-format off @@ -419,9 +425,25 @@ SRS_DECLARE_PRIVATE: // clang-format on srs_error_t consume_packets(std::vector &pkts); }; +// Video packet cache interface +class ISrsRtcFrameBuilderVideoPacketCache +{ +public: + ISrsRtcFrameBuilderVideoPacketCache(); + virtual ~ISrsRtcFrameBuilderVideoPacketCache(); + +public: + virtual SrsRtpPacket *get_packet(uint16_t sequence_number) = 0; + virtual void store_packet(SrsRtpPacket *pkt) = 0; + virtual void clear_all() = 0; + virtual SrsRtpPacket *take_packet(uint16_t sequence_number) = 0; + virtual int32_t find_next_lost_sn(uint16_t current_sn, uint16_t header_sn, uint16_t &end_sn) = 0; + virtual bool check_frame_complete(const uint16_t start, const uint16_t end) = 0; +}; + // Video packet cache for RTP packet management // TODO: Maybe should use SrsRtpRingBuffer? -class SrsRtcFrameBuilderVideoPacketCache +class SrsRtcFrameBuilderVideoPacketCache : public ISrsRtcFrameBuilderVideoPacketCache { // clang-format off SRS_DECLARE_PRIVATE: // clang-format on @@ -462,18 +484,33 @@ SRS_DECLARE_PRIVATE: // clang-format on } }; +// Video frame detector interface +class ISrsRtcFrameBuilderVideoFrameDetector +{ +public: + ISrsRtcFrameBuilderVideoFrameDetector(); + virtual ~ISrsRtcFrameBuilderVideoFrameDetector(); + +public: + virtual void on_keyframe_start(SrsRtpPacket *pkt) = 0; + virtual srs_error_t detect_frame(uint16_t received, uint16_t &frame_start, uint16_t &frame_end, bool &frame_ready) = 0; + virtual srs_error_t detect_next_frame(uint16_t next_head, uint16_t &next_start, uint16_t &next_end, bool &next_ready) = 0; + virtual void on_keyframe_detached() = 0; + virtual bool is_lost_sn(uint16_t received) = 0; +}; + // Video frame detector for managing frame boundaries and packet loss detection -class SrsRtcFrameBuilderVideoFrameDetector +class SrsRtcFrameBuilderVideoFrameDetector : public ISrsRtcFrameBuilderVideoFrameDetector { // clang-format off SRS_DECLARE_PRIVATE: // clang-format on - SrsRtcFrameBuilderVideoPacketCache *video_cache_; + ISrsRtcFrameBuilderVideoPacketCache *video_cache_; uint16_t header_sn_; uint16_t lost_sn_; int64_t rtp_key_frame_ts_; public: - SrsRtcFrameBuilderVideoFrameDetector(SrsRtcFrameBuilderVideoPacketCache *cache); + SrsRtcFrameBuilderVideoFrameDetector(ISrsRtcFrameBuilderVideoPacketCache *cache); virtual ~SrsRtcFrameBuilderVideoFrameDetector(); public: @@ -484,8 +521,20 @@ public: bool is_lost_sn(uint16_t received); }; +// Audio packet cache interface +class ISrsRtcFrameBuilderAudioPacketCache +{ +public: + ISrsRtcFrameBuilderAudioPacketCache(); + virtual ~ISrsRtcFrameBuilderAudioPacketCache(); + +public: + virtual srs_error_t process_packet(SrsRtpPacket *src, std::vector &ready_packets) = 0; + virtual void clear_all() = 0; +}; + // Audio packet cache for RTP packet jitter buffer management -class SrsRtcFrameBuilderAudioPacketCache +class SrsRtcFrameBuilderAudioPacketCache : public ISrsRtcFrameBuilderAudioPacketCache { // clang-format off SRS_DECLARE_PRIVATE: // clang-format on @@ -518,6 +567,10 @@ public: // Collect and build WebRTC RTP packets to AV frames. class SrsRtcFrameBuilder { +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; + // clang-format off SRS_DECLARE_PRIVATE: // clang-format on ISrsFrameTarget *frame_target_; @@ -530,9 +583,9 @@ SRS_DECLARE_PRIVATE: // clang-format on // clang-format off SRS_DECLARE_PRIVATE: // clang-format on - SrsRtcFrameBuilderAudioPacketCache *audio_cache_; - SrsRtcFrameBuilderVideoPacketCache *video_cache_; - SrsRtcFrameBuilderVideoFrameDetector *frame_detector_; + ISrsRtcFrameBuilderAudioPacketCache *audio_cache_; + ISrsRtcFrameBuilderVideoPacketCache *video_cache_; + ISrsRtcFrameBuilderVideoFrameDetector *frame_detector_; // clang-format off SRS_DECLARE_PRIVATE: // clang-format on @@ -547,7 +600,7 @@ SRS_DECLARE_PRIVATE: // clang-format on SrsRtpPacket *obs_whip_pps_; public: - SrsRtcFrameBuilder(ISrsFrameTarget *target); + SrsRtcFrameBuilder(ISrsAppFactory *factory, ISrsFrameTarget *target); virtual ~SrsRtcFrameBuilder(); public: @@ -830,7 +883,7 @@ SRS_DECLARE_PROTECTED: // clang-format on uint64_t last_sender_report_sys_time_; public: - SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs, bool is_audio); + SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs, bool is_audio, bool init_rate_from_sdp); virtual ~SrsRtcRecvTrack(); public: @@ -864,7 +917,7 @@ SRS_DECLARE_PROTECTED: // clang-format on class SrsRtcAudioRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler { public: - SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc); + SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool init_rate_from_sdp); virtual ~SrsRtcAudioRecvTrack(); public: @@ -878,7 +931,7 @@ public: class SrsRtcVideoRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler { public: - SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs); + SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs, bool init_rate_from_sdp); virtual ~SrsRtcVideoRecvTrack(); public: diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index a116b3f69..3370fa55d 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -16,6 +16,7 @@ using namespace std; #include #include +#include #include #include #include @@ -229,6 +230,7 @@ SrsRtmpConn::SrsRtmpConn(ISrsRtmpTransport *transport, string cip, int cport) publish_1stpkt_timeout_ = 0; publish_normal_timeout_ = 0; + app_factory_ = _srs_app_factory; config_ = _srs_config; manager_ = _srs_conn_manager; stream_publish_tokens_ = _srs_stream_publish_tokens; @@ -269,6 +271,7 @@ SrsRtmpConn::~SrsRtmpConn() srs_freep(refer_); srs_freep(security_); + app_factory_ = NULL; config_ = NULL; manager_ = NULL; stream_publish_tokens_ = NULL; @@ -1064,7 +1067,7 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsSharedPtr source) // Bridge to RTC streaming. // TODO: FIXME: Need to convert RTMP to SRT. - SrsRtmpBridge *bridge = new SrsRtmpBridge(); + SrsRtmpBridge *bridge = new SrsRtmpBridge(app_factory_); #if defined(SRS_FFMPEG_FIT) bool rtmp_to_rtc = config_->get_rtc_from_rtmp(req->vhost_); diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index cb8f46c91..133e6df88 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -47,6 +47,7 @@ class ISrsStreamPublishTokenManager; class ISrsLiveSourceManager; class ISrsStatistic; class ISrsHttpHooks; +class ISrsAppFactory; class ISrsRtcSourceManager; class ISrsSrtSourceManager; class ISrsRtspSourceManager; @@ -174,6 +175,7 @@ class SrsRtmpConn : public ISrsConnection, // It's a resource. // clang-format off SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; ISrsResourceManager *manager_; ISrsAppConfig *config_; ISrsStreamPublishTokenManager *stream_publish_tokens_; diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 1e84714ba..619726a16 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -9,6 +9,7 @@ using namespace std; #include +#include #include #include #include @@ -501,7 +502,7 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish() } // Bridge to RTMP and RTC streaming. - SrsSrtBridge *bridge = new SrsSrtBridge(); + SrsSrtBridge *bridge = new SrsSrtBridge(_srs_app_factory); bool srt_to_rtmp = config_->get_srt_to_rtmp(req_->vhost_); if (srt_to_rtmp && edge) { @@ -620,14 +621,15 @@ srs_error_t SrsMpegtsSrtConn::do_playing() int nb_packets = 0; while (true) { - if ((err = trd_->pull()) != srs_success) { - return srs_error_wrap(err, "srt play thread"); - } - + // Check recv thread error first, so we can detect the client disconnecting event. if ((err = srt_recv_trd.get_recv_err()) != srs_success) { return srs_error_wrap(err, "srt play recv thread"); } + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "srt play thread"); + } + // Wait for amount of packets. SrsSrtPacket *pkt_raw = NULL; consumer->dump_packet(&pkt_raw); diff --git a/trunk/src/app/srs_app_stream_bridge.cpp b/trunk/src/app/srs_app_stream_bridge.cpp index eefcd50f1..6e8921d65 100644 --- a/trunk/src/app/srs_app_stream_bridge.cpp +++ b/trunk/src/app/srs_app_stream_bridge.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,7 @@ ISrsRtmpBridge::~ISrsRtmpBridge() { } -SrsRtmpBridge::SrsRtmpBridge() +SrsRtmpBridge::SrsRtmpBridge(ISrsAppFactory *factory) { #ifdef SRS_FFMPEG_FIT rtp_builder_ = NULL; @@ -63,6 +64,8 @@ SrsRtmpBridge::SrsRtmpBridge() rtsp_target_ = NULL; #endif rtc_target_ = NULL; + + app_factory_ = factory; } SrsRtmpBridge::~SrsRtmpBridge() @@ -75,6 +78,8 @@ SrsRtmpBridge::~SrsRtmpBridge() rtsp_target_ = NULL; #endif rtc_target_ = NULL; + + app_factory_ = NULL; } bool SrsRtmpBridge::empty() @@ -111,7 +116,7 @@ srs_error_t SrsRtmpBridge::initialize(ISrsRequest *r) #ifdef SRS_FFMPEG_FIT if (rtc_target_.get()) { srs_freep(rtp_builder_); - rtp_builder_ = new SrsRtcRtpBuilder(rtc_target_.get(), rtc_target_); + rtp_builder_ = new SrsRtcRtpBuilder(app_factory_, rtc_target_.get(), rtc_target_); if ((err = rtp_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "rtp builder initialize"); } @@ -211,7 +216,7 @@ ISrsSrtBridge::~ISrsSrtBridge() { } -SrsSrtBridge::SrsSrtBridge() +SrsSrtBridge::SrsSrtBridge(ISrsAppFactory *factory) { frame_builder_ = new SrsSrtFrameBuilder(this); rtmp_target_ = NULL; @@ -220,6 +225,8 @@ SrsSrtBridge::SrsSrtBridge() rtp_builder_ = NULL; #endif rtc_target_ = NULL; + + app_factory_ = factory; } SrsSrtBridge::~SrsSrtBridge() @@ -231,6 +238,8 @@ SrsSrtBridge::~SrsSrtBridge() #ifdef SRS_FFMPEG_FIT srs_freep(rtp_builder_); #endif + + app_factory_ = NULL; } bool SrsSrtBridge::empty() @@ -259,7 +268,7 @@ srs_error_t SrsSrtBridge::initialize(ISrsRequest *r) #ifdef SRS_FFMPEG_FIT if (rtc_target_.get()) { srs_freep(rtp_builder_); - rtp_builder_ = new SrsRtcRtpBuilder(rtc_target_.get(), rtc_target_); + rtp_builder_ = new SrsRtcRtpBuilder(app_factory_, rtc_target_.get(), rtc_target_); if ((err = rtp_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "rtp builder initialize"); } @@ -356,13 +365,15 @@ ISrsRtcBridge::~ISrsRtcBridge() { } -SrsRtcBridge::SrsRtcBridge() +SrsRtcBridge::SrsRtcBridge(ISrsAppFactory *factory) { req_ = NULL; #ifdef SRS_FFMPEG_FIT frame_builder_ = NULL; #endif rtmp_target_ = NULL; + + app_factory_ = factory; } SrsRtcBridge::~SrsRtcBridge() @@ -372,6 +383,8 @@ SrsRtcBridge::~SrsRtcBridge() srs_freep(frame_builder_); #endif rtmp_target_ = NULL; + + app_factory_ = NULL; } void SrsRtcBridge::enable_rtc2rtmp(SrsSharedPtr rtmp_target) @@ -394,7 +407,7 @@ srs_error_t SrsRtcBridge::initialize(ISrsRequest *r) #ifdef SRS_FFMPEG_FIT srs_assert(rtmp_target_.get()); srs_freep(frame_builder_); - frame_builder_ = new SrsRtcFrameBuilder(rtmp_target_.get()); + frame_builder_ = app_factory_->create_rtc_frame_builder(rtmp_target_.get()); #endif return err; diff --git a/trunk/src/app/srs_app_stream_bridge.hpp b/trunk/src/app/srs_app_stream_bridge.hpp index 7257e7c52..c6fddccad 100644 --- a/trunk/src/app/srs_app_stream_bridge.hpp +++ b/trunk/src/app/srs_app_stream_bridge.hpp @@ -28,6 +28,7 @@ class SrsRtcFrameBuilder; class ISrsStreamBridge; class SrsSrtFrameBuilder; class SrsSrtPacket; +class ISrsAppFactory; // A target to feed AV frame, such as a RTMP live source, or a RTMP bridge // that take frame and converts to RTC packets, or a SRT bridge that converts @@ -85,6 +86,10 @@ public: // Then, deliver the RTP packets to RTP target, which binds to a RTC/RTSP source. class SrsRtmpBridge : public ISrsRtmpBridge { +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; + // clang-format off SRS_DECLARE_PRIVATE: // clang-format on #ifdef SRS_FFMPEG_FIT @@ -100,7 +105,7 @@ SRS_DECLARE_PRIVATE: // clang-format on #endif public: - SrsRtmpBridge(); + SrsRtmpBridge(ISrsAppFactory *factory); virtual ~SrsRtmpBridge(); public: @@ -136,6 +141,10 @@ public: // Then, deliver the AV frames to frame target, which binds to a RTMP/RTC source. class SrsSrtBridge : public ISrsSrtBridge, public ISrsFrameTarget { +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; + // clang-format off SRS_DECLARE_PRIVATE: // clang-format on // Convert SRT TS packets to media frame packets. @@ -150,7 +159,7 @@ SRS_DECLARE_PRIVATE: // clang-format on SrsSharedPtr rtc_target_; public: - SrsSrtBridge(); + SrsSrtBridge(ISrsAppFactory *factory); virtual ~SrsSrtBridge(); public: @@ -186,6 +195,10 @@ public: // Then, deliver the RTMP frame packet to RTMP target, which binds to a live source. class SrsRtcBridge : public ISrsRtcBridge { +// clang-format off +SRS_DECLARE_PRIVATE: // clang-format on + ISrsAppFactory *app_factory_; + // clang-format off SRS_DECLARE_PRIVATE: // clang-format on ISrsRequest *req_; @@ -197,7 +210,7 @@ SRS_DECLARE_PRIVATE: // clang-format on SrsSharedPtr rtmp_target_; public: - SrsRtcBridge(); + SrsRtcBridge(ISrsAppFactory *factory); virtual ~SrsRtcBridge(); public: diff --git a/trunk/src/kernel/srs_kernel_packet.cpp b/trunk/src/kernel/srs_kernel_packet.cpp index 790306e15..dfc8481b0 100644 --- a/trunk/src/kernel/srs_kernel_packet.cpp +++ b/trunk/src/kernel/srs_kernel_packet.cpp @@ -142,6 +142,25 @@ srs_error_t SrsParsedPacket::add_sample(char *bytes, int size) return err; } +SrsParsedPacket *SrsParsedPacket::copy() +{ + SrsParsedPacket *p = new SrsParsedPacket(); + do_copy(p); + return p; +} + +void SrsParsedPacket::do_copy(SrsParsedPacket *p) +{ + p->codec_ = codec_; + p->nb_samples_ = nb_samples_; + for (int i = 0; i < nb_samples_; i++) { + p->samples_[i].size_ = samples_[i].size_; + p->samples_[i].bytes_ = samples_[i].bytes_; + } + p->dts_ = dts_; + p->cts_ = cts_; +} + SrsParsedAudioPacket::SrsParsedAudioPacket() { aac_packet_type_ = SrsAudioAacFrameTraitForbidden; @@ -156,6 +175,16 @@ SrsAudioCodecConfig *SrsParsedAudioPacket::acodec() return (SrsAudioCodecConfig *)codec_; } +SrsParsedAudioPacket *SrsParsedAudioPacket::copy() +{ + SrsParsedAudioPacket *p = new SrsParsedAudioPacket(); + + do_copy(p); + p->aac_packet_type_ = aac_packet_type_; + + return p; +} + SrsParsedVideoPacket::SrsParsedVideoPacket() { frame_type_ = SrsVideoAvcFrameTypeForbidden; @@ -213,6 +242,21 @@ srs_error_t SrsParsedVideoPacket::add_sample(char *bytes, int size) return err; } +SrsParsedVideoPacket *SrsParsedVideoPacket::copy() +{ + SrsParsedVideoPacket *p = new SrsParsedVideoPacket(); + + do_copy(p); + p->frame_type_ = frame_type_; + p->avc_packet_type_ = avc_packet_type_; + p->has_idr_ = has_idr_; + p->has_aud_ = has_aud_; + p->has_sps_pps_ = has_sps_pps_; + p->first_nalu_type_ = first_nalu_type_; + + return p; +} + SrsVideoCodecConfig *SrsParsedVideoPacket::vcodec() { return (SrsVideoCodecConfig *)codec_; diff --git a/trunk/src/kernel/srs_kernel_packet.hpp b/trunk/src/kernel/srs_kernel_packet.hpp index 3ac7609cb..23d4cf1f0 100644 --- a/trunk/src/kernel/srs_kernel_packet.hpp +++ b/trunk/src/kernel/srs_kernel_packet.hpp @@ -109,6 +109,12 @@ public: virtual srs_error_t initialize(SrsCodecConfig *c); // Add a sample to frame. virtual srs_error_t add_sample(char *bytes, int size); + +// clang-format off +SRS_DECLARE_PROTECTED: // clang-format on + // Copy the packet. + virtual SrsParsedPacket *copy(); + virtual void do_copy(SrsParsedPacket *p); }; // A parsed audio packet, besides a frame, contains the audio frame info, such as frame type. @@ -123,6 +129,10 @@ public: public: virtual SrsAudioCodecConfig *acodec(); + +// clang-format off +SRS_DECLARE_PROTECTED: // clang-format on + virtual SrsParsedAudioPacket *copy(); }; // A parsed video packet, besides a frame, contains the video frame info, such as frame type. @@ -151,6 +161,10 @@ public: // Add the sample without ANNEXB or IBMF header, or RAW AAC or MP3 data. virtual srs_error_t add_sample(char *bytes, int size); +// clang-format off +SRS_DECLARE_PROTECTED: // clang-format on + virtual SrsParsedVideoPacket *copy(); + public: virtual SrsVideoCodecConfig *vcodec(); diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index b94b1323c..a20439151 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -35,6 +35,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -63,6 +64,11 @@ SrsConfig *_srs_config = NULL; ISrsAppFactory *_srs_app_factory = new SrsAppFactory(); ISrsKernelFactory *_srs_kernel_factory = _srs_app_factory; +#ifdef SRS_FFMPEG_FIT +// Register FFmpeg log callback funciton. +SrsFFmpegLogHelper _srs_ffmpeg_log_helper; +#endif + // @global version of srs, which can grep keyword "XCORE" extern const char *_srs_version; diff --git a/trunk/src/protocol/srs_protocol_http_stack.cpp b/trunk/src/protocol/srs_protocol_http_stack.cpp index 6afcb3398..ceedfc223 100644 --- a/trunk/src/protocol/srs_protocol_http_stack.cpp +++ b/trunk/src/protocol/srs_protocol_http_stack.cpp @@ -1165,7 +1165,7 @@ srs_error_t SrsHttpAuthMux::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag { srs_error_t err; if ((err = do_auth(w, r)) != srs_success) { - srs_error("do_auth %s", srs_error_desc(err).c_str()); + srs_warn("do_auth %s", srs_error_desc(err).c_str()); srs_freep(err); w->write_header(SRS_CONSTS_HTTP_Unauthorized); return w->final_request(); diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index aa24ee97d..2dd89f953 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -32,6 +32,7 @@ using namespace std; // For TCP test server and client #include +#include #include // Temporary disk config. @@ -53,6 +54,11 @@ bool _srs_config_by_env = false; ISrsAppFactory *_srs_app_factory = new SrsAppFactory(); ISrsKernelFactory *_srs_kernel_factory = _srs_app_factory; +#ifdef SRS_FFMPEG_FIT +// Register FFmpeg log callback funciton. +SrsFFmpegLogHelper _srs_ffmpeg_log_helper; +#endif + // The binary name of SRS. const char *_srs_binary = NULL; @@ -97,6 +103,11 @@ srs_error_t prepare_main() return srs_error_wrap(err, "srt log initialize"); } +#ifdef SRS_FFMPEG_FIT + // Disable FFmpeg detail log in utest. + _srs_ffmpeg_log_helper.disable_ffmpeg_log(); +#endif + // Prevent the output of srt logs in utest. srt_setloghandler(NULL, srs_srt_utest_null_log_handler); // Set SRT log level to FATAL to suppress ERROR and WARNING logs in unit tests. diff --git a/trunk/src/utest/srs_utest_ai08.cpp b/trunk/src/utest/srs_utest_ai08.cpp index 130381dae..7d5f69dca 100644 --- a/trunk/src/utest/srs_utest_ai08.cpp +++ b/trunk/src/utest/srs_utest_ai08.cpp @@ -242,7 +242,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_BasicFunctionality) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); // Test initial state - bridge should be empty EXPECT_TRUE(bridge->empty()); @@ -260,7 +260,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_WithRtcTarget) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create and enable RTC target first @@ -287,7 +287,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_WithRtspTarget) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create and enable RTSP target first @@ -313,7 +313,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_WithRtcAndRtspTargets) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create and enable both RTC and RTSP targets @@ -348,7 +348,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspTargetReplacement) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Set first RTSP target @@ -377,7 +377,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_FrameHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -407,7 +407,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameRtpBuilder) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Test frame handling without any targets first @@ -444,7 +444,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameRtspBuilder) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -479,7 +479,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameBothBuilders) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Enable both RTC and RTSP targets @@ -512,7 +512,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_BasicFunctionality) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); // Test initial state - bridge should be empty EXPECT_TRUE(bridge->empty()); @@ -530,7 +530,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_WithRtmpTarget) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -558,7 +558,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_WithRtcTarget) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create and enable RTC target first @@ -584,7 +584,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_PacketHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -606,7 +606,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_FrameHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -628,7 +628,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameRtmpTarget) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -662,7 +662,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameRtpBuilder) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -697,7 +697,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameBothTargets) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Enable both RTMP and RTC targets @@ -728,7 +728,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameBothTargets) // Test SrsRtcBridge basic functionality VOID TEST(StreamBridgeTest, SrsRtcBridge_BasicFunctionality) { - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); // Test initial state - bridge should be empty EXPECT_TRUE(bridge->empty()); @@ -740,7 +740,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_BasicFunctionality) // Test SrsRtcBridge with RTMP target VOID TEST(StreamBridgeTest, SrsRtcBridge_WithRtmpTarget) { - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); // Create a mock RTMP target using shared pointer SrsSharedPtr rtmp_source(new SrsLiveSource()); @@ -758,7 +758,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpPacketHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTMP target for the bridge @@ -793,7 +793,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpPacketTypes) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTMP target for the bridge @@ -829,7 +829,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpWithoutFrameBuilder) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Test RTP handling without proper initialization (no frame builder) @@ -844,7 +844,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpLifecycle) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTMP target @@ -877,7 +877,7 @@ VOID TEST(StreamBridgeTest, Bridge_ErrorHandling) srs_error_t err; // Test SrsRtmpBridge with invalid frame - SrsUniquePtr rtmp_bridge(new SrsRtmpBridge()); + SrsUniquePtr rtmp_bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); HELPER_EXPECT_SUCCESS(rtmp_bridge->initialize(req.get())); @@ -886,7 +886,7 @@ VOID TEST(StreamBridgeTest, Bridge_ErrorHandling) HELPER_EXPECT_SUCCESS(rtmp_bridge->on_frame(NULL)); // Test SrsSrtBridge with invalid packet - SrsUniquePtr srt_bridge(new SrsSrtBridge()); + SrsUniquePtr srt_bridge(new SrsSrtBridge(_srs_app_factory)); HELPER_EXPECT_SUCCESS(srt_bridge->initialize(req.get())); // Note: Skip NULL packet test as it causes segmentation fault @@ -899,7 +899,7 @@ VOID TEST(StreamBridgeTest, Bridge_LifecycleManagement) srs_error_t err; // Test multiple initialize calls - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // First initialize @@ -930,7 +930,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_MultipleTargets) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -970,7 +970,7 @@ VOID TEST(StreamBridgeTest, Bridge_TargetReplacement) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Initialize bridge @@ -1001,7 +1001,7 @@ VOID TEST(StreamBridgeTest, Bridge_StateConsistency) { srs_error_t err; - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Test empty state consistency @@ -1029,7 +1029,7 @@ VOID TEST(StreamBridgeTest, Bridge_MemoryManagement) // Test that bridges properly manage their internal components { - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); HELPER_EXPECT_SUCCESS(bridge->initialize(req.get())); @@ -1048,7 +1048,7 @@ VOID TEST(StreamBridgeTest, Bridge_MemoryManagement) } { - SrsUniquePtr bridge(new SrsSrtBridge()); + SrsUniquePtr bridge(new SrsSrtBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); HELPER_EXPECT_SUCCESS(bridge->initialize(req.get())); @@ -1064,7 +1064,7 @@ VOID TEST(StreamBridgeTest, Bridge_MemoryManagement) } { - SrsUniquePtr bridge(new SrsRtcBridge()); + SrsUniquePtr bridge(new SrsRtcBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); SrsSharedPtr rtmp_source(new SrsLiveSource()); @@ -1086,7 +1086,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspFrameHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create and enable RTSP target @@ -1115,7 +1115,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspLifecycle) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Test lifecycle without target @@ -1143,7 +1143,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspErrorHandling) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTSP target @@ -1167,7 +1167,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspMemoryManagement) // Test multiple RTSP bridge creation and destruction for (int i = 0; i < 5; ++i) { - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); SrsSharedPtr rtsp_source(new SrsRtspSource()); @@ -1192,7 +1192,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtmpToRtspConversion) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTSP target for protocol conversion @@ -1227,7 +1227,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspCodecChanges) { srs_error_t err; - SrsUniquePtr bridge(new SrsRtmpBridge()); + SrsUniquePtr bridge(new SrsRtmpBridge(_srs_app_factory)); SrsUniquePtr req(new MockStreamBridgeRequest()); // Create RTSP target @@ -1265,7 +1265,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1344,7 +1344,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringAVC) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1425,7 +1425,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1500,7 +1500,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1587,7 +1587,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterIDRDetection) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1641,7 +1641,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterErrorHandling) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1687,7 +1687,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterNonAVCCodecSkipsSEIFiltering) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1755,7 +1755,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterZeroSamples) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1797,7 +1797,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1871,7 +1871,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoLargeNaluPackageFuA) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -1956,7 +1956,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoExtremelyLargeNaluPackageFuA HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2036,7 +2036,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusWithMultipleNalus) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2119,7 +2119,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMultipleLargeNalusPackageFuA HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2199,7 +2199,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusLargePayload) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2286,7 +2286,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioRealAacFrames) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2353,7 +2353,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioAddSampleFailure) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2409,7 +2409,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioTranscodeFailure) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2463,7 +2463,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioMemoryCleanup) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2522,7 +2522,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2587,7 +2587,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoUnsupportedCodec) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2627,7 +2627,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoNoVcodecParsed) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2666,7 +2666,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2730,7 +2730,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2815,7 +2815,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFormatError) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2878,7 +2878,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2956,7 +2956,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_BasicInstantiation) MockRtpTarget rtp_target; // Test basic instantiation - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -2976,7 +2976,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_InitializeAudioTrack) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder first HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3022,7 +3022,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_InitializeVideoTrack) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder first HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3068,7 +3068,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_TrackInitializationCodecs) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder first HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3166,7 +3166,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_TrackInitializationWithSourceTracks rtc_source->set_stream_desc(source_desc); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3220,7 +3220,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioFormatConsumeSuccess) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3282,7 +3282,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioFormatConsumeError) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3328,7 +3328,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioNoAcodecParsed) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3377,7 +3377,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioUnsupportedCodec) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3456,7 +3456,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioSupportedCodecs) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3543,7 +3543,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioCodecValidationFailure) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3606,7 +3606,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioComprehensiveCoverage) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3709,7 +3709,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_LazyInitialization) HELPER_EXPECT_SUCCESS(rtc_source->initialize(req.get())); MockRtpTarget rtp_target; - SrsRtcRtpBuilder builder(&rtp_target, rtc_source); + SrsRtcRtpBuilder builder(_srs_app_factory, &rtp_target, rtc_source); // Initialize the builder HELPER_EXPECT_SUCCESS(builder.initialize(req.get())); @@ -3796,8 +3796,8 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_MultipleBuilders) srs_error_t err; MockRtcFrameTarget target1, target2; - SrsRtcFrameBuilder builder1(&target1); - SrsRtcFrameBuilder builder2(&target2); + SrsRtcFrameBuilder builder1(_srs_app_factory, &target1); + SrsRtcFrameBuilder builder2(_srs_app_factory, &target2); // Initialize both builders SrsUniquePtr req1(new MockRtcRequest("vhost1", "app1", "stream1")); @@ -3826,14 +3826,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_Success) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(2); // Mock transcoder will output 2 packets // Access private member through friendship (utests have access to private members) @@ -3873,14 +3873,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_TranscoderError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); srs_error_t mock_error = srs_error_new(ERROR_RTC_RTP_MUXER, "mock transcoder error"); mock_transcoder->set_transcode_error(mock_error); @@ -3918,14 +3918,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_FrameTargetError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(1); // Mock transcoder will output 1 packet builder.audio_transcoder_ = mock_transcoder; @@ -3965,14 +3965,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_MultipleOutputPackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(5); // Mock transcoder will output 5 packets builder.audio_transcoder_ = mock_transcoder; @@ -4011,14 +4011,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_NoOutputPackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(0); // Mock transcoder will output 0 packets builder.audio_transcoder_ = mock_transcoder; @@ -4055,14 +4055,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_FrameTargetErrorOnTranscodedFrame) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(3); // Mock transcoder will output 3 packets builder.audio_transcoder_ = mock_transcoder; @@ -4126,14 +4126,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_SpecificCodePath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); // Set up mock transcoder to output packets with specific timestamps and sample data const char sample_data[] = {0x21, 0x10, 0x04, 0x60, (char)0x8C}; // Mock AAC data @@ -4187,14 +4187,14 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_ErrorInTranscoderLoop) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(3); // Mock transcoder will output 3 packets builder.audio_transcoder_ = mock_transcoder; @@ -4257,7 +4257,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_CompleteFrameDetectionWithPacketVideo srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4308,7 +4308,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_IsLostSnTrueErrorPath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4379,7 +4379,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_PreciseLostSequenceScenario) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4438,7 +4438,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoRtmp_RecursiveCallErrorHandling) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4506,7 +4506,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_ExactIsLostSnCodePathCoverage srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); diff --git a/trunk/src/utest/srs_utest_ai09.cpp b/trunk/src/utest/srs_utest_ai09.cpp index 03c5498ab..0769ed5c8 100644 --- a/trunk/src/utest/srs_utest_ai09.cpp +++ b/trunk/src/utest/srs_utest_ai09.cpp @@ -50,21 +50,24 @@ void MockRtcFrameTarget::reset() srs_freep(frame_error_); } -MockAudioTranscoder::MockAudioTranscoder() +MockAudioTranscoderForUtest::MockAudioTranscoderForUtest() { transcode_error_ = srs_success; should_output_packets_ = false; - aac_header_data_ = NULL; - aac_header_len_ = 0; + // Set default AAC header for mock transcoder + aac_header_len_ = 2; + aac_header_data_ = new uint8_t[aac_header_len_]; + aac_header_data_[0] = 0x12; // Mock AAC header byte 1 + aac_header_data_[1] = 0x10; // Mock AAC header byte 2 } -MockAudioTranscoder::~MockAudioTranscoder() +MockAudioTranscoderForUtest::~MockAudioTranscoderForUtest() { reset(); srs_freepa(aac_header_data_); } -srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate) +srs_error_t MockAudioTranscoderForUtest::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate) { // Create default AAC header for testing if (!aac_header_data_) { @@ -76,7 +79,7 @@ srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecI return srs_success; } -srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector &outs) +srs_error_t MockAudioTranscoderForUtest::transcode(SrsParsedAudioPacket *in, std::vector &outs) { if (transcode_error_ != srs_success) { return srs_error_copy(transcode_error_); @@ -105,7 +108,7 @@ srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector return srs_success; } -void MockAudioTranscoder::free_frames(std::vector &frames) +void MockAudioTranscoderForUtest::free_frames(std::vector &frames) { for (std::vector::iterator it = frames.begin(); it != frames.end(); ++it) { SrsParsedAudioPacket *p = *it; @@ -119,13 +122,13 @@ void MockAudioTranscoder::free_frames(std::vector &frame } } -void MockAudioTranscoder::aac_codec_header(uint8_t **data, int *len) +void MockAudioTranscoderForUtest::aac_codec_header(uint8_t **data, int *len) { *data = aac_header_data_; *len = aac_header_len_; } -void MockAudioTranscoder::reset() +void MockAudioTranscoderForUtest::reset() { srs_freep(transcode_error_); @@ -141,7 +144,7 @@ void MockAudioTranscoder::reset() should_output_packets_ = false; } -void MockAudioTranscoder::set_output_packets(int count, const char *sample_data, int sample_size) +void MockAudioTranscoderForUtest::set_output_packets(int count, const char *sample_data, int sample_size) { reset(); should_output_packets_ = true; @@ -167,7 +170,7 @@ void MockAudioTranscoder::set_output_packets(int count, const char *sample_data, } } -void MockAudioTranscoder::set_transcode_error(srs_error_t err) +void MockAudioTranscoderForUtest::set_transcode_error(srs_error_t err) { srs_freep(transcode_error_); transcode_error_ = srs_error_copy(err); @@ -362,7 +365,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -385,7 +388,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_InitialState) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -407,7 +410,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_StateZero) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -431,7 +434,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ValidAvsyncTime_SyncStateTransition) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -457,7 +460,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ValidAvsyncTime_SyncStateAlreadyTwo) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -483,7 +486,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_AudioPacketProcessing) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -508,7 +511,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_VideoPacketProcessing) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -529,7 +532,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_MixedAudioVideoPackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -555,7 +558,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_DifferentSSRCValues) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -580,7 +583,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_DifferentSequenceNumbers) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -605,7 +608,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_DifferentTimestamps) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -630,7 +633,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_SyncStateTransitions) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -664,7 +667,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_BoundaryAvsyncTimeValues) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -696,7 +699,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NullPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -713,7 +716,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_RapidPacketSequence) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -738,7 +741,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_AlternatingAudioVideo) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -763,7 +766,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcPayload_WithVPSS srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -786,7 +789,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcPayload_MissingV srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -829,7 +832,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcPayload_MissingS srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -872,7 +875,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcPayload_MissingP srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -915,7 +918,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipVPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -955,7 +958,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -995,7 +998,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1035,7 +1038,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipMissingVPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1074,7 +1077,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipMissingSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1113,7 +1116,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_OBSWhipMissingPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1152,7 +1155,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcWithOBSWhipVPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1204,7 +1207,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcWithOBSWhipSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1256,7 +1259,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_STAPHevcWithOBSWhipPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1308,7 +1311,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_NonHEVCCodec) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec (not HEVC) SrsUniquePtr req(new MockRtcRequest()); @@ -1331,7 +1334,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_NonVPSSPSPPSRawPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1354,7 +1357,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_NullPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1385,7 +1388,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_CacheResetAfterUse) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1432,7 +1435,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderHevc_ComprehensiveCoverage) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1479,7 +1482,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_SameTimestampDifferentSequence) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1504,7 +1507,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_FrameTargetError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1529,7 +1532,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_FrameTargetError) VOID TEST(RtcFrameBuilderTest, OnRtp_UninitializedBuilder) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Do NOT initialize the builder @@ -1553,7 +1556,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_LargePayloadPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1584,7 +1587,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ZeroLengthPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1615,7 +1618,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_MaxSequenceNumber) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1639,7 +1642,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_MaxTimestamp) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1663,7 +1666,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ComprehensiveCoverage) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1705,7 +1708,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_TraceLogScenarios) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1739,7 +1742,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ComprehensiveCodePathCoverage) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -1848,7 +1851,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_WithSPSAndPP srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1871,7 +1874,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_MissingSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1909,7 +1912,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_MissingPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1947,7 +1950,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_OBSWhipSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -1979,7 +1982,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_OBSWhipPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2011,7 +2014,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_OBSWhipMissingSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2042,7 +2045,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_OBSWhipMissingPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2073,7 +2076,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAWithOBSWhipSPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2120,7 +2123,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAWithOBSWhipPPS) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2167,7 +2170,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_NonSPSPPSRawPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2190,7 +2193,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_EmptySTAPAPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2224,7 +2227,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_FrameTargetError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2249,7 +2252,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_CacheCleanup) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2284,7 +2287,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_NoSTAPANoRawPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2320,7 +2323,7 @@ VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_ComprehensiveCoverage) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2359,7 +2362,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ExactSyncStateTransitions) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -2394,7 +2397,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_AvsyncTimeBoundaryConditions) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -2427,7 +2430,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_AudioPacketProcessingPath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -2466,7 +2469,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_VideoPacketProcessingPath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -2501,7 +2504,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_MixedAudioVideoWithPayloads) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -2565,7 +2568,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_ErrorHandlingPacketVideoRtmpFails) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2618,7 +2621,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_FrameTargetFailureInPacketVideoRtmp) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2661,7 +2664,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_LostPacketRecoveryErrorPath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2703,7 +2706,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_MultipleFrameCompletionErrorHandling) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2752,7 +2755,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_HEVCCodecErrorHandling) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2845,7 +2848,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_BoundarySequenceNumbersErrorHandling) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2891,7 +2894,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_ErrorHandlingPacketVideoRtmpF srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -2934,7 +2937,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_HEVCErrorHandling) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3001,7 +3004,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_LostSequenceNumberErrorPath) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3045,7 +3048,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_SequenceHeaderAndFrameErrors) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3084,7 +3087,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_BoundarySequenceNumbers) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3128,7 +3131,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_ComprehensiveErrorPathCoverag srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3187,7 +3190,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ErrorPropagationFromPacketAudio) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3212,7 +3215,7 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ErrorPropagationFromPacketVideo) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3237,7 +3240,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SinglePacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3279,7 +3282,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MultipleSequentialPackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3319,7 +3322,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3380,7 +3383,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3433,7 +3436,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3488,7 +3491,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets) VOID TEST(RtcFrameBuilderTest, PacketAudio_NullPacket) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3515,7 +3518,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_NoPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3548,7 +3551,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ZeroLengthPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3583,7 +3586,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LargePayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3620,7 +3623,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_FrameTargetError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3661,7 +3664,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3717,7 +3720,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3773,7 +3776,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3824,7 +3827,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -3867,7 +3870,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_VPSPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3905,7 +3908,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_STAPAPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3953,7 +3956,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_FUAPayloadIDR) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -3993,7 +3996,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_FUAPayloadNonIDR) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4033,7 +4036,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_AudioPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4068,7 +4071,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_AudioPacket) VOID TEST(RtcFrameBuilderTest, PacketVideo_NullPacket) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4094,7 +4097,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_NoPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4124,7 +4127,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_ZeroLengthPayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4159,7 +4162,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_LargePayload) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4196,7 +4199,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_SequenceWrapAround) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4245,7 +4248,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_TimestampWrapAround) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4294,7 +4297,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_DifferentSSRC) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4340,7 +4343,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_FrameTargetError) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4382,7 +4385,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_RapidSequence) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4425,7 +4428,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_MixedKeyframeSequence) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4474,7 +4477,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_KeyframeAVC) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4512,7 +4515,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_KeyframeHEVC) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with HEVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4550,7 +4553,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_NonKeyframe) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4588,7 +4591,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_SPSPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4626,7 +4629,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_PPSPacket) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); @@ -4664,7 +4667,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4706,7 +4709,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder SrsUniquePtr req(new MockRtcRequest()); @@ -4783,7 +4786,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideoKeyFrame_OutOfOrderKeyframePackets) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtcRequest()); diff --git a/trunk/src/utest/srs_utest_ai09.hpp b/trunk/src/utest/srs_utest_ai09.hpp index df79788ec..e61905081 100644 --- a/trunk/src/utest/srs_utest_ai09.hpp +++ b/trunk/src/utest/srs_utest_ai09.hpp @@ -39,7 +39,7 @@ public: }; // Mock audio transcoder for testing SrsRtcFrameBuilder::transcode_audio -class MockAudioTranscoder : public ISrsAudioTranscoder +class MockAudioTranscoderForUtest : public ISrsAudioTranscoder { public: // Control behavior @@ -50,8 +50,8 @@ public: int aac_header_len_; public: - MockAudioTranscoder(); - virtual ~MockAudioTranscoder(); + MockAudioTranscoderForUtest(); + virtual ~MockAudioTranscoderForUtest(); public: // ISrsAudioTranscoder interface diff --git a/trunk/src/utest/srs_utest_ai10.cpp b/trunk/src/utest/srs_utest_ai10.cpp index a95ffbbcd..1a655668e 100644 --- a/trunk/src/utest/srs_utest_ai10.cpp +++ b/trunk/src/utest/srs_utest_ai10.cpp @@ -63,7 +63,7 @@ SrsCodecPayload *create_test_codec_payload(uint8_t pt, std::string name, int sam VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeBasic) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test with NULL packet int null_size = builder.calculate_packet_payload_size(NULL); @@ -84,7 +84,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeBasic) VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeFUA) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.264 FU-A payload (SrsRtpFUAPayload2) - start fragment SrsUniquePtr fua_start_pkt(new SrsRtpPacket()); @@ -149,7 +149,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeFUA) VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeSTAP) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.264 STAP-A payload (SrsRtpSTAPPayload) with multiple NALUs SrsUniquePtr stap_pkt(new SrsRtpPacket()); @@ -221,7 +221,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeSTAP) VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeFUAHevc) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.265 FU-A payload (SrsRtpFUAPayloadHevc2) - start fragment SrsUniquePtr fua_hevc_start_pkt(new SrsRtpPacket()); @@ -286,7 +286,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeFUAHevc) VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeSTAPHevc) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.265 STAP payload (SrsRtpSTAPPayloadHevc) with multiple NALUs SrsUniquePtr stap_hevc_pkt(new SrsRtpPacket()); @@ -366,7 +366,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeSTAPHevc) VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeEdgeCases) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test with unknown payload type (should fall through to default case) SrsUniquePtr unknown_pkt(new SrsRtpPacket()); @@ -394,7 +394,7 @@ VOID TEST(SrsRtcFrameBuilderTest, CalculatePacketPayloadSizeEdgeCases) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferRaw) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with raw payload SrsUniquePtr pkt(new SrsRtpPacket()); @@ -435,7 +435,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferRaw) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAStart) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.264 FU-A start fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -482,7 +482,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAStart) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAMiddle) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.264 FU-A middle fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -523,7 +523,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAMiddle) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAEnd) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.264 FU-A end fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -579,7 +579,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAEnd) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevc) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.265 FU-A start fragment SrsUniquePtr hevc_pkt(new SrsRtpPacket()); @@ -623,7 +623,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevc) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAEdgeCases) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Test H.264 FU-A with zero-size payload SrsUniquePtr zero_pkt(new SrsRtpPacket()); @@ -694,7 +694,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAEdgeCases) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUASequence) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); char buffer_data[1024]; SrsBuffer buffer(buffer_data, sizeof(buffer_data)); @@ -782,7 +782,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUASequence) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAP) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.264 STAP payload SrsUniquePtr pkt(new SrsRtpPacket()); @@ -857,7 +857,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAP) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAPWithEmptyNALUs) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.264 STAP payload SrsUniquePtr pkt(new SrsRtpPacket()); @@ -930,7 +930,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAPWithEmptyNALUs) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcStart) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.265 FU-A start fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -978,7 +978,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcStart) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcMiddle) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.265 FU-A middle fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -1018,7 +1018,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcMiddle) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcEnd) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.265 FU-A end fragment SrsUniquePtr pkt(new SrsRtpPacket()); @@ -1073,7 +1073,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferFUAHevcEnd) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAPHevc) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.265 STAP payload SrsUniquePtr pkt(new SrsRtpPacket()); @@ -1148,7 +1148,7 @@ VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAPHevc) VOID TEST(SrsRtcFrameBuilderTest, WritePacketPayloadToBufferSTAPHevcWithEmptyNALUs) { MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Create test RTP packet with H.265 STAP payload SrsUniquePtr pkt(new SrsRtpPacket()); @@ -1229,7 +1229,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluBasic) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1280,7 +1280,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluNoNextFrame) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1323,7 +1323,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluRecursiveCall) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1377,7 +1377,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluMultipleEmptyFrames) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1438,7 +1438,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluZeroSizePayloads) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1497,7 +1497,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluHevc) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.265 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1548,7 +1548,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluSequenceWrapAround) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -1597,7 +1597,7 @@ VOID TEST(SrsRtcFrameBuilderTest, PacketVideoRtmpEmptyNaluFrameProcessing) srs_error_t err; MockRtcFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize builder with H.264 codec SrsUniquePtr req(new MockRtcRequest()); @@ -2253,7 +2253,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadEmptyBuffer) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2276,7 +2276,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264RawNALU) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2307,7 +2307,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264STAP) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2342,7 +2342,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264FUA) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2376,7 +2376,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCRawNALU) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H265", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2407,7 +2407,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCSTAP) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H265", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2444,7 +2444,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCFUA) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H265", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2479,7 +2479,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadUnknownCodec) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("VP8", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2510,7 +2510,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadNoMediaCodec) srs_freep(desc->media_); desc->media_ = NULL; - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2529,7 +2529,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264IDR) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2560,7 +2560,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCIDR) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H265", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2591,7 +2591,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadSingleByte) { MockRtcPacketReceiver mock_receiver; SrsUniquePtr desc(create_video_track_description("H264", 12345)); - SrsRtcVideoRecvTrack track(&mock_receiver, desc.get()); + SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false); SrsUniquePtr pkt(create_test_rtp_packet(100, 1000, 12345)); @@ -2928,7 +2928,7 @@ VOID TEST(SrsRtcAudioRecvTrackTest, OnBeforeDecodePayload) // Create the audio receive track MockRtcPacketReceiver mock_receiver; - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc, false); // Test case 1: Empty buffer - should return early without setting payload { @@ -2996,7 +2996,7 @@ VOID TEST(SrsRtcAudioRecvTrackTest, CheckSendNacksWithMock) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("audio", 12345)); - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get()); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get(), false); // Test case 1: Basic check_send_nacks call - should execute successfully HELPER_EXPECT_SUCCESS(audio_track.check_send_nacks()); @@ -3017,7 +3017,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, CheckSendNacksWithMock) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("video", 54321)); - SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get()); + SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get(), false); // Test case 1: Basic check_send_nacks call - should execute successfully HELPER_EXPECT_SUCCESS(video_track.check_send_nacks()); @@ -3038,7 +3038,7 @@ VOID TEST(SrsRtcRecvTrackTest, DoCheckSendNacksBasic) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("audio", 98765)); - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get()); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get(), false); // Test case 1: do_check_send_nacks should execute successfully uint32_t timeout_nacks = 999; @@ -3060,7 +3060,7 @@ VOID TEST(SrsRtcAudioRecvTrackTest, CheckSendNacksMultipleCalls) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("audio", 11111)); - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get()); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get(), false); // Test multiple consecutive calls - all should succeed HELPER_EXPECT_SUCCESS(audio_track.check_send_nacks()); @@ -3079,7 +3079,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, CheckSendNacksTimeoutScenarios) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("video", 22222)); - SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get()); + SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get(), false); // Test multiple calls - all should succeed HELPER_EXPECT_SUCCESS(video_track.check_send_nacks()); @@ -3106,7 +3106,7 @@ VOID TEST(SrsRtcRecvTrackTest, DoCheckSendNacksDifferentSSRC) uint32_t test_ssrc = test_ssrcs[i]; SrsUniquePtr track_desc(create_test_track_description("video", test_ssrc)); - SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get()); + SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get(), false); uint32_t timeout_nacks = 999; HELPER_EXPECT_SUCCESS(video_track.do_check_send_nacks(timeout_nacks)); @@ -3123,7 +3123,7 @@ VOID TEST(SrsRtcAudioRecvTrackTest, CheckSendNacksEdgeCases) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("audio", 33333)); - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get()); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc.get(), false); // Test multiple calls with different scenarios - all should succeed HELPER_EXPECT_SUCCESS(audio_track.check_send_nacks()); @@ -3142,7 +3142,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, CheckSendNacksEdgeCases) MockRtcPacketReceiver mock_receiver; SrsUniquePtr track_desc(create_test_track_description("video", 44444)); - SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get()); + SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc.get(), false); // Test multiple calls with different scenarios - all should succeed HELPER_EXPECT_SUCCESS(video_track.check_send_nacks()); @@ -3163,8 +3163,8 @@ VOID TEST(SrsRtcRecvTrackTest, NackReceiverParameterPassing) SrsUniquePtr track_desc1(create_test_track_description("audio", 55555)); SrsUniquePtr track_desc2(create_test_track_description("video", 66666)); - SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc1.get()); - SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc2.get()); + SrsRtcAudioRecvTrack audio_track(&mock_receiver, track_desc1.get(), false); + SrsRtcVideoRecvTrack video_track(&mock_receiver, track_desc2.get(), false); // Test audio track functionality uint32_t timeout_nacks = 0; diff --git a/trunk/src/utest/srs_utest_ai11.cpp b/trunk/src/utest/srs_utest_ai11.cpp index 5fb340550..59d4674fc 100644 --- a/trunk/src/utest/srs_utest_ai11.cpp +++ b/trunk/src/utest/srs_utest_ai11.cpp @@ -1835,7 +1835,7 @@ VOID TEST(RtcPublishStreamTest, SendRtcpXrRrtr) audio_desc->id_ = "audio_track_1"; audio_desc->ssrc_ = 12345; audio_desc->is_active_ = true; - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc, false); publish_stream->audio_tracks_.push_back(audio_track); // Create video track @@ -1844,7 +1844,7 @@ VOID TEST(RtcPublishStreamTest, SendRtcpXrRrtr) video_desc->id_ = "video_track_1"; video_desc->ssrc_ = 67890; video_desc->is_active_ = true; - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc, false); publish_stream->video_tracks_.push_back(video_track); // Test successful case @@ -1899,8 +1899,8 @@ VOID TEST(RtcPublishStreamTest, SendRtcpRrSuccess) audio_track_desc->ssrc_ = 67890; // Create video and audio recv tracks - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc.get()); - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc.get()); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc.get(), false); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc.get(), false); // Add tracks to publish stream (using private member access) // The publish stream will take ownership and free them in destructor @@ -1934,7 +1934,7 @@ VOID TEST(RtcPublishStreamTest, SendRtcpRrVideoTrackError) video_track_desc->ssrc_ = 12345; // Create video recv track - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc.get()); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc.get(), false); // Add track to publish stream (only video track to simplify) publish_stream->video_tracks_.push_back(video_track); @@ -2003,10 +2003,10 @@ VOID TEST(RtcPublishStreamTest, SendRtcpRrMultipleTracks) audio_track_desc2->ssrc_ = 67891; // Create tracks - SrsRtcVideoRecvTrack *video_track1 = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc1.get()); - SrsRtcVideoRecvTrack *video_track2 = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc2.get()); - SrsRtcAudioRecvTrack *audio_track1 = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc1.get()); - SrsRtcAudioRecvTrack *audio_track2 = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc2.get()); + SrsRtcVideoRecvTrack *video_track1 = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc1.get(), false); + SrsRtcVideoRecvTrack *video_track2 = new SrsRtcVideoRecvTrack(&mock_receiver, video_track_desc2.get(), false); + SrsRtcAudioRecvTrack *audio_track1 = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc1.get(), false); + SrsRtcAudioRecvTrack *audio_track2 = new SrsRtcAudioRecvTrack(&mock_receiver, audio_track_desc2.get(), false); // Add tracks to publish stream publish_stream->video_tracks_.push_back(video_track1); diff --git a/trunk/src/utest/srs_utest_ai12.cpp b/trunk/src/utest/srs_utest_ai12.cpp index 8b5cd25dd..e97d0f3ec 100644 --- a/trunk/src/utest/srs_utest_ai12.cpp +++ b/trunk/src/utest/srs_utest_ai12.cpp @@ -23,7 +23,7 @@ extern bool srs_sdp_has_h264_profile(const SrsSdp &sdp, const string &profile); // Mock video recv track implementation MockRtcVideoRecvTrackForNack::MockRtcVideoRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc) - : SrsRtcVideoRecvTrack(receiver, track_desc) + : SrsRtcVideoRecvTrack(receiver, track_desc, false) { check_send_nacks_error_ = srs_success; check_send_nacks_count_ = 0; @@ -52,7 +52,7 @@ void MockRtcVideoRecvTrackForNack::reset() // Mock audio recv track implementation MockRtcAudioRecvTrackForNack::MockRtcAudioRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc) - : SrsRtcAudioRecvTrack(receiver, track_desc) + : SrsRtcAudioRecvTrack(receiver, track_desc, false) { check_send_nacks_error_ = srs_success; check_send_nacks_count_ = 0; @@ -200,7 +200,7 @@ VOID TEST(SrsRtcPublishStreamTest, OnRtpPlaintextTypicalScenario) video_desc.id_ = "video_track_test"; video_desc.ssrc_ = 0xDEF01234; // SSRC from RTP packet (0xDE, 0xF0, 0x12, 0x34) video_desc.is_active_ = true; - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc, false); publish_stream->video_tracks_.push_back(video_track); // Enable tracks for processing @@ -308,12 +308,12 @@ VOID TEST(SrsRtcPublishStreamTest, OnBeforeDecodePayloadTypicalScenario) // Create video track with proper codec payload SrsUniquePtr video_desc(create_video_track_description_with_codec("H264", 0x12345678)); - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc.get()); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc.get(), false); publish_stream->video_tracks_.push_back(video_track); // Create audio track with proper codec payload SrsUniquePtr audio_desc(create_test_track_description("audio", 0x87654321)); - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get()); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get(), false); publish_stream->audio_tracks_.push_back(audio_track); // Test scenario 1: Empty buffer - should return early without processing @@ -484,7 +484,7 @@ VOID TEST(SrsRtcPublishStreamTest, OnRtcpXrPathTypicalScenario) video_desc.id_ = "video_track_xr_path_test"; video_desc.ssrc_ = 0x12345678; video_desc.is_active_ = true; - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc, false); publish_stream->video_tracks_.push_back(video_track); // Create a valid RTCP XR packet with DLRR block (block type 5) @@ -535,7 +535,7 @@ VOID TEST(SrsRtcPublishStreamTest, OnRtcpXrTypicalScenario) video_desc.id_ = "video_track_xr_test"; video_desc.ssrc_ = 0x12345678; video_desc.is_active_ = true; - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc, false); publish_stream->video_tracks_.push_back(video_track); // Create a valid RTCP XR packet with DLRR block (block type 5) @@ -625,7 +625,7 @@ VOID TEST(SrsRtcPublishStreamTest, UpdateRttTypicalScenario) audio_desc.id_ = "audio_track_rtt_test"; audio_desc.ssrc_ = 0x87654321; audio_desc.is_active_ = true; - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, &audio_desc); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, &audio_desc, false); publish_stream->audio_tracks_.push_back(audio_track); // Test typical RTT update scenario for audio track @@ -660,7 +660,7 @@ VOID TEST(SrsRtcPublishStreamTest, UpdateSendReportTimeTypicalScenario) // Create test audio track SrsUniquePtr audio_desc(create_test_track_description("audio", 0x87654321)); audio_desc->media_ = new SrsAudioPayload(111, "opus", 48000, 2); - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get()); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get(), false); publish_stream->audio_tracks_.push_back(audio_track); // Test typical scenario: update send report time for audio track @@ -740,7 +740,7 @@ VOID TEST(SrsRtcPublishStreamTest, DoOnRtpPlaintextAudioTrackTypicalScenario) // Create audio track with matching SSRC for the RTP packet SrsUniquePtr audio_desc(create_test_track_description("audio", 0x87654321)); audio_desc->media_ = new SrsAudioPayload(111, "opus", 48000, 2); - SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get()); + SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get(), false); publish_stream->audio_tracks_.push_back(audio_track); // The publish stream already has its own source_ created in constructor, no need to create a new one @@ -2266,7 +2266,7 @@ VOID TEST(SrsRtcConnectionTest, OnRtpPlaintextTypicalScenario) // Create video track with matching SSRC for the RTP packet using helper function SrsUniquePtr video_desc(create_video_track_description_with_codec("H264", test_ssrc)); - SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc.get()); + SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc.get(), false); publish_stream->video_tracks_.push_back(video_track); // Enable tracks for processing diff --git a/trunk/src/utest/srs_utest_ai24.cpp b/trunk/src/utest/srs_utest_ai24.cpp new file mode 100644 index 000000000..362f41cd4 --- /dev/null +++ b/trunk/src/utest/srs_utest_ai24.cpp @@ -0,0 +1,305 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// +#include + +#include +#include +#include +#include + +using namespace std; + +// Mock class to access protected members of SrsRtcRecvTrack +class MockSrsRtcRecvTrackForAVSync : public SrsRtcRecvTrack +{ + SRS_DECLARE_PRIVATE: + static SrsRtcTrackDescription* create_track_desc(const string& type, uint32_t ssrc, int sample_rate) + { + SrsRtcTrackDescription *desc = new SrsRtcTrackDescription(); + desc->type_ = type; + desc->id_ = "test_track"; + desc->ssrc_ = ssrc; + desc->is_active_ = true; + + // Create media description with sample rate + desc->media_ = new SrsAudioPayload(); + desc->media_->sample_ = sample_rate; + + return desc; + } + +public: + MockSrsRtcRecvTrackForAVSync(const string &type, uint32_t ssrc, int sample_rate, bool is_audio) + : SrsRtcRecvTrack(NULL, create_track_desc(type, ssrc, sample_rate), is_audio, true) + { + } + + // Expose protected methods for testing + double get_rate() const { return rate_; } + + void set_rate(double rate) { rate_ = rate; } + + int64_t test_cal_avsync_time(uint32_t rtp_time) + { + return cal_avsync_time(rtp_time); + } + + void test_update_send_report_time(const SrsNtp &ntp, uint32_t rtp_time) + { + update_send_report_time(ntp, rtp_time); + } + + // Implement pure virtual methods + virtual srs_error_t on_rtp(SrsSharedPtr &source, SrsRtpPacket *pkt) + { + return srs_success; + } + + virtual srs_error_t check_send_nacks() + { + return srs_success; + } +}; + +// Test: Rate initialization from SDP for audio track (48kHz) +VOID TEST(RtcAVSyncTest, AudioRateInitFromSDP) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // Rate should be initialized to 48 (48000 Hz / 1000 = 48 RTP units per ms) + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); +} + +// Test: Rate initialization from SDP for video track (90kHz) +VOID TEST(RtcAVSyncTest, VideoRateInitFromSDP) +{ + MockSrsRtcRecvTrackForAVSync track("video", 67890, 90000, false); + + // Rate should be initialized to 90 (90000 Hz / 1000 = 90 RTP units per ms) + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); +} + +// Test: cal_avsync_time with SDP rate (before receiving SR) +VOID TEST(RtcAVSyncTest, CalAVSyncTimeWithSDPRate) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // Simulate first SR received + SrsNtp ntp; + ntp.system_ms_ = 1000; // 1000 ms + uint32_t rtp_time = 48000; // 48000 RTP units + track.test_update_send_report_time(ntp, rtp_time); + + // Calculate avsync time for a later RTP packet + // RTP time: 48000 + 4800 = 52800 (100ms later at 48kHz) + // Expected avsync_time: 1000 + (52800 - 48000) / 48 = 1000 + 100 = 1100 ms + int64_t avsync_time = track.test_cal_avsync_time(52800); + EXPECT_EQ(1100, avsync_time); +} + +// Test: cal_avsync_time returns -1 when rate is 0 +VOID TEST(RtcAVSyncTest, CalAVSyncTimeWithZeroRate) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // Manually set rate to 0 + track.set_rate(0.0); + + // Should return -1 when rate is too small + int64_t avsync_time = track.test_cal_avsync_time(1000); + EXPECT_EQ(-1, avsync_time); +} + +// Test: Rate update after receiving 2nd SR (audio) +VOID TEST(RtcAVSyncTest, AudioRateUpdateAfter2ndSR) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // Initial rate from SDP + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 48000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Rate should still be 48 (from SDP) + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); + + // Second SR (20ms later, RTP increased by 960) + SrsNtp ntp2; + ntp2.system_ms_ = 1020; // 20ms later + uint32_t rtp_time2 = 48960; // 960 RTP units later (48 * 20) + track.test_update_send_report_time(ntp2, rtp_time2); + + // Rate should be updated to calculated value: 960 / 20 = 48 + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); +} + +// Test: Rate update after receiving 2nd SR (video) +VOID TEST(RtcAVSyncTest, VideoRateUpdateAfter2ndSR) +{ + MockSrsRtcRecvTrackForAVSync track("video", 67890, 90000, false); + + // Initial rate from SDP + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 2000; + uint32_t rtp_time1 = 180000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Rate should still be 90 (from SDP) + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); + + // Second SR (100ms later, RTP increased by 9000) + SrsNtp ntp2; + ntp2.system_ms_ = 2100; // 100ms later + uint32_t rtp_time2 = 189000; // 9000 RTP units later (90 * 100) + track.test_update_send_report_time(ntp2, rtp_time2); + + // Rate should be updated to calculated value: 9000 / 100 = 90 + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); +} + +// Test: Rate calculation with clock drift (slightly off from SDP) +VOID TEST(RtcAVSyncTest, RateUpdateWithClockDrift) +{ + MockSrsRtcRecvTrackForAVSync track("video", 67890, 90000, false); + + // Initial rate from SDP + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 90000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Second SR with slight clock drift + // Expected: 100ms -> 9000 RTP units + // Actual: 100ms -> 9010 RTP units (slight drift) + SrsNtp ntp2; + ntp2.system_ms_ = 1100; + uint32_t rtp_time2 = 99010; // Slightly more than expected + track.test_update_send_report_time(ntp2, rtp_time2); + + // Rate should be updated to: round(9010 / 100) = 90 + EXPECT_DOUBLE_EQ(90.0, track.get_rate()); +} + +// Test: Rate calculation with larger time interval +VOID TEST(RtcAVSyncTest, RateUpdateWithLargeInterval) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 5000; + uint32_t rtp_time1 = 240000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Second SR (1000ms later) + SrsNtp ntp2; + ntp2.system_ms_ = 6000; + uint32_t rtp_time2 = 288000; // 48000 RTP units later (48 * 1000) + track.test_update_send_report_time(ntp2, rtp_time2); + + // Rate should be: 48000 / 1000 = 48 + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); +} + +// Test: cal_avsync_time with precise rate after 2nd SR +VOID TEST(RtcAVSyncTest, CalAVSyncTimeAfter2ndSR) +{ + MockSrsRtcRecvTrackForAVSync track("video", 67890, 90000, false); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 90000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Second SR + SrsNtp ntp2; + ntp2.system_ms_ = 1100; + uint32_t rtp_time2 = 99000; + track.test_update_send_report_time(ntp2, rtp_time2); + + // Now calculate avsync time for a packet + // RTP time: 99000 + 4500 = 103500 (50ms later at 90kHz) + // Expected: 1100 + (103500 - 99000) / 90 = 1100 + 50 = 1150 ms + int64_t avsync_time = track.test_cal_avsync_time(103500); + EXPECT_EQ(1150, avsync_time); +} + +// Test: Immediate A/V sync availability (issue #4418 fix) +VOID TEST(RtcAVSyncTest, ImmediateAVSyncAvailability) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // Before any SR, rate should be available from SDP + EXPECT_DOUBLE_EQ(48.0, track.get_rate()); + + // First SR received + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 48000; + track.test_update_send_report_time(ntp1, rtp_time1); + + // Should be able to calculate avsync_time immediately (not -1) + int64_t avsync_time = track.test_cal_avsync_time(48480); // 10ms later + EXPECT_GT(avsync_time, 0); // Should be > 0, not -1 + EXPECT_EQ(1010, avsync_time); // Should be 1000 + 10 = 1010 +} + +// Test: RTP timestamp wraparound handling +VOID TEST(RtcAVSyncTest, RTPTimestampWraparound) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // First SR near wraparound + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 0xFFFFF000; // Near max uint32_t + track.test_update_send_report_time(ntp1, rtp_time1); + + // Second SR after wraparound + SrsNtp ntp2; + ntp2.system_ms_ = 1020; // 20ms later + uint32_t rtp_time2 = 0x000003C0; // Wrapped around, 960 units after wraparound + track.test_update_send_report_time(ntp2, rtp_time2); + + // Note: Current implementation may not handle wraparound correctly + // This test documents the current behavior + // Rate calculation: (0x000003C0 - 0xFFFFF000) will underflow + // This is a known limitation that may need fixing in the future +} + +// Test: Zero time elapsed between SRs (edge case) +VOID TEST(RtcAVSyncTest, ZeroTimeElapsedBetweenSRs) +{ + MockSrsRtcRecvTrackForAVSync track("audio", 12345, 48000, true); + + // First SR + SrsNtp ntp1; + ntp1.system_ms_ = 1000; + uint32_t rtp_time1 = 48000; + track.test_update_send_report_time(ntp1, rtp_time1); + + double rate_before = track.get_rate(); + + // Second SR with same timestamp (0ms elapsed) + SrsNtp ntp2; + ntp2.system_ms_ = 1000; // Same time + uint32_t rtp_time2 = 48000; // Same RTP time + track.test_update_send_report_time(ntp2, rtp_time2); + + // Rate should remain unchanged (SDP rate) + EXPECT_DOUBLE_EQ(rate_before, track.get_rate()); +} diff --git a/trunk/src/utest/srs_utest_ai24.hpp b/trunk/src/utest/srs_utest_ai24.hpp new file mode 100644 index 000000000..1a34c0082 --- /dev/null +++ b/trunk/src/utest/srs_utest_ai24.hpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// +#ifndef SRS_UTEST_AI_RTC_AVSYNC_HPP +#define SRS_UTEST_AI_RTC_AVSYNC_HPP + +#include + +#endif diff --git a/trunk/src/utest/srs_utest_manual_app_rtc2rtmp.cpp b/trunk/src/utest/srs_utest_manual_app_rtc2rtmp.cpp index 615afd157..1fa3caf90 100644 --- a/trunk/src/utest/srs_utest_manual_app_rtc2rtmp.cpp +++ b/trunk/src/utest/srs_utest_manual_app_rtc2rtmp.cpp @@ -334,7 +334,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_SameKeyframeTimestampVideoSequence) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -404,7 +404,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_SameStapForIdrVideoSequence) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -456,7 +456,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_DifferentKeyframeTimestampVideoSequen srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -524,7 +524,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_TypicalVideoSequence) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -595,7 +595,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_SingleVideoSequence) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -652,7 +652,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_SingleVideoSequence_LargePFrame) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -728,7 +728,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_AcceptableVideoSequence) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -792,7 +792,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_EmptyIDRBeforeNormalFrames) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -855,7 +855,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_EmptyIDRBeforeNormalFrames_FUA) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -917,7 +917,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_BaselinePackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -985,7 +985,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_NoSpsPpsPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1044,7 +1044,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_ReorderingIdrPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1113,7 +1113,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_PframeBeforeIdrPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1188,7 +1188,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_PframeReorderingPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1262,7 +1262,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_IdrPframeReorderingPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1341,7 +1341,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketVideo_PframeLostPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with AVC codec SrsUniquePtr req(new MockRtc2RtmpRequest()); @@ -1402,14 +1402,14 @@ VOID TEST(Rtc2RtmpConvertTest, PacketAudio_ThreeAudioPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with Opus codec (typical for WebRTC) SrsUniquePtr req(new MockRtc2RtmpRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdOpus, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock to avoid FFmpeg issues - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(1); // Each input packet produces 1 output packet // Access private member through friendship (utests have access to private members) @@ -1452,14 +1452,14 @@ VOID TEST(Rtc2RtmpConvertTest, PacketAudio_ReorderingAudioPackets) srs_error_t err; MockRtc2RtmpFrameTarget target; - SrsRtcFrameBuilder builder(&target); + SrsRtcFrameBuilder builder(_srs_app_factory, &target); // Initialize the builder with Opus codec (typical for WebRTC) SrsUniquePtr req(new MockRtc2RtmpRequest()); HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdOpus, SrsVideoCodecIdAVC)); // Replace the audio transcoder with our mock to avoid FFmpeg issues - MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder(); + MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest(); mock_transcoder->set_output_packets(1); // Each input packet produces 1 output packet // Access private member through friendship (utests have access to private members) diff --git a/trunk/src/utest/srs_utest_manual_mock.cpp b/trunk/src/utest/srs_utest_manual_mock.cpp index 858b21f88..efd8932a8 100644 --- a/trunk/src/utest/srs_utest_manual_mock.cpp +++ b/trunk/src/utest/srs_utest_manual_mock.cpp @@ -180,6 +180,10 @@ MockRtcTrackDescriptionFactory::MockRtcTrackDescriptionFactory() audio_ssrc_ = 12345; video_ssrc_ = 67890; screen_ssrc_ = 98765; + + audio_pt_ = 111; + video_pt_ = 96; + screen_pt_ = 97; } MockRtcTrackDescriptionFactory::~MockRtcTrackDescriptionFactory() @@ -227,12 +231,17 @@ SrsRtcTrackDescription *MockRtcTrackDescriptionFactory::create_audio_track(uint3 audio_desc->is_active_ = true; audio_desc->direction_ = "sendrecv"; audio_desc->mid_ = mid; - audio_desc->media_ = new SrsAudioPayload(111, "opus", 48000, 2); + audio_desc->media_ = new SrsAudioPayload(audio_pt_, "opus", 48000, 2); return audio_desc; } SrsRtcTrackDescription *MockRtcTrackDescriptionFactory::create_video_track(uint32_t ssrc, std::string id, std::string mid) { + uint8_t pt = video_pt_; + if (ssrc == screen_ssrc_) { + pt = screen_pt_; + } + SrsRtcTrackDescription *video_desc = new SrsRtcTrackDescription(); video_desc->type_ = "video"; video_desc->ssrc_ = ssrc; @@ -240,7 +249,7 @@ SrsRtcTrackDescription *MockRtcTrackDescriptionFactory::create_video_track(uint3 video_desc->is_active_ = true; video_desc->direction_ = "sendrecv"; video_desc->mid_ = mid; - video_desc->media_ = new SrsVideoPayload(96, "H264", 90000); + video_desc->media_ = new SrsVideoPayload(pt, "H264", 90000); return video_desc; } @@ -294,6 +303,21 @@ ISrsRequest *MockRtcAsyncCallRequest::as_http() return this; } +MockRtcSource::MockRtcSource() +{ + on_rtp_count_ = 0; +} + +MockRtcSource::~MockRtcSource() +{ +} + +srs_error_t MockRtcSource::on_rtp(SrsRtpPacket *pkt) +{ + on_rtp_count_++; + return SrsRtcSource::on_rtp(pkt); +} + // MockRtcSourceManager implementation MockRtcSourceManager::MockRtcSourceManager() { @@ -301,7 +325,7 @@ MockRtcSourceManager::MockRtcSourceManager() fetch_or_create_error_ = srs_success; initialize_count_ = 0; fetch_or_create_count_ = 0; - mock_source_ = SrsSharedPtr(new SrsRtcSource()); + mock_source_ = SrsSharedPtr(new MockRtcSource()); } MockRtcSourceManager::~MockRtcSourceManager() @@ -523,485 +547,6 @@ void MockRtcPacketSender::set_send_packet_error(srs_error_t err) send_packet_error_ = err; } -// MockAppConfig implementation -MockAppConfig::MockAppConfig() -{ - http_hooks_enabled_ = true; - on_stop_directive_ = NULL; - on_unpublish_directive_ = NULL; - rtc_nack_enabled_ = true; - rtc_nack_no_copy_ = false; - rtc_drop_for_pt_ = 0; - rtc_twcc_enabled_ = true; - srt_enabled_ = false; - rtc_to_rtmp_ = false; - dash_dispose_ = 0; - dash_enabled_ = false; - api_as_candidates_ = true; - resolve_api_domain_ = true; - keep_api_domain_ = false; - mw_msgs_ = 8; - mw_sleep_ = 350 * SRS_UTIME_MILLISECONDS; - rtc_dtls_role_ = "passive"; - default_vhost_ = NULL; - srt_to_rtmp_ = true; - rtc_from_rtmp_ = false; - forwards_directive_ = NULL; - backend_directive_ = NULL; -} - -MockAppConfig::~MockAppConfig() -{ - clear_on_stop_directive(); - clear_on_unpublish_directive(); - - srs_freep(default_vhost_); - srs_freep(forwards_directive_); - srs_freep(backend_directive_); -} - -void MockAppConfig::set_forward_destinations(const std::vector &destinations) -{ - srs_freep(forwards_directive_); - - if (!destinations.empty()) { - forwards_directive_ = new SrsConfDirective(); - forwards_directive_->name_ = "destination"; - forwards_directive_->args_ = destinations; - } -} - -void MockAppConfig::set_forward_backend(const std::string &backend_url) -{ - srs_freep(backend_directive_); - - if (!backend_url.empty()) { - backend_directive_ = new SrsConfDirective(); - backend_directive_->name_ = "backend"; - backend_directive_->args_.push_back(backend_url); - } -} - -srs_utime_t MockAppConfig::get_pithy_print() -{ - return 10 * SRS_UTIME_SECONDS; -} - -std::string MockAppConfig::get_default_app_name() -{ - return "live"; -} - -void MockAppConfig::subscribe(ISrsReloadHandler *handler) -{ - // Do nothing in mock -} - -void MockAppConfig::unsubscribe(ISrsReloadHandler *handler) -{ - // Do nothing in mock -} - -bool MockAppConfig::get_vhost_http_hooks_enabled(std::string vhost) -{ - return http_hooks_enabled_; -} - -SrsConfDirective *MockAppConfig::get_vhost_on_stop(std::string vhost) -{ - return on_stop_directive_; -} - -SrsConfDirective *MockAppConfig::get_vhost_on_unpublish(std::string vhost) -{ - return on_unpublish_directive_; -} - -SrsConfDirective *MockAppConfig::get_vhost_on_dvr(std::string vhost) -{ - return NULL; -} - -bool MockAppConfig::get_rtc_nack_enabled(std::string vhost) -{ - return rtc_nack_enabled_; -} - -bool MockAppConfig::get_rtc_nack_no_copy(std::string vhost) -{ - return rtc_nack_no_copy_; -} - -bool MockAppConfig::get_realtime_enabled(std::string vhost, bool is_rtc) -{ - return true; -} - -int MockAppConfig::get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc) -{ - return mw_msgs_; -} - -int MockAppConfig::get_rtc_drop_for_pt(std::string vhost) -{ - return rtc_drop_for_pt_; -} - -bool MockAppConfig::get_rtc_twcc_enabled(std::string vhost) -{ - return rtc_twcc_enabled_; -} - -bool MockAppConfig::get_srt_enabled() -{ - return srt_enabled_; -} - -bool MockAppConfig::get_srt_enabled(std::string vhost) -{ - return srt_enabled_; -} - -std::string MockAppConfig::get_srt_default_streamid() -{ - return "#!::r=live/livestream,m=request"; -} - -bool MockAppConfig::get_srt_to_rtmp(std::string vhost) -{ - return srt_to_rtmp_; -} - -bool MockAppConfig::get_rtc_to_rtmp(std::string vhost) -{ - return rtc_to_rtmp_; -} - -srs_utime_t MockAppConfig::get_rtc_stun_timeout(std::string vhost) -{ - return 30 * SRS_UTIME_SECONDS; -} - -bool MockAppConfig::get_rtc_stun_strict_check(std::string vhost) -{ - return false; -} - -std::string MockAppConfig::get_rtc_dtls_role(std::string vhost) -{ - return rtc_dtls_role_; -} - -std::string MockAppConfig::get_rtc_dtls_version(std::string vhost) -{ - return "auto"; -} - -SrsConfDirective *MockAppConfig::get_vhost_on_hls(std::string vhost) -{ - return NULL; -} - -SrsConfDirective *MockAppConfig::get_vhost_on_hls_notify(std::string vhost) -{ - return NULL; -} - -bool MockAppConfig::get_hls_enabled(std::string vhost) -{ - return false; -} - -bool MockAppConfig::get_hls_enabled(SrsConfDirective *vhost) -{ - return false; -} - -bool MockAppConfig::get_hls_use_fmp4(std::string vhost) -{ - return false; -} - -std::string MockAppConfig::get_hls_entry_prefix(std::string vhost) -{ - return ""; -} - -std::string MockAppConfig::get_hls_path(std::string vhost) -{ - return "./objs/nginx/html"; -} - -std::string MockAppConfig::get_hls_m3u8_file(std::string vhost) -{ - return "[app]/[stream].m3u8"; -} - -std::string MockAppConfig::get_hls_ts_file(std::string vhost) -{ - return "[app]/[stream]-[seq].ts"; -} - -std::string MockAppConfig::get_hls_fmp4_file(std::string vhost) -{ - return "[app]/[stream]-[seq].m4s"; -} - -std::string MockAppConfig::get_hls_init_file(std::string vhost) -{ - return "[app]/[stream]-init.mp4"; -} - -bool MockAppConfig::get_hls_ts_floor(std::string vhost) -{ - return false; -} - -srs_utime_t MockAppConfig::get_hls_fragment(std::string vhost) -{ - return 10 * SRS_UTIME_SECONDS; -} - -double MockAppConfig::get_hls_td_ratio(std::string vhost) -{ - return 1.5; -} - -double MockAppConfig::get_hls_aof_ratio(std::string vhost) -{ - return 2.0; -} - -srs_utime_t MockAppConfig::get_hls_window(std::string vhost) -{ - return 60 * SRS_UTIME_SECONDS; -} - -std::string MockAppConfig::get_hls_on_error(std::string vhost) -{ - return "continue"; -} - -bool MockAppConfig::get_hls_cleanup(std::string vhost) -{ - return true; -} - -srs_utime_t MockAppConfig::get_hls_dispose(std::string vhost) -{ - return 120 * SRS_UTIME_SECONDS; -} - -bool MockAppConfig::get_hls_wait_keyframe(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_hls_keys(std::string vhost) -{ - return false; -} - -int MockAppConfig::get_hls_fragments_per_key(std::string vhost) -{ - return 5; -} - -std::string MockAppConfig::get_hls_key_file(std::string vhost) -{ - return "[app]/[stream]-[seq].key"; -} - -std::string MockAppConfig::get_hls_key_file_path(std::string vhost) -{ - return "./objs/nginx/html"; -} - -std::string MockAppConfig::get_hls_key_url(std::string vhost) -{ - return ""; -} - -int MockAppConfig::get_vhost_hls_nb_notify(std::string vhost) -{ - return 64; -} - -bool MockAppConfig::get_vhost_hls_dts_directly(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_hls_ctx_enabled(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_hls_ts_ctx_enabled(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_hls_master_m3u8_path_relative(std::string vhost) -{ - return false; -} - -bool MockAppConfig::get_hls_recover(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_forward_enabled(std::string vhost) -{ - return forwards_directive_ != NULL || backend_directive_ != NULL; -} - -SrsConfDirective *MockAppConfig::get_forwards(std::string vhost) -{ - return forwards_directive_; -} - -srs_utime_t MockAppConfig::get_queue_length(std::string vhost) -{ - return 30 * SRS_UTIME_SECONDS; -} - -SrsConfDirective *MockAppConfig::get_forward_backend(std::string vhost) -{ - return backend_directive_; -} - -bool MockAppConfig::get_atc(std::string vhost) -{ - return false; -} - -int MockAppConfig::get_time_jitter(std::string vhost) -{ - return SrsRtmpJitterAlgorithmFULL; -} - -bool MockAppConfig::get_mix_correct(std::string vhost) -{ - return false; -} - -bool MockAppConfig::try_annexb_first(std::string vhost) -{ - return true; -} - -bool MockAppConfig::get_vhost_is_edge(std::string vhost) -{ - return false; -} - -bool MockAppConfig::get_atc_auto(std::string vhost) -{ - return false; -} - -bool MockAppConfig::get_reduce_sequence_header(std::string vhost) -{ - return false; -} - -bool MockAppConfig::get_parse_sps(std::string vhost) -{ - return true; -} - -void MockAppConfig::set_http_hooks_enabled(bool enabled) -{ - http_hooks_enabled_ = enabled; -} - -void MockAppConfig::set_on_stop_urls(const std::vector &urls) -{ - clear_on_stop_directive(); - if (!urls.empty()) { - on_stop_directive_ = new SrsConfDirective(); - on_stop_directive_->name_ = "on_stop"; - on_stop_directive_->args_ = urls; - } -} - -void MockAppConfig::clear_on_stop_directive() -{ - srs_freep(on_stop_directive_); -} - -void MockAppConfig::set_on_unpublish_urls(const std::vector &urls) -{ - clear_on_unpublish_directive(); - if (!urls.empty()) { - on_unpublish_directive_ = new SrsConfDirective(); - on_unpublish_directive_->name_ = "on_unpublish"; - on_unpublish_directive_->args_ = urls; - } -} - -void MockAppConfig::clear_on_unpublish_directive() -{ - srs_freep(on_unpublish_directive_); -} - -void MockAppConfig::set_rtc_nack_enabled(bool enabled) -{ - rtc_nack_enabled_ = enabled; -} - -void MockAppConfig::set_rtc_nack_no_copy(bool no_copy) -{ - rtc_nack_no_copy_ = no_copy; -} - -void MockAppConfig::set_rtc_drop_for_pt(int pt) -{ - rtc_drop_for_pt_ = pt; -} - -void MockAppConfig::set_rtc_twcc_enabled(bool enabled) -{ - rtc_twcc_enabled_ = enabled; -} - -void MockAppConfig::set_srt_enabled(bool enabled) -{ - srt_enabled_ = enabled; -} - -void MockAppConfig::set_rtc_to_rtmp(bool enabled) -{ - rtc_to_rtmp_ = enabled; -} - -void MockAppConfig::set_api_as_candidates(bool enabled) -{ - api_as_candidates_ = enabled; -} - -void MockAppConfig::set_resolve_api_domain(bool enabled) -{ - resolve_api_domain_ = enabled; -} - -void MockAppConfig::set_keep_api_domain(bool enabled) -{ - keep_api_domain_ = enabled; -} - -bool MockAppConfig::get_security_enabled(std::string vhost) -{ - return false; -} - -SrsConfDirective *MockAppConfig::get_security_rules(std::string vhost) -{ - return NULL; -} - // Mock RTC packet receiver implementation MockRtcPacketReceiver::MockRtcPacketReceiver() { @@ -1160,6 +705,7 @@ MockLiveSource::MockLiveSource() on_audio_count_ = 0; on_video_count_ = 0; on_dump_packets_count_ = 0; + on_frame_count_ = 0; } MockLiveSource::~MockLiveSource() @@ -1196,16 +742,25 @@ srs_error_t MockLiveSource::consumer_dumps(ISrsLiveConsumer *consumer, bool ds, srs_error_t MockLiveSource::on_audio(SrsRtmpCommonMessage *audio) { - on_audio_count_++; return SrsLiveSource::on_audio(audio); } srs_error_t MockLiveSource::on_video(SrsRtmpCommonMessage *video) { - on_video_count_++; return SrsLiveSource::on_video(video); } +srs_error_t MockLiveSource::on_frame(SrsMediaPacket *msg) +{ + on_frame_count_++; + if (msg->is_audio()) { + on_audio_count_++; + } else if (msg->is_video()) { + on_video_count_++; + } + return SrsLiveSource::on_frame(msg); +} + // Mock SRT source implementation MockSrtSource::MockSrtSource() { @@ -1360,6 +915,19 @@ MockRtmpServer::~MockRtmpServer() recv_msgs_.clear(); } +void MockRtmpServer::set_request(SrsRtmpConnType type, std::string ip, std::string vhost, std::string app, std::string stream, std::string tcUrl, std::string schema, int port, std::string host) +{ + type_ = type; + ip_ = ip; + vhost_ = vhost; + app_ = app; + stream_ = stream; + tcUrl_ = tcUrl; + schema_ = schema; + port_ = port; + host_ = host; +} + void MockRtmpServer::set_recv_timeout(srs_utime_t tm) { } @@ -2464,6 +2032,31 @@ void MockOriginHub::set_on_forwarder_start_error(srs_error_t err) on_forwarder_start_error_ = srs_error_copy(err); } +// MockAudioCache implementation +MockAudioCache::MockAudioCache() +{ + process_packet_count_ = 0; +} + +MockAudioCache::~MockAudioCache() +{ +} + +srs_error_t MockAudioCache::process_packet(SrsRtpPacket *src, std::vector &ready_packets) +{ + process_packet_count_++; + + // Copy the packet. + SrsRtpPacket *copy = src->copy(); + ready_packets.push_back(copy); + + return srs_success; +} + +void MockAudioCache::clear_all() +{ +} + // Mock ISrsBasicRtmpClient implementation MockRtmpClient::MockRtmpClient() { @@ -2625,3 +2218,51 @@ void MockRtmpClient::set_url(std::string url) { url_ = url; } + +MockAudioTranscoder::MockAudioTranscoder() +{ + transcode_count_ = 0; + // Set default AAC header for mock transcoder + aac_header_ = std::string("\xAF\x00\x12\x10", 4); +} + +MockAudioTranscoder::~MockAudioTranscoder() +{ +} + +srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate) +{ + return srs_success; +} + +srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector &outs) +{ + transcode_count_++; + + SrsParsedAudioPacket *out = in->copy(); + output_packets_.push_back(out); + outs.push_back(out); + + return srs_success; +} + +void MockAudioTranscoder::free_frames(std::vector &frames) +{ + for (std::vector::iterator it = frames.begin(); it != frames.end(); ++it) { + SrsParsedAudioPacket *p = *it; + srs_freep(p); + } +} + +void MockAudioTranscoder::aac_codec_header(uint8_t **data, int *len) +{ + int size = aac_header_.size(); + if (size <= 0) { + return; + } + + uint8_t *copy = new uint8_t[size]; + memcpy(copy, aac_header_.data(), size); + *data = copy; + *len = size; +} diff --git a/trunk/src/utest/srs_utest_manual_mock.hpp b/trunk/src/utest/srs_utest_manual_mock.hpp index 0fbd96d9a..f1c5564f8 100644 --- a/trunk/src/utest/srs_utest_manual_mock.hpp +++ b/trunk/src/utest/srs_utest_manual_mock.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,11 @@ public: uint32_t video_ssrc_; uint32_t screen_ssrc_; +public: + uint8_t audio_pt_; + uint8_t video_pt_; + uint8_t screen_pt_; + public: // Create a map of track descriptions with audio and video tracks (for play stream) std::map create_audio_video_tracks(); @@ -151,6 +157,20 @@ public: virtual ISrsRequest *as_http(); }; +// Mock RTC source for testing +class MockRtcSource : public SrsRtcSource +{ +public: + int on_rtp_count_; + +public: + MockRtcSource(); + virtual ~MockRtcSource(); + +public: + virtual srs_error_t on_rtp(SrsRtpPacket *pkt); +}; + // Mock RTC source manager for testing class MockRtcSourceManager : public ISrsRtcSourceManager { @@ -269,20 +289,74 @@ public: bool rtc_from_rtmp_; SrsConfDirective *forwards_directive_; SrsConfDirective *backend_directive_; + bool rtc_server_enabled_; + bool rtc_enabled_; + bool rtc_init_rate_from_sdp_; public: - MockAppConfig(); - virtual ~MockAppConfig(); + MockAppConfig() + { + http_hooks_enabled_ = true; + on_stop_directive_ = NULL; + on_unpublish_directive_ = NULL; + rtc_nack_enabled_ = true; + rtc_nack_no_copy_ = false; + rtc_drop_for_pt_ = 0; + rtc_twcc_enabled_ = true; + srt_enabled_ = false; + rtc_to_rtmp_ = false; + dash_dispose_ = 0; + dash_enabled_ = false; + api_as_candidates_ = true; + resolve_api_domain_ = true; + keep_api_domain_ = false; + mw_msgs_ = 8; + mw_sleep_ = 350 * SRS_UTIME_MILLISECONDS; + rtc_dtls_role_ = "passive"; + default_vhost_ = NULL; + srt_to_rtmp_ = true; + rtc_from_rtmp_ = false; + forwards_directive_ = NULL; + backend_directive_ = NULL; + rtc_server_enabled_ = false; + rtc_enabled_ = false; + rtc_init_rate_from_sdp_ = false; + } + virtual ~MockAppConfig() + { + clear_on_stop_directive(); + clear_on_unpublish_directive(); + + srs_freep(default_vhost_); + srs_freep(forwards_directive_); + srs_freep(backend_directive_); + } public: // Helper methods for setting forward configuration - void set_forward_destinations(const std::vector &destinations); - void set_forward_backend(const std::string &backend_url); + void set_forward_destinations(const std::vector &destinations) + { + srs_freep(forwards_directive_); + if (!destinations.empty()) { + forwards_directive_ = new SrsConfDirective(); + forwards_directive_->name_ = "destination"; + forwards_directive_->args_ = destinations; + } + } + void set_forward_backend(const std::string &backend_url) + { + srs_freep(backend_directive_); + if (!backend_url.empty()) { + backend_directive_ = new SrsConfDirective(); + backend_directive_->name_ = "backend"; + backend_directive_->args_.push_back(backend_url); + } + } // ISrsConfig methods - virtual srs_utime_t get_pithy_print(); - virtual std::string get_default_app_name(); - virtual void subscribe(ISrsReloadHandler *handler); - virtual void unsubscribe(ISrsReloadHandler *handler); + srs_utime_t get_pithy_print() { return 10 * SRS_UTIME_SECONDS; } + std::string get_default_app_name() { return "live"; } + void subscribe(ISrsReloadHandler *handler) {} + void unsubscribe(ISrsReloadHandler *handler) {} virtual srs_error_t reload(SrsReloadState *pstate) { return srs_success; } virtual srs_error_t persistence() { return srs_success; } virtual std::string config() { return ""; } @@ -322,7 +396,7 @@ public: virtual std::string get_https_stream_ssl_cert() { return ""; } virtual std::string get_http_stream_dir() { return ""; } virtual bool get_http_stream_crossdomain() { return false; } - virtual bool get_rtc_server_enabled() { return false; } + virtual bool get_rtc_server_enabled() { return rtc_server_enabled_; } virtual bool get_rtc_server_tcp_enabled() { return false; } virtual std::vector get_rtc_server_tcp_listens() { @@ -402,74 +476,75 @@ public: virtual SrsConfDirective *get_vhost_on_close(std::string vhost) { return NULL; } virtual SrsConfDirective *get_vhost_on_publish(std::string vhost) { return NULL; } virtual SrsConfDirective *get_vhost_on_play(std::string vhost) { return NULL; } - virtual bool get_rtc_enabled(std::string vhost) { return false; } + virtual bool get_rtc_enabled(std::string vhost) { return rtc_enabled_; } virtual bool get_rtsp_enabled(std::string vhost) { return false; } virtual bool get_rtc_from_rtmp(std::string vhost) { return rtc_from_rtmp_; } virtual bool get_rtsp_from_rtmp(std::string vhost) { return false; } // ISrsAppConfig methods - virtual bool get_vhost_http_hooks_enabled(std::string vhost); - virtual SrsConfDirective *get_vhost_on_stop(std::string vhost); - virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost); - virtual SrsConfDirective *get_vhost_on_dvr(std::string vhost); - virtual bool get_rtc_nack_enabled(std::string vhost); - virtual bool get_rtc_nack_no_copy(std::string vhost); - virtual bool get_realtime_enabled(std::string vhost, bool is_rtc); - virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc); - virtual int get_rtc_drop_for_pt(std::string vhost); - virtual bool get_rtc_twcc_enabled(std::string vhost); - virtual bool get_srt_enabled(); - virtual bool get_srt_enabled(std::string vhost); - virtual std::string get_srt_default_streamid(); - virtual bool get_srt_to_rtmp(std::string vhost); - virtual bool get_rtc_to_rtmp(std::string vhost); - virtual srs_utime_t get_rtc_stun_timeout(std::string vhost); - virtual bool get_rtc_stun_strict_check(std::string vhost); - virtual std::string get_rtc_dtls_role(std::string vhost); - virtual std::string get_rtc_dtls_version(std::string vhost); - virtual SrsConfDirective *get_vhost_on_hls(std::string vhost); - virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost); + virtual bool get_vhost_http_hooks_enabled(std::string vhost) { return http_hooks_enabled_; } + virtual SrsConfDirective *get_vhost_on_stop(std::string vhost) { return on_stop_directive_; } + virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost) { return on_unpublish_directive_; } + virtual SrsConfDirective *get_vhost_on_dvr(std::string vhost) { return NULL; } + virtual bool get_rtc_nack_enabled(std::string vhost) { return rtc_nack_enabled_; } + virtual bool get_rtc_nack_no_copy(std::string vhost) { return rtc_nack_no_copy_; } + virtual bool get_realtime_enabled(std::string vhost, bool is_rtc) { return true; } + virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc) { return mw_msgs_; } + virtual int get_rtc_drop_for_pt(std::string vhost) { return rtc_drop_for_pt_; } + virtual bool get_rtc_twcc_enabled(std::string vhost) { return rtc_twcc_enabled_; } + virtual bool get_rtc_init_rate_from_sdp(std::string vhost) { return rtc_init_rate_from_sdp_; } + virtual bool get_srt_enabled() { return srt_enabled_; } + virtual bool get_srt_enabled(std::string vhost) { return srt_enabled_; } + virtual std::string get_srt_default_streamid() { return "#!::r=live/livestream,m=request"; } + virtual bool get_srt_to_rtmp(std::string vhost) { return srt_to_rtmp_; } + virtual bool get_rtc_to_rtmp(std::string vhost) { return rtc_to_rtmp_; } + virtual srs_utime_t get_rtc_stun_timeout(std::string vhost) { return 30 * SRS_UTIME_SECONDS; } + virtual bool get_rtc_stun_strict_check(std::string vhost) { return false; } + virtual std::string get_rtc_dtls_role(std::string vhost) { return rtc_dtls_role_; } + virtual std::string get_rtc_dtls_version(std::string vhost) { return "auto"; } + virtual SrsConfDirective *get_vhost_on_hls(std::string vhost) { return NULL; } + virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost) { return NULL; } // HLS methods - virtual bool get_hls_enabled(std::string vhost); - virtual bool get_hls_enabled(SrsConfDirective *vhost); - virtual bool get_hls_use_fmp4(std::string vhost); - virtual std::string get_hls_entry_prefix(std::string vhost); - virtual std::string get_hls_path(std::string vhost); - virtual std::string get_hls_m3u8_file(std::string vhost); - virtual std::string get_hls_ts_file(std::string vhost); - virtual std::string get_hls_fmp4_file(std::string vhost); - virtual std::string get_hls_init_file(std::string vhost); - virtual bool get_hls_ts_floor(std::string vhost); - virtual srs_utime_t get_hls_fragment(std::string vhost); - virtual double get_hls_td_ratio(std::string vhost); - virtual double get_hls_aof_ratio(std::string vhost); - virtual srs_utime_t get_hls_window(std::string vhost); - virtual std::string get_hls_on_error(std::string vhost); - virtual bool get_hls_cleanup(std::string vhost); - virtual srs_utime_t get_hls_dispose(std::string vhost); - virtual bool get_hls_wait_keyframe(std::string vhost); - virtual bool get_hls_keys(std::string vhost); - virtual int get_hls_fragments_per_key(std::string vhost); - virtual std::string get_hls_key_file(std::string vhost); - virtual std::string get_hls_key_file_path(std::string vhost); - virtual std::string get_hls_key_url(std::string vhost); - virtual int get_vhost_hls_nb_notify(std::string vhost); - virtual bool get_vhost_hls_dts_directly(std::string vhost); - virtual bool get_hls_ctx_enabled(std::string vhost); - virtual bool get_hls_ts_ctx_enabled(std::string vhost); - virtual bool get_hls_master_m3u8_path_relative(std::string vhost); - virtual bool get_hls_recover(std::string vhost); - virtual bool get_forward_enabled(std::string vhost); - virtual SrsConfDirective *get_forwards(std::string vhost); - virtual srs_utime_t get_queue_length(std::string vhost); - virtual SrsConfDirective *get_forward_backend(std::string vhost); - virtual bool get_atc(std::string vhost); - virtual int get_time_jitter(std::string vhost); - virtual bool get_mix_correct(std::string vhost); - virtual bool try_annexb_first(std::string vhost); - virtual bool get_vhost_is_edge(std::string vhost); - virtual bool get_atc_auto(std::string vhost); - virtual bool get_reduce_sequence_header(std::string vhost); - virtual bool get_parse_sps(std::string vhost); + virtual bool get_hls_enabled(std::string vhost) { return false; } + virtual bool get_hls_enabled(SrsConfDirective *vhost) { return false; } + virtual bool get_hls_use_fmp4(std::string vhost) { return false; } + virtual std::string get_hls_entry_prefix(std::string vhost) { return ""; } + virtual std::string get_hls_path(std::string vhost) { return "./objs/nginx/html"; } + virtual std::string get_hls_m3u8_file(std::string vhost) { return "[app]/[stream].m3u8"; } + virtual std::string get_hls_ts_file(std::string vhost) { return "[app]/[stream]-[seq].ts"; } + virtual std::string get_hls_fmp4_file(std::string vhost) { return "[app]/[stream]-[seq].m4s"; } + virtual std::string get_hls_init_file(std::string vhost) { return "[app]/[stream]-init.mp4"; } + virtual bool get_hls_ts_floor(std::string vhost) { return false; } + virtual srs_utime_t get_hls_fragment(std::string vhost) { return 10 * SRS_UTIME_SECONDS; } + virtual double get_hls_td_ratio(std::string vhost) { return 1.5; } + virtual double get_hls_aof_ratio(std::string vhost) { return 2.0; } + virtual srs_utime_t get_hls_window(std::string vhost) { return 60 * SRS_UTIME_SECONDS; } + virtual std::string get_hls_on_error(std::string vhost) { return "continue"; } + virtual bool get_hls_cleanup(std::string vhost) { return true; } + virtual srs_utime_t get_hls_dispose(std::string vhost) { return 120 * SRS_UTIME_SECONDS; } + virtual bool get_hls_wait_keyframe(std::string vhost) { return true; } + virtual bool get_hls_keys(std::string vhost) { return false; } + virtual int get_hls_fragments_per_key(std::string vhost) { return 5; } + virtual std::string get_hls_key_file(std::string vhost) { return "[app]/[stream]-[seq].key"; } + virtual std::string get_hls_key_file_path(std::string vhost) { return "./objs/nginx/html"; } + virtual std::string get_hls_key_url(std::string vhost) { return ""; } + virtual int get_vhost_hls_nb_notify(std::string vhost) { return 64; } + virtual bool get_vhost_hls_dts_directly(std::string vhost) { return true; } + virtual bool get_hls_ctx_enabled(std::string vhost) { return true; } + virtual bool get_hls_ts_ctx_enabled(std::string vhost) { return true; } + virtual bool get_hls_master_m3u8_path_relative(std::string vhost) { return false; } + virtual bool get_hls_recover(std::string vhost) { return true; } + virtual bool get_forward_enabled(std::string vhost) { return forwards_directive_ != NULL || backend_directive_ != NULL; } + virtual SrsConfDirective *get_forwards(std::string vhost) { return forwards_directive_; } + virtual srs_utime_t get_queue_length(std::string vhost) { return 30 * SRS_UTIME_SECONDS; } + virtual SrsConfDirective *get_forward_backend(std::string vhost) { return backend_directive_; } + virtual bool get_atc(std::string vhost) { return false; } + virtual int get_time_jitter(std::string vhost) { return SrsRtmpJitterAlgorithmFULL; } + virtual bool get_mix_correct(std::string vhost) { return false; } + virtual bool try_annexb_first(std::string vhost) { return true; } + virtual bool get_vhost_is_edge(std::string vhost) { return false; } + virtual bool get_atc_auto(std::string vhost) { return false; } + virtual bool get_reduce_sequence_header(std::string vhost) { return false; } + virtual bool get_parse_sps(std::string vhost) { return true; } // DVR methods virtual std::string get_dvr_path(std::string vhost) { return "./[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv"; } virtual std::string get_dvr_plan(std::string vhost) { return "session"; } @@ -541,22 +616,38 @@ public: virtual std::vector get_engine_aparams(SrsConfDirective *conf) { return std::vector(); } virtual std::string get_engine_oformat(SrsConfDirective *conf) { return ""; } virtual std::string get_engine_output(SrsConfDirective *conf) { return ""; } - void set_http_hooks_enabled(bool enabled); - void set_on_stop_urls(const std::vector &urls); - void clear_on_stop_directive(); - void set_on_unpublish_urls(const std::vector &urls); - void clear_on_unpublish_directive(); - void set_rtc_nack_enabled(bool enabled); - void set_rtc_nack_no_copy(bool no_copy); - void set_rtc_drop_for_pt(int pt); - void set_rtc_twcc_enabled(bool enabled); - void set_srt_enabled(bool enabled); - void set_rtc_to_rtmp(bool enabled); - void set_api_as_candidates(bool enabled); - void set_resolve_api_domain(bool enabled); - void set_keep_api_domain(bool enabled); - virtual bool get_security_enabled(std::string vhost); - virtual SrsConfDirective *get_security_rules(std::string vhost); + void set_http_hooks_enabled(bool enabled) { http_hooks_enabled_ = enabled; } + void set_on_stop_urls(const std::vector &urls) + { + clear_on_stop_directive(); + if (!urls.empty()) { + on_stop_directive_ = new SrsConfDirective(); + on_stop_directive_->name_ = "on_stop"; + on_stop_directive_->args_ = urls; + } + } + void clear_on_stop_directive() { srs_freep(on_stop_directive_); } + void set_on_unpublish_urls(const std::vector &urls) + { + clear_on_unpublish_directive(); + if (!urls.empty()) { + on_unpublish_directive_ = new SrsConfDirective(); + on_unpublish_directive_->name_ = "on_unpublish"; + on_unpublish_directive_->args_ = urls; + } + } + void clear_on_unpublish_directive() { srs_freep(on_unpublish_directive_); } + void set_rtc_nack_enabled(bool enabled) { rtc_nack_enabled_ = enabled; } + void set_rtc_nack_no_copy(bool no_copy) { rtc_nack_no_copy_ = no_copy; } + void set_rtc_drop_for_pt(int pt) { rtc_drop_for_pt_ = pt; } + void set_rtc_twcc_enabled(bool enabled) { rtc_twcc_enabled_ = enabled; } + void set_srt_enabled(bool enabled) { srt_enabled_ = enabled; } + void set_rtc_to_rtmp(bool enabled) { rtc_to_rtmp_ = enabled; } + void set_api_as_candidates(bool enabled) { api_as_candidates_ = enabled; } + void set_resolve_api_domain(bool enabled) { resolve_api_domain_ = enabled; } + void set_keep_api_domain(bool enabled) { keep_api_domain_ = enabled; } + bool get_security_enabled(std::string vhost) { return false; } + SrsConfDirective *get_security_rules(std::string vhost) { return NULL; } }; // Mock RTC packet receiver for testing SrsRtcPublishStream @@ -634,6 +725,7 @@ public: int on_audio_count_; int on_video_count_; int on_dump_packets_count_; + int on_frame_count_; public: MockLiveSource(); @@ -647,6 +739,7 @@ public: public: virtual srs_error_t on_audio(SrsRtmpCommonMessage *audio); virtual srs_error_t on_video(SrsRtmpCommonMessage *video); + virtual srs_error_t on_frame(SrsMediaPacket *msg); }; // Mock SRT source for testing SrsRtcPublishStream @@ -743,6 +836,9 @@ public: MockRtmpServer(); virtual ~MockRtmpServer(); +public: + void set_request(SrsRtmpConnType type, std::string ip, std::string vhost, std::string app, std::string stream, std::string tcUrl, std::string schema, int port, std::string host); + public: virtual void set_recv_timeout(srs_utime_t tm); virtual void set_send_timeout(srs_utime_t tm); @@ -1104,6 +1200,21 @@ public: void set_on_dvr_request_sh_error(srs_error_t err); }; +// Mock audio cache for ISrsRtcFrameBuilderAudioPacketCache +class MockAudioCache : public ISrsRtcFrameBuilderAudioPacketCache +{ +public: + int process_packet_count_; + +public: + MockAudioCache(); + virtual ~MockAudioCache(); + +public: + virtual srs_error_t process_packet(SrsRtpPacket *src, std::vector &ready_packets); + virtual void clear_all(); +}; + // Mock ISrsBasicRtmpClient for testing SrsForwarder class MockRtmpClient : public ISrsBasicRtmpClient { @@ -1157,4 +1268,23 @@ public: virtual void set_url(std::string url); }; +// Mock the audio transcoder ISrsAudioTranscoder. +class MockAudioTranscoder : public ISrsAudioTranscoder +{ +public: + int transcode_count_; + std::vector output_packets_; + std::string aac_header_; + +public: + MockAudioTranscoder(); + virtual ~MockAudioTranscoder(); + +public: + virtual srs_error_t initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate); + virtual srs_error_t transcode(SrsParsedAudioPacket *in, std::vector &outs); + virtual void free_frames(std::vector &frames); + virtual void aac_codec_header(uint8_t **data, int *len); +}; + #endif diff --git a/trunk/src/utest/srs_utest_manual_rtc.cpp b/trunk/src/utest/srs_utest_manual_rtc.cpp index 0416512b1..393a6c321 100644 --- a/trunk/src/utest/srs_utest_manual_rtc.cpp +++ b/trunk/src/utest/srs_utest_manual_rtc.cpp @@ -1607,7 +1607,7 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus) ds.type_ = "audio"; ds.id_ = "NSNWOn19NDn12o8nNeji2"; ds.ssrc_ = 100; - audio = new SrsRtcAudioRecvTrack(&mock_receiver, &ds); + audio = new SrsRtcAudioRecvTrack(&mock_receiver, &ds, false); publish->audio_tracks_.push_back(audio); } if (true) { @@ -1615,7 +1615,7 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus) ds.type_ = "video"; ds.id_ = "VMo22nfLDn122nfnDNL2"; ds.ssrc_ = 200; - video = new SrsRtcVideoRecvTrack(&mock_receiver, &ds); + video = new SrsRtcVideoRecvTrack(&mock_receiver, &ds, false); publish->video_tracks_.push_back(video); } EXPECT_FALSE(audio->get_track_status()); @@ -1668,7 +1668,7 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportNormal) video_ds.id_ = "VMo22nfLDn122nfnDNL2"; video_ds.ssrc_ = 200; - SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds); + SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds, false); publish.video_tracks_.push_back(video); publish.set_all_tracks_status(true); @@ -1736,7 +1736,7 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportOutOfOrder) video_ds.id_ = "VMo22nfLDn122nfnDNL2"; video_ds.ssrc_ = 200; - SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds); + SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds, false); publish.video_tracks_.push_back(video); publish.set_all_tracks_status(true); @@ -1809,7 +1809,7 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportConsecutive) video_ds.id_ = "VMo22nfLDn122nfnDNL2"; video_ds.ssrc_ = 200; - SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds); + SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds, false); publish.video_tracks_.push_back(video); publish.set_all_tracks_status(true); @@ -1915,7 +1915,7 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportDuplicated) video_ds.id_ = "VMo22nfLDn122nfnDNL2"; video_ds.ssrc_ = 200; - SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds); + SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds, false); publish.video_tracks_.push_back(video); publish.set_all_tracks_status(true); diff --git a/trunk/src/utest/srs_utest_manual_rtc_recv_track.cpp b/trunk/src/utest/srs_utest_manual_rtc_recv_track.cpp index e6e95b72e..0daeab9de 100644 --- a/trunk/src/utest/srs_utest_manual_rtc_recv_track.cpp +++ b/trunk/src/utest/srs_utest_manual_rtc_recv_track.cpp @@ -78,7 +78,7 @@ public: } MockSrsRtcRecvTrack() - : SrsRtcRecvTrack(nullptr, create_default_track_desc(), true) {} // true for is_audio + : SrsRtcRecvTrack(nullptr, create_default_track_desc(), true, false) {} // true for is_audio, false for init_rate_from_sdp }; VOID TEST(RtcRecvTrackTest, OnNackBasicTest) diff --git a/trunk/src/utest/srs_utest_manual_st.cpp b/trunk/src/utest/srs_utest_manual_st.cpp index ddd19c26b..c9715075b 100644 --- a/trunk/src/utest/srs_utest_manual_st.cpp +++ b/trunk/src/utest/srs_utest_manual_st.cpp @@ -43,9 +43,9 @@ VOID TEST(StTest, StUtimeInMicroseconds) EXPECT_GT(st_time_1, 0); EXPECT_GT(st_time_2, 0); EXPECT_GE(st_time_2, st_time_1); - // st_time_2 - st_time_1 should be in range of [1, 1000] microseconds + // st_time_2 - st_time_1 should be in range of [1, 3000] microseconds EXPECT_GE(st_time_2 - st_time_1, 0); - EXPECT_LE(st_time_2 - st_time_1, 1000); + EXPECT_LE(st_time_2 - st_time_1, 3000); } static inline st_utime_t time_gettimeofday() diff --git a/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp new file mode 100644 index 000000000..2a44a1beb --- /dev/null +++ b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp @@ -0,0 +1,190 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Mock app factory for RTC to RTMP workflow testing +class MockAppFactoryForRtc2Rtmp : public SrsAppFactory +{ +public: + MockAudioCache *last_created_audio_cache_; + MockAudioTranscoder *last_created_audio_transcoder_; + +public: + MockAppFactoryForRtc2Rtmp() + { + last_created_audio_cache_ = NULL; + last_created_audio_transcoder_ = NULL; + } + + virtual ~MockAppFactoryForRtc2Rtmp() + { + // Don't delete last_created_audio_cache_ or last_created_audio_transcoder_ here, + // they are managed by frame builder + } + +#ifdef SRS_FFMPEG_FIT + virtual ISrsRtcFrameBuilderAudioPacketCache *create_rtc_frame_builder_audio_packet_cache() + { + // Create a new mock audio cache each time + MockAudioCache *cache = new MockAudioCache(); + last_created_audio_cache_ = cache; + return cache; + } + + virtual ISrsAudioTranscoder *create_audio_transcoder() + { + // Create a new mock audio transcoder each time + MockAudioTranscoder *transcoder = new MockAudioTranscoder(); + last_created_audio_transcoder_ = transcoder; + return transcoder; + } +#endif +}; + +// This test is used to verify the basic workflow of the RTC connection. +// It's finished with the help of AI, but each step is manually designed +// and verified. So this is not dominated by AI, but by humanbeing. +VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario) +{ + srs_error_t err; + + // Create mock objects for dependencies + SrsUniquePtr mock_config(new MockAppConfig()); + SrsUniquePtr mock_rtc_sources(new MockRtcSourceManager()); + SrsUniquePtr mock_stat(new MockAppStatistic()); + SrsUniquePtr mock_request(new MockRtcAsyncCallRequest("test.vhost", "live", "stream1")); + SrsUniquePtr mock_exec(new MockRtcAsyncTaskExecutor()); + SrsUniquePtr mock_expire(new MockExpire()); + SrsUniquePtr mock_receiver(new MockRtcPacketReceiver()); + SrsUniquePtr track_factory(new MockRtcTrackDescriptionFactory()); + SrsUniquePtr mock_sources(new MockLiveSourceManager()); + SrsUniquePtr mock_factory(new MockAppFactoryForRtc2Rtmp()); + + mock_config->rtc_to_rtmp_ = true; + mock_config->rtc_init_rate_from_sdp_ = true; + + // Create RTC publish stream - use real pli_worker_ + SrsContextId cid; + cid.set_value("test-rtc2rtmp-workflow-typical-scenario"); + SrsUniquePtr publish_stream(new SrsRtcPublishStream(mock_exec.get(), mock_expire.get(), mock_receiver.get(), cid)); + + // Mock the publish stream object + if (true) { + // Inject mock dependencies + publish_stream->config_ = mock_config.get(); + publish_stream->rtc_sources_ = mock_rtc_sources.get(); + publish_stream->live_sources_ = mock_sources.get(); + publish_stream->stat_ = mock_stat.get(); + publish_stream->app_factory_ = mock_factory.get(); + } + + // Initialize publish stream, rtc2rtmp bridge should be created + SrsRtcBridge *bridge = NULL; + SrsLiveSource *live_source = NULL; + if (true) { + SrsUniquePtr stream_desc(track_factory->create_stream_description()); + + // Initialize the publish stream (it will take ownership of track descriptions) + HELPER_EXPECT_SUCCESS(publish_stream->initialize(mock_request.get(), stream_desc.get())); + + // Check the tracks, should be one audio track + EXPECT_EQ(publish_stream->audio_tracks_.size(), 1); + // Check the tracks, should be one video track + EXPECT_EQ(publish_stream->video_tracks_.size(), 1); + + // source bridge should be created + bridge = dynamic_cast(publish_stream->source_->rtc_bridge_); + EXPECT_TRUE(bridge != NULL); + + live_source = bridge->rtmp_target_.get(); + EXPECT_TRUE(live_source != NULL); + } + + // Start the publish stream. + SrsRtcFrameBuilder *frame_builder = NULL; + if (true) { + // Test: First call to start() should succeed + HELPER_EXPECT_SUCCESS(publish_stream->start()); + + // Wait for coroutine to start. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify is_sender_started_ flag is set + EXPECT_TRUE(publish_stream->is_sender_started_); + + // When starting the publish stream, the frame builder should be recreated + frame_builder = bridge->frame_builder_; + EXPECT_TRUE(frame_builder != NULL); + + // Verify the audio cache was created by the factory + EXPECT_TRUE(mock_factory->last_created_audio_cache_ != NULL); + EXPECT_EQ(frame_builder->audio_cache_, mock_factory->last_created_audio_cache_); + + // Verify the audio transcoder was created by the factory + EXPECT_TRUE(mock_factory->last_created_audio_transcoder_ != NULL); + EXPECT_EQ(frame_builder->audio_transcoder_, mock_factory->last_created_audio_transcoder_); + } + + // Got a RTP audio packet. + MockLiveSource *mock_source = dynamic_cast(mock_sources->mock_source_.get()); + if (true) { + SrsRtpPacket pkt; + pkt.header_.set_ssrc(track_factory->audio_ssrc_); + pkt.header_.set_sequence(100); + pkt.header_.set_timestamp(1000); + pkt.header_.set_payload_type(track_factory->audio_pt_); + + // Create fake audio payload. + SrsRtpRawPayload *raw = new SrsRtpRawPayload(); + pkt.set_payload(raw, SrsRtpPacketPayloadTypeRaw); + raw->payload_ = pkt.wrap(100); + raw->nn_payload_ = 100; + + SrsUniquePtr data(new char[1500]); + SrsBuffer buf(data.get(), 1500); + HELPER_EXPECT_SUCCESS(pkt.encode(&buf)); + + HELPER_EXPECT_SUCCESS(publish_stream->on_rtp_plaintext(data.get(), buf.pos())); + + // The live source should got 2 audio packets, one is sequence header, another is audio data. + EXPECT_EQ(mock_source->on_audio_count_, 2); + EXPECT_EQ(mock_source->on_frame_count_, 2); + EXPECT_EQ(mock_source->on_video_count_, 0); + } + + publish_stream->stop(); +} diff --git a/trunk/src/utest/srs_utest_workflow_rtc2rtmp.hpp b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.hpp new file mode 100644 index 000000000..b2b6cf65a --- /dev/null +++ b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.hpp @@ -0,0 +1,32 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_UTEST_WORKFLOW_RTC2RTMP_HPP +#define SRS_UTEST_WORKFLOW_RTC2RTMP_HPP + +/* +#include +*/ +#include + +#endif diff --git a/trunk/src/utest/srs_utest_workflow_rtc_conn.hpp b/trunk/src/utest/srs_utest_workflow_rtc_conn.hpp index 1b9dc4d39..6ee035a6e 100644 --- a/trunk/src/utest/srs_utest_workflow_rtc_conn.hpp +++ b/trunk/src/utest/srs_utest_workflow_rtc_conn.hpp @@ -21,11 +21,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SRS_UTEST_RTC_CONN_HPP -#define SRS_UTEST_RTC_CONN_HPP +#ifndef SRS_UTEST_WORKFLOW_RTC_CONN_HPP +#define SRS_UTEST_WORKFLOW_RTC_CONN_HPP /* -#include +#include */ #include diff --git a/trunk/src/utest/srs_utest_workflow_rtc_playstream.cpp b/trunk/src/utest/srs_utest_workflow_rtc_playstream.cpp index 4f756d241..cf582ab8d 100644 --- a/trunk/src/utest/srs_utest_workflow_rtc_playstream.cpp +++ b/trunk/src/utest/srs_utest_workflow_rtc_playstream.cpp @@ -221,9 +221,4 @@ VOID TEST(BasicWorkflowRtcPlayStreamTest, ManuallyVerify) // Stop the play stream play_stream->stop(); - - // Clean up - set to NULL to avoid double-free - play_stream->config_ = NULL; - play_stream->rtc_sources_ = NULL; - play_stream->stat_ = NULL; } diff --git a/trunk/src/utest/srs_utest_workflow_rtc_publishstream.cpp b/trunk/src/utest/srs_utest_workflow_rtc_publishstream.cpp index 5a8f48e57..1d8060a97 100644 --- a/trunk/src/utest/srs_utest_workflow_rtc_publishstream.cpp +++ b/trunk/src/utest/srs_utest_workflow_rtc_publishstream.cpp @@ -96,9 +96,4 @@ VOID TEST(BasicWorkflowRtcPublishStreamTest, ManuallyVerify) // Stop the publish stream publish_stream->stop(); - - // Clean up - set injected fields to NULL to avoid double-free - publish_stream->config_ = NULL; - publish_stream->rtc_sources_ = NULL; - publish_stream->stat_ = NULL; } diff --git a/trunk/src/utest/srs_utest_workflow_rtmp2rtc.cpp b/trunk/src/utest/srs_utest_workflow_rtmp2rtc.cpp new file mode 100644 index 000000000..0176fcdd0 --- /dev/null +++ b/trunk/src/utest/srs_utest_workflow_rtmp2rtc.cpp @@ -0,0 +1,250 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Mock app factory for RTMP to RTC workflow testing +class MockAppFactoryForRtmp2Rtc : public SrsAppFactory +{ +public: + MockAudioTranscoder *last_created_audio_transcoder_; + +public: + MockAppFactoryForRtmp2Rtc() + { + last_created_audio_transcoder_ = NULL; + } + + virtual ~MockAppFactoryForRtmp2Rtc() + { + // Don't delete last_created_audio_transcoder_ here, + // it is managed by RTP builder + } + +#ifdef SRS_FFMPEG_FIT + virtual ISrsAudioTranscoder *create_audio_transcoder() + { + // Create a new mock audio transcoder each time + MockAudioTranscoder *transcoder = new MockAudioTranscoder(); + last_created_audio_transcoder_ = transcoder; + return transcoder; + } +#endif +}; + +// This test is used to verify the basic workflow of the RTMP connection. +// It's finished with the help of AI, but each step is manually designed +// and verified. So this is not dominated by AI, but by humanbeing. +VOID TEST(BasicWorkflowRtmp2RtcTest, ManuallyVerifyTypicalScenario) +{ + srs_error_t err; + + // Mock all interface dependencies + SrsUniquePtr mock_factory(new MockAppFactoryForRtmp2Rtc()); + SrsUniquePtr mock_config(new MockAppConfig()); + SrsUniquePtr mock_manager(new MockConnectionManager()); + SrsUniquePtr mock_sources(new MockLiveSourceManager()); + SrsUniquePtr mock_tokens(new MockStreamPublishTokenManager()); + SrsUniquePtr mock_stat(new MockAppStatistic()); + SrsUniquePtr mock_hooks(new MockHttpHooks()); + SrsUniquePtr mock_rtc_sources(new MockRtcSourceManager()); + SrsUniquePtr mock_srt_sources(new MockSrtSourceManager()); +#ifdef SRS_RTSP + SrsUniquePtr mock_rtsp_sources(new MockRtspSourceManager()); +#endif + MockRtmpServer *mock_rtmp_server = new MockRtmpServer(); + MockSecurity *mock_security = new MockSecurity(); + + mock_config->default_vhost_ = new SrsConfDirective(); + mock_config->default_vhost_->name_ = "vhost"; + mock_config->default_vhost_->args_.push_back("__defaultVhost__"); + + mock_config->mw_msgs_ = 0; // Handle each RTMP message, no merging write. + mock_config->mw_sleep_ = 0; // Handle each RTMP message, no merging write. + + mock_config->rtc_server_enabled_ = true; + mock_config->rtc_enabled_ = true; + mock_config->rtc_from_rtmp_ = true; + + mock_rtmp_server->set_request(SrsRtmpConnFMLEPublish, "192.168.1.100", "utest.ossrs.io", "utest", "livestream", "rtmp://127.0.0.1/utest", "rtmp", 1935, "127.0.0.1"); + + // Create SrsRtmpConn - it takes ownership of transport + ISrsRtmpTransport *transport = new MockRtmpTransport(); + SrsUniquePtr conn(new SrsRtmpConn(transport, "192.168.1.100", 1935)); + + conn->app_factory_ = mock_factory.get(); + conn->config_ = mock_config.get(); + conn->manager_ = mock_manager.get(); + conn->live_sources_ = mock_sources.get(); + conn->stream_publish_tokens_ = mock_tokens.get(); + conn->stat_ = mock_stat.get(); + conn->hooks_ = mock_hooks.get(); + conn->rtc_sources_ = mock_rtc_sources.get(); + conn->srt_sources_ = mock_srt_sources.get(); +#ifdef SRS_RTSP + conn->rtsp_sources_ = mock_rtsp_sources.get(); +#endif + srs_freep(conn->rtmp_); + conn->rtmp_ = mock_rtmp_server; + srs_freep(conn->security_); + conn->security_ = mock_security; + + // Start the RTMP connection. + MockLiveSource *mock_source = dynamic_cast(mock_sources->mock_source_.get()); + SrsRtmpBridge *bridge = NULL; + SrsRtcRtpBuilder *builder = NULL; + if (true) { + // Mock the client type to be a player + HELPER_EXPECT_SUCCESS(conn->start()); + + // Wait for coroutine to start. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify the req should be parsed. + ISrsRequest *req = conn->info_->req_; + EXPECT_STREQ("192.168.1.100", req->ip_.c_str()); + EXPECT_STREQ("rtmp://127.0.0.1/utest", req->tcUrl_.c_str()); + EXPECT_STREQ("rtmp", req->schema_.c_str()); + EXPECT_STREQ("__defaultVhost__", req->vhost_.c_str()); + EXPECT_STREQ("127.0.0.1", req->host_.c_str()); + EXPECT_EQ(1935, req->port_); + EXPECT_STREQ("utest", req->app_.c_str()); + EXPECT_STREQ("livestream", req->stream_.c_str()); + EXPECT_EQ(0, req->duration_); + EXPECT_TRUE(NULL == req->args_); + EXPECT_STREQ("rtmp", req->protocol_.c_str()); + EXPECT_FALSE(conn->info_->edge_); + + // Bridge must be created. + bridge = dynamic_cast(mock_source->rtmp_bridge_); + EXPECT_TRUE(bridge != NULL); + builder = bridge->rtp_builder_; + EXPECT_TRUE(builder != NULL); + +#ifdef SRS_FFMPEG_FIT + // Verify that the mock factory created the audio transcoder + EXPECT_TRUE(mock_factory->last_created_audio_transcoder_ != NULL); +#endif + } + + // Send AAC sequence header first (required before raw data). + MockRtcSource *mock_rtc_source = dynamic_cast(mock_rtc_sources->mock_source_.get()); + if (true) { + // Create AAC sequence header message. + // AAC audio format in RTMP/FLV: + // Byte 0: (SoundFormat << 4) | (SoundRate << 2) | (SoundSize << 1) | SoundType + // SoundFormat=10 (AAC), SoundRate=3 (44kHz), SoundSize=1 (16-bit), SoundType=1 (stereo) + // = 0xAF + // Byte 1: AACPacketType (0=sequence header, 1=raw data) + // Remaining bytes: AudioSpecificConfig (ASC) data + int payload_size = 4; + SrsRtmpCommonMessage *msg = new SrsRtmpCommonMessage(); + msg->header_.initialize_audio(payload_size, 0, 1); + msg->create_payload(payload_size); + + // Fill in AAC sequence header + SrsBuffer stream(msg->payload(), payload_size); + // Audio format byte: AAC(10), 44kHz(3), 16-bit(1), stereo(1) = 0xAF + stream.write_1bytes(0xAF); + // AAC packet type: 0 = AAC sequence header + stream.write_1bytes(0x00); + // AudioSpecificConfig (ASC) data: 0x12 0x10 + // This represents AAC-LC profile, 44.1kHz sample rate, 2 channels + stream.write_1bytes(0x12); + stream.write_1bytes(0x10); + + // Feed sequence header to rtmp server. + mock_rtmp_server->recv_msgs_.push_back(msg); + mock_rtmp_server->cond_->signal(); + + // Wait for consumer to process the message. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that the sequence header is sent to the RTC source. + EXPECT_EQ(1, mock_source->on_audio_count_); + EXPECT_EQ(0, mock_rtc_source->on_rtp_count_); + } + + // Send AAC raw data frame. + if (true) { + // Create AAC raw data message. + // Byte 0: Audio format byte (0xAF) + // Byte 1: AACPacketType (1=raw data) + // Remaining bytes: AAC raw frame data + int payload_size = 10; + SrsRtmpCommonMessage *msg = new SrsRtmpCommonMessage(); + msg->header_.initialize_audio(payload_size, 23, 1); // 23ms timestamp for second frame + msg->create_payload(payload_size); + + // Fill in AAC raw data + SrsBuffer stream(msg->payload(), payload_size); + // Audio format byte: AAC(10), 44kHz(3), 16-bit(1), stereo(1) = 0xAF + stream.write_1bytes(0xAF); + // AAC packet type: 1 = AAC raw data + stream.write_1bytes(0x01); + // AAC raw frame data (8 bytes of dummy audio data) + for (int i = 0; i < 8; i++) { + stream.write_1bytes(0x00); + } + + // Feed raw data to rtmp server. + mock_rtmp_server->recv_msgs_.push_back(msg); + mock_rtmp_server->cond_->signal(); + + // Wait for consumer to process the message. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that the raw data is sent to the client. + EXPECT_EQ(2, mock_source->on_audio_count_); + EXPECT_EQ(1, mock_rtc_source->on_rtp_count_); + } + + // Simulate client quit event, the receive thread will get this error. + if (true) { + mock_rtmp_server->recv_err_ = srs_error_new(ERROR_SOCKET_READ, "mock client quit"); + mock_rtmp_server->cond_->signal(); + + // Wait for coroutine to stop. + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + } + + // Stop the RTMP connection. + conn->stop(); +} diff --git a/trunk/src/utest/srs_utest_workflow_rtmp2rtc.hpp b/trunk/src/utest/srs_utest_workflow_rtmp2rtc.hpp new file mode 100644 index 000000000..ded38cc05 --- /dev/null +++ b/trunk/src/utest/srs_utest_workflow_rtmp2rtc.hpp @@ -0,0 +1,32 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_UTEST_WORKFLOW_RTMP2RTC_HPP +#define SRS_UTEST_WORKFLOW_RTMP2RTC_HPP + +/* +#include +*/ +#include + +#endif diff --git a/trunk/src/utest/srs_utest_workflow_rtmp_conn.cpp b/trunk/src/utest/srs_utest_workflow_rtmp_conn.cpp index 0b64ef910..002c4f3d1 100644 --- a/trunk/src/utest/srs_utest_workflow_rtmp_conn.cpp +++ b/trunk/src/utest/srs_utest_workflow_rtmp_conn.cpp @@ -67,16 +67,7 @@ VOID TEST(BasicWorkflowRtmpConnTest, ManuallyVerifyForPublisher) mock_config->mw_msgs_ = 0; // Handle each RTMP message, no merging write. mock_config->mw_sleep_ = 0; // Handle each RTMP message, no merging write. - mock_rtmp_server->type_ = SrsRtmpConnFMLEPublish; - mock_rtmp_server->stream_ = "livestream"; - mock_rtmp_server->ip_ = "192.168.1.100"; - mock_rtmp_server->vhost_ = "utest.ossrs.io"; - mock_rtmp_server->app_ = "utest"; - mock_rtmp_server->stream_ = "livestream"; - mock_rtmp_server->tcUrl_ = "rtmp://127.0.0.1/utest"; - mock_rtmp_server->schema_ = "rtmp"; - mock_rtmp_server->port_ = 1935; - mock_rtmp_server->host_ = "127.0.0.1"; + mock_rtmp_server->set_request(SrsRtmpConnFMLEPublish, "192.168.1.100", "utest.ossrs.io", "utest", "livestream", "rtmp://127.0.0.1/utest", "rtmp", 1935, "127.0.0.1"); // Create SrsRtmpConn - it takes ownership of transport ISrsRtmpTransport *transport = new MockRtmpTransport(); diff --git a/trunk/src/utest/srs_utest_workflow_srt_conn.cpp b/trunk/src/utest/srs_utest_workflow_srt_conn.cpp index 75e919e3c..f6176cb7b 100644 --- a/trunk/src/utest/srs_utest_workflow_srt_conn.cpp +++ b/trunk/src/utest/srs_utest_workflow_srt_conn.cpp @@ -239,6 +239,7 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer) // Simulate client quit event, the receive thread will get this error. if (true) { mock_srt_conn->read_error_ = srs_error_new(ERROR_SOCKET_READ, "mock client quit"); + mock_srt_conn->cond_->signal(); // Wait for coroutine to stop. srs_usleep(1 * SRS_UTIME_MILLISECONDS);