Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ cmake --build $HOME/git/srs/trunk/cmake/build

## macOS: SRS UTest

The most straightforward way is to select a test name like `WorkflowRtcManuallyVerifyForPublisher`,
then select `Debug gtest (macOS CodeLLDB)` and run the debug.

Or you can use the following way to run specified test from the test panel.

Install the following extensions:

- C++ TestMate
Expand Down
57 changes: 29 additions & 28 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch SRS with conf/console.conf",
"name": "Debug SRS with conf/console.conf",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/trunk/cmake/build/srs",
Expand Down Expand Up @@ -30,7 +30,7 @@
}
},
{
"name": "Launch SRS with conf/rtc.conf",
"name": "Debug SRS with conf/rtc.conf",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/trunk/cmake/build/srs",
Expand Down Expand Up @@ -58,40 +58,41 @@
}
},
{
"name": "Launch SRS with console.conf",
"type": "cppdbg",
"name": "Debug srs-proxy",
"type": "go",
"request": "launch",
"mode": "auto",
"cwd": "${workspaceFolder}/proxy",
"program": "${workspaceFolder}/proxy"
},
{
"name": "Debug SRS (macOS, CodeLLDB) console.conf",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/trunk/cmake/build/srs",
"args": ["-c", "console.conf"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/trunk",
"environment": [],
"externalConsole": false,
"linux": {
"MIMode": "gdb"
},
"osx": {
"MIMode": "lldb"
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
"stopOnEntry": false,
"terminal": "integrated",
"initCommands": [
"command script import lldb.formatters.cpp.libcxx"
],
"preLaunchTask": "build",
"logging": {
"engineLogging": true
}
"env": {},
"sourceLanguages": ["cpp"]
},
{
"name": "Launch srs-proxy",
"type": "go",
"name": "Debug gtest (macOS CodeLLDB)",
"type": "lldb",
"request": "launch",
"mode": "auto",
"cwd": "${workspaceFolder}/proxy",
"program": "${workspaceFolder}/proxy"
}
"program": "${workspaceFolder}/trunk/cmake/build/utest",
"args": ["--gtest_filter=*${selectedText}*"],
"cwd": "${workspaceFolder}/trunk",
"terminal": "integrated",
"initCommands": [
"command script import lldb.formatters.cpp.libcxx"
],
"sourceLanguages": ["cpp"]
}
]
}
1 change: 1 addition & 0 deletions trunk/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a>

## SRS 7.0 Changelog
* v7.0, 2025-11-11, AI: WebRTC: Support optional msid attribute per RFC 8830. v7.0.126 (#4570)
* v7.0, 2025-11-11, AI: SRT: Stop TS parsing after codec detection. v7.0.125 (#4569)
* v7.0, 2025-11-09, AI: WebRTC: Support G.711 (PCMU/PCMA) audio codec for WebRTC. v7.0.124 (#4075)
* v7.0, 2025-11-08, AI: WebRTC: Support VP9 codec for WebRTC-to-WebRTC streaming. v7.0.123 (#4548)
Expand Down
21 changes: 17 additions & 4 deletions trunk/src/app/srs_app_rtc_conn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3601,12 +3601,25 @@ srs_error_t SrsRtcPublisherNegotiator::negotiate_publish_capability(SrsRtcUserCo
for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) {
const SrsSSRCInfo &ssrc_info = remote_media_desc.ssrc_infos_.at(j);

// Generate msid because it's optional in sdp.
string msid_tracker = ssrc_info.msid_tracker_;
if (msid_tracker.empty()) {
msid_tracker = srs_fmt_sprintf("track-%s-%s-%d",
track_desc->type_.c_str(), ssrc_info.cname_.c_str(), ssrc_info.ssrc_);
}

// Generate msid because it's optional in sdp.
string msid = ssrc_info.msid_;
if (msid.empty()) {
msid = req->app_ + "/" + req->stream_;
}

// ssrc have same track id, will be description in the same track description.
if (track_id != ssrc_info.msid_tracker_) {
if (track_id != msid_tracker) {
SrsRtcTrackDescription *track_desc_copy = track_desc->copy();
track_desc_copy->ssrc_ = ssrc_info.ssrc_;
track_desc_copy->id_ = ssrc_info.msid_tracker_;
track_desc_copy->msid_ = ssrc_info.msid_;
track_desc_copy->id_ = msid_tracker;
track_desc_copy->msid_ = msid;

if (remote_media_desc.is_audio() && !stream_desc->audio_track_desc_) {
stream_desc->audio_track_desc_ = track_desc_copy;
Expand All @@ -3616,7 +3629,7 @@ srs_error_t SrsRtcPublisherNegotiator::negotiate_publish_capability(SrsRtcUserCo
srs_freep(track_desc_copy);
}
}
track_id = ssrc_info.msid_tracker_;
track_id = msid_tracker;
}

// set track fec_ssrc and rtx_ssrc
Expand Down
2 changes: 1 addition & 1 deletion trunk/src/core/srs_core_version7.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

#define VERSION_MAJOR 7
#define VERSION_MINOR 0
#define VERSION_REVISION 125
#define VERSION_REVISION 126

#endif
7 changes: 4 additions & 3 deletions trunk/src/protocol/srs_protocol_sdp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,10 @@ vector<SrsMediaPayloadType> SrsMediaDesc::find_media_with_encoding_name(const st
transform(encoding_name.begin(), encoding_name.end(), upper_name.begin(), ::toupper);

for (size_t i = 0; i < payload_types_.size(); ++i) {
if (payload_types_[i].encoding_name_ == std::string(lower_name.c_str()) ||
payload_types_[i].encoding_name_ == std::string(upper_name.c_str())) {
payloads.push_back(payload_types_[i]);
SrsMediaPayloadType payload = payload_types_[i];
if (payload.encoding_name_ == std::string(lower_name.c_str()) ||
payload.encoding_name_ == std::string(upper_name.c_str())) {
payloads.push_back(payload);
}
}

Expand Down
110 changes: 110 additions & 0 deletions trunk/src/utest/srs_utest_ai12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,116 @@ VOID TEST(SrsRtcPublisherNegotiatorTest, TypicalUseScenario)
EXPECT_EQ("video", video_sdp.media_descs_[0].type_);
}

VOID TEST(SrsRtcPublisherNegotiatorTest, LibdatachannelUseScenario)
{
srs_error_t err;

// Create SrsRtcPublisherNegotiator
SrsUniquePtr<SrsRtcPublisherNegotiator> negotiator(new SrsRtcPublisherNegotiator());

// Create mock request for initialization
SrsUniquePtr<MockRtcConnectionRequest> mock_request(new MockRtcConnectionRequest("test.vhost", "live", "stream1"));

// Create mock RTC user config with remote SDP
SrsUniquePtr<SrsRtcUserConfig> ruc(new SrsRtcUserConfig());
ruc->req_ = mock_request->copy();
ruc->publish_ = true;
ruc->dtls_ = true;
ruc->srtp_ = true;
ruc->audio_before_video_ = true;

// SDP from issue 4570 - libdatachannel format with video first, then audio
ruc->remote_sdp_str_ =
"v=0\r\n"
"o=- rtc 4158491451 0 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"t=0 0\r\n"
"a=group:BUNDLE video audio\r\n"
"a=group:LS video audio\r\n"
"a=msid-semantic:WMS *\r\n"
"a=ice-options:ice2,trickle\r\n"
"a=fingerprint:sha-256 28:37:F7:18:77:FC:46:33:6F:B2:0F:12:83:C2:BF:5C:61:5E:96:EB:4B:B9:97:81:92:7C:82:10:97:B8:8E:60\r\n"
"m=video 56144 UDP/TLS/RTP/SAVPF 96 97\r\n"
"c=IN IP4 172.24.64.1\r\n"
"a=mid:video\r\n"
"a=sendonly\r\n"
"a=ssrc:42 cname:video-send\r\n"
"a=rtcp-mux\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=rtcp-fb:96 nack\r\n"
"a=rtcp-fb:96 nack pli\r\n"
"a=rtcp-fb:96 goog-remb\r\n"
"a=fmtp:96 profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1\r\n"
"a=rtpmap:97 RTX/90000\r\n"
"a=fmtp:97 apt=96\r\n"
"a=setup:actpass\r\n"
"a=ice-ufrag:fEw/\r\n"
"a=ice-pwd:jBua8YGWQKc/Vn6Y9EZ9+0\r\n"
"a=candidate:1 1 UDP 2122317823 172.24.64.1 56144 typ host\r\n"
"a=candidate:2 1 UDP 2122315767 10.0.0.94 56144 typ host\r\n"
"a=candidate:3 1 UDP 1686189695 111.43.134.137 56144 typ srflx raddr 0.0.0.0 rport 0\r\n"
"a=end-of-candidates\r\n"
"m=audio 56144 UDP/TLS/RTP/SAVPF 111\r\n"
"c=IN IP4 172.24.64.1\r\n"
"a=mid:audio\r\n"
"a=sendonly\r\n"
"a=ssrc:43 cname:audio-send\r\n"
"a=rtcp-mux\r\n"
"a=rtpmap:111 opus/48000/2\r\n"
"a=fmtp:111 minptime=10;maxaveragebitrate=98000;stereo=1;sprop-stereo=1;useinbandfec=1\r\n"
"a=setup:actpass\r\n"
"a=ice-ufrag:fEw/\r\n"
"a=ice-pwd:jBua8YGWQKc/Vn6Y9EZ9+0\r\n";

// Parse the remote SDP
HELPER_EXPECT_SUCCESS(ruc->remote_sdp_.parse(ruc->remote_sdp_str_));

// Create stream description for negotiation output
SrsUniquePtr<SrsRtcSourceDescription> stream_desc(new SrsRtcSourceDescription());

// Test negotiate_publish_capability - typical WebRTC publisher negotiation
HELPER_EXPECT_SUCCESS(negotiator->negotiate_publish_capability(ruc.get(), stream_desc.get()));

// Verify that stream description was populated with audio and video tracks
EXPECT_TRUE(stream_desc->audio_track_desc_ != NULL);
EXPECT_FALSE(stream_desc->video_track_descs_.empty());
EXPECT_EQ("audio", stream_desc->audio_track_desc_->type_);
EXPECT_EQ("video", stream_desc->video_track_descs_[0]->type_);

// Test generate_publish_local_sdp - create answer SDP
SrsSdp local_sdp;
HELPER_EXPECT_SUCCESS(negotiator->generate_publish_local_sdp(
ruc->req_, local_sdp, stream_desc.get(),
ruc->remote_sdp_.is_unified(), ruc->audio_before_video_));

// Verify that local SDP was generated with media descriptions
EXPECT_FALSE(local_sdp.media_descs_.empty());

// Find audio and video media descriptions
bool has_audio = false, has_video = false;
for (size_t i = 0; i < local_sdp.media_descs_.size(); i++) {
if (local_sdp.media_descs_[i].type_ == "audio")
has_audio = true;
if (local_sdp.media_descs_[i].type_ == "video")
has_video = true;
}
EXPECT_TRUE(has_audio);
EXPECT_TRUE(has_video);

// Test individual SDP generation methods
SrsSdp audio_sdp, video_sdp;
HELPER_EXPECT_SUCCESS(negotiator->generate_publish_local_sdp_for_audio(audio_sdp, stream_desc.get()));
HELPER_EXPECT_SUCCESS(negotiator->generate_publish_local_sdp_for_video(video_sdp, stream_desc.get(), true));

// Verify audio SDP generation
EXPECT_FALSE(audio_sdp.media_descs_.empty());
EXPECT_EQ("audio", audio_sdp.media_descs_[0].type_);

// Verify video SDP generation
EXPECT_FALSE(video_sdp.media_descs_.empty());
EXPECT_EQ("video", video_sdp.media_descs_[0].type_);
}

VOID TEST(SrsRtcConnectionTest, InitializeTypicalScenario)
{
srs_error_t err;
Expand Down
Loading
Loading