@@ -2039,6 +2039,116 @@ VOID TEST(SrsRtcPublisherNegotiatorTest, TypicalUseScenario)
20392039 EXPECT_EQ (" video" , video_sdp.media_descs_ [0 ].type_ );
20402040}
20412041
2042+ VOID TEST (SrsRtcPublisherNegotiatorTest, LibdatachannelUseScenario)
2043+ {
2044+ srs_error_t err;
2045+
2046+ // Create SrsRtcPublisherNegotiator
2047+ SrsUniquePtr<SrsRtcPublisherNegotiator> negotiator (new SrsRtcPublisherNegotiator ());
2048+
2049+ // Create mock request for initialization
2050+ SrsUniquePtr<MockRtcConnectionRequest> mock_request (new MockRtcConnectionRequest (" test.vhost" , " live" , " stream1" ));
2051+
2052+ // Create mock RTC user config with remote SDP
2053+ SrsUniquePtr<SrsRtcUserConfig> ruc (new SrsRtcUserConfig ());
2054+ ruc->req_ = mock_request->copy ();
2055+ ruc->publish_ = true ;
2056+ ruc->dtls_ = true ;
2057+ ruc->srtp_ = true ;
2058+ ruc->audio_before_video_ = true ;
2059+
2060+ // SDP from issue 4570 - libdatachannel format with video first, then audio
2061+ ruc->remote_sdp_str_ =
2062+ " v=0\r\n "
2063+ " o=- rtc 4158491451 0 IN IP4 127.0.0.1\r\n "
2064+ " s=-\r\n "
2065+ " t=0 0\r\n "
2066+ " a=group:BUNDLE video audio\r\n "
2067+ " a=group:LS video audio\r\n "
2068+ " a=msid-semantic:WMS *\r\n "
2069+ " a=ice-options:ice2,trickle\r\n "
2070+ " 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 "
2071+ " m=video 56144 UDP/TLS/RTP/SAVPF 96 97\r\n "
2072+ " c=IN IP4 172.24.64.1\r\n "
2073+ " a=mid:video\r\n "
2074+ " a=sendonly\r\n "
2075+ " a=ssrc:42 cname:video-send\r\n "
2076+ " a=rtcp-mux\r\n "
2077+ " a=rtpmap:96 H264/90000\r\n "
2078+ " a=rtcp-fb:96 nack\r\n "
2079+ " a=rtcp-fb:96 nack pli\r\n "
2080+ " a=rtcp-fb:96 goog-remb\r\n "
2081+ " a=fmtp:96 profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1\r\n "
2082+ " a=rtpmap:97 RTX/90000\r\n "
2083+ " a=fmtp:97 apt=96\r\n "
2084+ " a=setup:actpass\r\n "
2085+ " a=ice-ufrag:fEw/\r\n "
2086+ " a=ice-pwd:jBua8YGWQKc/Vn6Y9EZ9+0\r\n "
2087+ " a=candidate:1 1 UDP 2122317823 172.24.64.1 56144 typ host\r\n "
2088+ " a=candidate:2 1 UDP 2122315767 10.0.0.94 56144 typ host\r\n "
2089+ " a=candidate:3 1 UDP 1686189695 111.43.134.137 56144 typ srflx raddr 0.0.0.0 rport 0\r\n "
2090+ " a=end-of-candidates\r\n "
2091+ " m=audio 56144 UDP/TLS/RTP/SAVPF 111\r\n "
2092+ " c=IN IP4 172.24.64.1\r\n "
2093+ " a=mid:audio\r\n "
2094+ " a=sendonly\r\n "
2095+ " a=ssrc:43 cname:audio-send\r\n "
2096+ " a=rtcp-mux\r\n "
2097+ " a=rtpmap:111 opus/48000/2\r\n "
2098+ " a=fmtp:111 minptime=10;maxaveragebitrate=98000;stereo=1;sprop-stereo=1;useinbandfec=1\r\n "
2099+ " a=setup:actpass\r\n "
2100+ " a=ice-ufrag:fEw/\r\n "
2101+ " a=ice-pwd:jBua8YGWQKc/Vn6Y9EZ9+0\r\n " ;
2102+
2103+ // Parse the remote SDP
2104+ HELPER_EXPECT_SUCCESS (ruc->remote_sdp_ .parse (ruc->remote_sdp_str_ ));
2105+
2106+ // Create stream description for negotiation output
2107+ SrsUniquePtr<SrsRtcSourceDescription> stream_desc (new SrsRtcSourceDescription ());
2108+
2109+ // Test negotiate_publish_capability - typical WebRTC publisher negotiation
2110+ HELPER_EXPECT_SUCCESS (negotiator->negotiate_publish_capability (ruc.get (), stream_desc.get ()));
2111+
2112+ // Verify that stream description was populated with audio and video tracks
2113+ EXPECT_TRUE (stream_desc->audio_track_desc_ != NULL );
2114+ EXPECT_FALSE (stream_desc->video_track_descs_ .empty ());
2115+ EXPECT_EQ (" audio" , stream_desc->audio_track_desc_ ->type_ );
2116+ EXPECT_EQ (" video" , stream_desc->video_track_descs_ [0 ]->type_ );
2117+
2118+ // Test generate_publish_local_sdp - create answer SDP
2119+ SrsSdp local_sdp;
2120+ HELPER_EXPECT_SUCCESS (negotiator->generate_publish_local_sdp (
2121+ ruc->req_ , local_sdp, stream_desc.get (),
2122+ ruc->remote_sdp_ .is_unified (), ruc->audio_before_video_ ));
2123+
2124+ // Verify that local SDP was generated with media descriptions
2125+ EXPECT_FALSE (local_sdp.media_descs_ .empty ());
2126+
2127+ // Find audio and video media descriptions
2128+ bool has_audio = false , has_video = false ;
2129+ for (size_t i = 0 ; i < local_sdp.media_descs_ .size (); i++) {
2130+ if (local_sdp.media_descs_ [i].type_ == " audio" )
2131+ has_audio = true ;
2132+ if (local_sdp.media_descs_ [i].type_ == " video" )
2133+ has_video = true ;
2134+ }
2135+ EXPECT_TRUE (has_audio);
2136+ EXPECT_TRUE (has_video);
2137+
2138+ // Test individual SDP generation methods
2139+ SrsSdp audio_sdp, video_sdp;
2140+ HELPER_EXPECT_SUCCESS (negotiator->generate_publish_local_sdp_for_audio (audio_sdp, stream_desc.get ()));
2141+ HELPER_EXPECT_SUCCESS (negotiator->generate_publish_local_sdp_for_video (video_sdp, stream_desc.get (), true ));
2142+
2143+ // Verify audio SDP generation
2144+ EXPECT_FALSE (audio_sdp.media_descs_ .empty ());
2145+ EXPECT_EQ (" audio" , audio_sdp.media_descs_ [0 ].type_ );
2146+
2147+ // Verify video SDP generation
2148+ EXPECT_FALSE (video_sdp.media_descs_ .empty ());
2149+ EXPECT_EQ (" video" , video_sdp.media_descs_ [0 ].type_ );
2150+ }
2151+
20422152VOID TEST (SrsRtcConnectionTest, InitializeTypicalScenario)
20432153{
20442154 srs_error_t err;
0 commit comments