This commit is contained in:
parent
f47e3ab458
commit
00494d5f87
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
|||
<a name="v7-changes"></a>
|
||||
|
||||
## SRS 7.0 Changelog
|
||||
* v7.0, 2025-12-03, AI: WebRTC: Fix audio-only WHIP publish without SSRC. v7.0.132 (#4570)
|
||||
* v7.0, 2025-11-30, SRT: Support default_mode config for short streamid format. v7.0.131
|
||||
* v7.0, 2025-11-28, SRT: Fix player not exiting when publisher disconnects. v7.0.130 (#4591)
|
||||
* v7.0, 2025-11-27, Merge [#4588](https://github.com/ossrs/srs/pull/4588): RTMP: Ignore FMLE start packet after flash publish. v7.0.129 (#4588)
|
||||
|
|
|
|||
|
|
@ -3632,6 +3632,26 @@ srs_error_t SrsRtcPublisherNegotiator::negotiate_publish_capability(SrsRtcUserCo
|
|||
track_id = msid_tracker;
|
||||
}
|
||||
|
||||
// Handle case where no SSRC info is present in the offer (e.g., libdatachannel audio-only).
|
||||
// We still need to create track description to generate proper SDP answer.
|
||||
// See https://github.com/paullouisageneau/libdatachannel which may not include SSRC.
|
||||
// See https://github.com/ossrs/srs/issues/4570#issuecomment-3604598513
|
||||
if (remote_media_desc.ssrc_infos_.empty()) {
|
||||
SrsRtcTrackDescription *track_desc_copy = track_desc->copy();
|
||||
// Generate synthetic values since no SSRC info provided.
|
||||
track_desc_copy->ssrc_ = 0;
|
||||
track_desc_copy->id_ = srs_fmt_sprintf("track-%s-%s", track_desc->type_.c_str(), remote_media_desc.mid_.c_str());
|
||||
track_desc_copy->msid_ = req->app_ + "/" + req->stream_;
|
||||
|
||||
if (remote_media_desc.is_audio() && !stream_desc->audio_track_desc_) {
|
||||
stream_desc->audio_track_desc_ = track_desc_copy;
|
||||
} else if (remote_media_desc.is_video()) {
|
||||
stream_desc->video_track_descs_.push_back(track_desc_copy);
|
||||
} else {
|
||||
srs_freep(track_desc_copy);
|
||||
}
|
||||
}
|
||||
|
||||
// set track fec_ssrc and rtx_ssrc
|
||||
for (int j = 0; j < (int)remote_media_desc.ssrc_groups_.size(); ++j) {
|
||||
const SrsSSRCGroup &ssrc_group = remote_media_desc.ssrc_groups_.at(j);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 7
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 131
|
||||
#define VERSION_REVISION 132
|
||||
|
||||
#endif
|
||||
|
|
@ -2149,6 +2149,91 @@ VOID TEST(SrsRtcPublisherNegotiatorTest, LibdatachannelUseScenario)
|
|||
EXPECT_EQ("video", video_sdp.media_descs_[0].type_);
|
||||
}
|
||||
|
||||
// Test audio-only libdatachannel scenario WITHOUT SSRC info.
|
||||
// This test demonstrates the bug where libdatachannel fails with:
|
||||
// "Remote description has no ICE user fragment"
|
||||
// Root cause: When the offer SDP has no a=ssrc: line, stream_desc->audio_track_desc_
|
||||
// is never set, so generate_publish_local_sdp_for_audio() doesn't add the m=audio
|
||||
// section to the answer SDP.
|
||||
VOID TEST(SrsRtcPublisherNegotiatorTest, LibdatachannelAudioOnlyWithoutSsrc)
|
||||
{
|
||||
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", "voice_stream"));
|
||||
|
||||
// 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;
|
||||
|
||||
// Audio-only SDP from libdatachannel - NO SSRC LINE (this is the key difference!)
|
||||
// This matches the actual user-reported SDP that causes the bug
|
||||
ruc->remote_sdp_str_ =
|
||||
"v=0\r\n"
|
||||
"o=rtc 4107523824 0 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"t=0 0\r\n"
|
||||
"a=group:BUNDLE audio\r\n"
|
||||
"a=group:LS audio\r\n"
|
||||
"a=msid-semantic:WMS *\r\n"
|
||||
"a=ice-options:ice2,trickle\r\n"
|
||||
"a=fingerprint:sha-256 C3:22:A4:0D:46:6C:8C:3E:3B:05:59:63:C3:8A:43:97:30:4C:3E:5F:01:BA:C9:77:AC:10:89:A7:83:BA:21:08\r\n"
|
||||
"m=audio 36954 UDP/TLS/RTP/SAVPF 111\r\n"
|
||||
"c=IN IP4 192.168.1.100\r\n"
|
||||
"a=mid:audio\r\n"
|
||||
"a=sendonly\r\n"
|
||||
"a=rtcp-mux\r\n"
|
||||
"a=rtpmap:111 opus/48000/2\r\n"
|
||||
"a=fmtp:111 minptime=10;maxaveragebitrate=96000;stereo=1;sprop-stereo=1;useinbandfec=1\r\n"
|
||||
"a=setup:actpass\r\n"
|
||||
"a=ice-ufrag:rUic\r\n"
|
||||
"a=ice-pwd:76ZWO/4FkRx6r2nMUF8yeH\r\n"
|
||||
// NOTE: No a=ssrc: line here - this is the bug trigger!
|
||||
"a=candidate:1 1 UDP 2114977791 192.168.1.100 36954 typ host\r\n"
|
||||
"a=end-of-candidates\r\n";
|
||||
|
||||
// Parse the remote SDP
|
||||
HELPER_EXPECT_SUCCESS(ruc->remote_sdp_.parse(ruc->remote_sdp_str_));
|
||||
|
||||
// Verify only audio media description is present
|
||||
EXPECT_EQ(1u, ruc->remote_sdp_.media_descs_.size());
|
||||
EXPECT_EQ("audio", ruc->remote_sdp_.media_descs_[0].type_);
|
||||
|
||||
// Verify NO SSRC info in the parsed SDP (this is the bug condition)
|
||||
EXPECT_TRUE(ruc->remote_sdp_.media_descs_[0].ssrc_infos_.empty());
|
||||
|
||||
// Create stream description for negotiation output
|
||||
SrsUniquePtr<SrsRtcSourceDescription> stream_desc(new SrsRtcSourceDescription());
|
||||
|
||||
// Test negotiate_publish_capability - this should work but audio_track_desc_ will be NULL
|
||||
HELPER_EXPECT_SUCCESS(negotiator->negotiate_publish_capability(ruc.get(), stream_desc.get()));
|
||||
|
||||
// BUG: audio_track_desc_ is NULL because there's no SSRC info in the offer
|
||||
// This causes generate_publish_local_sdp_for_audio() to not add m=audio section
|
||||
EXPECT_TRUE(stream_desc->audio_track_desc_ != NULL) << "BUG: audio_track_desc_ should not be NULL for audio-only SDP without SSRC";
|
||||
EXPECT_TRUE(stream_desc->video_track_descs_.empty());
|
||||
|
||||
// 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_));
|
||||
|
||||
// BUG: local_sdp.media_descs_ is empty because audio_track_desc_ was NULL
|
||||
// This causes the answer SDP to have no m=audio line, which makes libdatachannel fail
|
||||
EXPECT_EQ(1u, local_sdp.media_descs_.size()) << "BUG: Answer SDP should have m=audio section";
|
||||
if (!local_sdp.media_descs_.empty()) {
|
||||
EXPECT_EQ("audio", local_sdp.media_descs_[0].type_);
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(SrsRtcConnectionTest, InitializeTypicalScenario)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user