mediapipeline_unittest.cpp (28034B)
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 "logging.h" 8 #include "nss.h" 9 #include "ssl.h" 10 11 #include "api/audio/builtin_audio_processing_builder.h" 12 #include "api/audio_codecs/builtin_audio_decoder_factory.h" 13 #include "api/environment/environment_factory.h" 14 #include "api/scoped_refptr.h" 15 #include "AudioSegment.h" 16 #include "Canonicals.h" 17 #include "modules/audio_device/include/fake_audio_device.h" 18 #include "modules/audio_mixer/audio_mixer_impl.h" 19 #include "modules/audio_processing/include/audio_processing.h" 20 #include "mozilla/Mutex.h" 21 #include "mozilla/RefPtr.h" 22 #include "mozilla/SpinEventLoopUntil.h" 23 #include "MediaConduitInterface.h" 24 #include "MediaPipeline.h" 25 #include "MediaPipelineFilter.h" 26 #include "MediaTrackGraph.h" 27 #include "MediaTrackListener.h" 28 #include "mtransport_test_utils.h" 29 #include "SharedBuffer.h" 30 #include "MediaTransportHandler.h" 31 #include "WebrtcCallWrapper.h" 32 #include "WebrtcEnvironmentWrapper.h" 33 #include "WebrtcTaskQueueWrapper.h" 34 #include "PeerConnectionCtx.h" 35 36 #define GTEST_HAS_RTTI 0 37 #include "gtest/gtest.h" 38 39 using namespace mozilla; 40 MOZ_MTLOG_MODULE("transportbridge") 41 42 static MtransportTestUtils* test_utils; 43 44 namespace { 45 class MainAsCurrent : public webrtc::TaskQueueBase { 46 public: 47 MainAsCurrent() 48 : mTaskQueue(CreateWebrtcTaskQueueWrapper( 49 do_AddRef(GetMainThreadSerialEventTarget()), "MainAsCurrent"_ns, 50 false)), 51 mWebrtcTaskQueue(([&] { 52 // Shady but fine, as this raw pointer points to the WebrtcTaskQueue 53 // owned and kept alive by mTaskQueue. 54 webrtc::TaskQueueBase* queue{}; 55 MOZ_ALWAYS_SUCCEEDS(mTaskQueue->Dispatch(NS_NewRunnableFunction( 56 "MainAsCurrent::Current", 57 [&] { queue = webrtc::TaskQueueBase::Current(); }))); 58 NS_ProcessPendingEvents(nullptr); 59 MOZ_RELEASE_ASSERT(queue); 60 return queue; 61 })()), 62 mSetter(mWebrtcTaskQueue) { 63 MOZ_RELEASE_ASSERT(NS_IsMainThread()); 64 } 65 66 ~MainAsCurrent() = default; 67 68 void Delete() override { delete this; } 69 70 void PostTaskImpl(absl::AnyInvocable<void() &&> task, 71 const PostTaskTraits& traits, 72 const webrtc::Location& location) override { 73 mWebrtcTaskQueue->PostTask(std::move(task), location); 74 } 75 76 void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, 77 webrtc::TimeDelta delay, 78 const PostDelayedTaskTraits& traits, 79 const webrtc::Location& location) override { 80 if (traits.high_precision) { 81 mWebrtcTaskQueue->PostDelayedHighPrecisionTask(std::move(task), delay, 82 location); 83 return; 84 } 85 mWebrtcTaskQueue->PostDelayedTask(std::move(task), delay, location); 86 } 87 88 private: 89 RefPtr<TaskQueue> mTaskQueue; 90 webrtc::TaskQueueBase* mWebrtcTaskQueue; 91 CurrentTaskQueueSetter mSetter; 92 }; 93 94 class FakeAudioTrack : public ProcessedMediaTrack { 95 public: 96 FakeAudioTrack() 97 : ProcessedMediaTrack(44100, MediaSegment::AUDIO, nullptr), 98 mMutex("Fake AudioTrack") { 99 NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), 100 FakeAudioTrackGenerateData, this, 20, 101 nsITimer::TYPE_REPEATING_SLACK, 102 "FakeAudioTrack::FakeAudioTrackGenerateData"_ns, 103 test_utils->sts_target()); 104 } 105 106 void Destroy() override { 107 MutexAutoLock lock(mMutex); 108 MOZ_RELEASE_ASSERT(!mMainThreadDestroyed); 109 mMainThreadDestroyed = true; 110 mTimer->Cancel(); 111 mTimer = nullptr; 112 } 113 114 void QueueSetAutoend(bool) override {} 115 116 void AddListener(MediaTrackListener* aListener) override { 117 MutexAutoLock lock(mMutex); 118 MOZ_RELEASE_ASSERT(!mListener); 119 mListener = aListener; 120 } 121 122 RefPtr<GenericPromise> RemoveListener( 123 MediaTrackListener* aListener) override { 124 MutexAutoLock lock(mMutex); 125 MOZ_RELEASE_ASSERT(mListener == aListener); 126 mListener = nullptr; 127 return GenericPromise::CreateAndResolve(true, __func__); 128 } 129 130 void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override {} 131 132 uint32_t NumberOfChannels() const override { return NUM_CHANNELS; } 133 134 private: 135 Mutex mMutex MOZ_UNANNOTATED; 136 MediaTrackListener* mListener = nullptr; 137 nsCOMPtr<nsITimer> mTimer; 138 int mCount = 0; 139 140 static const int AUDIO_BUFFER_SIZE = 1600; 141 static const int NUM_CHANNELS = 2; 142 static void FakeAudioTrackGenerateData(nsITimer* timer, void* closure) { 143 auto t = static_cast<FakeAudioTrack*>(closure); 144 MutexAutoLock lock(t->mMutex); 145 if (t->mMainThreadDestroyed) { 146 return; 147 } 148 CheckedInt<size_t> bufferSize(sizeof(int16_t)); 149 bufferSize *= NUM_CHANNELS; 150 bufferSize *= AUDIO_BUFFER_SIZE; 151 RefPtr<SharedBuffer> samples = SharedBuffer::Create(bufferSize); 152 int16_t* data = reinterpret_cast<int16_t*>(samples->Data()); 153 for (int i = 0; i < (AUDIO_BUFFER_SIZE * NUM_CHANNELS); i++) { 154 // saw tooth audio sample 155 data[i] = ((t->mCount % 8) * 4000) - (7 * 4000) / 2; 156 t->mCount++; 157 } 158 159 AudioSegment segment; 160 AutoTArray<const int16_t*, 1> channels; 161 channels.AppendElement(data); 162 segment.AppendFrames(samples.forget(), channels, AUDIO_BUFFER_SIZE, 163 PRINCIPAL_HANDLE_NONE); 164 165 if (t->mListener) { 166 t->mListener->NotifyQueuedChanges(nullptr, 0, segment); 167 } 168 } 169 }; 170 171 template <typename Function> 172 void RunOnSts(Function&& aFunction) { 173 MOZ_ALWAYS_SUCCEEDS(test_utils->SyncDispatchToSTS( 174 NS_NewRunnableFunction(__func__, [&] { aFunction(); }))); 175 } 176 177 class LoopbackTransport : public MediaTransportHandler { 178 public: 179 LoopbackTransport() : MediaTransportHandler() { 180 RunOnSts([&] { 181 SetState("mux", TransportLayer::TS_INIT); 182 SetRtcpState("mux", TransportLayer::TS_INIT); 183 SetState("non-mux", TransportLayer::TS_INIT); 184 SetRtcpState("non-mux", TransportLayer::TS_INIT); 185 }); 186 } 187 188 static void InitAndConnect(LoopbackTransport& client, 189 LoopbackTransport& server) { 190 client.Connect(&server); 191 server.Connect(&client); 192 } 193 194 void Connect(LoopbackTransport* peer) { peer_ = peer; } 195 196 void Shutdown() { peer_ = nullptr; } 197 198 RefPtr<IceLogPromise> GetIceLog(const nsCString& aPattern) override { 199 return nullptr; 200 } 201 202 void ClearIceLog() override {} 203 void EnterPrivateMode() override {} 204 void ExitPrivateMode() override {} 205 206 void CreateIceCtx(const std::string& aName) override {} 207 208 nsresult SetIceConfig(const nsTArray<dom::RTCIceServer>& aIceServers, 209 dom::RTCIceTransportPolicy aIcePolicy) override { 210 return NS_OK; 211 } 212 213 void Destroy() override {} 214 215 // We will probably be able to move the proxy lookup stuff into 216 // this class once we move mtransport to its own process. 217 void SetProxyConfig(NrSocketProxyConfig&& aProxyConfig) override {} 218 219 void EnsureProvisionalTransport(const std::string& aTransportId, 220 const std::string& aLocalUfrag, 221 const std::string& aLocalPwd, 222 int aComponentCount) override {} 223 224 void SetTargetForDefaultLocalAddressLookup(const std::string& aTargetIp, 225 uint16_t aTargetPort) override {} 226 227 // We set default-route-only as late as possible because it depends on what 228 // capture permissions have been granted on the window, which could easily 229 // change between Init (ie; when the PC is created) and StartIceGathering 230 // (ie; when we set the local description). 231 void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateAddresses, 232 // TODO: It probably makes sense to look 233 // this up internally 234 const nsTArray<NrIceStunAddr>& aStunAddrs) override {} 235 236 void ActivateTransport( 237 const std::string& aTransportId, const std::string& aLocalUfrag, 238 const std::string& aLocalPwd, size_t aComponentCount, 239 const std::string& aUfrag, const std::string& aPassword, 240 const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer, 241 SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, 242 bool aPrivacyRequested) override {} 243 244 void RemoveTransportsExcept( 245 const std::set<std::string>& aTransportIds) override {} 246 247 void StartIceChecks(bool aIsControlling, 248 const std::vector<std::string>& aIceOptions) override {} 249 250 void AddIceCandidate(const std::string& aTransportId, 251 const std::string& aCandidate, const std::string& aUfrag, 252 const std::string& aObfuscatedAddress) override {} 253 254 void UpdateNetworkState(bool aOnline) override {} 255 256 RefPtr<dom::RTCStatsPromise> GetIceStats(const std::string& aTransportId, 257 DOMHighResTimeStamp aNow) override { 258 return nullptr; 259 } 260 261 void SendPacket(const std::string& aTransportId, 262 MediaPacket&& aPacket) override { 263 peer_->LoopbackPacketReceived(aTransportId, aPacket); 264 } 265 266 void SetState(const std::string& aTransportId, TransportLayer::State aState) { 267 MediaTransportHandler::OnStateChange(aTransportId, aState); 268 } 269 270 void SetRtcpState(const std::string& aTransportId, 271 TransportLayer::State aState) { 272 MediaTransportHandler::OnRtcpStateChange(aTransportId, aState); 273 } 274 275 void LoopbackPacketReceived(const std::string& aTransportId, 276 const MediaPacket& aPacket) { 277 if (aPacket.len() && aPacket.type() == MediaPacket::RTCP) { 278 ++rtcp_packets_received_; 279 } 280 mRtpPacketReceived.Notify(aTransportId, aPacket); 281 } 282 283 int RtcpPacketsReceived() const { return rtcp_packets_received_; } 284 285 private: 286 RefPtr<LoopbackTransport> peer_; 287 std::atomic<int> rtcp_packets_received_{0}; 288 }; 289 290 struct MediaPipelineTestOptions { 291 bool is_rtcp_mux = true; 292 bool activate_receive = true; 293 unsigned int ms_until_filter_update = 500; 294 unsigned int ms_of_traffic_after_answer = 10000; 295 }; 296 297 class TestAgent { 298 public: 299 explicit TestAgent(const RefPtr<WebrtcEnvironmentWrapper>& aEnvWrapper, 300 const RefPtr<SharedWebrtcState>& aSharedState) 301 : control_(aSharedState->mCallWorkerThread), 302 audio_config_(109, "opus", 48000, 2, false), 303 call_(WebrtcCallWrapper::Create( 304 aEnvWrapper, mozilla::dom::RTCStatsTimestampMaker::Create(), 305 nullptr, aSharedState)), 306 audio_conduit_( 307 AudioSessionConduit::Create(call_, test_utils->sts_target())), 308 transport_(new LoopbackTransport) { 309 (void)WaitFor(InvokeAsync(call_->mCallThread, __func__, [&] { 310 audio_conduit_->InitControl(&control_); 311 return GenericPromise::CreateAndResolve(true, "TestAgent()"); 312 })); 313 } 314 315 static void Connect(TestAgent* client, TestAgent* server) { 316 LoopbackTransport::InitAndConnect(*client->transport_, *server->transport_); 317 } 318 319 virtual void CreatePipeline(const std::string& aTransportId, 320 const MediaPipelineTestOptions& aOptions) = 0; 321 322 void SetState_s(const std::string& aTransportId, 323 TransportLayer::State aState) { 324 transport_->SetState(aTransportId, aState); 325 } 326 327 void SetRtcpState_s(const std::string& aTransportId, 328 TransportLayer::State aState) { 329 transport_->SetRtcpState(aTransportId, aState); 330 } 331 332 void UpdateTransport_s(const std::string& aTransportId, 333 UniquePtr<MediaPipelineFilter>&& aFilter) { 334 audio_pipeline_->UpdateTransport_s(aTransportId, std::move(aFilter), false); 335 } 336 337 void Stop() { 338 MOZ_MTLOG(ML_DEBUG, "Stopping"); 339 340 control_.Update([](auto& aControl) { 341 aControl.mTransmitting = false; 342 aControl.mReceiving = false; 343 }); 344 } 345 346 void Shutdown_s() { transport_->Shutdown(); } 347 348 void Shutdown() { 349 if (audio_pipeline_) { 350 audio_pipeline_->Shutdown(); 351 } 352 if (audio_conduit_) { 353 (void)WaitFor(audio_conduit_->Shutdown()); 354 } 355 if (call_) { 356 call_->Destroy(); 357 } 358 if (audio_track_) { 359 audio_track_->Destroy(); 360 audio_track_ = nullptr; 361 } 362 363 test_utils->SyncDispatchToSTS(WrapRunnable(this, &TestAgent::Shutdown_s)); 364 } 365 366 uint32_t GetRemoteSSRC() { 367 return audio_conduit_->GetRemoteSSRC().valueOr(0); 368 } 369 370 uint32_t GetLocalSSRC() { 371 std::vector<uint32_t> res; 372 res = audio_conduit_->GetLocalSSRCs(); 373 return res.empty() ? 0 : res[0]; 374 } 375 376 int GetAudioRtpCountSent() { return audio_pipeline_->RtpPacketsSent(); } 377 378 int GetAudioRtpCountReceived() { 379 return audio_pipeline_->RtpPacketsReceived(); 380 } 381 382 int GetAudioRtcpCountSent() { return audio_pipeline_->RtcpPacketsSent(); } 383 384 int GetAudioRtcpCountReceived() { return transport_->RtcpPacketsReceived(); } 385 386 protected: 387 ConcreteControl control_; 388 AudioCodecConfig audio_config_; 389 RefPtr<WebrtcCallWrapper> call_; 390 RefPtr<AudioSessionConduit> audio_conduit_; 391 RefPtr<FakeAudioTrack> audio_track_; 392 // TODO(bcampen@mozilla.com): Right now this does not let us test RTCP in 393 // both directions; only the sender's RTCP is sent, but the receiver should 394 // be sending it too. 395 RefPtr<MediaPipeline> audio_pipeline_; 396 RefPtr<LoopbackTransport> transport_; 397 }; 398 399 class TestAgentSend : public TestAgent { 400 public: 401 explicit TestAgentSend(const RefPtr<WebrtcEnvironmentWrapper>& aEnvWrapper, 402 const RefPtr<SharedWebrtcState>& aSharedState) 403 : TestAgent(aEnvWrapper, aSharedState) { 404 control_.Update([&](auto& aControl) { 405 aControl.mAudioSendCodec = Some(audio_config_); 406 }); 407 audio_track_ = new FakeAudioTrack(); 408 } 409 410 virtual void CreatePipeline(const std::string& aTransportId, 411 const MediaPipelineTestOptions& aOptions) { 412 std::string test_pc; 413 414 RefPtr<MediaPipelineTransmit> audio_pipeline = 415 MediaPipelineTransmit::Create( 416 test_pc, transport_, AbstractThread::MainThread(), 417 test_utils->sts_target(), false, audio_conduit_); 418 (void)WaitFor(InvokeAsync(call_->mCallThread, __func__, [&] { 419 audio_pipeline->InitControl(&control_); 420 return GenericPromise::CreateAndResolve(true, __func__); 421 })); 422 423 audio_pipeline->SetSendTrackOverride(audio_track_); 424 control_.Update([](auto& aControl) { aControl.mTransmitting = true; }); 425 audio_pipeline->UpdateTransport_m(aTransportId, nullptr, true); 426 audio_pipeline_ = audio_pipeline; 427 } 428 }; 429 430 class TestAgentReceive : public TestAgent { 431 public: 432 explicit TestAgentReceive(const RefPtr<WebrtcEnvironmentWrapper>& aEnvWrapper, 433 const RefPtr<SharedWebrtcState>& aSharedState) 434 : TestAgent(aEnvWrapper, aSharedState) { 435 control_.Update([&](auto& aControl) { 436 std::vector<AudioCodecConfig> codecs; 437 codecs.push_back(audio_config_); 438 aControl.mAudioRecvCodecs = codecs; 439 }); 440 } 441 442 virtual void CreatePipeline(const std::string& aTransportId, 443 const MediaPipelineTestOptions& aOptions) { 444 std::string test_pc; 445 446 auto audio_pipeline = MakeRefPtr<MediaPipelineReceiveAudio>( 447 test_pc, transport_, AbstractThread::MainThread(), 448 test_utils->sts_target(), 449 static_cast<AudioSessionConduit*>(audio_conduit_.get()), nullptr, 450 TrackingId(), PRINCIPAL_HANDLE_NONE, PrincipalPrivacy::NonPrivate); 451 (void)WaitFor(InvokeAsync(call_->mCallThread, __func__, [&] { 452 audio_pipeline->InitControl(&control_); 453 return GenericPromise::CreateAndResolve(true, __func__); 454 })); 455 456 control_.Update([activate = aOptions.activate_receive](auto& aControl) { 457 aControl.mReceiving = activate; 458 }); 459 audio_pipeline->UpdateTransport_m(aTransportId, std::move(bundle_filter_), 460 true); 461 audio_pipeline_ = audio_pipeline; 462 } 463 464 void SetBundleFilter(UniquePtr<MediaPipelineFilter>&& filter) { 465 bundle_filter_ = std::move(filter); 466 } 467 468 void UpdateTransport_s(const std::string& aTransportId, 469 UniquePtr<MediaPipelineFilter>&& filter) { 470 audio_pipeline_->UpdateTransport_s(aTransportId, std::move(filter), false); 471 } 472 473 private: 474 UniquePtr<MediaPipelineFilter> bundle_filter_; 475 }; 476 477 void WaitFor(TimeDuration aDuration) { 478 bool done = false; 479 NS_DelayedDispatchToCurrentThread( 480 NS_NewRunnableFunction(__func__, [&] { done = true; }), 481 aDuration.ToMilliseconds()); 482 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>( 483 "WaitFor(TimeDuration aDuration)"_ns, [&] { return done; }); 484 } 485 486 webrtc::AudioState::Config CreateAudioStateConfig( 487 const webrtc::Environment& aEnv) { 488 webrtc::AudioState::Config audio_state_config; 489 audio_state_config.audio_mixer = webrtc::AudioMixerImpl::Create(); 490 491 webrtc::BuiltinAudioProcessingBuilder audio_processing_builder; 492 audio_state_config.audio_processing = audio_processing_builder.Build(aEnv); 493 audio_state_config.audio_device_module = new webrtc::FakeAudioDeviceModule(); 494 return audio_state_config; 495 } 496 497 class MediaPipelineTest : public ::testing::Test { 498 public: 499 explicit MediaPipelineTest(MediaPipelineTestOptions options = {}) 500 : main_task_queue_( 501 std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( 502 new MainAsCurrent())), 503 options_(options), 504 env_wrapper_(WebrtcEnvironmentWrapper::Create( 505 mozilla::dom::RTCStatsTimestampMaker::Create())), 506 shared_state_(MakeAndAddRef<SharedWebrtcState>( 507 AbstractThread::MainThread(), 508 CreateAudioStateConfig(env_wrapper_->Environment()), 509 already_AddRefed( 510 webrtc::CreateBuiltinAudioDecoderFactory().release()), 511 WrapUnique(new webrtc::MozTrialsConfig()))), 512 p1_(env_wrapper_, shared_state_), 513 p2_(env_wrapper_, shared_state_) {} 514 515 ~MediaPipelineTest() { 516 p1_.Shutdown(); 517 p2_.Shutdown(); 518 } 519 520 static void SetUpTestCase() { 521 test_utils = new MtransportTestUtils(); 522 NSS_NoDB_Init(nullptr); 523 NSS_SetDomesticPolicy(); 524 } 525 526 // Setup transport. 527 void InitTransports() { 528 test_utils->SyncDispatchToSTS( 529 WrapRunnableNM(&TestAgent::Connect, &p2_, &p1_)); 530 } 531 532 // Verify RTP and RTCP 533 void TestAudioSend(MediaPipelineTestOptions options, 534 UniquePtr<MediaPipelineFilter>&& initialFilter = nullptr, 535 UniquePtr<MediaPipelineFilter>&& refinedFilter = nullptr) { 536 bool bundle = !!(initialFilter); 537 // We do not support testing bundle without rtcp mux, since that doesn't 538 // make any sense. 539 ASSERT_FALSE(!options.is_rtcp_mux && bundle); 540 541 p2_.SetBundleFilter(std::move(initialFilter)); 542 543 // Setup transport flows 544 InitTransports(); 545 546 std::string transportId = options.is_rtcp_mux ? "mux" : "non-mux"; 547 p1_.CreatePipeline(transportId, options); 548 p2_.CreatePipeline(transportId, options); 549 550 // Set state of transports to CONNECTING. MediaPipeline doesn't really care 551 // about this transition, but we're trying to simluate what happens in a 552 // real case. 553 RunOnSts([&] { 554 p1_.SetState_s(transportId, TransportLayer::TS_CONNECTING); 555 p1_.SetRtcpState_s(transportId, TransportLayer::TS_CONNECTING); 556 p2_.SetState_s(transportId, TransportLayer::TS_CONNECTING); 557 p2_.SetRtcpState_s(transportId, TransportLayer::TS_CONNECTING); 558 }); 559 560 WaitFor(TimeDuration::FromMilliseconds(10)); 561 562 // Set state of transports to OPEN (ie; connected). This should result in 563 // media flowing. 564 RunOnSts([&] { 565 p1_.SetState_s(transportId, TransportLayer::TS_OPEN); 566 p1_.SetRtcpState_s(transportId, TransportLayer::TS_OPEN); 567 p2_.SetState_s(transportId, TransportLayer::TS_OPEN); 568 p2_.SetRtcpState_s(transportId, TransportLayer::TS_OPEN); 569 }); 570 571 if (bundle) { 572 WaitFor(TimeDuration::FromMilliseconds(options.ms_until_filter_update)); 573 574 // Leaving refinedFilter not set implies we want to just update with 575 // the other side's SSRC 576 if (!refinedFilter) { 577 refinedFilter = MakeUnique<MediaPipelineFilter>(); 578 // Might not be safe, strictly speaking. 579 refinedFilter->AddRemoteSSRC(p1_.GetLocalSSRC()); 580 } 581 582 RunOnSts([&] { 583 p2_.UpdateTransport_s(transportId, std::move(refinedFilter)); 584 }); 585 } 586 587 // wait for some RTP/RTCP tx and rx to happen 588 WaitFor(TimeDuration::FromMilliseconds(options.ms_of_traffic_after_answer)); 589 590 p1_.Stop(); 591 p2_.Stop(); 592 593 // wait for any packets in flight to arrive 594 WaitFor(TimeDuration::FromMilliseconds(200)); 595 596 p1_.Shutdown(); 597 p2_.Shutdown(); 598 599 if (!bundle) { 600 // If we are filtering, allow the test-case to do this checking. 601 ASSERT_GE(p1_.GetAudioRtpCountSent(), 40); 602 ASSERT_EQ(p1_.GetAudioRtpCountReceived(), p2_.GetAudioRtpCountSent()); 603 ASSERT_EQ(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); 604 } 605 606 // No RTCP packets should have been dropped, because we do not filter them. 607 // Calling ShutdownMedia_m on both pipelines does not stop the flow of 608 // RTCP. So, we might be off by one here. 609 ASSERT_LE(p2_.GetAudioRtcpCountReceived(), p1_.GetAudioRtcpCountSent()); 610 ASSERT_GE(p2_.GetAudioRtcpCountReceived() + 1, p1_.GetAudioRtcpCountSent()); 611 } 612 613 void TestAudioReceiverBundle( 614 UniquePtr<MediaPipelineFilter>&& initialFilter, 615 UniquePtr<MediaPipelineFilter>&& refinedFilter = nullptr, 616 MediaPipelineTestOptions options = {}) { 617 TestAudioSend(options, std::move(initialFilter), std::move(refinedFilter)); 618 } 619 620 protected: 621 // main_task_queue_ has this type to make sure it goes through Delete() when 622 // we're destroyed. 623 std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> 624 main_task_queue_; 625 const MediaPipelineTestOptions options_; 626 const RefPtr<WebrtcEnvironmentWrapper> env_wrapper_; 627 const RefPtr<SharedWebrtcState> shared_state_; 628 TestAgentSend p1_; 629 TestAgentReceive p2_; 630 }; 631 632 class MediaPipelineFilterTest : public ::testing::Test { 633 public: 634 bool Filter(MediaPipelineFilter& filter, uint32_t ssrc, uint8_t payload_type, 635 const Maybe<std::string>& mid = Nothing()) { 636 webrtc::RTPHeader header; 637 header.ssrc = ssrc; 638 header.payloadType = payload_type; 639 mid.apply([&](const auto& mid) { header.extension.mid = mid; }); 640 return filter.Filter(header); 641 } 642 }; 643 644 TEST_F(MediaPipelineFilterTest, TestConstruct) { MediaPipelineFilter filter; } 645 646 TEST_F(MediaPipelineFilterTest, TestDefault) { 647 MediaPipelineFilter filter; 648 EXPECT_FALSE(Filter(filter, 233, 110)); 649 } 650 651 TEST_F(MediaPipelineFilterTest, TestSSRCFilter) { 652 MediaPipelineFilter filter; 653 filter.AddRemoteSSRC(555); 654 EXPECT_TRUE(Filter(filter, 555, 110)); 655 EXPECT_FALSE(Filter(filter, 556, 110)); 656 } 657 658 TEST_F(MediaPipelineFilterTest, TestSSRCFilterOverridesPayloadTypeFilter) { 659 MediaPipelineFilter filter; 660 filter.AddRemoteSSRC(555); 661 filter.AddUniqueReceivePT(110); 662 // We have a configured ssrc but still need to allow payload type matching. 663 EXPECT_TRUE(Filter(filter, 556, 110)); 664 EXPECT_TRUE(Filter(filter, 555, 110)); 665 } 666 667 #define SSRC(ssrc) \ 668 ((ssrc >> 24) & 0xFF), ((ssrc >> 16) & 0xFF), ((ssrc >> 8) & 0xFF), \ 669 (ssrc & 0xFF) 670 #define REPORT_FRAGMENT(ssrc) \ 671 SSRC(ssrc), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 672 673 #define RTCP_TYPEINFO(num_rrs, type, size) 0x80 + num_rrs, type, 0, size 674 675 TEST_F(MediaPipelineFilterTest, TestMidFilter) { 676 MediaPipelineFilter filter; 677 const auto mid = Some(std::string("mid0")); 678 filter.SetRemoteMediaStreamId(mid); 679 680 EXPECT_FALSE(Filter(filter, 16, 110)); 681 EXPECT_TRUE(Filter(filter, 16, 110, mid)); 682 EXPECT_TRUE(Filter(filter, 16, 110)); 683 EXPECT_FALSE(Filter(filter, 17, 110)); 684 685 // The mid filter maintains a set of SSRCs. Adding a new SSRC should work 686 // and still allow previous SSRCs to work. Unrecognized SSRCs should still be 687 // filtered out. 688 EXPECT_TRUE(Filter(filter, 18, 111, mid)); 689 EXPECT_TRUE(Filter(filter, 18, 111)); 690 EXPECT_TRUE(Filter(filter, 16, 110)); 691 EXPECT_FALSE(Filter(filter, 17, 110)); 692 } 693 694 TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilter) { 695 MediaPipelineFilter filter; 696 filter.AddUniqueReceivePT(110); 697 EXPECT_TRUE(Filter(filter, 555, 110)); 698 EXPECT_FALSE(Filter(filter, 556, 111)); 699 // Matching based on unique payload type causes us to learn the ssrc. 700 EXPECT_TRUE(Filter(filter, 555, 98)); 701 // Once we have learned an SSRC we still need to learn new ones 702 // based on payload type. 703 EXPECT_TRUE(Filter(filter, 557, 110)); 704 } 705 706 TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithMid) { 707 MediaPipelineFilter filter; 708 const auto mid0 = Some(std::string("mid0")); 709 const auto mid1 = Some(std::string("mid1")); 710 filter.SetRemoteMediaStreamId(mid0); 711 ASSERT_TRUE(Filter(filter, 555, 110, mid0)); 712 ASSERT_TRUE(Filter(filter, 555, 110)); 713 // Present a new MID binding 714 ASSERT_FALSE(Filter(filter, 555, 110, mid1)); 715 ASSERT_FALSE(Filter(filter, 555, 110)); 716 } 717 718 TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) { 719 // If the remote SDP doesn't have SSRCs, right now this is a no-op and 720 // there is no point of even incorporating a filter, but we make the 721 // behavior consistent to avoid confusion. 722 MediaPipelineFilter filter; 723 const auto mid = Some(std::string("mid0")); 724 filter.SetRemoteMediaStreamId(mid); 725 filter.AddUniqueReceivePT(111); 726 EXPECT_TRUE(Filter(filter, 555, 110, mid)); 727 EXPECT_TRUE(Filter(filter, 555, 110)); 728 729 // Update but remember binding./ 730 MediaPipelineFilter filter2; 731 732 filter.Update(filter2, true); 733 734 // Ensure that the old SSRC still works. 735 EXPECT_TRUE(Filter(filter, 555, 110)); 736 737 // Forget the previous binding 738 MediaPipelineFilter filter3; 739 filter3.SetRemoteMediaStreamId(Some(std::string("mid1"))); 740 filter.Update(filter3, true); 741 742 ASSERT_FALSE(Filter(filter, 555, 110)); 743 } 744 745 TEST_F(MediaPipelineTest, TestAudioSendNoMux) { 746 TestAudioSend({.is_rtcp_mux = false}); 747 } 748 749 TEST_F(MediaPipelineTest, TestAudioSendMux) { 750 TestAudioSend({.is_rtcp_mux = true}); 751 } 752 753 TEST_F(MediaPipelineTest, TestAudioSendBundle) { 754 auto filter = MakeUnique<MediaPipelineFilter>(); 755 // These durations have to be _extremely_ long to have any assurance that 756 // some RTCP will be sent at all. This is because the first RTCP packet 757 // is sometimes sent before the transports are ready, which causes it to 758 // be dropped. 759 TestAudioReceiverBundle( 760 std::move(filter), 761 // We do not specify the filter for the remote description, so it will be 762 // set to something sane after a short time. 763 nullptr, 764 {.ms_until_filter_update = 10000, .ms_of_traffic_after_answer = 10000}); 765 766 // Some packets should have been dropped, but not all 767 ASSERT_GT(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); 768 ASSERT_GT(p2_.GetAudioRtpCountReceived(), 40); 769 ASSERT_GT(p1_.GetAudioRtcpCountSent(), 1); 770 } 771 772 TEST_F(MediaPipelineTest, TestAudioSendEmptyBundleFilter) { 773 auto filter = MakeUnique<MediaPipelineFilter>(); 774 auto bad_answer_filter = MakeUnique<MediaPipelineFilter>(); 775 TestAudioReceiverBundle(std::move(filter), std::move(bad_answer_filter)); 776 // Filter is empty, so should drop everything. 777 ASSERT_EQ(0, p2_.GetAudioRtpCountReceived()); 778 } 779 780 TEST_F(MediaPipelineTest, TestAudioInactiveNoRecv) { 781 auto filter = MakeUnique<MediaPipelineFilter>(); 782 TestAudioReceiverBundle(std::move(filter), nullptr, 783 {.activate_receive = false, 784 .ms_until_filter_update = 200, 785 .ms_of_traffic_after_answer = 800}); 786 787 // Packets should have been sent but not received. 788 ASSERT_NE(p1_.GetAudioRtpCountSent(), 0); 789 ASSERT_EQ(p2_.GetAudioRtpCountReceived(), 0); 790 } 791 792 } // end namespace