RTC: Fix DVR missing first 4-6 seconds by initializing rate from SDP (#4541)

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 <winlinvip@gmail.com>
Co-authored-by: OSSRS-AI <winlinam@gmail.com>
This commit is contained in:
Haibo Chen(陈海博) 2025-10-28 21:33:40 +08:00 committed by GitHub
parent 550760f2d0
commit ef048b0d65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 1913 additions and 1026 deletions

View File

@ -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.

8
trunk/configure vendored
View File

@ -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

View File

@ -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_);

View File

@ -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:

View File

@ -23,7 +23,9 @@
#ifdef SRS_RTSP
#include <srs_app_rtsp_source.hpp>
#endif
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_st.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>
@ -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);

View File

@ -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);

View File

@ -42,17 +42,29 @@ static const AVCodec *srs_find_encoder_by_id(SrsAudioCodecId id)
return NULL;
}
class SrsFFmpegLogHelper
{
public:
SrsFFmpegLogHelper()
SrsFFmpegLogHelper::SrsFFmpegLogHelper()
{
av_log_set_callback(ffmpeg_log_callback);
av_log_set_level(AV_LOG_TRACE);
}
static void ffmpeg_log_callback(void *, int level, const char *fmt, va_list vl)
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 char buf[4096] = {0};
int nbytes = vsnprintf(buf, sizeof(buf), fmt, vl);
if (nbytes > 0 && nbytes < (int)sizeof(buf)) {
@ -81,10 +93,6 @@ public:
}
}
}
};
// Register FFmpeg log callback funciton.
SrsFFmpegLogHelper _srs_ffmpeg_log_helper;
ISrsAudioTranscoder::ISrsAudioTranscoder()
{

View File

@ -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
{

View File

@ -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.

View File

@ -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

View File

@ -32,11 +32,10 @@
#include <srs_protocol_rtmp_msg_array.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_utility.hpp>
#ifdef SRS_FFMPEG_FIT
#include <srs_app_rtc_codec.hpp>
#endif
#include <srs_app_factory.hpp>
#include <srs_kernel_kbps.hpp>
#include <srs_protocol_raw_avc.hpp>
#include <srs_protocol_rtp.hpp>
@ -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<SrsRtcSource> source)
SrsRtcRtpBuilder::SrsRtcRtpBuilder(ISrsAppFactory *factory, ISrsRtpTarget *target, SrsSharedPtr<SrsRtcSource> 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, SrsSharedPtr<SrsRtcSou
// Lazy initialization flags
audio_initialized_ = false;
video_initialized_ = false;
app_factory_ = factory;
}
SrsRtcRtpBuilder::~SrsRtcRtpBuilder()
@ -910,6 +915,8 @@ SrsRtcRtpBuilder::~SrsRtcRtpBuilder()
srs_freep(codec_);
srs_freep(meta_);
srs_freep(video_builder_);
app_factory_ = NULL;
}
srs_error_t SrsRtcRtpBuilder::initialize_audio_track(SrsAudioCodecId codec)
@ -1097,7 +1104,7 @@ srs_error_t SrsRtcRtpBuilder::init_codec(SrsAudioCodecId codec)
// Create a new codec.
srs_freep(codec_);
codec_ = new SrsAudioTranscoder();
codec_ = app_factory_->create_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<SrsRtpPacket *> &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<double>(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<double>(last_sender_report_rtp_time_) - static_cast<double>(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)
{
}

View File

@ -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<SrsRtcSource> source);
SrsRtcRtpBuilder(ISrsAppFactory *factory, ISrsRtpTarget *target, SrsSharedPtr<SrsRtcSource> source);
virtual ~SrsRtcRtpBuilder();
// clang-format off
@ -419,9 +425,25 @@ SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t consume_packets(std::vector<SrsRtpPacket *> &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<SrsRtpPacket *> &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:

View File

@ -16,6 +16,7 @@ using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_edge.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_hls.hpp>
#include <srs_app_http_hooks.hpp>
#include <srs_app_recv_thread.hpp>
@ -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<SrsLiveSource> 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_);

View File

@ -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_;

View File

@ -9,6 +9,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_hooks.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_rtmp_source.hpp>
@ -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);

View File

@ -7,6 +7,7 @@
#include <srs_app_stream_bridge.hpp>
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_rtmp_source.hpp>
#include <srs_app_srt_source.hpp>
@ -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<SrsLiveSource> 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;

View File

@ -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<SrsRtcSource> 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<SrsLiveSource> rtmp_target_;
public:
SrsRtcBridge();
SrsRtcBridge(ISrsAppFactory *factory);
virtual ~SrsRtcBridge();
public:

View File

@ -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_;

View File

@ -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();

View File

@ -35,6 +35,7 @@ using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_log.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_server.hpp>
#include <srs_app_srt_server.hpp>
@ -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;

View File

@ -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();

View File

@ -32,6 +32,7 @@ using namespace std;
// For TCP test server and client
#include <srs_app_listener.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_st.hpp>
// 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.

View File

@ -242,7 +242,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_BasicFunctionality)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> 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<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create and enable RTC target first
@ -287,7 +287,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_WithRtspTarget)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create and enable RTSP target first
@ -313,7 +313,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_WithRtcAndRtspTargets)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Set first RTSP target
@ -377,7 +377,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_FrameHandling)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -407,7 +407,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameRtpBuilder)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Test frame handling without any targets first
@ -444,7 +444,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameRtspBuilder)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -479,7 +479,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_OnFrameBothBuilders)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Enable both RTC and RTSP targets
@ -512,7 +512,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_BasicFunctionality)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> 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<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -558,7 +558,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_WithRtcTarget)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create and enable RTC target first
@ -584,7 +584,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_PacketHandling)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -606,7 +606,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_FrameHandling)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -628,7 +628,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameRtmpTarget)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -662,7 +662,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameRtpBuilder)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -697,7 +697,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_OnFrameBothTargets)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> 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<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
// Create a mock RTMP target using shared pointer
SrsSharedPtr<SrsLiveSource> rtmp_source(new SrsLiveSource());
@ -758,7 +758,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpPacketHandling)
{
srs_error_t err;
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create RTMP target for the bridge
@ -793,7 +793,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpPacketTypes)
{
srs_error_t err;
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create RTMP target for the bridge
@ -829,7 +829,7 @@ VOID TEST(StreamBridgeTest, SrsRtcBridge_RtpWithoutFrameBuilder)
{
srs_error_t err;
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtmpBridge> rtmp_bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> rtmp_bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsSrtBridge> srt_bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> 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<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// First initialize
@ -930,7 +930,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_MultipleTargets)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -970,7 +970,7 @@ VOID TEST(StreamBridgeTest, Bridge_TargetReplacement)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Initialize bridge
@ -1001,7 +1001,7 @@ VOID TEST(StreamBridgeTest, Bridge_StateConsistency)
{
srs_error_t err;
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
HELPER_EXPECT_SUCCESS(bridge->initialize(req.get()));
@ -1048,7 +1048,7 @@ VOID TEST(StreamBridgeTest, Bridge_MemoryManagement)
}
{
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge());
SrsUniquePtr<SrsSrtBridge> bridge(new SrsSrtBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
HELPER_EXPECT_SUCCESS(bridge->initialize(req.get()));
@ -1064,7 +1064,7 @@ VOID TEST(StreamBridgeTest, Bridge_MemoryManagement)
}
{
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge());
SrsUniquePtr<SrsRtcBridge> bridge(new SrsRtcBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
SrsSharedPtr<SrsLiveSource> rtmp_source(new SrsLiveSource());
@ -1086,7 +1086,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspFrameHandling)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create and enable RTSP target
@ -1115,7 +1115,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspLifecycle)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Test lifecycle without target
@ -1143,7 +1143,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspErrorHandling)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
SrsSharedPtr<SrsRtspSource> rtsp_source(new SrsRtspSource());
@ -1192,7 +1192,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtmpToRtspConversion)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> req(new MockStreamBridgeRequest());
// Create RTSP target for protocol conversion
@ -1227,7 +1227,7 @@ VOID TEST(StreamBridgeTest, SrsRtmpBridge_RtspCodecChanges)
{
srs_error_t err;
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge());
SrsUniquePtr<SrsRtmpBridge> bridge(new SrsRtmpBridge(_srs_app_factory));
SrsUniquePtr<MockStreamBridgeRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> req(new MockRtcRequest());

View File

@ -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<SrsParsedAudioPacket *> &outs)
srs_error_t MockAudioTranscoderForUtest::transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &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<SrsParsedAudioPacket *> &frames)
void MockAudioTranscoderForUtest::free_frames(std::vector<SrsParsedAudioPacket *> &frames)
{
for (std::vector<SrsParsedAudioPacket *>::iterator it = frames.begin(); it != frames.end(); ++it) {
SrsParsedAudioPacket *p = *it;
@ -119,13 +122,13 @@ void MockAudioTranscoder::free_frames(std::vector<SrsParsedAudioPacket *> &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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> req(new MockRtcRequest());

View File

@ -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

View File

@ -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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<SrsRtpPacket> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> 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<MockRtcRequest> req(new MockRtcRequest());
@ -2253,7 +2253,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadEmptyBuffer)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2276,7 +2276,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264RawNALU)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2307,7 +2307,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264STAP)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2342,7 +2342,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264FUA)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2376,7 +2376,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCRawNALU)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H265", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2407,7 +2407,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCSTAP)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H265", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2444,7 +2444,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCFUA)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H265", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2479,7 +2479,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadUnknownCodec)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("VP8", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> 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<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2529,7 +2529,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadH264IDR)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2560,7 +2560,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadHEVCIDR)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H265", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> pkt(create_test_rtp_packet(100, 1000, 12345));
@ -2591,7 +2591,7 @@ VOID TEST(SrsRtcVideoRecvTrackTest, OnBeforeDecodePayloadSingleByte)
{
MockRtcPacketReceiver mock_receiver;
SrsUniquePtr<SrsRtcTrackDescription> desc(create_video_track_description("H264", 12345));
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get());
SrsRtcVideoRecvTrack track(&mock_receiver, desc.get(), false);
SrsUniquePtr<SrsRtpPacket> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> track_desc1(create_test_track_description("audio", 55555));
SrsUniquePtr<SrsRtcTrackDescription> 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;

View File

@ -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);

View File

@ -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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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<SrsRtcTrackDescription> 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

View File

@ -0,0 +1,305 @@
//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#include <srs_utest_ai24.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_rtc_rtcp.hpp>
#include <srs_protocol_sdp.hpp>
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<SrsRtcSource> &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());
}

View File

@ -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 <srs_utest.hpp>
#endif

View File

@ -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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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<MockRtc2RtmpRequest> 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)

View File

@ -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<SrsRtcSource>(new SrsRtcSource());
mock_source_ = SrsSharedPtr<SrsRtcSource>(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<std::string> &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<std::string> &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<std::string> &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<SrsRtpPacket *> &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<SrsParsedAudioPacket *> &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<SrsParsedAudioPacket *> &frames)
{
for (std::vector<SrsParsedAudioPacket *>::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;
}

View File

@ -17,6 +17,7 @@
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_ffmpeg.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_dtls.hpp>
#include <srs_app_rtc_source.hpp>
@ -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<uint32_t, SrsRtcTrackDescription *> 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<std::string> &destinations);
void set_forward_backend(const std::string &backend_url);
void set_forward_destinations(const std::vector<std::string> &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<std::string> 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<std::string> get_engine_aparams(SrsConfDirective *conf) { return std::vector<std::string>(); }
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<std::string> &urls);
void clear_on_stop_directive();
void set_on_unpublish_urls(const std::vector<std::string> &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<std::string> &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<std::string> &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<SrsRtpPacket *> &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<SrsParsedAudioPacket *> 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<SrsParsedAudioPacket *> &outs);
virtual void free_frames(std::vector<SrsParsedAudioPacket *> &frames);
virtual void aac_codec_header(uint8_t **data, int *len);
};
#endif

View File

@ -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);

View File

@ -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)

View File

@ -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()

View File

@ -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 <srs_utest_workflow_rtc2rtmp.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_server.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_stream_token.hpp>
#include <srs_kernel_error.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_utest_ai11.hpp>
#include <srs_utest_manual_mock.hpp>
#include <srs_utest_manual_service.hpp>
#include <srs_utest_workflow_rtc_conn.hpp>
// 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<MockAppConfig> mock_config(new MockAppConfig());
SrsUniquePtr<MockRtcSourceManager> mock_rtc_sources(new MockRtcSourceManager());
SrsUniquePtr<MockAppStatistic> mock_stat(new MockAppStatistic());
SrsUniquePtr<MockRtcAsyncCallRequest> mock_request(new MockRtcAsyncCallRequest("test.vhost", "live", "stream1"));
SrsUniquePtr<MockRtcAsyncTaskExecutor> mock_exec(new MockRtcAsyncTaskExecutor());
SrsUniquePtr<MockExpire> mock_expire(new MockExpire());
SrsUniquePtr<MockRtcPacketReceiver> mock_receiver(new MockRtcPacketReceiver());
SrsUniquePtr<MockRtcTrackDescriptionFactory> track_factory(new MockRtcTrackDescriptionFactory());
SrsUniquePtr<MockLiveSourceManager> mock_sources(new MockLiveSourceManager());
SrsUniquePtr<MockAppFactoryForRtc2Rtmp> 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<SrsRtcPublishStream> 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<SrsRtcSourceDescription> 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<SrsRtcBridge *>(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<MockLiveSource *>(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<char[]> 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();
}

View File

@ -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 <srs_utest_workflow_rtc2rtmp.hpp>
*/
#include <srs_utest.hpp>
#endif

View File

@ -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 <srs_utest_rtc_conn.hpp>
#include <srs_utest_workflow_rtc_conn.hpp>
*/
#include <srs_utest.hpp>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <srs_utest_workflow_rtmp2rtc.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_protocol_conn.hpp>
#include <srs_protocol_io.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_st.hpp>
#include <srs_utest_ai11.hpp>
#include <srs_utest_ai15.hpp>
#include <srs_utest_ai18.hpp>
#include <srs_utest_ai22.hpp>
#include <srs_utest_manual_mock.hpp>
#include <srs_utest_manual_service.hpp>
#include <sys/socket.h>
#include <unistd.h>
// 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<MockAppFactoryForRtmp2Rtc> mock_factory(new MockAppFactoryForRtmp2Rtc());
SrsUniquePtr<MockAppConfig> mock_config(new MockAppConfig());
SrsUniquePtr<MockConnectionManager> mock_manager(new MockConnectionManager());
SrsUniquePtr<MockLiveSourceManager> mock_sources(new MockLiveSourceManager());
SrsUniquePtr<MockStreamPublishTokenManager> mock_tokens(new MockStreamPublishTokenManager());
SrsUniquePtr<MockAppStatistic> mock_stat(new MockAppStatistic());
SrsUniquePtr<MockHttpHooks> mock_hooks(new MockHttpHooks());
SrsUniquePtr<MockRtcSourceManager> mock_rtc_sources(new MockRtcSourceManager());
SrsUniquePtr<MockSrtSourceManager> mock_srt_sources(new MockSrtSourceManager());
#ifdef SRS_RTSP
SrsUniquePtr<MockRtspSourceManager> 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<SrsRtmpConn> 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<MockLiveSource *>(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<SrsRtmpBridge *>(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<MockRtcSource *>(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();
}

View File

@ -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 <srs_utest_workflow_rtmp2rtc.hpp>
*/
#include <srs_utest.hpp>
#endif

View File

@ -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();

View File

@ -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);