diff --git a/trunk/conf/console.conf b/trunk/conf/console.conf
index 900f6b936..a48946833 100644
--- a/trunk/conf/console.conf
+++ b/trunk/conf/console.conf
@@ -21,6 +21,10 @@ rtc_server {
# @see https://ossrs.io/lts/en-us/docs/v7/doc/webrtc#config-candidate
candidate $CANDIDATE;
}
+srt_server {
+ enabled on;
+ listen 10080;
+}
rtsp_server {
enabled on;
listen 8554;
@@ -40,6 +44,10 @@ vhost __defaultVhost__ {
# @see https://ossrs.io/lts/en-us/docs/v7/doc/webrtc#rtc-to-rtmp
rtc_to_rtmp on;
}
+ srt {
+ enabled on;
+ srt_to_rtmp on;
+ }
rtsp {
enabled on;
rtmp_to_rtsp on;
diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf
index 7a8729e67..3029cecd4 100644
--- a/trunk/conf/full.conf
+++ b/trunk/conf/full.conf
@@ -751,7 +751,7 @@ vhost srt.vhost.srs.com {
enabled on;
# Whether covert SRT to RTMP stream.
# Overwrite by env SRS_VHOST_SRT_TO_RTMP for all vhosts.
- # Default: on
+ # Default: off
srt_to_rtmp on;
}
}
diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md
index f1790125f..0e4b70e72 100644
--- a/trunk/doc/CHANGELOG.md
+++ b/trunk/doc/CHANGELOG.md
@@ -7,6 +7,7 @@ The changelog for SRS.
## SRS 7.0 Changelog
+* v7.0, 2025-11-04, AI: SRT: Report video/audio codec info and frame stats in HTTP API. v7.0.117 (#4554)
* v7.0, 2025-11-03, Merge [#4556](https://github.com/ossrs/srs/pull/4556): Fill missing defs for H264/AVC video levels. v7.0.116 (#4556)
* v7.0, 2025-10-31, Merge [#4547](https://github.com/ossrs/srs/pull/4547): Add ignore configuration for cursor. v7.0.115 (#4547)
* v7.0, 2025-10-30, WebRTC: Use realtime for TWCC timestamp accuracy. v7.0.114
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index faf0155a3..45716df8e 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -7696,10 +7696,10 @@ bool SrsConfig::get_srt_enabled(std::string vhost)
bool SrsConfig::get_srt_to_rtmp(std::string vhost)
{
- SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.srt.srt_to_rtmp"); // SRS_VHOST_SRT_SRT_TO_RTMP
- SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.srt.to_rtmp"); // SRS_VHOST_SRT_TO_RTMP
+ SRS_OVERWRITE_BY_ENV_BOOL2("srs.vhost.srt.srt_to_rtmp"); // SRS_VHOST_SRT_SRT_TO_RTMP
+ SRS_OVERWRITE_BY_ENV_BOOL2("srs.vhost.srt.to_rtmp"); // SRS_VHOST_SRT_TO_RTMP
- static bool DEFAULT = true;
+ static bool DEFAULT = false;
SrsConfDirective *conf = get_srt(vhost);
if (!conf) {
diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp
index 619726a16..a2a958291 100644
--- a/trunk/src/app/srs_app_srt_conn.cpp
+++ b/trunk/src/app/srs_app_srt_conn.cpp
@@ -696,7 +696,7 @@ srs_error_t SrsMpegtsSrtConn::on_srt_packet(char *buf, int nb_buf)
SrsUniquePtr packet(new SrsSrtPacket());
packet->wrap(buf, nb_buf);
- if ((err = srt_source_->on_packet(packet.get())) != srs_success) {
+ if ((err = srt_source_->on_srt_packet(packet.get())) != srs_success) {
return srs_error_wrap(err, "on srt packet");
}
diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp
index 9adcae61f..f34d9471a 100644
--- a/trunk/src/app/srs_app_srt_source.cpp
+++ b/trunk/src/app/srs_app_srt_source.cpp
@@ -16,7 +16,9 @@ using namespace std;
#include
#include
#include
+#include
#include
+#include
#include
#include
@@ -337,7 +339,7 @@ srs_error_t SrsSrtFrameBuilder::on_publish()
return srs_success;
}
-srs_error_t SrsSrtFrameBuilder::on_packet(SrsSrtPacket *pkt)
+srs_error_t SrsSrtFrameBuilder::on_srt_packet(SrsSrtPacket *pkt)
{
srs_error_t err = srs_success;
@@ -924,6 +926,253 @@ srs_error_t SrsSrtFrameBuilder::on_aac_frame(SrsTsMessage *msg, uint32_t pts, ch
return err;
}
+ISrsSrtFormat::ISrsSrtFormat()
+{
+}
+
+ISrsSrtFormat::~ISrsSrtFormat()
+{
+}
+
+SrsSrtFormat::SrsSrtFormat()
+{
+ req_ = NULL;
+ ts_ctx_ = new SrsTsContext();
+ format_ = new SrsRtmpFormat();
+ video_codec_reported_ = false;
+ audio_codec_reported_ = false;
+
+ stat_ = _srs_stat;
+}
+
+SrsSrtFormat::~SrsSrtFormat()
+{
+ req_ = NULL;
+ srs_freep(ts_ctx_);
+ srs_freep(format_);
+
+ stat_ = NULL;
+}
+
+srs_error_t SrsSrtFormat::initialize(ISrsRequest *req)
+{
+ srs_error_t err = srs_success;
+
+ req_ = req;
+
+ return err;
+}
+
+srs_error_t SrsSrtFormat::on_srt_packet(SrsSrtPacket *pkt)
+{
+ srs_error_t err = srs_success;
+
+ char *buf = pkt->data();
+ int nb_buf = pkt->size();
+
+ // Parse TS packets to extract codec information
+ int nb_packet = nb_buf / SRS_TS_PACKET_SIZE;
+ for (int i = 0; i < nb_packet; i++) {
+ char *p = buf + (i * SRS_TS_PACKET_SIZE);
+ SrsUniquePtr stream(new SrsBuffer(p, SRS_TS_PACKET_SIZE));
+
+ // Decode TS packet and call on_ts_message for each message
+ if ((err = ts_ctx_->decode(stream.get(), this)) != srs_success) {
+ // Ignore parse errors, just log and continue
+ srs_warn("srt format parse ts packet err=%s", srs_error_desc(err).c_str());
+ srs_freep(err);
+ continue;
+ }
+ }
+
+ return err;
+}
+
+srs_error_t SrsSrtFormat::on_ts_message(SrsTsMessage *msg)
+{
+ srs_error_t err = srs_success;
+
+ // Only parse video and audio messages
+ if (msg->channel_->stream_ == SrsTsStreamVideoH264 || msg->channel_->stream_ == SrsTsStreamVideoHEVC) {
+ if (video_codec_reported_) {
+ return err;
+ }
+
+ if ((err = parse_video_codec(msg)) != srs_success) {
+ return srs_error_wrap(err, "parse video codec");
+ }
+
+ if (format_->vcodec_) {
+ video_codec_reported_ = true;
+
+ SrsVideoCodecConfig *c = format_->vcodec_;
+ if ((err = stat_->on_video_info(req_, c->id_, c->avc_profile_, c->avc_level_, c->width_, c->height_)) != srs_success) {
+ return srs_error_wrap(err, "stat video info");
+ }
+
+ srs_trace("srt: parsed %s codec, profile=%s, level=%s, %dx%d",
+ srs_video_codec_id2str(c->id_).c_str(),
+ srs_avc_profile2str(c->avc_profile_).c_str(), srs_avc_level2str(c->avc_level_).c_str(),
+ c->width_, c->height_);
+ }
+ } else if (msg->channel_->stream_ == SrsTsStreamAudioAAC) {
+ if (audio_codec_reported_) {
+ return err;
+ }
+
+ if ((err = parse_audio_codec(msg)) != srs_success) {
+ return srs_error_wrap(err, "parse audio codec");
+ }
+
+ if (format_->acodec_) {
+ audio_codec_reported_ = true;
+
+ SrsAudioCodecConfig *c = format_->acodec_;
+ SrsAudioChannels channels = c->sound_type_;
+ if (c->id_ == SrsAudioCodecIdAAC) {
+ channels = (c->aac_channels_ == 1) ? SrsAudioChannelsMono : SrsAudioChannelsStereo;
+ }
+ if ((err = stat_->on_audio_info(req_, c->id_, c->sound_rate_, channels, c->aac_object_)) != srs_success) {
+ return srs_error_wrap(err, "stat audio info");
+ }
+
+ srs_trace("srt: parsed %s codec, sample_rate=%dHZ, channels=%d, profile=%s",
+ srs_audio_codec_id2str(c->id_).c_str(),
+ srs_audio_sample_rate2number(c->sound_rate_), (int)channels + 1,
+ srs_aac_object2str(c->aac_object_).c_str());
+ }
+ }
+
+ return err;
+}
+
+srs_error_t SrsSrtFormat::parse_video_codec(SrsTsMessage *msg)
+{
+ srs_error_t err = srs_success;
+
+ // Parse the video codec from TS message payload
+ SrsBuffer avs(msg->payload_->bytes(), msg->payload_->length());
+
+ // Parse H.265/HEVC to extract VPS/SPS/PPS
+ // TODO: FIXME: Implement HEVC codec parsing similar to H.264
+ if (msg->channel_->stream_ == SrsTsStreamVideoHEVC) {
+ video_codec_reported_ = true;
+ return err;
+ }
+
+ // Only parse H.264 video messages
+ if (msg->channel_->stream_ == SrsTsStreamVideoH264) {
+ // Parse H.264 to extract SPS/PPS
+ SrsUniquePtr avc(new SrsRawH264Stream());
+ std::string sps, pps;
+
+ while (!avs.empty()) {
+ char *data = NULL;
+ int data_size = 0;
+ if ((err = avc->annexb_demux(&avs, &data, &data_size)) != srs_success) {
+ return srs_error_wrap(err, "demux annexb");
+ }
+
+ if (data == NULL || data_size == 0) {
+ continue;
+ }
+
+ // Extract SPS
+ if (avc->is_sps(data, data_size)) {
+ if ((err = avc->sps_demux(data, data_size, sps)) != srs_success) {
+ return srs_error_wrap(err, "demux sps");
+ }
+ }
+
+ // Extract PPS
+ if (avc->is_pps(data, data_size)) {
+ if ((err = avc->pps_demux(data, data_size, pps)) != srs_success) {
+ return srs_error_wrap(err, "demux pps");
+ }
+ }
+
+ // Skip until we have both SPS and PPS
+ if (sps.empty() || pps.empty()) {
+ continue;
+ }
+
+ // If we have both SPS and PPS, parse codec details
+ std::string sh;
+ if ((err = avc->mux_sequence_header(sps, pps, sh)) != srs_success) {
+ return srs_error_wrap(err, "mux sequence header");
+ }
+
+ // Create a temporary media packet to parse codec info
+ char *flv = NULL;
+ int nb_flv = 0;
+ uint32_t dts = 0;
+ if ((err = avc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, dts, dts, &flv, &nb_flv)) != srs_success) {
+ return srs_error_wrap(err, "avc to flv");
+ }
+
+ SrsMediaPacket frame;
+ frame.wrap(flv, nb_flv);
+
+ // Parse the video format to extract codec details
+ if ((err = format_->on_video(&frame)) != srs_success) {
+ return srs_error_wrap(err, "format parse video");
+ }
+
+ return err;
+ }
+ }
+
+ return err;
+}
+
+srs_error_t SrsSrtFormat::parse_audio_codec(SrsTsMessage *msg)
+{
+ srs_error_t err = srs_success;
+
+ // Parse the audio codec from TS message payload
+ SrsBuffer avs(msg->payload_->bytes(), msg->payload_->length());
+
+ if (msg->channel_->stream_ == SrsTsStreamAudioAAC) {
+ // Parse AAC to extract audio specific config
+ SrsUniquePtr aac(new SrsRawAacStream());
+
+ char *frame = NULL;
+ int frame_size = 0;
+ SrsRawAacStreamCodec codec;
+ if ((err = aac->adts_demux(&avs, &frame, &frame_size, codec)) != srs_success) {
+ return srs_error_wrap(err, "demux adts");
+ }
+
+ if (frame_size <= 0) {
+ return err;
+ }
+
+ std::string sh;
+ if ((err = aac->mux_sequence_header(&codec, sh)) != srs_success) {
+ return srs_error_wrap(err, "mux sequence header");
+ }
+
+ // Create a temporary media packet to parse codec info
+ int rtmp_len = sh.size() + 2;
+ char *buf = new char[rtmp_len];
+ SrsBuffer stream(buf, rtmp_len);
+ uint8_t aac_flag = (SrsAudioCodecIdAAC << 4) | (codec.sound_rate_ << 2) | (codec.sound_size_ << 1) | codec.sound_type_;
+ stream.write_1bytes(aac_flag);
+ stream.write_1bytes(0);
+ stream.write_bytes((char *)sh.data(), sh.size());
+
+ SrsMediaPacket frame_pkt;
+ frame_pkt.wrap(buf, rtmp_len);
+
+ // Parse the audio format to extract codec details
+ if ((err = format_->on_audio(&frame_pkt)) != srs_success) {
+ return srs_error_wrap(err, "format parse audio");
+ }
+ }
+
+ return err;
+}
+
ISrsSrtSource::ISrsSrtSource()
{
}
@@ -940,6 +1189,7 @@ SrsSrtSource::SrsSrtSource()
stream_die_at_ = 0;
stat_ = _srs_stat;
+ format_ = new SrsSrtFormat();
}
SrsSrtSource::~SrsSrtSource()
@@ -950,6 +1200,7 @@ SrsSrtSource::~SrsSrtSource()
srs_freep(srt_bridge_);
srs_freep(req_);
+ srs_freep(format_);
SrsContextId cid = _source_id;
if (cid.empty())
@@ -977,6 +1228,11 @@ srs_error_t SrsSrtSource::initialize(ISrsRequest *r)
req_ = r->copy();
+ // Initialize format parser for codec detection
+ if ((err = format_->initialize(req_)) != srs_success) {
+ return srs_error_wrap(err, "format initialize");
+ }
+
return err;
}
@@ -1131,10 +1387,18 @@ void SrsSrtSource::on_unpublish()
can_publish_ = true;
}
-srs_error_t SrsSrtSource::on_packet(SrsSrtPacket *packet)
+srs_error_t SrsSrtSource::on_srt_packet(SrsSrtPacket *packet)
{
srs_error_t err = srs_success;
+ // Parse packet to extract codec information for statistics
+ // This is lightweight and only parses until codec info is found
+ if ((err = format_->on_srt_packet(packet)) != srs_success) {
+ // Don't fail on parse errors, just log and continue
+ srs_warn("srt source parse packet err=%s", srs_error_desc(err).c_str());
+ srs_freep(err);
+ }
+
for (int i = 0; i < (int)consumers_.size(); i++) {
ISrsSrtConsumer *consumer = consumers_.at(i);
if ((err = consumer->enqueue(packet->copy())) != srs_success) {
@@ -1142,7 +1406,7 @@ srs_error_t SrsSrtSource::on_packet(SrsSrtPacket *packet)
}
}
- if (srt_bridge_ && (err = srt_bridge_->on_packet(packet)) != srs_success) {
+ if (srt_bridge_ && (err = srt_bridge_->on_srt_packet(packet)) != srs_success) {
return srs_error_wrap(err, "bridge consume message");
}
diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp
index 13177bdb0..48a33c916 100644
--- a/trunk/src/app/srs_app_srt_source.hpp
+++ b/trunk/src/app/srs_app_srt_source.hpp
@@ -149,6 +149,50 @@ public:
virtual void wait(int nb_msgs, srs_utime_t timeout);
};
+// The SRT format interface.
+class ISrsSrtFormat
+{
+public:
+ ISrsSrtFormat();
+ virtual ~ISrsSrtFormat();
+
+public:
+ virtual srs_error_t initialize(ISrsRequest *req) = 0;
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt) = 0;
+};
+
+// Lightweight format parser for SRT streams to extract codec information
+// from MPEG-TS packets and update statistics.
+class SrsSrtFormat : public ISrsSrtFormat, public ISrsTsHandler
+{
+public:
+ SrsSrtFormat();
+ virtual ~SrsSrtFormat();
+
+public:
+ srs_error_t initialize(ISrsRequest *req);
+ srs_error_t on_srt_packet(SrsSrtPacket *pkt);
+
+public:
+ // Interface ISrsTsHandler
+ virtual srs_error_t on_ts_message(SrsTsMessage *msg);
+
+// clang-format off
+SRS_DECLARE_PRIVATE: // clang-format on
+ srs_error_t parse_video_codec(SrsTsMessage *msg);
+ srs_error_t parse_audio_codec(SrsTsMessage *msg);
+
+// clang-format off
+SRS_DECLARE_PRIVATE: // clang-format on
+ ISrsRequest *req_;
+ ISrsStatistic *stat_;
+ SrsTsContext *ts_ctx_;
+ SrsRtmpFormat *format_;
+ // Track whether we've already reported codec info to avoid duplicate updates
+ bool video_codec_reported_;
+ bool audio_codec_reported_;
+};
+
// Collect and build SRT TS packet to AV frames.
class SrsSrtFrameBuilder : public ISrsTsHandler
{
@@ -161,7 +205,7 @@ public:
public:
virtual srs_error_t on_publish();
- virtual srs_error_t on_packet(SrsSrtPacket *pkt);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt);
virtual void on_unpublish();
// Interface ISrsTsHandler
public:
@@ -270,7 +314,7 @@ public:
virtual void on_unpublish();
public:
- srs_error_t on_packet(SrsSrtPacket *packet);
+ srs_error_t on_srt_packet(SrsSrtPacket *packet);
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
@@ -288,6 +332,8 @@ SRS_DECLARE_PRIVATE: // clang-format on
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSrtBridge *srt_bridge_;
+ // Format parser for extracting codec information and updating statistics
+ ISrsSrtFormat *format_;
};
#endif
diff --git a/trunk/src/app/srs_app_stream_bridge.cpp b/trunk/src/app/srs_app_stream_bridge.cpp
index 6e8921d65..59ae9ac80 100644
--- a/trunk/src/app/srs_app_stream_bridge.cpp
+++ b/trunk/src/app/srs_app_stream_bridge.cpp
@@ -327,11 +327,11 @@ void SrsSrtBridge::on_unpublish()
// So there is no need to free its components here.
}
-srs_error_t SrsSrtBridge::on_packet(SrsSrtPacket *pkt)
+srs_error_t SrsSrtBridge::on_srt_packet(SrsSrtPacket *pkt)
{
srs_error_t err = srs_success;
- if ((err = frame_builder_->on_packet(pkt)) != srs_success) {
+ if ((err = frame_builder_->on_srt_packet(pkt)) != srs_success) {
return srs_error_wrap(err, "frame builder on packet");
}
diff --git a/trunk/src/app/srs_app_stream_bridge.hpp b/trunk/src/app/srs_app_stream_bridge.hpp
index c6fddccad..b494a2fb6 100644
--- a/trunk/src/app/srs_app_stream_bridge.hpp
+++ b/trunk/src/app/srs_app_stream_bridge.hpp
@@ -64,7 +64,7 @@ public:
virtual ~ISrsSrtTarget();
public:
- virtual srs_error_t on_packet(SrsSrtPacket *pkt) = 0;
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt) = 0;
};
// A RTMP bridge is used to convert RTMP stream to different protocols,
@@ -171,7 +171,7 @@ public:
virtual srs_error_t initialize(ISrsRequest *r);
virtual srs_error_t on_publish();
virtual void on_unpublish();
- virtual srs_error_t on_packet(SrsSrtPacket *pkt);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt);
virtual srs_error_t on_frame(SrsMediaPacket *frame);
};
diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp
index b814f60f4..dabdd8f26 100644
--- a/trunk/src/core/srs_core_version7.hpp
+++ b/trunk/src/core/srs_core_version7.hpp
@@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
-#define VERSION_REVISION 116
+#define VERSION_REVISION 117
#endif
\ No newline at end of file
diff --git a/trunk/src/utest/srs_utest_ai01.cpp b/trunk/src/utest/srs_utest_ai01.cpp
index eff8f0915..a1ceea4a5 100644
--- a/trunk/src/utest/srs_utest_ai01.cpp
+++ b/trunk/src/utest/srs_utest_ai01.cpp
@@ -7152,9 +7152,9 @@ VOID TEST(ConfigSrtVhostTest, CheckSrtToRtmp)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF));
- // Default should be true
- EXPECT_TRUE(conf.get_srt_to_rtmp("__defaultVhost__"));
- EXPECT_TRUE(conf.get_srt_to_rtmp("test.com"));
+ // Default should be false (off)
+ EXPECT_FALSE(conf.get_srt_to_rtmp("__defaultVhost__"));
+ EXPECT_FALSE(conf.get_srt_to_rtmp("test.com"));
}
// Test default value when vhost exists but no srt section
@@ -7163,7 +7163,7 @@ VOID TEST(ConfigSrtVhostTest, CheckSrtToRtmp)
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF "vhost test.com{hls{enabled on;}}"));
// Should return default value when no srt section
- EXPECT_TRUE(conf.get_srt_to_rtmp("test.com"));
+ EXPECT_FALSE(conf.get_srt_to_rtmp("test.com"));
}
// Test default value when srt section exists but no srt_to_rtmp config
@@ -7172,7 +7172,7 @@ VOID TEST(ConfigSrtVhostTest, CheckSrtToRtmp)
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF "vhost test.com{srt{enabled on;}}"));
// Should return default value when no srt_to_rtmp config
- EXPECT_TRUE(conf.get_srt_to_rtmp("test.com"));
+ EXPECT_FALSE(conf.get_srt_to_rtmp("test.com"));
}
// Test explicit srt_to_rtmp enabled
@@ -7206,7 +7206,7 @@ VOID TEST(ConfigSrtVhostTest, CheckSrtToRtmp)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF "vhost test.com{srt{srt_to_rtmp;}}"));
- EXPECT_TRUE(conf.get_srt_to_rtmp("test.com")); // Default value
+ EXPECT_FALSE(conf.get_srt_to_rtmp("test.com")); // Default value is false (off)
}
}
diff --git a/trunk/src/utest/srs_utest_ai08.cpp b/trunk/src/utest/srs_utest_ai08.cpp
index 7d5f69dca..9aa0f8439 100644
--- a/trunk/src/utest/srs_utest_ai08.cpp
+++ b/trunk/src/utest/srs_utest_ai08.cpp
@@ -142,7 +142,7 @@ MockSrtTarget::~MockSrtTarget()
srs_freep(packet_error_);
}
-srs_error_t MockSrtTarget::on_packet(SrsSrtPacket *pkt)
+srs_error_t MockSrtTarget::on_srt_packet(SrsSrtPacket *pkt)
{
on_packet_count_++;
last_packet_ = pkt;
@@ -230,8 +230,8 @@ VOID TEST(StreamBridgeTest, ISrsSrtTarget_Interface)
char *data = pkt->wrap(188); // TS packet size
data[0] = 0x47; // TS sync byte
- // Test on_packet call
- srs_error_t err = target.on_packet(pkt.get());
+ // Test on_srt_packet call
+ srs_error_t err = target.on_srt_packet(pkt.get());
EXPECT_TRUE(err == srs_success);
EXPECT_EQ(1, target.on_packet_count_);
EXPECT_EQ(pkt.get(), target.last_packet_);
@@ -598,7 +598,7 @@ VOID TEST(StreamBridgeTest, SrsSrtBridge_PacketHandling)
data[0] = 0x47;
// Test packet handling (should succeed even without targets)
- HELPER_EXPECT_SUCCESS(bridge->on_packet(pkt.get()));
+ HELPER_EXPECT_SUCCESS(bridge->on_srt_packet(pkt.get()));
}
// Test SrsSrtBridge frame handling - comprehensive coverage of on_frame() method
diff --git a/trunk/src/utest/srs_utest_ai08.hpp b/trunk/src/utest/srs_utest_ai08.hpp
index 0657ab903..9b02ac598 100644
--- a/trunk/src/utest/srs_utest_ai08.hpp
+++ b/trunk/src/utest/srs_utest_ai08.hpp
@@ -79,7 +79,7 @@ public:
public:
MockSrtTarget();
virtual ~MockSrtTarget();
- virtual srs_error_t on_packet(SrsSrtPacket *pkt);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt);
void set_packet_error(srs_error_t err);
};
diff --git a/trunk/src/utest/srs_utest_ai18.cpp b/trunk/src/utest/srs_utest_ai18.cpp
index 85dc263fd..5a6c5a679 100644
--- a/trunk/src/utest/srs_utest_ai18.cpp
+++ b/trunk/src/utest/srs_utest_ai18.cpp
@@ -845,7 +845,7 @@ MockSrtSourceForPacket::~MockSrtSourceForPacket()
srs_freep(last_packet_);
}
-srs_error_t MockSrtSourceForPacket::on_packet(SrsSrtPacket *packet)
+srs_error_t MockSrtSourceForPacket::on_srt_packet(SrsSrtPacket *packet)
{
on_packet_called_count_++;
diff --git a/trunk/src/utest/srs_utest_ai18.hpp b/trunk/src/utest/srs_utest_ai18.hpp
index 641c3cf36..d5261df02 100644
--- a/trunk/src/utest/srs_utest_ai18.hpp
+++ b/trunk/src/utest/srs_utest_ai18.hpp
@@ -121,7 +121,7 @@ public:
public:
MockSrtSourceForPacket();
virtual ~MockSrtSourceForPacket();
- virtual srs_error_t on_packet(SrsSrtPacket *packet);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *packet);
};
// Mock ISrsAppConfig for testing SrsMpegtsSrtConn HTTP hooks
diff --git a/trunk/src/utest/srs_utest_ai21.cpp b/trunk/src/utest/srs_utest_ai21.cpp
index 61a014a93..e05e45bbb 100644
--- a/trunk/src/utest/srs_utest_ai21.cpp
+++ b/trunk/src/utest/srs_utest_ai21.cpp
@@ -1359,7 +1359,7 @@ void MockSrtBridge::on_unpublish()
on_unpublish_count_++;
}
-srs_error_t MockSrtBridge::on_packet(SrsSrtPacket *packet)
+srs_error_t MockSrtBridge::on_srt_packet(SrsSrtPacket *packet)
{
on_packet_count_++;
return srs_error_copy(on_packet_error_);
@@ -1589,8 +1589,8 @@ VOID TEST(SrsSrtSourceTest, OnPacketDistribution)
const char *test_data = "Test SRT Packet Data";
packet->wrap((char *)test_data, strlen(test_data));
- // Test: on_packet should distribute to all consumers and bridge
- HELPER_EXPECT_SUCCESS(source->on_packet(packet.get()));
+ // Test: on_srt_packet should distribute to all consumers and bridge
+ HELPER_EXPECT_SUCCESS(source->on_srt_packet(packet.get()));
// Verify both consumers received the packet
EXPECT_EQ(1, consumer1->enqueue_count_);
diff --git a/trunk/src/utest/srs_utest_ai21.hpp b/trunk/src/utest/srs_utest_ai21.hpp
index 9259e620c..3ecdd04ad 100644
--- a/trunk/src/utest/srs_utest_ai21.hpp
+++ b/trunk/src/utest/srs_utest_ai21.hpp
@@ -87,7 +87,7 @@ public:
virtual srs_error_t initialize(ISrsRequest *r);
virtual srs_error_t on_publish();
virtual void on_unpublish();
- virtual srs_error_t on_packet(SrsSrtPacket *packet);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *packet);
void set_on_publish_error(srs_error_t err);
void set_on_packet_error(srs_error_t err);
void reset();
diff --git a/trunk/src/utest/srs_utest_manual_mock.cpp b/trunk/src/utest/srs_utest_manual_mock.cpp
index efd8932a8..9bb9ff6ed 100644
--- a/trunk/src/utest/srs_utest_manual_mock.cpp
+++ b/trunk/src/utest/srs_utest_manual_mock.cpp
@@ -784,10 +784,10 @@ srs_error_t MockSrtSource::on_publish()
return SrsSrtSource::on_publish();
}
-srs_error_t MockSrtSource::on_packet(SrsSrtPacket *packet)
+srs_error_t MockSrtSource::on_srt_packet(SrsSrtPacket *packet)
{
on_packet_count_++;
- return SrsSrtSource::on_packet(packet);
+ return SrsSrtSource::on_srt_packet(packet);
}
void MockSrtSource::set_can_publish(bool can_publish)
@@ -795,6 +795,33 @@ void MockSrtSource::set_can_publish(bool can_publish)
can_publish_result_ = can_publish;
}
+// Mock SRT format implementation
+MockSrtFormat::MockSrtFormat()
+{
+ initialize_count_ = 0;
+ on_srt_packet_count_ = 0;
+ initialize_error_ = srs_success;
+ on_srt_packet_error_ = srs_success;
+}
+
+MockSrtFormat::~MockSrtFormat()
+{
+ srs_freep(initialize_error_);
+ srs_freep(on_srt_packet_error_);
+}
+
+srs_error_t MockSrtFormat::initialize(ISrsRequest *req)
+{
+ initialize_count_++;
+ return srs_error_copy(initialize_error_);
+}
+
+srs_error_t MockSrtFormat::on_srt_packet(SrsSrtPacket *pkt)
+{
+ on_srt_packet_count_++;
+ return srs_error_copy(on_srt_packet_error_);
+}
+
// Mock SRT source manager implementation
MockSrtSourceManager::MockSrtSourceManager()
{
diff --git a/trunk/src/utest/srs_utest_manual_mock.hpp b/trunk/src/utest/srs_utest_manual_mock.hpp
index 36f5adcc2..95b9ad473 100644
--- a/trunk/src/utest/srs_utest_manual_mock.hpp
+++ b/trunk/src/utest/srs_utest_manual_mock.hpp
@@ -762,12 +762,30 @@ public:
public:
virtual bool can_publish();
virtual srs_error_t on_publish();
- virtual srs_error_t on_packet(SrsSrtPacket *packet);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *packet);
public:
virtual void set_can_publish(bool can_publish);
};
+// Mock SRT format for testing
+class MockSrtFormat : public ISrsSrtFormat
+{
+public:
+ int initialize_count_;
+ int on_srt_packet_count_;
+ srs_error_t initialize_error_;
+ srs_error_t on_srt_packet_error_;
+
+public:
+ MockSrtFormat();
+ virtual ~MockSrtFormat();
+
+public:
+ virtual srs_error_t initialize(ISrsRequest *req);
+ virtual srs_error_t on_srt_packet(SrsSrtPacket *pkt);
+};
+
// Mock SRT source manager for testing SrsRtcPublishStream
class MockSrtSourceManager : public ISrsSrtSourceManager
{
diff --git a/trunk/src/utest/srs_utest_workflow_srt_conn.cpp b/trunk/src/utest/srs_utest_workflow_srt_conn.cpp
index f6176cb7b..687147b66 100644
--- a/trunk/src/utest/srs_utest_workflow_srt_conn.cpp
+++ b/trunk/src/utest/srs_utest_workflow_srt_conn.cpp
@@ -53,6 +53,7 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPublisher)
SrsUniquePtr mock_srt_sources(new MockSrtSourceManager());
MockSrtConnection *mock_srt_conn = new MockSrtConnection();
MockSecurity *mock_security = new MockSecurity();
+ MockSrtFormat *mock_format = new MockSrtFormat();
mock_config->default_vhost_ = new SrsConfDirective();
mock_config->default_vhost_->name_ = "vhost";
@@ -99,6 +100,11 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPublisher)
// Create MPEG-TS packets to feed the SRT source.
MockSrtSource *mock_srt_source = dynamic_cast(mock_srt_sources->mock_source_.get());
+ // Inject mock format into SRT source
+ if (true) {
+ srs_freep(mock_srt_source->format_);
+ mock_srt_source->format_ = mock_format;
+ }
if (true) {
// Create a simple MPEG-TS packet (188 bytes)
// This is a minimal TS packet structure for testing
@@ -153,6 +159,7 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer)
SrsUniquePtr mock_srt_sources(new MockSrtSourceManager());
MockSrtConnection *mock_srt_conn = new MockSrtConnection();
MockSecurity *mock_security = new MockSecurity();
+ MockSrtFormat *mock_format = new MockSrtFormat();
mock_config->default_vhost_ = new SrsConfDirective();
mock_config->default_vhost_->name_ = "vhost";
@@ -183,7 +190,6 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer)
conn->security_ = mock_security;
// Start the SRT connection.
- MockSrtSource *srt_source = dynamic_cast(mock_srt_sources->mock_source_.get());
if (true) {
HELPER_EXPECT_SUCCESS(conn->start());
@@ -196,7 +202,15 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer)
EXPECT_STREQ("__defaultVhost__", req->vhost_.c_str());
EXPECT_STREQ("live", req->app_.c_str());
EXPECT_STREQ("livestream", req->stream_.c_str());
- EXPECT_EQ(1, (int)srt_source->consumers_.size());
+ }
+
+ // Create MPEG-TS packets to feed the SRT source.
+ MockSrtSource *mock_srt_source = dynamic_cast(mock_srt_sources->mock_source_.get());
+ EXPECT_EQ(1, (int)mock_srt_source->consumers_.size());
+ // Inject mock format into SRT source
+ if (true) {
+ srs_freep(mock_srt_source->format_);
+ mock_srt_source->format_ = mock_format;
}
// Feed TS packets to the SRT source consumer.
@@ -213,8 +227,8 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer)
SrsUniquePtr packet1(new SrsSrtPacket());
packet1->wrap(ts_packet1, sizeof(ts_packet1));
- HELPER_EXPECT_SUCCESS(srt_source->on_packet(packet1.get()));
- EXPECT_EQ(1, srt_source->on_packet_count_);
+ HELPER_EXPECT_SUCCESS(mock_srt_source->on_srt_packet(packet1.get()));
+ EXPECT_EQ(1, mock_srt_source->on_packet_count_);
// Create second MPEG-TS packet to trigger consumer signal
char ts_packet2[188];
@@ -226,8 +240,8 @@ VOID TEST(BasicWorkflowSrtConnTest, ManuallyVerifyForPlayer)
SrsUniquePtr packet2(new SrsSrtPacket());
packet2->wrap(ts_packet2, sizeof(ts_packet2));
- HELPER_EXPECT_SUCCESS(srt_source->on_packet(packet2.get()));
- EXPECT_EQ(2, srt_source->on_packet_count_);
+ HELPER_EXPECT_SUCCESS(mock_srt_source->on_srt_packet(packet2.get()));
+ EXPECT_EQ(2, mock_srt_source->on_packet_count_);
// Wait for consumer to process the messages.
srs_usleep(1 * SRS_UTIME_MILLISECONDS);