From eb9fca888dca214a792193069c6286a69812422b Mon Sep 17 00:00:00 2001 From: OSSRS-AI Date: Tue, 4 Nov 2025 10:25:28 -0500 Subject: [PATCH] AI: SRT: Report video/audio codec info and frame stats in HTTP API. v7.0.117 (#4554) --- trunk/conf/console.conf | 8 + trunk/conf/full.conf | 2 +- trunk/doc/CHANGELOG.md | 1 + trunk/src/app/srs_app_config.cpp | 6 +- trunk/src/app/srs_app_srt_conn.cpp | 2 +- trunk/src/app/srs_app_srt_source.cpp | 270 +++++++++++++++++- trunk/src/app/srs_app_srt_source.hpp | 50 +++- trunk/src/app/srs_app_stream_bridge.cpp | 4 +- trunk/src/app/srs_app_stream_bridge.hpp | 4 +- trunk/src/core/srs_core_version7.hpp | 2 +- trunk/src/utest/srs_utest_ai01.cpp | 12 +- trunk/src/utest/srs_utest_ai08.cpp | 8 +- trunk/src/utest/srs_utest_ai08.hpp | 2 +- trunk/src/utest/srs_utest_ai18.cpp | 2 +- trunk/src/utest/srs_utest_ai18.hpp | 2 +- trunk/src/utest/srs_utest_ai21.cpp | 6 +- trunk/src/utest/srs_utest_ai21.hpp | 2 +- trunk/src/utest/srs_utest_manual_mock.cpp | 31 +- trunk/src/utest/srs_utest_manual_mock.hpp | 20 +- .../src/utest/srs_utest_workflow_srt_conn.cpp | 26 +- 20 files changed, 419 insertions(+), 41 deletions(-) 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);