|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 // Original author: ekr@rtfm.com |
|
6 |
|
7 #include <iostream> |
|
8 |
|
9 #include "sigslot.h" |
|
10 |
|
11 #include "logging.h" |
|
12 #include "nsThreadUtils.h" |
|
13 #include "nsXPCOM.h" |
|
14 #include "nss.h" |
|
15 #include "ssl.h" |
|
16 #include "sslproto.h" |
|
17 |
|
18 #include "dtlsidentity.h" |
|
19 #include "mozilla/RefPtr.h" |
|
20 #include "FakeMediaStreams.h" |
|
21 #include "FakeMediaStreamsImpl.h" |
|
22 #include "MediaConduitErrors.h" |
|
23 #include "MediaConduitInterface.h" |
|
24 #include "MediaPipeline.h" |
|
25 #include "MediaPipelineFilter.h" |
|
26 #include "runnable_utils.h" |
|
27 #include "transportflow.h" |
|
28 #include "transportlayerloopback.h" |
|
29 #include "transportlayerdtls.h" |
|
30 #include "mozilla/SyncRunnable.h" |
|
31 |
|
32 |
|
33 #include "mtransport_test_utils.h" |
|
34 #include "runnable_utils.h" |
|
35 |
|
36 #include "webrtc/modules/interface/module_common_types.h" |
|
37 |
|
38 #define GTEST_HAS_RTTI 0 |
|
39 #include "gtest/gtest.h" |
|
40 #include "gtest_utils.h" |
|
41 |
|
42 using namespace mozilla; |
|
43 MOZ_MTLOG_MODULE("mediapipeline") |
|
44 |
|
45 MtransportTestUtils *test_utils; |
|
46 |
|
47 namespace { |
|
48 |
|
49 class TransportInfo { |
|
50 public: |
|
51 TransportInfo() : |
|
52 flow_(nullptr), |
|
53 loopback_(nullptr), |
|
54 dtls_(nullptr) {} |
|
55 |
|
56 static void InitAndConnect(TransportInfo &client, TransportInfo &server) { |
|
57 client.Init(true); |
|
58 server.Init(false); |
|
59 client.PushLayers(); |
|
60 server.PushLayers(); |
|
61 client.Connect(&server); |
|
62 server.Connect(&client); |
|
63 } |
|
64 |
|
65 void Init(bool client) { |
|
66 nsresult res; |
|
67 |
|
68 flow_ = new TransportFlow(); |
|
69 loopback_ = new TransportLayerLoopback(); |
|
70 dtls_ = new TransportLayerDtls(); |
|
71 |
|
72 res = loopback_->Init(); |
|
73 if (res != NS_OK) { |
|
74 FreeLayers(); |
|
75 } |
|
76 ASSERT_EQ((nsresult)NS_OK, res); |
|
77 |
|
78 std::vector<uint16_t> ciphers; |
|
79 ciphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80); |
|
80 dtls_->SetSrtpCiphers(ciphers); |
|
81 dtls_->SetIdentity(DtlsIdentity::Generate()); |
|
82 dtls_->SetRole(client ? TransportLayerDtls::CLIENT : |
|
83 TransportLayerDtls::SERVER); |
|
84 dtls_->SetVerificationAllowAll(); |
|
85 } |
|
86 |
|
87 void PushLayers() { |
|
88 nsresult res; |
|
89 |
|
90 nsAutoPtr<std::queue<TransportLayer *> > layers( |
|
91 new std::queue<TransportLayer *>); |
|
92 layers->push(loopback_); |
|
93 layers->push(dtls_); |
|
94 res = flow_->PushLayers(layers); |
|
95 if (res != NS_OK) { |
|
96 FreeLayers(); |
|
97 } |
|
98 ASSERT_EQ((nsresult)NS_OK, res); |
|
99 } |
|
100 |
|
101 void Connect(TransportInfo* peer) { |
|
102 MOZ_ASSERT(loopback_); |
|
103 MOZ_ASSERT(peer->loopback_); |
|
104 |
|
105 loopback_->Connect(peer->loopback_); |
|
106 } |
|
107 |
|
108 // Free the memory allocated at the beginning of Init |
|
109 // if failure occurs before layers setup. |
|
110 void FreeLayers() { |
|
111 delete loopback_; |
|
112 loopback_ = nullptr; |
|
113 delete dtls_; |
|
114 dtls_ = nullptr; |
|
115 } |
|
116 |
|
117 void Shutdown() { |
|
118 if (loopback_) { |
|
119 loopback_->Disconnect(); |
|
120 } |
|
121 loopback_ = nullptr; |
|
122 dtls_ = nullptr; |
|
123 flow_ = nullptr; |
|
124 } |
|
125 |
|
126 mozilla::RefPtr<TransportFlow> flow_; |
|
127 TransportLayerLoopback *loopback_; |
|
128 TransportLayerDtls *dtls_; |
|
129 }; |
|
130 |
|
131 class TestAgent { |
|
132 public: |
|
133 TestAgent() : |
|
134 audio_config_(109, "opus", 48000, 960, 2, 64000), |
|
135 audio_conduit_(mozilla::AudioSessionConduit::Create(nullptr)), |
|
136 audio_(), |
|
137 audio_pipeline_() { |
|
138 } |
|
139 |
|
140 static void ConnectRtp(TestAgent *client, TestAgent *server) { |
|
141 TransportInfo::InitAndConnect(client->audio_rtp_transport_, |
|
142 server->audio_rtp_transport_); |
|
143 } |
|
144 |
|
145 static void ConnectRtcp(TestAgent *client, TestAgent *server) { |
|
146 TransportInfo::InitAndConnect(client->audio_rtcp_transport_, |
|
147 server->audio_rtcp_transport_); |
|
148 } |
|
149 |
|
150 static void ConnectBundle(TestAgent *client, TestAgent *server) { |
|
151 TransportInfo::InitAndConnect(client->bundle_transport_, |
|
152 server->bundle_transport_); |
|
153 } |
|
154 |
|
155 virtual void CreatePipelines_s(bool aIsRtcpMux) = 0; |
|
156 |
|
157 void Start() { |
|
158 nsresult ret; |
|
159 |
|
160 MOZ_MTLOG(ML_DEBUG, "Starting"); |
|
161 |
|
162 mozilla::SyncRunnable::DispatchToThread( |
|
163 test_utils->sts_target(), |
|
164 WrapRunnableRet(audio_->GetStream(), &Fake_MediaStream::Start, &ret)); |
|
165 |
|
166 ASSERT_TRUE(NS_SUCCEEDED(ret)); |
|
167 } |
|
168 |
|
169 void StopInt() { |
|
170 audio_->GetStream()->Stop(); |
|
171 } |
|
172 |
|
173 void Stop() { |
|
174 MOZ_MTLOG(ML_DEBUG, "Stopping"); |
|
175 |
|
176 if (audio_pipeline_) |
|
177 audio_pipeline_->ShutdownMedia_m(); |
|
178 |
|
179 mozilla::SyncRunnable::DispatchToThread( |
|
180 test_utils->sts_target(), |
|
181 WrapRunnable(this, &TestAgent::StopInt)); |
|
182 } |
|
183 |
|
184 void Shutdown_s() { |
|
185 audio_rtp_transport_.Shutdown(); |
|
186 audio_rtcp_transport_.Shutdown(); |
|
187 bundle_transport_.Shutdown(); |
|
188 if (audio_pipeline_) |
|
189 audio_pipeline_->ShutdownTransport_s(); |
|
190 } |
|
191 |
|
192 void Shutdown() { |
|
193 if (audio_pipeline_) |
|
194 audio_pipeline_->ShutdownMedia_m(); |
|
195 |
|
196 mozilla::SyncRunnable::DispatchToThread( |
|
197 test_utils->sts_target(), |
|
198 WrapRunnable(this, &TestAgent::Shutdown_s)); |
|
199 } |
|
200 |
|
201 uint32_t GetRemoteSSRC() { |
|
202 uint32_t res = 0; |
|
203 audio_conduit_->GetRemoteSSRC(&res); |
|
204 return res; |
|
205 } |
|
206 |
|
207 uint32_t GetLocalSSRC() { |
|
208 uint32_t res = 0; |
|
209 audio_conduit_->GetLocalSSRC(&res); |
|
210 return res; |
|
211 } |
|
212 |
|
213 int GetAudioRtpCountSent() { |
|
214 return audio_pipeline_->rtp_packets_sent(); |
|
215 } |
|
216 |
|
217 int GetAudioRtpCountReceived() { |
|
218 return audio_pipeline_->rtp_packets_received(); |
|
219 } |
|
220 |
|
221 int GetAudioRtcpCountSent() { |
|
222 return audio_pipeline_->rtcp_packets_sent(); |
|
223 } |
|
224 |
|
225 int GetAudioRtcpCountReceived() { |
|
226 return audio_pipeline_->rtcp_packets_received(); |
|
227 } |
|
228 |
|
229 protected: |
|
230 mozilla::AudioCodecConfig audio_config_; |
|
231 mozilla::RefPtr<mozilla::MediaSessionConduit> audio_conduit_; |
|
232 nsRefPtr<DOMMediaStream> audio_; |
|
233 // TODO(bcampen@mozilla.com): Right now this does not let us test RTCP in |
|
234 // both directions; only the sender's RTCP is sent, but the receiver should |
|
235 // be sending it too. |
|
236 mozilla::RefPtr<mozilla::MediaPipeline> audio_pipeline_; |
|
237 TransportInfo audio_rtp_transport_; |
|
238 TransportInfo audio_rtcp_transport_; |
|
239 TransportInfo bundle_transport_; |
|
240 }; |
|
241 |
|
242 class TestAgentSend : public TestAgent { |
|
243 public: |
|
244 TestAgentSend() : use_bundle_(false) {} |
|
245 |
|
246 virtual void CreatePipelines_s(bool aIsRtcpMux) { |
|
247 audio_ = new Fake_DOMMediaStream(new Fake_AudioStreamSource()); |
|
248 |
|
249 mozilla::MediaConduitErrorCode err = |
|
250 static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get())-> |
|
251 ConfigureSendMediaCodec(&audio_config_); |
|
252 EXPECT_EQ(mozilla::kMediaConduitNoError, err); |
|
253 |
|
254 std::string test_pc("PC"); |
|
255 |
|
256 if (aIsRtcpMux) { |
|
257 ASSERT_FALSE(audio_rtcp_transport_.flow_); |
|
258 } |
|
259 |
|
260 RefPtr<TransportFlow> rtp(audio_rtp_transport_.flow_); |
|
261 RefPtr<TransportFlow> rtcp(audio_rtcp_transport_.flow_); |
|
262 |
|
263 if (use_bundle_) { |
|
264 rtp = bundle_transport_.flow_; |
|
265 rtcp = nullptr; |
|
266 } |
|
267 |
|
268 audio_pipeline_ = new mozilla::MediaPipelineTransmit( |
|
269 test_pc, |
|
270 nullptr, |
|
271 test_utils->sts_target(), |
|
272 audio_, |
|
273 1, |
|
274 1, |
|
275 audio_conduit_, |
|
276 rtp, |
|
277 rtcp); |
|
278 |
|
279 audio_pipeline_->Init(); |
|
280 } |
|
281 |
|
282 void SetUsingBundle(bool use_bundle) { |
|
283 use_bundle_ = use_bundle; |
|
284 } |
|
285 |
|
286 private: |
|
287 bool use_bundle_; |
|
288 }; |
|
289 |
|
290 |
|
291 class TestAgentReceive : public TestAgent { |
|
292 public: |
|
293 virtual void CreatePipelines_s(bool aIsRtcpMux) { |
|
294 mozilla::SourceMediaStream *audio = new Fake_SourceMediaStream(); |
|
295 audio->SetPullEnabled(true); |
|
296 |
|
297 mozilla::AudioSegment* segment= new mozilla::AudioSegment(); |
|
298 audio->AddTrack(0, 100, 0, segment); |
|
299 audio->AdvanceKnownTracksTime(mozilla::STREAM_TIME_MAX); |
|
300 |
|
301 audio_ = new Fake_DOMMediaStream(audio); |
|
302 |
|
303 std::vector<mozilla::AudioCodecConfig *> codecs; |
|
304 codecs.push_back(&audio_config_); |
|
305 |
|
306 mozilla::MediaConduitErrorCode err = |
|
307 static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get())-> |
|
308 ConfigureRecvMediaCodecs(codecs); |
|
309 EXPECT_EQ(mozilla::kMediaConduitNoError, err); |
|
310 |
|
311 std::string test_pc("PC"); |
|
312 |
|
313 if (aIsRtcpMux) { |
|
314 ASSERT_FALSE(audio_rtcp_transport_.flow_); |
|
315 } |
|
316 |
|
317 // For now, assume bundle always uses rtcp mux |
|
318 RefPtr<TransportFlow> dummy; |
|
319 RefPtr<TransportFlow> bundle_transport; |
|
320 if (bundle_filter_) { |
|
321 bundle_transport = bundle_transport_.flow_; |
|
322 bundle_filter_->AddLocalSSRC(GetLocalSSRC()); |
|
323 } |
|
324 |
|
325 audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio( |
|
326 test_pc, |
|
327 nullptr, |
|
328 test_utils->sts_target(), |
|
329 audio_->GetStream(), 1, 1, |
|
330 static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()), |
|
331 audio_rtp_transport_.flow_, |
|
332 audio_rtcp_transport_.flow_, |
|
333 bundle_transport, |
|
334 dummy, |
|
335 bundle_filter_); |
|
336 |
|
337 audio_pipeline_->Init(); |
|
338 } |
|
339 |
|
340 void SetBundleFilter(nsAutoPtr<MediaPipelineFilter> filter) { |
|
341 bundle_filter_ = filter; |
|
342 } |
|
343 |
|
344 void SetUsingBundle_s(bool decision) { |
|
345 audio_pipeline_->SetUsingBundle_s(decision); |
|
346 } |
|
347 |
|
348 void UpdateFilterFromRemoteDescription_s( |
|
349 nsAutoPtr<MediaPipelineFilter> filter) { |
|
350 audio_pipeline_->UpdateFilterFromRemoteDescription_s(filter); |
|
351 } |
|
352 |
|
353 private: |
|
354 nsAutoPtr<MediaPipelineFilter> bundle_filter_; |
|
355 }; |
|
356 |
|
357 |
|
358 class MediaPipelineTest : public ::testing::Test { |
|
359 public: |
|
360 ~MediaPipelineTest() { |
|
361 p1_.Stop(); |
|
362 p2_.Stop(); |
|
363 p1_.Shutdown(); |
|
364 p2_.Shutdown(); |
|
365 } |
|
366 |
|
367 // Setup transport. |
|
368 void InitTransports(bool aIsRtcpMux) { |
|
369 // RTP, p1_ is server, p2_ is client |
|
370 mozilla::SyncRunnable::DispatchToThread( |
|
371 test_utils->sts_target(), |
|
372 WrapRunnableNM(&TestAgent::ConnectRtp, &p2_, &p1_)); |
|
373 |
|
374 // Create RTCP flows separately if we are not muxing them. |
|
375 if(!aIsRtcpMux) { |
|
376 // RTCP, p1_ is server, p2_ is client |
|
377 mozilla::SyncRunnable::DispatchToThread( |
|
378 test_utils->sts_target(), |
|
379 WrapRunnableNM(&TestAgent::ConnectRtcp, &p2_, &p1_)); |
|
380 } |
|
381 |
|
382 // BUNDLE, p1_ is server, p2_ is client |
|
383 mozilla::SyncRunnable::DispatchToThread( |
|
384 test_utils->sts_target(), |
|
385 WrapRunnableNM(&TestAgent::ConnectBundle, &p2_, &p1_)); |
|
386 } |
|
387 |
|
388 // Verify RTP and RTCP |
|
389 void TestAudioSend(bool aIsRtcpMux, |
|
390 bool bundle = false, |
|
391 nsAutoPtr<MediaPipelineFilter> localFilter = |
|
392 nsAutoPtr<MediaPipelineFilter>(nullptr), |
|
393 nsAutoPtr<MediaPipelineFilter> remoteFilter = |
|
394 nsAutoPtr<MediaPipelineFilter>(nullptr), |
|
395 unsigned int ms_until_answer = 500, |
|
396 unsigned int ms_of_traffic_after_answer = 10000) { |
|
397 |
|
398 // We do not support testing bundle without rtcp mux, since that doesn't |
|
399 // make any sense. |
|
400 ASSERT_FALSE(!aIsRtcpMux && bundle); |
|
401 |
|
402 p1_.SetUsingBundle(bundle); |
|
403 p2_.SetBundleFilter(localFilter); |
|
404 |
|
405 // Setup transport flows |
|
406 InitTransports(aIsRtcpMux); |
|
407 |
|
408 mozilla::SyncRunnable::DispatchToThread( |
|
409 test_utils->sts_target(), |
|
410 WrapRunnable(&p1_, &TestAgent::CreatePipelines_s, aIsRtcpMux)); |
|
411 |
|
412 mozilla::SyncRunnable::DispatchToThread( |
|
413 test_utils->sts_target(), |
|
414 WrapRunnable(&p2_, &TestAgent::CreatePipelines_s, aIsRtcpMux)); |
|
415 |
|
416 p2_.Start(); |
|
417 p1_.Start(); |
|
418 |
|
419 // Simulate pre-answer traffic |
|
420 PR_Sleep(ms_until_answer); |
|
421 |
|
422 mozilla::SyncRunnable::DispatchToThread( |
|
423 test_utils->sts_target(), |
|
424 WrapRunnable(&p2_, &TestAgentReceive::SetUsingBundle_s, bundle)); |
|
425 |
|
426 if (bundle) { |
|
427 // Leaving remoteFilter not set implies we want to test sunny-day |
|
428 if (!remoteFilter) { |
|
429 remoteFilter = new MediaPipelineFilter; |
|
430 // Might not be safe, strictly speaking. |
|
431 remoteFilter->AddRemoteSSRC(p1_.GetLocalSSRC()); |
|
432 } |
|
433 |
|
434 mozilla::SyncRunnable::DispatchToThread( |
|
435 test_utils->sts_target(), |
|
436 WrapRunnable(&p2_, |
|
437 &TestAgentReceive::UpdateFilterFromRemoteDescription_s, |
|
438 remoteFilter)); |
|
439 } |
|
440 |
|
441 |
|
442 // wait for some RTP/RTCP tx and rx to happen |
|
443 PR_Sleep(ms_of_traffic_after_answer); |
|
444 |
|
445 p1_.Stop(); |
|
446 p2_.Stop(); |
|
447 |
|
448 // wait for any packets in flight to arrive |
|
449 PR_Sleep(100); |
|
450 |
|
451 p1_.Shutdown(); |
|
452 p2_.Shutdown(); |
|
453 |
|
454 if (!bundle) { |
|
455 // If we are doing bundle, allow the test-case to do this checking. |
|
456 ASSERT_GE(p1_.GetAudioRtpCountSent(), 40); |
|
457 ASSERT_EQ(p1_.GetAudioRtpCountReceived(), p2_.GetAudioRtpCountSent()); |
|
458 ASSERT_EQ(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); |
|
459 |
|
460 // Calling ShutdownMedia_m on both pipelines does not stop the flow of |
|
461 // RTCP. So, we might be off by one here. |
|
462 ASSERT_LE(p2_.GetAudioRtcpCountReceived(), p1_.GetAudioRtcpCountSent()); |
|
463 ASSERT_GE(p2_.GetAudioRtcpCountReceived() + 1, p1_.GetAudioRtcpCountSent()); |
|
464 } |
|
465 |
|
466 } |
|
467 |
|
468 void TestAudioReceiverOffersBundle(bool bundle_accepted, |
|
469 nsAutoPtr<MediaPipelineFilter> localFilter, |
|
470 nsAutoPtr<MediaPipelineFilter> remoteFilter = |
|
471 nsAutoPtr<MediaPipelineFilter>(nullptr), |
|
472 unsigned int ms_until_answer = 500, |
|
473 unsigned int ms_of_traffic_after_answer = 10000) { |
|
474 TestAudioSend(true, |
|
475 bundle_accepted, |
|
476 localFilter, |
|
477 remoteFilter, |
|
478 ms_until_answer, |
|
479 ms_of_traffic_after_answer); |
|
480 } |
|
481 protected: |
|
482 TestAgentSend p1_; |
|
483 TestAgentReceive p2_; |
|
484 }; |
|
485 |
|
486 class MediaPipelineFilterTest : public ::testing::Test { |
|
487 public: |
|
488 bool Filter(MediaPipelineFilter& filter, |
|
489 int32_t correlator, |
|
490 uint32_t ssrc, |
|
491 uint8_t payload_type) { |
|
492 |
|
493 webrtc::RTPHeader header; |
|
494 header.ssrc = ssrc; |
|
495 header.payloadType = payload_type; |
|
496 return filter.Filter(header, correlator); |
|
497 } |
|
498 }; |
|
499 |
|
500 TEST_F(MediaPipelineFilterTest, TestConstruct) { |
|
501 MediaPipelineFilter filter; |
|
502 } |
|
503 |
|
504 TEST_F(MediaPipelineFilterTest, TestDefault) { |
|
505 MediaPipelineFilter filter; |
|
506 ASSERT_FALSE(Filter(filter, 0, 233, 110)); |
|
507 } |
|
508 |
|
509 TEST_F(MediaPipelineFilterTest, TestSSRCFilter) { |
|
510 MediaPipelineFilter filter; |
|
511 filter.AddRemoteSSRC(555); |
|
512 ASSERT_TRUE(Filter(filter, 0, 555, 110)); |
|
513 ASSERT_FALSE(Filter(filter, 0, 556, 110)); |
|
514 } |
|
515 |
|
516 #define SSRC(ssrc) \ |
|
517 ((ssrc >> 24) & 0xFF), \ |
|
518 ((ssrc >> 16) & 0xFF), \ |
|
519 ((ssrc >> 8 ) & 0xFF), \ |
|
520 (ssrc & 0xFF) |
|
521 |
|
522 #define REPORT_FRAGMENT(ssrc) \ |
|
523 SSRC(ssrc), \ |
|
524 0,0,0,0, \ |
|
525 0,0,0,0, \ |
|
526 0,0,0,0, \ |
|
527 0,0,0,0, \ |
|
528 0,0,0,0 |
|
529 |
|
530 #define RTCP_TYPEINFO(num_rrs, type, size) \ |
|
531 0x80 + num_rrs, type, 0, size |
|
532 |
|
533 const unsigned char rtcp_rr_s16[] = { |
|
534 // zero rrs, size 1 words |
|
535 RTCP_TYPEINFO(0, MediaPipelineFilter::RECEIVER_REPORT_T, 1), |
|
536 SSRC(16) |
|
537 }; |
|
538 |
|
539 const unsigned char rtcp_rr_s16_r17[] = { |
|
540 // one rr, 7 words |
|
541 RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), |
|
542 SSRC(16), |
|
543 REPORT_FRAGMENT(17) |
|
544 }; |
|
545 |
|
546 const unsigned char rtcp_rr_s16_r17_18[] = { |
|
547 // two rrs, size 13 words |
|
548 RTCP_TYPEINFO(2, MediaPipelineFilter::RECEIVER_REPORT_T, 13), |
|
549 SSRC(16), |
|
550 REPORT_FRAGMENT(17), |
|
551 REPORT_FRAGMENT(18) |
|
552 }; |
|
553 |
|
554 const unsigned char rtcp_sr_s16[] = { |
|
555 // zero rrs, size 6 words |
|
556 RTCP_TYPEINFO(0, MediaPipelineFilter::SENDER_REPORT_T, 6), |
|
557 REPORT_FRAGMENT(16) |
|
558 }; |
|
559 |
|
560 const unsigned char rtcp_sr_s16_r17[] = { |
|
561 // one rr, size 12 words |
|
562 RTCP_TYPEINFO(1, MediaPipelineFilter::SENDER_REPORT_T, 12), |
|
563 REPORT_FRAGMENT(16), |
|
564 REPORT_FRAGMENT(17) |
|
565 }; |
|
566 |
|
567 const unsigned char rtcp_sr_s16_r17_18[] = { |
|
568 // two rrs, size 18 words |
|
569 RTCP_TYPEINFO(2, MediaPipelineFilter::SENDER_REPORT_T, 18), |
|
570 REPORT_FRAGMENT(16), |
|
571 REPORT_FRAGMENT(17), |
|
572 REPORT_FRAGMENT(18) |
|
573 }; |
|
574 |
|
575 const unsigned char unknown_type[] = { |
|
576 RTCP_TYPEINFO(1, 222, 0) |
|
577 }; |
|
578 |
|
579 TEST_F(MediaPipelineFilterTest, TestEmptyFilterReport0) { |
|
580 MediaPipelineFilter filter; |
|
581 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
582 filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); |
|
583 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
584 filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); |
|
585 } |
|
586 |
|
587 TEST_F(MediaPipelineFilterTest, TestFilterReport0) { |
|
588 MediaPipelineFilter filter; |
|
589 filter.AddRemoteSSRC(16); |
|
590 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
591 filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); |
|
592 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
593 filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); |
|
594 } |
|
595 |
|
596 TEST_F(MediaPipelineFilterTest, TestFilterReport0SSRCTruncated) { |
|
597 MediaPipelineFilter filter; |
|
598 filter.AddRemoteSSRC(16); |
|
599 const unsigned char data[] = { |
|
600 RTCP_TYPEINFO(0, MediaPipelineFilter::RECEIVER_REPORT_T, 1), |
|
601 0,0,0 |
|
602 }; |
|
603 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
604 filter.FilterRTCP(data, sizeof(data))); |
|
605 } |
|
606 |
|
607 TEST_F(MediaPipelineFilterTest, TestFilterReport0PTTruncated) { |
|
608 MediaPipelineFilter filter; |
|
609 filter.AddRemoteSSRC(16); |
|
610 const unsigned char data[] = {0x80}; |
|
611 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
612 filter.FilterRTCP(data, sizeof(data))); |
|
613 } |
|
614 |
|
615 TEST_F(MediaPipelineFilterTest, TestFilterReport0CountTruncated) { |
|
616 MediaPipelineFilter filter; |
|
617 filter.AddRemoteSSRC(16); |
|
618 const unsigned char data[] = {}; |
|
619 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
620 filter.FilterRTCP(data, sizeof(data))); |
|
621 } |
|
622 |
|
623 TEST_F(MediaPipelineFilterTest, TestFilterReport1BothMatch) { |
|
624 MediaPipelineFilter filter; |
|
625 filter.AddRemoteSSRC(16); |
|
626 filter.AddLocalSSRC(17); |
|
627 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
628 filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); |
|
629 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
630 filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); |
|
631 } |
|
632 |
|
633 TEST_F(MediaPipelineFilterTest, TestFilterReport1SSRCTruncated) { |
|
634 MediaPipelineFilter filter; |
|
635 filter.AddRemoteSSRC(16); |
|
636 filter.AddLocalSSRC(17); |
|
637 const unsigned char rr[] = { |
|
638 RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), |
|
639 SSRC(16), |
|
640 0,0,0 |
|
641 }; |
|
642 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
643 filter.FilterRTCP(rr, sizeof(rr))); |
|
644 const unsigned char sr[] = { |
|
645 RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 12), |
|
646 REPORT_FRAGMENT(16), |
|
647 0,0,0 |
|
648 }; |
|
649 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
650 filter.FilterRTCP(sr, sizeof(rr))); |
|
651 } |
|
652 |
|
653 TEST_F(MediaPipelineFilterTest, TestFilterReport1BigSSRC) { |
|
654 MediaPipelineFilter filter; |
|
655 filter.AddRemoteSSRC(0x01020304); |
|
656 filter.AddLocalSSRC(0x11121314); |
|
657 const unsigned char rr[] = { |
|
658 RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), |
|
659 SSRC(0x01020304), |
|
660 REPORT_FRAGMENT(0x11121314) |
|
661 }; |
|
662 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
663 filter.FilterRTCP(rr, sizeof(rr))); |
|
664 const unsigned char sr[] = { |
|
665 RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 12), |
|
666 SSRC(0x01020304), |
|
667 REPORT_FRAGMENT(0x11121314) |
|
668 }; |
|
669 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
670 filter.FilterRTCP(sr, sizeof(rr))); |
|
671 } |
|
672 |
|
673 TEST_F(MediaPipelineFilterTest, TestFilterReport1LocalMatch) { |
|
674 MediaPipelineFilter filter; |
|
675 filter.AddLocalSSRC(17); |
|
676 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
677 filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); |
|
678 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
679 filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); |
|
680 } |
|
681 |
|
682 TEST_F(MediaPipelineFilterTest, TestFilterReport1Inconsistent) { |
|
683 MediaPipelineFilter filter; |
|
684 filter.AddRemoteSSRC(16); |
|
685 // We assume that the filter is exactly correct in terms of local ssrcs. |
|
686 // So, when RTCP shows up with a remote SSRC that matches, and a local |
|
687 // ssrc that doesn't, we assume the other end has messed up and put ssrcs |
|
688 // from more than one m-line in the packet. |
|
689 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
690 filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); |
|
691 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
692 filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); |
|
693 } |
|
694 |
|
695 TEST_F(MediaPipelineFilterTest, TestFilterReport1NeitherMatch) { |
|
696 MediaPipelineFilter filter; |
|
697 filter.AddRemoteSSRC(17); |
|
698 filter.AddLocalSSRC(18); |
|
699 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
700 filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); |
|
701 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
702 filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); |
|
703 } |
|
704 |
|
705 TEST_F(MediaPipelineFilterTest, TestFilterReport2AllMatch) { |
|
706 MediaPipelineFilter filter; |
|
707 filter.AddRemoteSSRC(16); |
|
708 filter.AddLocalSSRC(17); |
|
709 filter.AddLocalSSRC(18); |
|
710 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
711 filter.FilterRTCP(rtcp_sr_s16_r17_18, |
|
712 sizeof(rtcp_sr_s16_r17_18))); |
|
713 } |
|
714 |
|
715 TEST_F(MediaPipelineFilterTest, TestFilterReport2LocalMatch) { |
|
716 MediaPipelineFilter filter; |
|
717 filter.AddLocalSSRC(17); |
|
718 filter.AddLocalSSRC(18); |
|
719 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
720 filter.FilterRTCP(rtcp_sr_s16_r17_18, |
|
721 sizeof(rtcp_sr_s16_r17_18))); |
|
722 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
723 filter.FilterRTCP(rtcp_rr_s16_r17_18, |
|
724 sizeof(rtcp_rr_s16_r17_18))); |
|
725 } |
|
726 |
|
727 TEST_F(MediaPipelineFilterTest, TestFilterReport2Inconsistent101) { |
|
728 MediaPipelineFilter filter; |
|
729 filter.AddRemoteSSRC(16); |
|
730 filter.AddLocalSSRC(18); |
|
731 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
732 filter.FilterRTCP(rtcp_sr_s16_r17_18, |
|
733 sizeof(rtcp_sr_s16_r17_18))); |
|
734 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
735 filter.FilterRTCP(rtcp_rr_s16_r17_18, |
|
736 sizeof(rtcp_rr_s16_r17_18))); |
|
737 } |
|
738 |
|
739 TEST_F(MediaPipelineFilterTest, TestFilterReport2Inconsistent001) { |
|
740 MediaPipelineFilter filter; |
|
741 filter.AddLocalSSRC(18); |
|
742 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
743 filter.FilterRTCP(rtcp_sr_s16_r17_18, |
|
744 sizeof(rtcp_sr_s16_r17_18))); |
|
745 ASSERT_EQ(MediaPipelineFilter::FAIL, |
|
746 filter.FilterRTCP(rtcp_rr_s16_r17_18, |
|
747 sizeof(rtcp_rr_s16_r17_18))); |
|
748 } |
|
749 |
|
750 TEST_F(MediaPipelineFilterTest, TestFilterUnknownRTCPType) { |
|
751 MediaPipelineFilter filter; |
|
752 filter.AddLocalSSRC(18); |
|
753 ASSERT_EQ(MediaPipelineFilter::UNSUPPORTED, |
|
754 filter.FilterRTCP(unknown_type, sizeof(unknown_type))); |
|
755 } |
|
756 |
|
757 TEST_F(MediaPipelineFilterTest, TestCorrelatorFilter) { |
|
758 MediaPipelineFilter filter; |
|
759 filter.SetCorrelator(7777); |
|
760 ASSERT_TRUE(Filter(filter, 7777, 16, 110)); |
|
761 ASSERT_FALSE(Filter(filter, 7778, 17, 110)); |
|
762 // This should also have resulted in the SSRC 16 being added to the filter |
|
763 ASSERT_TRUE(Filter(filter, 0, 16, 110)); |
|
764 ASSERT_FALSE(Filter(filter, 0, 17, 110)); |
|
765 |
|
766 // rtcp_sr_s16 has 16 as an SSRC |
|
767 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
768 filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); |
|
769 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
770 filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); |
|
771 } |
|
772 |
|
773 TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilter) { |
|
774 MediaPipelineFilter filter; |
|
775 filter.AddUniquePT(110); |
|
776 ASSERT_TRUE(Filter(filter, 0, 555, 110)); |
|
777 ASSERT_FALSE(Filter(filter, 0, 556, 111)); |
|
778 } |
|
779 |
|
780 TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilterSSRCUpdate) { |
|
781 MediaPipelineFilter filter; |
|
782 filter.AddUniquePT(110); |
|
783 ASSERT_TRUE(Filter(filter, 0, 16, 110)); |
|
784 |
|
785 // rtcp_sr_s16 has 16 as an SSRC |
|
786 ASSERT_EQ(MediaPipelineFilter::PASS, |
|
787 filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); |
|
788 } |
|
789 |
|
790 TEST_F(MediaPipelineFilterTest, TestAnswerAddsSSRCs) { |
|
791 MediaPipelineFilter filter; |
|
792 filter.SetCorrelator(7777); |
|
793 ASSERT_TRUE(Filter(filter, 7777, 555, 110)); |
|
794 ASSERT_FALSE(Filter(filter, 7778, 556, 110)); |
|
795 // This should also have resulted in the SSRC 555 being added to the filter |
|
796 ASSERT_TRUE(Filter(filter, 0, 555, 110)); |
|
797 ASSERT_FALSE(Filter(filter, 0, 556, 110)); |
|
798 |
|
799 // This sort of thing can happen when getting an answer with SSRC attrs |
|
800 // The answer will not contain the correlator. |
|
801 MediaPipelineFilter filter2; |
|
802 filter2.AddRemoteSSRC(555); |
|
803 filter2.AddRemoteSSRC(556); |
|
804 filter2.AddRemoteSSRC(557); |
|
805 |
|
806 filter.IncorporateRemoteDescription(filter2); |
|
807 |
|
808 // Ensure that the old SSRC still works. |
|
809 ASSERT_TRUE(Filter(filter, 0, 555, 110)); |
|
810 |
|
811 // Ensure that the new SSRCs work. |
|
812 ASSERT_TRUE(Filter(filter, 0, 556, 110)); |
|
813 ASSERT_TRUE(Filter(filter, 0, 557, 110)); |
|
814 |
|
815 // Ensure that the correlator continues to work |
|
816 ASSERT_TRUE(Filter(filter, 7777, 558, 110)); |
|
817 } |
|
818 |
|
819 TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithSDP) { |
|
820 MediaPipelineFilter filter; |
|
821 filter.SetCorrelator(7777); |
|
822 filter.AddUniquePT(111); |
|
823 ASSERT_TRUE(Filter(filter, 7777, 555, 110)); |
|
824 |
|
825 MediaPipelineFilter filter2; |
|
826 filter2.AddRemoteSSRC(556); |
|
827 |
|
828 filter.IncorporateRemoteDescription(filter2); |
|
829 |
|
830 // Ensure that the old SSRC has been removed. |
|
831 ASSERT_FALSE(Filter(filter, 0, 555, 110)); |
|
832 |
|
833 // Ensure that the new SSRC works. |
|
834 ASSERT_TRUE(Filter(filter, 0, 556, 110)); |
|
835 |
|
836 // Ensure that the correlator continues to work |
|
837 ASSERT_TRUE(Filter(filter, 7777, 558, 110)); |
|
838 |
|
839 // Ensure that the payload type mapping continues to work |
|
840 ASSERT_TRUE(Filter(filter, 0, 559, 111)); |
|
841 } |
|
842 |
|
843 TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithCorrelator) { |
|
844 MediaPipelineFilter filter; |
|
845 filter.SetCorrelator(7777); |
|
846 ASSERT_TRUE(Filter(filter, 7777, 555, 110)); |
|
847 ASSERT_TRUE(Filter(filter, 0, 555, 110)); |
|
848 ASSERT_FALSE(Filter(filter, 7778, 555, 110)); |
|
849 ASSERT_FALSE(Filter(filter, 0, 555, 110)); |
|
850 } |
|
851 |
|
852 TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) { |
|
853 // If the remote SDP doesn't have SSRCs, right now this is a no-op and |
|
854 // there is no point of even incorporating a filter, but we make the |
|
855 // behavior consistent to avoid confusion. |
|
856 MediaPipelineFilter filter; |
|
857 filter.SetCorrelator(7777); |
|
858 filter.AddUniquePT(111); |
|
859 ASSERT_TRUE(Filter(filter, 7777, 555, 110)); |
|
860 |
|
861 MediaPipelineFilter filter2; |
|
862 |
|
863 filter.IncorporateRemoteDescription(filter2); |
|
864 |
|
865 // Ensure that the old SSRC still works. |
|
866 ASSERT_TRUE(Filter(filter, 7777, 555, 110)); |
|
867 } |
|
868 |
|
869 TEST_F(MediaPipelineTest, TestAudioSendNoMux) { |
|
870 TestAudioSend(false); |
|
871 } |
|
872 |
|
873 TEST_F(MediaPipelineTest, TestAudioSendMux) { |
|
874 TestAudioSend(true); |
|
875 } |
|
876 |
|
877 TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndDeclined) { |
|
878 nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); |
|
879 TestAudioReceiverOffersBundle(false, filter); |
|
880 } |
|
881 |
|
882 TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndAccepted) { |
|
883 nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); |
|
884 // These durations have to be _extremely_ long to have any assurance that |
|
885 // some RTCP will be sent at all. This is because the first RTCP packet |
|
886 // is sometimes sent before the transports are ready, which causes it to |
|
887 // be dropped. |
|
888 TestAudioReceiverOffersBundle(true, |
|
889 filter, |
|
890 // We do not specify the filter for the remote description, so it will be |
|
891 // set to something sane after a short time. |
|
892 nsAutoPtr<MediaPipelineFilter>(), |
|
893 10000, |
|
894 10000); |
|
895 |
|
896 // Some packets should have been dropped, but not all |
|
897 ASSERT_GT(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); |
|
898 ASSERT_GT(p2_.GetAudioRtpCountReceived(), 40); |
|
899 ASSERT_GT(p1_.GetAudioRtcpCountSent(), 1); |
|
900 ASSERT_GT(p1_.GetAudioRtcpCountSent(), p2_.GetAudioRtcpCountReceived()); |
|
901 ASSERT_GT(p2_.GetAudioRtcpCountReceived(), 0); |
|
902 } |
|
903 |
|
904 TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndAcceptedEmptyFilter) { |
|
905 nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); |
|
906 nsAutoPtr<MediaPipelineFilter> bad_answer_filter(new MediaPipelineFilter); |
|
907 TestAudioReceiverOffersBundle(true, filter, bad_answer_filter); |
|
908 // Filter is empty, so should drop everything. |
|
909 ASSERT_EQ(0, p2_.GetAudioRtpCountReceived()); |
|
910 ASSERT_EQ(0, p2_.GetAudioRtcpCountReceived()); |
|
911 } |
|
912 |
|
913 } // end namespace |
|
914 |
|
915 |
|
916 int main(int argc, char **argv) { |
|
917 test_utils = new MtransportTestUtils(); |
|
918 // Start the tests |
|
919 NSS_NoDB_Init(nullptr); |
|
920 NSS_SetDomesticPolicy(); |
|
921 ::testing::InitGoogleTest(&argc, argv); |
|
922 |
|
923 int rv = RUN_ALL_TESTS(); |
|
924 delete test_utils; |
|
925 return rv; |
|
926 } |
|
927 |
|
928 |
|
929 |