AI: Add RTMP2RTC workflow test.

This commit is contained in:
OSSRS-AI 2025-10-27 22:39:00 -04:00 committed by winlin
parent 72f723b016
commit 2604d0a239
7 changed files with 125 additions and 18 deletions

View File

@ -23,9 +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_rtc_codec.hpp>
#include <srs_app_st.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>

View File

@ -35,10 +35,10 @@
#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>
#include <srs_app_factory.hpp>
// The NACK sent by us(SFU).
SrsPps *_srs_pps_snack = NULL;

View File

@ -230,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;
@ -270,6 +271,7 @@ SrsRtmpConn::~SrsRtmpConn()
srs_freep(refer_);
srs_freep(security_);
app_factory_ = NULL;
config_ = NULL;
manager_ = NULL;
stream_publish_tokens_ = NULL;
@ -1065,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(_srs_app_factory);
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

@ -303,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()
{
@ -310,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()
@ -2726,7 +2741,7 @@ void MockAudioTranscoder::aac_codec_header(uint8_t **data, int *len)
if (size <= 0) {
return;
}
uint8_t *copy = new uint8_t[size];
memcpy(copy, aac_header_.data(), size);
*data = copy;

View File

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

View File

@ -23,6 +23,8 @@
#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>
@ -38,6 +40,35 @@
#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.
@ -46,6 +77,7 @@ 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());
@ -77,6 +109,7 @@ VOID TEST(BasicWorkflowRtmp2RtcTest, ManuallyVerifyTypicalScenario)
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();
@ -124,42 +157,83 @@ VOID TEST(BasicWorkflowRtmp2RtcTest, ManuallyVerifyTypicalScenario)
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
}
// Create an RTMP audio message to feed consumer.
// 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 a real AAC audio message with proper format.
// 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: AAC data
int payload_size = 10;
// 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 audio data
// 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: 1 = AAC raw data
stream.write_1bytes(0x01);
// AAC raw data (8 bytes of dummy audio data)
for (int i = 0; i < 8; i++) {
stream.write_1bytes(0x00);
}
// 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 audio to rtmp server.
// 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 message is sent to the client.
// 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.