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 "logging.h"
10 #include "nss.h"
11
12 #include "AudioSegment.h"
13 #include "AudioStreamTrack.h"
14 #include "mozilla/Mutex.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/SpinEventLoopUntil.h"
17 #include "MediaPipeline.h"
18 #include "MediaPipelineFilter.h"
19 #include "MediaTrackGraph.h"
20 #include "MediaTrackListener.h"
21 #include "MediaStreamTrack.h"
22 #include "transportflow.h"
23 #include "transportlayerloopback.h"
24 #include "transportlayerdtls.h"
25 #include "transportlayersrtp.h"
26 #include "mozilla/SyncRunnable.h"
27 #include "mtransport_test_utils.h"
28 #include "SharedBuffer.h"
29 #include "MediaTransportHandler.h"
30
31 #define GTEST_HAS_RTTI 0
32 #include "gtest/gtest.h"
33
34 using namespace mozilla;
35 MOZ_MTLOG_MODULE("transportbridge")
36
37 static MtransportTestUtils* test_utils;
38
39 namespace {
40
41 class FakeAudioTrack : public mozilla::ProcessedMediaTrack {
42 public:
FakeAudioTrack()43 FakeAudioTrack()
44 : ProcessedMediaTrack(44100, MediaSegment::AUDIO, nullptr),
45 mMutex("Fake AudioTrack") {
46 Resume();
47 }
48
Destroy()49 void Destroy() override {
50 MOZ_ASSERT(!mMainThreadDestroyed);
51 mMainThreadDestroyed = true;
52 Suspend();
53 }
54
QueueSetAutoend(bool)55 void QueueSetAutoend(bool) override {}
56
Suspend()57 void Suspend() override {
58 mozilla::MutexAutoLock lock(mMutex);
59 if (mSuspended) {
60 return;
61 }
62 mSuspended = true;
63 mTimer->Cancel();
64 mTimer = nullptr;
65 }
66
Resume()67 void Resume() override {
68 mozilla::MutexAutoLock lock(mMutex);
69 if (!mSuspended) {
70 return;
71 }
72 mSuspended = false;
73 NS_NewTimerWithFuncCallback(
74 getter_AddRefs(mTimer), FakeAudioTrackGenerateData, this, 20,
75 nsITimer::TYPE_REPEATING_SLACK,
76 "FakeAudioTrack::FakeAudioTrackGenerateData", test_utils->sts_target());
77 }
78
AddListener(MediaTrackListener * aListener)79 void AddListener(MediaTrackListener* aListener) override {
80 mozilla::MutexAutoLock lock(mMutex);
81 MOZ_ASSERT(!mListener);
82 mListener = aListener;
83 }
84
RemoveListener(MediaTrackListener * aListener)85 RefPtr<GenericPromise> RemoveListener(
86 MediaTrackListener* aListener) override {
87 mozilla::MutexAutoLock lock(mMutex);
88 MOZ_ASSERT(mListener == aListener);
89 mListener = nullptr;
90 return GenericPromise::CreateAndResolve(true, __func__);
91 }
92
ProcessInput(GraphTime aFrom,GraphTime aTo,uint32_t aFlags)93 void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override {}
94
NumberOfChannels() const95 uint32_t NumberOfChannels() const override { return NUM_CHANNELS; }
96
97 private:
98 mozilla::Mutex mMutex;
99 MediaTrackListener* mListener = nullptr;
100 bool mSuspended = true;
101 nsCOMPtr<nsITimer> mTimer;
102 int mCount = 0;
103
104 static const int AUDIO_BUFFER_SIZE = 1600;
105 static const int NUM_CHANNELS = 2;
FakeAudioTrackGenerateData(nsITimer * timer,void * closure)106 static void FakeAudioTrackGenerateData(nsITimer* timer, void* closure) {
107 auto t = static_cast<FakeAudioTrack*>(closure);
108 mozilla::MutexAutoLock lock(t->mMutex);
109 if (t->mSuspended) {
110 return;
111 }
112
113 CheckedInt<size_t> bufferSize(sizeof(int16_t));
114 bufferSize *= NUM_CHANNELS;
115 bufferSize *= AUDIO_BUFFER_SIZE;
116 RefPtr<mozilla::SharedBuffer> samples =
117 mozilla::SharedBuffer::Create(bufferSize);
118 int16_t* data = reinterpret_cast<int16_t*>(samples->Data());
119 for (int i = 0; i < (AUDIO_BUFFER_SIZE * NUM_CHANNELS); i++) {
120 // saw tooth audio sample
121 data[i] = ((t->mCount % 8) * 4000) - (7 * 4000) / 2;
122 t->mCount++;
123 }
124
125 mozilla::AudioSegment segment;
126 AutoTArray<const int16_t*, 1> channels;
127 channels.AppendElement(data);
128 segment.AppendFrames(samples.forget(), channels, AUDIO_BUFFER_SIZE,
129 PRINCIPAL_HANDLE_NONE);
130
131 if (t->mListener) {
132 t->mListener->NotifyQueuedChanges(nullptr, 0, segment);
133 }
134 }
135 };
136
137 class LoopbackTransport : public MediaTransportHandler {
138 public:
LoopbackTransport()139 LoopbackTransport() : MediaTransportHandler(nullptr) {
140 SetState("mux", TransportLayer::TS_INIT, false);
141 SetState("mux", TransportLayer::TS_INIT, true);
142 SetState("non-mux", TransportLayer::TS_INIT, false);
143 SetState("non-mux", TransportLayer::TS_INIT, true);
144 }
145
InitAndConnect(LoopbackTransport & client,LoopbackTransport & server)146 static void InitAndConnect(LoopbackTransport& client,
147 LoopbackTransport& server) {
148 client.Connect(&server);
149 server.Connect(&client);
150 }
151
Connect(LoopbackTransport * peer)152 void Connect(LoopbackTransport* peer) { peer_ = peer; }
153
Shutdown()154 void Shutdown() { peer_ = nullptr; }
155
GetIceLog(const nsCString & aPattern)156 RefPtr<IceLogPromise> GetIceLog(const nsCString& aPattern) override {
157 return nullptr;
158 }
159
ClearIceLog()160 void ClearIceLog() override {}
EnterPrivateMode()161 void EnterPrivateMode() override {}
ExitPrivateMode()162 void ExitPrivateMode() override {}
163
CreateIceCtx(const std::string & aName,const nsTArray<dom::RTCIceServer> & aIceServers,dom::RTCIceTransportPolicy aIcePolicy)164 nsresult CreateIceCtx(const std::string& aName,
165 const nsTArray<dom::RTCIceServer>& aIceServers,
166 dom::RTCIceTransportPolicy aIcePolicy) override {
167 return NS_OK;
168 }
169
Destroy()170 void Destroy() override {}
171
172 // We will probably be able to move the proxy lookup stuff into
173 // this class once we move mtransport to its own process.
SetProxyConfig(NrSocketProxyConfig && aProxyConfig)174 void SetProxyConfig(NrSocketProxyConfig&& aProxyConfig) override {}
175
EnsureProvisionalTransport(const std::string & aTransportId,const std::string & aLocalUfrag,const std::string & aLocalPwd,size_t aComponentCount)176 void EnsureProvisionalTransport(const std::string& aTransportId,
177 const std::string& aLocalUfrag,
178 const std::string& aLocalPwd,
179 size_t aComponentCount) override {}
180
SetTargetForDefaultLocalAddressLookup(const std::string & aTargetIp,uint16_t aTargetPort)181 void SetTargetForDefaultLocalAddressLookup(const std::string& aTargetIp,
182 uint16_t aTargetPort) override {}
183
184 // We set default-route-only as late as possible because it depends on what
185 // capture permissions have been granted on the window, which could easily
186 // change between Init (ie; when the PC is created) and StartIceGathering
187 // (ie; when we set the local description).
StartIceGathering(bool aDefaultRouteOnly,bool aObfuscateAddresses,const nsTArray<NrIceStunAddr> & aStunAddrs)188 void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateAddresses,
189 // TODO: It probably makes sense to look
190 // this up internally
191 const nsTArray<NrIceStunAddr>& aStunAddrs) override {}
192
ActivateTransport(const std::string & aTransportId,const std::string & aLocalUfrag,const std::string & aLocalPwd,size_t aComponentCount,const std::string & aUfrag,const std::string & aPassword,const nsTArray<uint8_t> & aKeyDer,const nsTArray<uint8_t> & aCertDer,SSLKEAType aAuthType,bool aDtlsClient,const DtlsDigestList & aDigests,bool aPrivacyRequested)193 void ActivateTransport(
194 const std::string& aTransportId, const std::string& aLocalUfrag,
195 const std::string& aLocalPwd, size_t aComponentCount,
196 const std::string& aUfrag, const std::string& aPassword,
197 const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
198 SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
199 bool aPrivacyRequested) override {}
200
RemoveTransportsExcept(const std::set<std::string> & aTransportIds)201 void RemoveTransportsExcept(
202 const std::set<std::string>& aTransportIds) override {}
203
StartIceChecks(bool aIsControlling,const std::vector<std::string> & aIceOptions)204 void StartIceChecks(bool aIsControlling,
205 const std::vector<std::string>& aIceOptions) override {}
206
AddIceCandidate(const std::string & aTransportId,const std::string & aCandidate,const std::string & aUfrag,const std::string & aObfuscatedAddress)207 void AddIceCandidate(const std::string& aTransportId,
208 const std::string& aCandidate, const std::string& aUfrag,
209 const std::string& aObfuscatedAddress) override {}
210
UpdateNetworkState(bool aOnline)211 void UpdateNetworkState(bool aOnline) override {}
212
GetIceStats(const std::string & aTransportId,DOMHighResTimeStamp aNow)213 RefPtr<dom::RTCStatsPromise> GetIceStats(const std::string& aTransportId,
214 DOMHighResTimeStamp aNow) override {
215 return nullptr;
216 }
217
SendPacket(const std::string & aTransportId,MediaPacket && aPacket)218 void SendPacket(const std::string& aTransportId,
219 MediaPacket&& aPacket) override {
220 peer_->SignalPacketReceived(aTransportId, aPacket);
221 }
222
SetState(const std::string & aTransportId,TransportLayer::State aState,bool aRtcp)223 void SetState(const std::string& aTransportId, TransportLayer::State aState,
224 bool aRtcp) {
225 if (aRtcp) {
226 MediaTransportHandler::OnRtcpStateChange(aTransportId, aState);
227 } else {
228 MediaTransportHandler::OnStateChange(aTransportId, aState);
229 }
230 }
231
232 private:
233 RefPtr<MediaTransportHandler> peer_;
234 };
235
236 class TestAgent {
237 public:
TestAgent()238 TestAgent()
239 : audio_config_(109, "opus", 48000, 2, false),
240 audio_conduit_(mozilla::AudioSessionConduit::Create(
241 WebRtcCallWrapper::Create(dom::RTCStatsTimestampMaker()),
242 test_utils->sts_target())),
243 audio_pipeline_(),
244 transport_(new LoopbackTransport) {}
245
Connect(TestAgent * client,TestAgent * server)246 static void Connect(TestAgent* client, TestAgent* server) {
247 LoopbackTransport::InitAndConnect(*client->transport_, *server->transport_);
248 }
249
250 virtual void CreatePipeline(const std::string& aTransportId) = 0;
251
SetState(const std::string & aTransportId,TransportLayer::State aState,bool aRtcp)252 void SetState(const std::string& aTransportId, TransportLayer::State aState,
253 bool aRtcp) {
254 test_utils->sts_target()->Dispatch(
255 WrapRunnable(transport_, &LoopbackTransport::SetState, aTransportId,
256 aState, aRtcp),
257 nsISerialEventTarget::DISPATCH_SYNC);
258 }
259
UpdateTransport(const std::string & aTransportId,UniquePtr<MediaPipelineFilter> && aFilter)260 void UpdateTransport(const std::string& aTransportId,
261 UniquePtr<MediaPipelineFilter>&& aFilter) {
262 test_utils->sts_target()->Dispatch(
263 NS_NewRunnableFunction(__func__,
264 [pipeline = audio_pipeline_, aTransportId,
265 filter = std::move(aFilter)]() mutable {
266 pipeline->UpdateTransport_s(aTransportId,
267 std::move(filter));
268 }),
269 nsISerialEventTarget::DISPATCH_SYNC);
270 }
271
Stop()272 void Stop() {
273 MOZ_MTLOG(ML_DEBUG, "Stopping");
274
275 if (audio_pipeline_) audio_pipeline_->Stop();
276 }
277
Shutdown_s()278 void Shutdown_s() { transport_->Shutdown(); }
279
Shutdown()280 void Shutdown() {
281 if (audio_pipeline_) audio_pipeline_->Shutdown_m();
282
283 test_utils->sts_target()->Dispatch(
284 WrapRunnable(this, &TestAgent::Shutdown_s),
285 nsISerialEventTarget::DISPATCH_SYNC);
286 }
287
GetRemoteSSRC()288 uint32_t GetRemoteSSRC() {
289 uint32_t res = 0;
290 audio_conduit_->GetRemoteSSRC(&res);
291 return res;
292 }
293
GetLocalSSRC()294 uint32_t GetLocalSSRC() {
295 std::vector<uint32_t> res;
296 res = audio_conduit_->GetLocalSSRCs();
297 return res.empty() ? 0 : res[0];
298 }
299
GetAudioRtpCountSent()300 int GetAudioRtpCountSent() { return audio_pipeline_->RtpPacketsSent(); }
301
GetAudioRtpCountReceived()302 int GetAudioRtpCountReceived() {
303 return audio_pipeline_->RtpPacketsReceived();
304 }
305
GetAudioRtcpCountSent()306 int GetAudioRtcpCountSent() { return audio_pipeline_->RtcpPacketsSent(); }
307
GetAudioRtcpCountReceived()308 int GetAudioRtcpCountReceived() {
309 return audio_pipeline_->RtcpPacketsReceived();
310 }
311
312 protected:
313 mozilla::AudioCodecConfig audio_config_;
314 RefPtr<mozilla::MediaSessionConduit> audio_conduit_;
315 RefPtr<FakeAudioTrack> audio_track_;
316 // TODO(bcampen@mozilla.com): Right now this does not let us test RTCP in
317 // both directions; only the sender's RTCP is sent, but the receiver should
318 // be sending it too.
319 RefPtr<mozilla::MediaPipeline> audio_pipeline_;
320 RefPtr<LoopbackTransport> transport_;
321 };
322
323 class TestAgentSend : public TestAgent {
324 public:
TestAgentSend()325 TestAgentSend() {
326 mozilla::MediaConduitErrorCode err =
327 static_cast<mozilla::AudioSessionConduit*>(audio_conduit_.get())
328 ->ConfigureSendMediaCodec(&audio_config_);
329 EXPECT_EQ(mozilla::kMediaConduitNoError, err);
330
331 audio_track_ = new FakeAudioTrack();
332 }
333
CreatePipeline(const std::string & aTransportId)334 virtual void CreatePipeline(const std::string& aTransportId) {
335 std::string test_pc;
336
337 RefPtr<MediaPipelineTransmit> audio_pipeline =
338 new mozilla::MediaPipelineTransmit(test_pc, transport_, nullptr,
339 test_utils->sts_target(), false,
340 audio_conduit_);
341
342 audio_pipeline->SetSendTrack(audio_track_);
343 audio_pipeline->Start();
344
345 audio_pipeline_ = audio_pipeline;
346
347 audio_pipeline_->UpdateTransport_m(aTransportId, nullptr);
348 }
349 };
350
351 class TestAgentReceive : public TestAgent {
352 public:
TestAgentReceive()353 TestAgentReceive() {
354 std::vector<UniquePtr<mozilla::AudioCodecConfig>> codecs;
355 codecs.emplace_back(new AudioCodecConfig(audio_config_));
356
357 mozilla::MediaConduitErrorCode err =
358 static_cast<mozilla::AudioSessionConduit*>(audio_conduit_.get())
359 ->ConfigureRecvMediaCodecs(codecs);
360 EXPECT_EQ(mozilla::kMediaConduitNoError, err);
361 }
362
CreatePipeline(const std::string & aTransportId)363 virtual void CreatePipeline(const std::string& aTransportId) {
364 std::string test_pc;
365
366 audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(
367 test_pc, transport_, nullptr, test_utils->sts_target(),
368 static_cast<mozilla::AudioSessionConduit*>(audio_conduit_.get()),
369 nullptr, PRINCIPAL_HANDLE_NONE);
370
371 audio_pipeline_->Start();
372
373 audio_pipeline_->UpdateTransport_m(aTransportId, std::move(bundle_filter_));
374 }
375
SetBundleFilter(UniquePtr<MediaPipelineFilter> && filter)376 void SetBundleFilter(UniquePtr<MediaPipelineFilter>&& filter) {
377 bundle_filter_ = std::move(filter);
378 }
379
UpdateTransport_s(const std::string & aTransportId,UniquePtr<MediaPipelineFilter> && filter)380 void UpdateTransport_s(const std::string& aTransportId,
381 UniquePtr<MediaPipelineFilter>&& filter) {
382 audio_pipeline_->UpdateTransport_s(aTransportId, std::move(filter));
383 }
384
385 private:
386 UniquePtr<MediaPipelineFilter> bundle_filter_;
387 };
388
WaitFor(TimeDuration aDuration)389 void WaitFor(TimeDuration aDuration) {
390 bool done = false;
391 NS_DelayedDispatchToCurrentThread(
392 NS_NewRunnableFunction(__func__, [&] { done = true; }),
393 aDuration.ToMilliseconds());
394 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
395 [&] { return done; });
396 }
397
398 class MediaPipelineTest : public ::testing::Test {
399 public:
~MediaPipelineTest()400 ~MediaPipelineTest() {
401 p1_.Shutdown();
402 p2_.Shutdown();
403 }
404
SetUpTestCase()405 static void SetUpTestCase() {
406 test_utils = new MtransportTestUtils();
407 NSS_NoDB_Init(nullptr);
408 NSS_SetDomesticPolicy();
409 }
410
411 // Setup transport.
InitTransports()412 void InitTransports() {
413 test_utils->sts_target()->Dispatch(
414 WrapRunnableNM(&TestAgent::Connect, &p2_, &p1_),
415 nsISerialEventTarget::DISPATCH_SYNC);
416 }
417
418 // Verify RTP and RTCP
TestAudioSend(bool aIsRtcpMux,UniquePtr<MediaPipelineFilter> && initialFilter=nullptr,UniquePtr<MediaPipelineFilter> && refinedFilter=nullptr,unsigned int ms_until_filter_update=500,unsigned int ms_of_traffic_after_answer=10000)419 void TestAudioSend(bool aIsRtcpMux,
420 UniquePtr<MediaPipelineFilter>&& initialFilter = nullptr,
421 UniquePtr<MediaPipelineFilter>&& refinedFilter = nullptr,
422 unsigned int ms_until_filter_update = 500,
423 unsigned int ms_of_traffic_after_answer = 10000) {
424 bool bundle = !!(initialFilter);
425 // We do not support testing bundle without rtcp mux, since that doesn't
426 // make any sense.
427 ASSERT_FALSE(!aIsRtcpMux && bundle);
428
429 p2_.SetBundleFilter(std::move(initialFilter));
430
431 // Setup transport flows
432 InitTransports();
433
434 std::string transportId = aIsRtcpMux ? "mux" : "non-mux";
435 p1_.CreatePipeline(transportId);
436 p2_.CreatePipeline(transportId);
437
438 // Set state of transports to CONNECTING. MediaPipeline doesn't really care
439 // about this transition, but we're trying to simluate what happens in a
440 // real case.
441 p1_.SetState(transportId, TransportLayer::TS_CONNECTING, false);
442 p1_.SetState(transportId, TransportLayer::TS_CONNECTING, true);
443 p2_.SetState(transportId, TransportLayer::TS_CONNECTING, false);
444 p2_.SetState(transportId, TransportLayer::TS_CONNECTING, true);
445
446 WaitFor(TimeDuration::FromMilliseconds(10));
447
448 // Set state of transports to OPEN (ie; connected). This should result in
449 // media flowing.
450 p1_.SetState(transportId, TransportLayer::TS_OPEN, false);
451 p1_.SetState(transportId, TransportLayer::TS_OPEN, true);
452 p2_.SetState(transportId, TransportLayer::TS_OPEN, false);
453 p2_.SetState(transportId, TransportLayer::TS_OPEN, true);
454
455 if (bundle) {
456 WaitFor(TimeDuration::FromMilliseconds(ms_until_filter_update));
457
458 // Leaving refinedFilter not set implies we want to just update with
459 // the other side's SSRC
460 if (!refinedFilter) {
461 refinedFilter = MakeUnique<MediaPipelineFilter>();
462 // Might not be safe, strictly speaking.
463 refinedFilter->AddRemoteSSRC(p1_.GetLocalSSRC());
464 }
465
466 p2_.UpdateTransport(transportId, std::move(refinedFilter));
467 }
468
469 // wait for some RTP/RTCP tx and rx to happen
470 WaitFor(TimeDuration::FromMilliseconds(ms_of_traffic_after_answer));
471
472 p1_.Stop();
473 p2_.Stop();
474
475 // wait for any packets in flight to arrive
476 WaitFor(TimeDuration::FromMilliseconds(200));
477
478 p1_.Shutdown();
479 p2_.Shutdown();
480
481 if (!bundle) {
482 // If we are filtering, allow the test-case to do this checking.
483 ASSERT_GE(p1_.GetAudioRtpCountSent(), 40);
484 ASSERT_EQ(p1_.GetAudioRtpCountReceived(), p2_.GetAudioRtpCountSent());
485 ASSERT_EQ(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived());
486 }
487
488 // No RTCP packets should have been dropped, because we do not filter them.
489 // Calling ShutdownMedia_m on both pipelines does not stop the flow of
490 // RTCP. So, we might be off by one here.
491 ASSERT_LE(p2_.GetAudioRtcpCountReceived(), p1_.GetAudioRtcpCountSent());
492 ASSERT_GE(p2_.GetAudioRtcpCountReceived() + 1, p1_.GetAudioRtcpCountSent());
493 }
494
TestAudioReceiverBundle(bool bundle_accepted,UniquePtr<MediaPipelineFilter> && initialFilter,UniquePtr<MediaPipelineFilter> && refinedFilter=nullptr,unsigned int ms_until_answer=500,unsigned int ms_of_traffic_after_answer=10000)495 void TestAudioReceiverBundle(
496 bool bundle_accepted, UniquePtr<MediaPipelineFilter>&& initialFilter,
497 UniquePtr<MediaPipelineFilter>&& refinedFilter = nullptr,
498 unsigned int ms_until_answer = 500,
499 unsigned int ms_of_traffic_after_answer = 10000) {
500 TestAudioSend(true, std::move(initialFilter), std::move(refinedFilter),
501 ms_until_answer, ms_of_traffic_after_answer);
502 }
503
504 protected:
505 TestAgentSend p1_;
506 TestAgentReceive p2_;
507 };
508
509 class MediaPipelineFilterTest : public ::testing::Test {
510 public:
Filter(MediaPipelineFilter & filter,uint32_t ssrc,uint8_t payload_type,const mozilla::Maybe<std::string> & mid=mozilla::Nothing ())511 bool Filter(MediaPipelineFilter& filter, uint32_t ssrc, uint8_t payload_type,
512 const mozilla::Maybe<std::string>& mid = mozilla::Nothing()) {
513 webrtc::RTPHeader header;
514 header.ssrc = ssrc;
515 header.payloadType = payload_type;
516 mid.apply([&](const auto& mid) {
517 header.extension.mid.Set(mid.c_str(), mid.length());
518 });
519 return filter.Filter(header);
520 }
521 };
522
TEST_F(MediaPipelineFilterTest,TestConstruct)523 TEST_F(MediaPipelineFilterTest, TestConstruct) { MediaPipelineFilter filter; }
524
TEST_F(MediaPipelineFilterTest,TestDefault)525 TEST_F(MediaPipelineFilterTest, TestDefault) {
526 MediaPipelineFilter filter;
527 EXPECT_FALSE(Filter(filter, 233, 110));
528 }
529
TEST_F(MediaPipelineFilterTest,TestSSRCFilter)530 TEST_F(MediaPipelineFilterTest, TestSSRCFilter) {
531 MediaPipelineFilter filter;
532 filter.AddRemoteSSRC(555);
533 EXPECT_TRUE(Filter(filter, 555, 110));
534 EXPECT_FALSE(Filter(filter, 556, 110));
535 }
536
537 #define SSRC(ssrc) \
538 ((ssrc >> 24) & 0xFF), ((ssrc >> 16) & 0xFF), ((ssrc >> 8) & 0xFF), \
539 (ssrc & 0xFF)
540 #define REPORT_FRAGMENT(ssrc) \
541 SSRC(ssrc), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
542
543 #define RTCP_TYPEINFO(num_rrs, type, size) 0x80 + num_rrs, type, 0, size
544
TEST_F(MediaPipelineFilterTest,TestMidFilter)545 TEST_F(MediaPipelineFilterTest, TestMidFilter) {
546 MediaPipelineFilter filter;
547 const auto mid = Some(std::string("mid0"));
548 filter.SetRemoteMediaStreamId(mid);
549
550 EXPECT_FALSE(Filter(filter, 16, 110));
551 EXPECT_TRUE(Filter(filter, 16, 110, mid));
552 EXPECT_TRUE(Filter(filter, 16, 110));
553 EXPECT_FALSE(Filter(filter, 17, 110));
554
555 // The mid filter maintains a set of SSRCs. Adding a new SSRC should work
556 // and still allow previous SSRCs to work. Unrecognized SSRCs should still be
557 // filtered out.
558 EXPECT_TRUE(Filter(filter, 18, 111, mid));
559 EXPECT_TRUE(Filter(filter, 18, 111));
560 EXPECT_TRUE(Filter(filter, 16, 110));
561 EXPECT_FALSE(Filter(filter, 17, 110));
562 }
563
TEST_F(MediaPipelineFilterTest,TestPayloadTypeFilter)564 TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilter) {
565 MediaPipelineFilter filter;
566 filter.AddUniquePT(110);
567 EXPECT_TRUE(Filter(filter, 555, 110));
568 EXPECT_FALSE(Filter(filter, 556, 111));
569 }
570
TEST_F(MediaPipelineFilterTest,TestSSRCMovedWithMid)571 TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithMid) {
572 MediaPipelineFilter filter;
573 const auto mid0 = Some(std::string("mid0"));
574 const auto mid1 = Some(std::string("mid1"));
575 filter.SetRemoteMediaStreamId(mid0);
576 ASSERT_TRUE(Filter(filter, 555, 110, mid0));
577 ASSERT_TRUE(Filter(filter, 555, 110));
578 // Present a new MID binding
579 ASSERT_FALSE(Filter(filter, 555, 110, mid1));
580 ASSERT_FALSE(Filter(filter, 555, 110));
581 }
582
TEST_F(MediaPipelineFilterTest,TestRemoteSDPNoSSRCs)583 TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) {
584 // If the remote SDP doesn't have SSRCs, right now this is a no-op and
585 // there is no point of even incorporating a filter, but we make the
586 // behavior consistent to avoid confusion.
587 MediaPipelineFilter filter;
588 const auto mid = Some(std::string("mid0"));
589 filter.SetRemoteMediaStreamId(mid);
590 filter.AddUniquePT(111);
591 EXPECT_TRUE(Filter(filter, 555, 110, mid));
592 EXPECT_TRUE(Filter(filter, 555, 110));
593
594 // Update but remember binding./
595 MediaPipelineFilter filter2;
596
597 filter.Update(filter2);
598
599 // Ensure that the old SSRC still works.
600 EXPECT_TRUE(Filter(filter, 555, 110));
601
602 // Forget the previous binding
603 MediaPipelineFilter filter3;
604 filter3.SetRemoteMediaStreamId(Some(std::string("mid1")));
605 filter.Update(filter3);
606
607 ASSERT_FALSE(Filter(filter, 555, 110));
608 }
609
TEST_F(MediaPipelineTest,TestAudioSendNoMux)610 TEST_F(MediaPipelineTest, TestAudioSendNoMux) { TestAudioSend(false); }
611
TEST_F(MediaPipelineTest,TestAudioSendMux)612 TEST_F(MediaPipelineTest, TestAudioSendMux) { TestAudioSend(true); }
613
TEST_F(MediaPipelineTest,TestAudioSendBundle)614 TEST_F(MediaPipelineTest, TestAudioSendBundle) {
615 auto filter = MakeUnique<MediaPipelineFilter>();
616 // These durations have to be _extremely_ long to have any assurance that
617 // some RTCP will be sent at all. This is because the first RTCP packet
618 // is sometimes sent before the transports are ready, which causes it to
619 // be dropped.
620 TestAudioReceiverBundle(
621 true, std::move(filter),
622 // We do not specify the filter for the remote description, so it will be
623 // set to something sane after a short time.
624 nullptr, 10000, 10000);
625
626 // Some packets should have been dropped, but not all
627 ASSERT_GT(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived());
628 ASSERT_GT(p2_.GetAudioRtpCountReceived(), 40);
629 ASSERT_GT(p1_.GetAudioRtcpCountSent(), 1);
630 }
631
TEST_F(MediaPipelineTest,TestAudioSendEmptyBundleFilter)632 TEST_F(MediaPipelineTest, TestAudioSendEmptyBundleFilter) {
633 auto filter = MakeUnique<MediaPipelineFilter>();
634 auto bad_answer_filter = MakeUnique<MediaPipelineFilter>();
635 TestAudioReceiverBundle(true, std::move(filter),
636 std::move(bad_answer_filter));
637 // Filter is empty, so should drop everything.
638 ASSERT_EQ(0, p2_.GetAudioRtpCountReceived());
639 }
640
641 } // end namespace
642