@@ -12,6 +12,7 @@ import (
1212 "time"
1313
1414 "github.com/pion/interceptor"
15+ "github.com/pion/srtp/v3"
1516 "github.com/pion/transport/v3/test"
1617 "github.com/pion/webrtc/v4/pkg/media"
1718 "github.com/stretchr/testify/assert"
@@ -64,3 +65,238 @@ func Test_RTPReceiver_SetReadDeadline(t *testing.T) {
6465 assert .NoError (t , wan .Stop ())
6566 closePairNow (t , sender , receiver )
6667}
68+
69+ func Test_configureStreams (t * testing.T ) {
70+ t .Run ("with RTX" , func (t * testing.T ) {
71+ trackStreams := & trackStreams {}
72+ decodingParams := RTPDecodingParameters {
73+ RTPCodingParameters : RTPCodingParameters {
74+ RID : "" ,
75+ SSRC : 0x89b82af4 ,
76+ PayloadType : 0x0 ,
77+ RTX : RTPRtxParameters {SSRC : 0x35c9eefc },
78+ FEC : RTPFecParameters {SSRC : 0x0 },
79+ },
80+ }
81+ codec := RTPCodecCapability {
82+ MimeType : "video/AV1" ,
83+ ClockRate : 0x15f90 ,
84+ Channels : 0x0 ,
85+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
86+ RTCPFeedback : []RTCPFeedback {
87+ {Type : "nack" , Parameter : "" },
88+ {Type : "nack" , Parameter : "pli" },
89+ {Type : "transport-cc" , Parameter : "" },
90+ },
91+ }
92+ globalParams := RTPParameters {
93+ HeaderExtensions : []RTPHeaderExtensionParameter {
94+ {
95+ URI : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" ,
96+ ID : 4 ,
97+ },
98+ },
99+ Codecs : []RTPCodecParameters {
100+ {
101+ RTPCodecCapability : RTPCodecCapability {
102+ MimeType : "video/AV1" ,
103+ ClockRate : 0x15f90 ,
104+ Channels : 0x0 ,
105+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
106+ RTCPFeedback : []RTCPFeedback {
107+ {Type : "nack" , Parameter : "" },
108+ {Type : "nack" , Parameter : "pli" },
109+ {Type : "transport-cc" , Parameter : "" },
110+ },
111+ },
112+ PayloadType : 0x2d ,
113+ statsID : "" ,
114+ },
115+ {
116+ RTPCodecCapability : RTPCodecCapability {
117+ MimeType : "video/rtx" ,
118+ ClockRate : 0x15f90 ,
119+ Channels : 0x0 ,
120+ SDPFmtpLine : "apt=45" ,
121+ RTCPFeedback : nil ,
122+ },
123+ PayloadType : 0x2e ,
124+ statsID : "" ,
125+ },
126+ },
127+ }
128+ expectedMediaStreamInfo := & interceptor.StreamInfo {
129+ ID : "" ,
130+ Attributes : interceptor.Attributes {},
131+ SSRC : 0x89b82af4 ,
132+ SSRCRetransmission : 0x35c9eefc ,
133+ SSRCForwardErrorCorrection : 0x0 ,
134+ PayloadType : 0x2d ,
135+ PayloadTypeRetransmission : 0x2e ,
136+ PayloadTypeForwardErrorCorrection : 0x0 ,
137+ RTPHeaderExtensions : []interceptor.RTPHeaderExtension {
138+ {URI : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" , ID : 4 },
139+ },
140+ MimeType : "video/AV1" ,
141+ ClockRate : 0x15f90 ,
142+ Channels : 0x0 ,
143+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
144+ RTCPFeedback : []interceptor.RTCPFeedback {
145+ {Type : "nack" , Parameter : "" },
146+ {Type : "nack" , Parameter : "pli" },
147+ {Type : "transport-cc" , Parameter : "" },
148+ },
149+ }
150+ expectedRTXStreamInfo := & interceptor.StreamInfo {
151+ ID : "" ,
152+ Attributes : interceptor.Attributes {},
153+ SSRC : 0x35c9eefc ,
154+ SSRCRetransmission : 0x0 ,
155+ SSRCForwardErrorCorrection : 0x0 ,
156+ PayloadType : 0x2e ,
157+ PayloadTypeRetransmission : 0x0 ,
158+ PayloadTypeForwardErrorCorrection : 0x0 ,
159+ RTPHeaderExtensions : []interceptor.RTPHeaderExtension {
160+ {URI : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" , ID : 4 },
161+ },
162+ MimeType : "video/AV1" ,
163+ ClockRate : 0x15f90 ,
164+ Channels : 0x0 ,
165+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
166+ RTCPFeedback : []interceptor.RTCPFeedback {
167+ {Type : "nack" , Parameter : "" },
168+ {Type : "nack" , Parameter : "pli" },
169+ {Type : "transport-cc" , Parameter : "" },
170+ },
171+ }
172+ callCount := 0
173+ haveRTX , err := trackStreams .configureStreams (
174+ decodingParams ,
175+ codec ,
176+ globalParams ,
177+ // Mock DTLSTransport.streamsForSSRC here, DTLSTransport.streamsForSSRC calls interceptor.BindRemoteStream,
178+ // so the interceptor.StreamInfo here is exactly the StreamInfo that will be passed into interceptors.
179+ func (s SSRC , si interceptor.StreamInfo ) (
180+ * srtp.ReadStreamSRTP ,
181+ interceptor.RTPReader ,
182+ * srtp.ReadStreamSRTCP ,
183+ interceptor.RTCPReader ,
184+ error ,
185+ ) {
186+ switch callCount {
187+ case 0 :
188+ assert .Equal (t , s , SSRC (0x89b82af4 ))
189+ assert .Equal (t , si , * expectedMediaStreamInfo )
190+ case 1 :
191+ assert .Equal (t , s , SSRC (0x35c9eefc ))
192+ assert .Equal (t , si , * expectedRTXStreamInfo )
193+ default :
194+ assert .Fail (t , "streamsForSSRC called more than twice when only video track and rtx track existed" )
195+ }
196+ callCount ++
197+
198+ return nil , nil , nil , nil , nil
199+ },
200+ )
201+ assert .NoError (t , err )
202+ assert .True (t , haveRTX )
203+ assert .Equal (t , trackStreams .mediaStream .streamInfo , expectedMediaStreamInfo )
204+ assert .Equal (t , trackStreams .rtxStream .streamInfo , expectedRTXStreamInfo )
205+ })
206+
207+ t .Run ("no RTX" , func (t * testing.T ) {
208+ trackStreams := & trackStreams {}
209+ decodingParams := RTPDecodingParameters {
210+ RTPCodingParameters : RTPCodingParameters {
211+ RID : "" ,
212+ SSRC : 0x89b82af4 ,
213+ PayloadType : 0x0 ,
214+ RTX : RTPRtxParameters {SSRC : 0x0 },
215+ FEC : RTPFecParameters {SSRC : 0x0 },
216+ },
217+ }
218+ codec := RTPCodecCapability {
219+ MimeType : "video/AV1" ,
220+ ClockRate : 0x15f90 ,
221+ Channels : 0x0 ,
222+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
223+ RTCPFeedback : []RTCPFeedback {
224+ {Type : "transport-cc" , Parameter : "" },
225+ },
226+ }
227+ globalParams := RTPParameters {
228+ HeaderExtensions : []RTPHeaderExtensionParameter {
229+ {
230+ URI : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" ,
231+ ID : 4 ,
232+ },
233+ },
234+ Codecs : []RTPCodecParameters {
235+ {
236+ RTPCodecCapability : RTPCodecCapability {
237+ MimeType : "video/AV1" ,
238+ ClockRate : 0x15f90 ,
239+ Channels : 0x0 ,
240+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
241+ RTCPFeedback : []RTCPFeedback {
242+ {Type : "transport-cc" , Parameter : "" },
243+ },
244+ },
245+ PayloadType : 0x2d ,
246+ statsID : "" ,
247+ },
248+ },
249+ }
250+ expectedMediaStreamInfo := & interceptor.StreamInfo {
251+ ID : "" ,
252+ Attributes : interceptor.Attributes {},
253+ SSRC : 0x89b82af4 ,
254+ SSRCRetransmission : 0x0 ,
255+ SSRCForwardErrorCorrection : 0x0 ,
256+ PayloadType : 0x2d ,
257+ PayloadTypeRetransmission : 0x0 ,
258+ PayloadTypeForwardErrorCorrection : 0x0 ,
259+ RTPHeaderExtensions : []interceptor.RTPHeaderExtension {
260+ {URI : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" , ID : 4 },
261+ },
262+ MimeType : "video/AV1" ,
263+ ClockRate : 0x15f90 ,
264+ Channels : 0x0 ,
265+ SDPFmtpLine : "level-idx=5;profile=0;tier=0" ,
266+ RTCPFeedback : []interceptor.RTCPFeedback {
267+ {Type : "transport-cc" , Parameter : "" },
268+ },
269+ }
270+ var expectedRTXStreamInfo * interceptor.StreamInfo
271+ callCount := 0
272+ haveRTX , err := trackStreams .configureStreams (
273+ decodingParams ,
274+ codec ,
275+ globalParams ,
276+ // Mock DTLSTransport.streamsForSSRC here, DTLSTransport.streamsForSSRC calls interceptor.BindRemoteStream,
277+ // so the interceptor.StreamInfo here is exactly the StreamInfo that will be passed into interceptors.
278+ func (s SSRC , si interceptor.StreamInfo ) (
279+ * srtp.ReadStreamSRTP ,
280+ interceptor.RTPReader ,
281+ * srtp.ReadStreamSRTCP ,
282+ interceptor.RTCPReader ,
283+ error ,
284+ ) {
285+ switch callCount {
286+ case 0 :
287+ assert .Equal (t , s , SSRC (0x89b82af4 ))
288+ assert .Equal (t , si , * expectedMediaStreamInfo )
289+ default :
290+ assert .Fail (t , "streamsForSSRC called more than once when only video track existed" )
291+ }
292+ callCount ++
293+
294+ return nil , nil , nil , nil , nil
295+ },
296+ )
297+ assert .NoError (t , err )
298+ assert .False (t , haveRTX )
299+ assert .Equal (t , trackStreams .mediaStream .streamInfo , expectedMediaStreamInfo )
300+ assert .Equal (t , trackStreams .rtxStream .streamInfo , expectedRTXStreamInfo )
301+ })
302+ }
0 commit comments