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