@@ -2149,6 +2149,91 @@ VOID TEST(SrsRtcPublisherNegotiatorTest, LibdatachannelUseScenario)
21492149 EXPECT_EQ (" video" , video_sdp.media_descs_ [0 ].type_ );
21502150}
21512151
2152+ // Test audio-only libdatachannel scenario WITHOUT SSRC info.
2153+ // This test demonstrates the bug where libdatachannel fails with:
2154+ // "Remote description has no ICE user fragment"
2155+ // Root cause: When the offer SDP has no a=ssrc: line, stream_desc->audio_track_desc_
2156+ // is never set, so generate_publish_local_sdp_for_audio() doesn't add the m=audio
2157+ // section to the answer SDP.
2158+ VOID TEST (SrsRtcPublisherNegotiatorTest, LibdatachannelAudioOnlyWithoutSsrc)
2159+ {
2160+ srs_error_t err;
2161+
2162+ // Create SrsRtcPublisherNegotiator
2163+ SrsUniquePtr<SrsRtcPublisherNegotiator> negotiator (new SrsRtcPublisherNegotiator ());
2164+
2165+ // Create mock request for initialization
2166+ SrsUniquePtr<MockRtcConnectionRequest> mock_request (new MockRtcConnectionRequest (" test.vhost" , " live" , " voice_stream" ));
2167+
2168+ // Create mock RTC user config with remote SDP
2169+ SrsUniquePtr<SrsRtcUserConfig> ruc (new SrsRtcUserConfig ());
2170+ ruc->req_ = mock_request->copy ();
2171+ ruc->publish_ = true ;
2172+ ruc->dtls_ = true ;
2173+ ruc->srtp_ = true ;
2174+ ruc->audio_before_video_ = true ;
2175+
2176+ // Audio-only SDP from libdatachannel - NO SSRC LINE (this is the key difference!)
2177+ // This matches the actual user-reported SDP that causes the bug
2178+ ruc->remote_sdp_str_ =
2179+ " v=0\r\n "
2180+ " o=rtc 4107523824 0 IN IP4 127.0.0.1\r\n "
2181+ " s=-\r\n "
2182+ " t=0 0\r\n "
2183+ " a=group:BUNDLE audio\r\n "
2184+ " a=group:LS audio\r\n "
2185+ " a=msid-semantic:WMS *\r\n "
2186+ " a=ice-options:ice2,trickle\r\n "
2187+ " 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 "
2188+ " m=audio 36954 UDP/TLS/RTP/SAVPF 111\r\n "
2189+ " c=IN IP4 192.168.1.100\r\n "
2190+ " a=mid:audio\r\n "
2191+ " a=sendonly\r\n "
2192+ " a=rtcp-mux\r\n "
2193+ " a=rtpmap:111 opus/48000/2\r\n "
2194+ " a=fmtp:111 minptime=10;maxaveragebitrate=96000;stereo=1;sprop-stereo=1;useinbandfec=1\r\n "
2195+ " a=setup:actpass\r\n "
2196+ " a=ice-ufrag:rUic\r\n "
2197+ " a=ice-pwd:76ZWO/4FkRx6r2nMUF8yeH\r\n "
2198+ // NOTE: No a=ssrc: line here - this is the bug trigger!
2199+ " a=candidate:1 1 UDP 2114977791 192.168.1.100 36954 typ host\r\n "
2200+ " a=end-of-candidates\r\n " ;
2201+
2202+ // Parse the remote SDP
2203+ HELPER_EXPECT_SUCCESS (ruc->remote_sdp_ .parse (ruc->remote_sdp_str_ ));
2204+
2205+ // Verify only audio media description is present
2206+ EXPECT_EQ (1u , ruc->remote_sdp_ .media_descs_ .size ());
2207+ EXPECT_EQ (" audio" , ruc->remote_sdp_ .media_descs_ [0 ].type_ );
2208+
2209+ // Verify NO SSRC info in the parsed SDP (this is the bug condition)
2210+ EXPECT_TRUE (ruc->remote_sdp_ .media_descs_ [0 ].ssrc_infos_ .empty ());
2211+
2212+ // Create stream description for negotiation output
2213+ SrsUniquePtr<SrsRtcSourceDescription> stream_desc (new SrsRtcSourceDescription ());
2214+
2215+ // Test negotiate_publish_capability - this should work but audio_track_desc_ will be NULL
2216+ HELPER_EXPECT_SUCCESS (negotiator->negotiate_publish_capability (ruc.get (), stream_desc.get ()));
2217+
2218+ // BUG: audio_track_desc_ is NULL because there's no SSRC info in the offer
2219+ // This causes generate_publish_local_sdp_for_audio() to not add m=audio section
2220+ EXPECT_TRUE (stream_desc->audio_track_desc_ != NULL ) << " BUG: audio_track_desc_ should not be NULL for audio-only SDP without SSRC" ;
2221+ EXPECT_TRUE (stream_desc->video_track_descs_ .empty ());
2222+
2223+ // Test generate_publish_local_sdp - create answer SDP
2224+ SrsSdp local_sdp;
2225+ HELPER_EXPECT_SUCCESS (negotiator->generate_publish_local_sdp (
2226+ ruc->req_ , local_sdp, stream_desc.get (),
2227+ ruc->remote_sdp_ .is_unified (), ruc->audio_before_video_ ));
2228+
2229+ // BUG: local_sdp.media_descs_ is empty because audio_track_desc_ was NULL
2230+ // This causes the answer SDP to have no m=audio line, which makes libdatachannel fail
2231+ EXPECT_EQ (1u , local_sdp.media_descs_ .size ()) << " BUG: Answer SDP should have m=audio section" ;
2232+ if (!local_sdp.media_descs_ .empty ()) {
2233+ EXPECT_EQ (" audio" , local_sdp.media_descs_ [0 ].type_ );
2234+ }
2235+ }
2236+
21522237VOID TEST (SrsRtcConnectionTest, InitializeTypicalScenario)
21532238{
21542239 srs_error_t err;
0 commit comments