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/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7a353826a..d326028dc 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -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_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 6c1249df2..04d76df4e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1291,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; diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 8cf1d3db1..71fe59dec 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -3128,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(); @@ -3150,7 +3150,7 @@ SrsRtcRecvTrack::SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDes // 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 (track_desc_->media_) { + 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_); @@ -3337,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) { } @@ -3385,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 89947daec..dba5e8b03 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -883,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: @@ -917,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: @@ -931,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/kernel/srs_kernel_packet.hpp b/trunk/src/kernel/srs_kernel_packet.hpp index 5f9e48b44..23d4cf1f0 100644 --- a/trunk/src/kernel/srs_kernel_packet.hpp +++ b/trunk/src/kernel/srs_kernel_packet.hpp @@ -111,7 +111,7 @@ public: virtual srs_error_t add_sample(char *bytes, int size); // clang-format off -SRS_DECLARE_PRIVATE: // clang-format on +SRS_DECLARE_PROTECTED: // clang-format on // Copy the packet. virtual SrsParsedPacket *copy(); virtual void do_copy(SrsParsedPacket *p); @@ -131,7 +131,7 @@ public: virtual SrsAudioCodecConfig *acodec(); // clang-format off -SRS_DECLARE_PRIVATE: // clang-format on +SRS_DECLARE_PROTECTED: // clang-format on virtual SrsParsedAudioPacket *copy(); }; @@ -162,7 +162,7 @@ public: virtual srs_error_t add_sample(char *bytes, int size); // clang-format off -SRS_DECLARE_PRIVATE: // clang-format on +SRS_DECLARE_PROTECTED: // clang-format on virtual SrsParsedVideoPacket *copy(); public: diff --git a/trunk/src/utest/srs_utest_ai10.cpp b/trunk/src/utest/srs_utest_ai10.cpp index 46ac8e394..1a655668e 100644 --- a/trunk/src/utest/srs_utest_ai10.cpp +++ b/trunk/src/utest/srs_utest_ai10.cpp @@ -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 index a0423e187..362f41cd4 100644 --- a/trunk/src/utest/srs_utest_ai24.cpp +++ b/trunk/src/utest/srs_utest_ai24.cpp @@ -33,7 +33,7 @@ class MockSrsRtcRecvTrackForAVSync : public SrsRtcRecvTrack 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) + : SrsRtcRecvTrack(NULL, create_track_desc(type, ssrc, sample_rate), is_audio, true) { } diff --git a/trunk/src/utest/srs_utest_manual_mock.cpp b/trunk/src/utest/srs_utest_manual_mock.cpp index 471fd97a1..efd8932a8 100644 --- a/trunk/src/utest/srs_utest_manual_mock.cpp +++ b/trunk/src/utest/srs_utest_manual_mock.cpp @@ -547,487 +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; - rtc_server_enabled_ = false; - rtc_enabled_ = false; -} - -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() { diff --git a/trunk/src/utest/srs_utest_manual_mock.hpp b/trunk/src/utest/srs_utest_manual_mock.hpp index f09a73a55..f1c5564f8 100644 --- a/trunk/src/utest/srs_utest_manual_mock.hpp +++ b/trunk/src/utest/srs_utest_manual_mock.hpp @@ -291,20 +291,72 @@ public: 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 ""; } @@ -429,69 +481,70 @@ public: 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"; } @@ -563,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 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_workflow_rtc2rtmp.cpp b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp index 4ee58c495..2a44a1beb 100644 --- a/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp +++ b/trunk/src/utest/srs_utest_workflow_rtc2rtmp.cpp @@ -95,6 +95,7 @@ VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario) 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;