1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/test/mediapipeline_unittest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,929 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// Original author: ekr@rtfm.com 1.9 + 1.10 +#include <iostream> 1.11 + 1.12 +#include "sigslot.h" 1.13 + 1.14 +#include "logging.h" 1.15 +#include "nsThreadUtils.h" 1.16 +#include "nsXPCOM.h" 1.17 +#include "nss.h" 1.18 +#include "ssl.h" 1.19 +#include "sslproto.h" 1.20 + 1.21 +#include "dtlsidentity.h" 1.22 +#include "mozilla/RefPtr.h" 1.23 +#include "FakeMediaStreams.h" 1.24 +#include "FakeMediaStreamsImpl.h" 1.25 +#include "MediaConduitErrors.h" 1.26 +#include "MediaConduitInterface.h" 1.27 +#include "MediaPipeline.h" 1.28 +#include "MediaPipelineFilter.h" 1.29 +#include "runnable_utils.h" 1.30 +#include "transportflow.h" 1.31 +#include "transportlayerloopback.h" 1.32 +#include "transportlayerdtls.h" 1.33 +#include "mozilla/SyncRunnable.h" 1.34 + 1.35 + 1.36 +#include "mtransport_test_utils.h" 1.37 +#include "runnable_utils.h" 1.38 + 1.39 +#include "webrtc/modules/interface/module_common_types.h" 1.40 + 1.41 +#define GTEST_HAS_RTTI 0 1.42 +#include "gtest/gtest.h" 1.43 +#include "gtest_utils.h" 1.44 + 1.45 +using namespace mozilla; 1.46 +MOZ_MTLOG_MODULE("mediapipeline") 1.47 + 1.48 +MtransportTestUtils *test_utils; 1.49 + 1.50 +namespace { 1.51 + 1.52 +class TransportInfo { 1.53 + public: 1.54 + TransportInfo() : 1.55 + flow_(nullptr), 1.56 + loopback_(nullptr), 1.57 + dtls_(nullptr) {} 1.58 + 1.59 + static void InitAndConnect(TransportInfo &client, TransportInfo &server) { 1.60 + client.Init(true); 1.61 + server.Init(false); 1.62 + client.PushLayers(); 1.63 + server.PushLayers(); 1.64 + client.Connect(&server); 1.65 + server.Connect(&client); 1.66 + } 1.67 + 1.68 + void Init(bool client) { 1.69 + nsresult res; 1.70 + 1.71 + flow_ = new TransportFlow(); 1.72 + loopback_ = new TransportLayerLoopback(); 1.73 + dtls_ = new TransportLayerDtls(); 1.74 + 1.75 + res = loopback_->Init(); 1.76 + if (res != NS_OK) { 1.77 + FreeLayers(); 1.78 + } 1.79 + ASSERT_EQ((nsresult)NS_OK, res); 1.80 + 1.81 + std::vector<uint16_t> ciphers; 1.82 + ciphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80); 1.83 + dtls_->SetSrtpCiphers(ciphers); 1.84 + dtls_->SetIdentity(DtlsIdentity::Generate()); 1.85 + dtls_->SetRole(client ? TransportLayerDtls::CLIENT : 1.86 + TransportLayerDtls::SERVER); 1.87 + dtls_->SetVerificationAllowAll(); 1.88 + } 1.89 + 1.90 + void PushLayers() { 1.91 + nsresult res; 1.92 + 1.93 + nsAutoPtr<std::queue<TransportLayer *> > layers( 1.94 + new std::queue<TransportLayer *>); 1.95 + layers->push(loopback_); 1.96 + layers->push(dtls_); 1.97 + res = flow_->PushLayers(layers); 1.98 + if (res != NS_OK) { 1.99 + FreeLayers(); 1.100 + } 1.101 + ASSERT_EQ((nsresult)NS_OK, res); 1.102 + } 1.103 + 1.104 + void Connect(TransportInfo* peer) { 1.105 + MOZ_ASSERT(loopback_); 1.106 + MOZ_ASSERT(peer->loopback_); 1.107 + 1.108 + loopback_->Connect(peer->loopback_); 1.109 + } 1.110 + 1.111 + // Free the memory allocated at the beginning of Init 1.112 + // if failure occurs before layers setup. 1.113 + void FreeLayers() { 1.114 + delete loopback_; 1.115 + loopback_ = nullptr; 1.116 + delete dtls_; 1.117 + dtls_ = nullptr; 1.118 + } 1.119 + 1.120 + void Shutdown() { 1.121 + if (loopback_) { 1.122 + loopback_->Disconnect(); 1.123 + } 1.124 + loopback_ = nullptr; 1.125 + dtls_ = nullptr; 1.126 + flow_ = nullptr; 1.127 + } 1.128 + 1.129 + mozilla::RefPtr<TransportFlow> flow_; 1.130 + TransportLayerLoopback *loopback_; 1.131 + TransportLayerDtls *dtls_; 1.132 +}; 1.133 + 1.134 +class TestAgent { 1.135 + public: 1.136 + TestAgent() : 1.137 + audio_config_(109, "opus", 48000, 960, 2, 64000), 1.138 + audio_conduit_(mozilla::AudioSessionConduit::Create(nullptr)), 1.139 + audio_(), 1.140 + audio_pipeline_() { 1.141 + } 1.142 + 1.143 + static void ConnectRtp(TestAgent *client, TestAgent *server) { 1.144 + TransportInfo::InitAndConnect(client->audio_rtp_transport_, 1.145 + server->audio_rtp_transport_); 1.146 + } 1.147 + 1.148 + static void ConnectRtcp(TestAgent *client, TestAgent *server) { 1.149 + TransportInfo::InitAndConnect(client->audio_rtcp_transport_, 1.150 + server->audio_rtcp_transport_); 1.151 + } 1.152 + 1.153 + static void ConnectBundle(TestAgent *client, TestAgent *server) { 1.154 + TransportInfo::InitAndConnect(client->bundle_transport_, 1.155 + server->bundle_transport_); 1.156 + } 1.157 + 1.158 + virtual void CreatePipelines_s(bool aIsRtcpMux) = 0; 1.159 + 1.160 + void Start() { 1.161 + nsresult ret; 1.162 + 1.163 + MOZ_MTLOG(ML_DEBUG, "Starting"); 1.164 + 1.165 + mozilla::SyncRunnable::DispatchToThread( 1.166 + test_utils->sts_target(), 1.167 + WrapRunnableRet(audio_->GetStream(), &Fake_MediaStream::Start, &ret)); 1.168 + 1.169 + ASSERT_TRUE(NS_SUCCEEDED(ret)); 1.170 + } 1.171 + 1.172 + void StopInt() { 1.173 + audio_->GetStream()->Stop(); 1.174 + } 1.175 + 1.176 + void Stop() { 1.177 + MOZ_MTLOG(ML_DEBUG, "Stopping"); 1.178 + 1.179 + if (audio_pipeline_) 1.180 + audio_pipeline_->ShutdownMedia_m(); 1.181 + 1.182 + mozilla::SyncRunnable::DispatchToThread( 1.183 + test_utils->sts_target(), 1.184 + WrapRunnable(this, &TestAgent::StopInt)); 1.185 + } 1.186 + 1.187 + void Shutdown_s() { 1.188 + audio_rtp_transport_.Shutdown(); 1.189 + audio_rtcp_transport_.Shutdown(); 1.190 + bundle_transport_.Shutdown(); 1.191 + if (audio_pipeline_) 1.192 + audio_pipeline_->ShutdownTransport_s(); 1.193 + } 1.194 + 1.195 + void Shutdown() { 1.196 + if (audio_pipeline_) 1.197 + audio_pipeline_->ShutdownMedia_m(); 1.198 + 1.199 + mozilla::SyncRunnable::DispatchToThread( 1.200 + test_utils->sts_target(), 1.201 + WrapRunnable(this, &TestAgent::Shutdown_s)); 1.202 + } 1.203 + 1.204 + uint32_t GetRemoteSSRC() { 1.205 + uint32_t res = 0; 1.206 + audio_conduit_->GetRemoteSSRC(&res); 1.207 + return res; 1.208 + } 1.209 + 1.210 + uint32_t GetLocalSSRC() { 1.211 + uint32_t res = 0; 1.212 + audio_conduit_->GetLocalSSRC(&res); 1.213 + return res; 1.214 + } 1.215 + 1.216 + int GetAudioRtpCountSent() { 1.217 + return audio_pipeline_->rtp_packets_sent(); 1.218 + } 1.219 + 1.220 + int GetAudioRtpCountReceived() { 1.221 + return audio_pipeline_->rtp_packets_received(); 1.222 + } 1.223 + 1.224 + int GetAudioRtcpCountSent() { 1.225 + return audio_pipeline_->rtcp_packets_sent(); 1.226 + } 1.227 + 1.228 + int GetAudioRtcpCountReceived() { 1.229 + return audio_pipeline_->rtcp_packets_received(); 1.230 + } 1.231 + 1.232 + protected: 1.233 + mozilla::AudioCodecConfig audio_config_; 1.234 + mozilla::RefPtr<mozilla::MediaSessionConduit> audio_conduit_; 1.235 + nsRefPtr<DOMMediaStream> audio_; 1.236 + // TODO(bcampen@mozilla.com): Right now this does not let us test RTCP in 1.237 + // both directions; only the sender's RTCP is sent, but the receiver should 1.238 + // be sending it too. 1.239 + mozilla::RefPtr<mozilla::MediaPipeline> audio_pipeline_; 1.240 + TransportInfo audio_rtp_transport_; 1.241 + TransportInfo audio_rtcp_transport_; 1.242 + TransportInfo bundle_transport_; 1.243 +}; 1.244 + 1.245 +class TestAgentSend : public TestAgent { 1.246 + public: 1.247 + TestAgentSend() : use_bundle_(false) {} 1.248 + 1.249 + virtual void CreatePipelines_s(bool aIsRtcpMux) { 1.250 + audio_ = new Fake_DOMMediaStream(new Fake_AudioStreamSource()); 1.251 + 1.252 + mozilla::MediaConduitErrorCode err = 1.253 + static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get())-> 1.254 + ConfigureSendMediaCodec(&audio_config_); 1.255 + EXPECT_EQ(mozilla::kMediaConduitNoError, err); 1.256 + 1.257 + std::string test_pc("PC"); 1.258 + 1.259 + if (aIsRtcpMux) { 1.260 + ASSERT_FALSE(audio_rtcp_transport_.flow_); 1.261 + } 1.262 + 1.263 + RefPtr<TransportFlow> rtp(audio_rtp_transport_.flow_); 1.264 + RefPtr<TransportFlow> rtcp(audio_rtcp_transport_.flow_); 1.265 + 1.266 + if (use_bundle_) { 1.267 + rtp = bundle_transport_.flow_; 1.268 + rtcp = nullptr; 1.269 + } 1.270 + 1.271 + audio_pipeline_ = new mozilla::MediaPipelineTransmit( 1.272 + test_pc, 1.273 + nullptr, 1.274 + test_utils->sts_target(), 1.275 + audio_, 1.276 + 1, 1.277 + 1, 1.278 + audio_conduit_, 1.279 + rtp, 1.280 + rtcp); 1.281 + 1.282 + audio_pipeline_->Init(); 1.283 + } 1.284 + 1.285 + void SetUsingBundle(bool use_bundle) { 1.286 + use_bundle_ = use_bundle; 1.287 + } 1.288 + 1.289 + private: 1.290 + bool use_bundle_; 1.291 +}; 1.292 + 1.293 + 1.294 +class TestAgentReceive : public TestAgent { 1.295 + public: 1.296 + virtual void CreatePipelines_s(bool aIsRtcpMux) { 1.297 + mozilla::SourceMediaStream *audio = new Fake_SourceMediaStream(); 1.298 + audio->SetPullEnabled(true); 1.299 + 1.300 + mozilla::AudioSegment* segment= new mozilla::AudioSegment(); 1.301 + audio->AddTrack(0, 100, 0, segment); 1.302 + audio->AdvanceKnownTracksTime(mozilla::STREAM_TIME_MAX); 1.303 + 1.304 + audio_ = new Fake_DOMMediaStream(audio); 1.305 + 1.306 + std::vector<mozilla::AudioCodecConfig *> codecs; 1.307 + codecs.push_back(&audio_config_); 1.308 + 1.309 + mozilla::MediaConduitErrorCode err = 1.310 + static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get())-> 1.311 + ConfigureRecvMediaCodecs(codecs); 1.312 + EXPECT_EQ(mozilla::kMediaConduitNoError, err); 1.313 + 1.314 + std::string test_pc("PC"); 1.315 + 1.316 + if (aIsRtcpMux) { 1.317 + ASSERT_FALSE(audio_rtcp_transport_.flow_); 1.318 + } 1.319 + 1.320 + // For now, assume bundle always uses rtcp mux 1.321 + RefPtr<TransportFlow> dummy; 1.322 + RefPtr<TransportFlow> bundle_transport; 1.323 + if (bundle_filter_) { 1.324 + bundle_transport = bundle_transport_.flow_; 1.325 + bundle_filter_->AddLocalSSRC(GetLocalSSRC()); 1.326 + } 1.327 + 1.328 + audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio( 1.329 + test_pc, 1.330 + nullptr, 1.331 + test_utils->sts_target(), 1.332 + audio_->GetStream(), 1, 1, 1.333 + static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()), 1.334 + audio_rtp_transport_.flow_, 1.335 + audio_rtcp_transport_.flow_, 1.336 + bundle_transport, 1.337 + dummy, 1.338 + bundle_filter_); 1.339 + 1.340 + audio_pipeline_->Init(); 1.341 + } 1.342 + 1.343 + void SetBundleFilter(nsAutoPtr<MediaPipelineFilter> filter) { 1.344 + bundle_filter_ = filter; 1.345 + } 1.346 + 1.347 + void SetUsingBundle_s(bool decision) { 1.348 + audio_pipeline_->SetUsingBundle_s(decision); 1.349 + } 1.350 + 1.351 + void UpdateFilterFromRemoteDescription_s( 1.352 + nsAutoPtr<MediaPipelineFilter> filter) { 1.353 + audio_pipeline_->UpdateFilterFromRemoteDescription_s(filter); 1.354 + } 1.355 + 1.356 + private: 1.357 + nsAutoPtr<MediaPipelineFilter> bundle_filter_; 1.358 +}; 1.359 + 1.360 + 1.361 +class MediaPipelineTest : public ::testing::Test { 1.362 + public: 1.363 + ~MediaPipelineTest() { 1.364 + p1_.Stop(); 1.365 + p2_.Stop(); 1.366 + p1_.Shutdown(); 1.367 + p2_.Shutdown(); 1.368 + } 1.369 + 1.370 + // Setup transport. 1.371 + void InitTransports(bool aIsRtcpMux) { 1.372 + // RTP, p1_ is server, p2_ is client 1.373 + mozilla::SyncRunnable::DispatchToThread( 1.374 + test_utils->sts_target(), 1.375 + WrapRunnableNM(&TestAgent::ConnectRtp, &p2_, &p1_)); 1.376 + 1.377 + // Create RTCP flows separately if we are not muxing them. 1.378 + if(!aIsRtcpMux) { 1.379 + // RTCP, p1_ is server, p2_ is client 1.380 + mozilla::SyncRunnable::DispatchToThread( 1.381 + test_utils->sts_target(), 1.382 + WrapRunnableNM(&TestAgent::ConnectRtcp, &p2_, &p1_)); 1.383 + } 1.384 + 1.385 + // BUNDLE, p1_ is server, p2_ is client 1.386 + mozilla::SyncRunnable::DispatchToThread( 1.387 + test_utils->sts_target(), 1.388 + WrapRunnableNM(&TestAgent::ConnectBundle, &p2_, &p1_)); 1.389 + } 1.390 + 1.391 + // Verify RTP and RTCP 1.392 + void TestAudioSend(bool aIsRtcpMux, 1.393 + bool bundle = false, 1.394 + nsAutoPtr<MediaPipelineFilter> localFilter = 1.395 + nsAutoPtr<MediaPipelineFilter>(nullptr), 1.396 + nsAutoPtr<MediaPipelineFilter> remoteFilter = 1.397 + nsAutoPtr<MediaPipelineFilter>(nullptr), 1.398 + unsigned int ms_until_answer = 500, 1.399 + unsigned int ms_of_traffic_after_answer = 10000) { 1.400 + 1.401 + // We do not support testing bundle without rtcp mux, since that doesn't 1.402 + // make any sense. 1.403 + ASSERT_FALSE(!aIsRtcpMux && bundle); 1.404 + 1.405 + p1_.SetUsingBundle(bundle); 1.406 + p2_.SetBundleFilter(localFilter); 1.407 + 1.408 + // Setup transport flows 1.409 + InitTransports(aIsRtcpMux); 1.410 + 1.411 + mozilla::SyncRunnable::DispatchToThread( 1.412 + test_utils->sts_target(), 1.413 + WrapRunnable(&p1_, &TestAgent::CreatePipelines_s, aIsRtcpMux)); 1.414 + 1.415 + mozilla::SyncRunnable::DispatchToThread( 1.416 + test_utils->sts_target(), 1.417 + WrapRunnable(&p2_, &TestAgent::CreatePipelines_s, aIsRtcpMux)); 1.418 + 1.419 + p2_.Start(); 1.420 + p1_.Start(); 1.421 + 1.422 + // Simulate pre-answer traffic 1.423 + PR_Sleep(ms_until_answer); 1.424 + 1.425 + mozilla::SyncRunnable::DispatchToThread( 1.426 + test_utils->sts_target(), 1.427 + WrapRunnable(&p2_, &TestAgentReceive::SetUsingBundle_s, bundle)); 1.428 + 1.429 + if (bundle) { 1.430 + // Leaving remoteFilter not set implies we want to test sunny-day 1.431 + if (!remoteFilter) { 1.432 + remoteFilter = new MediaPipelineFilter; 1.433 + // Might not be safe, strictly speaking. 1.434 + remoteFilter->AddRemoteSSRC(p1_.GetLocalSSRC()); 1.435 + } 1.436 + 1.437 + mozilla::SyncRunnable::DispatchToThread( 1.438 + test_utils->sts_target(), 1.439 + WrapRunnable(&p2_, 1.440 + &TestAgentReceive::UpdateFilterFromRemoteDescription_s, 1.441 + remoteFilter)); 1.442 + } 1.443 + 1.444 + 1.445 + // wait for some RTP/RTCP tx and rx to happen 1.446 + PR_Sleep(ms_of_traffic_after_answer); 1.447 + 1.448 + p1_.Stop(); 1.449 + p2_.Stop(); 1.450 + 1.451 + // wait for any packets in flight to arrive 1.452 + PR_Sleep(100); 1.453 + 1.454 + p1_.Shutdown(); 1.455 + p2_.Shutdown(); 1.456 + 1.457 + if (!bundle) { 1.458 + // If we are doing bundle, allow the test-case to do this checking. 1.459 + ASSERT_GE(p1_.GetAudioRtpCountSent(), 40); 1.460 + ASSERT_EQ(p1_.GetAudioRtpCountReceived(), p2_.GetAudioRtpCountSent()); 1.461 + ASSERT_EQ(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); 1.462 + 1.463 + // Calling ShutdownMedia_m on both pipelines does not stop the flow of 1.464 + // RTCP. So, we might be off by one here. 1.465 + ASSERT_LE(p2_.GetAudioRtcpCountReceived(), p1_.GetAudioRtcpCountSent()); 1.466 + ASSERT_GE(p2_.GetAudioRtcpCountReceived() + 1, p1_.GetAudioRtcpCountSent()); 1.467 + } 1.468 + 1.469 + } 1.470 + 1.471 + void TestAudioReceiverOffersBundle(bool bundle_accepted, 1.472 + nsAutoPtr<MediaPipelineFilter> localFilter, 1.473 + nsAutoPtr<MediaPipelineFilter> remoteFilter = 1.474 + nsAutoPtr<MediaPipelineFilter>(nullptr), 1.475 + unsigned int ms_until_answer = 500, 1.476 + unsigned int ms_of_traffic_after_answer = 10000) { 1.477 + TestAudioSend(true, 1.478 + bundle_accepted, 1.479 + localFilter, 1.480 + remoteFilter, 1.481 + ms_until_answer, 1.482 + ms_of_traffic_after_answer); 1.483 + } 1.484 +protected: 1.485 + TestAgentSend p1_; 1.486 + TestAgentReceive p2_; 1.487 +}; 1.488 + 1.489 +class MediaPipelineFilterTest : public ::testing::Test { 1.490 + public: 1.491 + bool Filter(MediaPipelineFilter& filter, 1.492 + int32_t correlator, 1.493 + uint32_t ssrc, 1.494 + uint8_t payload_type) { 1.495 + 1.496 + webrtc::RTPHeader header; 1.497 + header.ssrc = ssrc; 1.498 + header.payloadType = payload_type; 1.499 + return filter.Filter(header, correlator); 1.500 + } 1.501 +}; 1.502 + 1.503 +TEST_F(MediaPipelineFilterTest, TestConstruct) { 1.504 + MediaPipelineFilter filter; 1.505 +} 1.506 + 1.507 +TEST_F(MediaPipelineFilterTest, TestDefault) { 1.508 + MediaPipelineFilter filter; 1.509 + ASSERT_FALSE(Filter(filter, 0, 233, 110)); 1.510 +} 1.511 + 1.512 +TEST_F(MediaPipelineFilterTest, TestSSRCFilter) { 1.513 + MediaPipelineFilter filter; 1.514 + filter.AddRemoteSSRC(555); 1.515 + ASSERT_TRUE(Filter(filter, 0, 555, 110)); 1.516 + ASSERT_FALSE(Filter(filter, 0, 556, 110)); 1.517 +} 1.518 + 1.519 +#define SSRC(ssrc) \ 1.520 + ((ssrc >> 24) & 0xFF), \ 1.521 + ((ssrc >> 16) & 0xFF), \ 1.522 + ((ssrc >> 8 ) & 0xFF), \ 1.523 + (ssrc & 0xFF) 1.524 + 1.525 +#define REPORT_FRAGMENT(ssrc) \ 1.526 + SSRC(ssrc), \ 1.527 + 0,0,0,0, \ 1.528 + 0,0,0,0, \ 1.529 + 0,0,0,0, \ 1.530 + 0,0,0,0, \ 1.531 + 0,0,0,0 1.532 + 1.533 +#define RTCP_TYPEINFO(num_rrs, type, size) \ 1.534 + 0x80 + num_rrs, type, 0, size 1.535 + 1.536 +const unsigned char rtcp_rr_s16[] = { 1.537 + // zero rrs, size 1 words 1.538 + RTCP_TYPEINFO(0, MediaPipelineFilter::RECEIVER_REPORT_T, 1), 1.539 + SSRC(16) 1.540 +}; 1.541 + 1.542 +const unsigned char rtcp_rr_s16_r17[] = { 1.543 + // one rr, 7 words 1.544 + RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), 1.545 + SSRC(16), 1.546 + REPORT_FRAGMENT(17) 1.547 +}; 1.548 + 1.549 +const unsigned char rtcp_rr_s16_r17_18[] = { 1.550 + // two rrs, size 13 words 1.551 + RTCP_TYPEINFO(2, MediaPipelineFilter::RECEIVER_REPORT_T, 13), 1.552 + SSRC(16), 1.553 + REPORT_FRAGMENT(17), 1.554 + REPORT_FRAGMENT(18) 1.555 +}; 1.556 + 1.557 +const unsigned char rtcp_sr_s16[] = { 1.558 + // zero rrs, size 6 words 1.559 + RTCP_TYPEINFO(0, MediaPipelineFilter::SENDER_REPORT_T, 6), 1.560 + REPORT_FRAGMENT(16) 1.561 +}; 1.562 + 1.563 +const unsigned char rtcp_sr_s16_r17[] = { 1.564 + // one rr, size 12 words 1.565 + RTCP_TYPEINFO(1, MediaPipelineFilter::SENDER_REPORT_T, 12), 1.566 + REPORT_FRAGMENT(16), 1.567 + REPORT_FRAGMENT(17) 1.568 +}; 1.569 + 1.570 +const unsigned char rtcp_sr_s16_r17_18[] = { 1.571 + // two rrs, size 18 words 1.572 + RTCP_TYPEINFO(2, MediaPipelineFilter::SENDER_REPORT_T, 18), 1.573 + REPORT_FRAGMENT(16), 1.574 + REPORT_FRAGMENT(17), 1.575 + REPORT_FRAGMENT(18) 1.576 +}; 1.577 + 1.578 +const unsigned char unknown_type[] = { 1.579 + RTCP_TYPEINFO(1, 222, 0) 1.580 +}; 1.581 + 1.582 +TEST_F(MediaPipelineFilterTest, TestEmptyFilterReport0) { 1.583 + MediaPipelineFilter filter; 1.584 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.585 + filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); 1.586 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.587 + filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); 1.588 +} 1.589 + 1.590 +TEST_F(MediaPipelineFilterTest, TestFilterReport0) { 1.591 + MediaPipelineFilter filter; 1.592 + filter.AddRemoteSSRC(16); 1.593 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.594 + filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); 1.595 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.596 + filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); 1.597 +} 1.598 + 1.599 +TEST_F(MediaPipelineFilterTest, TestFilterReport0SSRCTruncated) { 1.600 + MediaPipelineFilter filter; 1.601 + filter.AddRemoteSSRC(16); 1.602 + const unsigned char data[] = { 1.603 + RTCP_TYPEINFO(0, MediaPipelineFilter::RECEIVER_REPORT_T, 1), 1.604 + 0,0,0 1.605 + }; 1.606 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.607 + filter.FilterRTCP(data, sizeof(data))); 1.608 +} 1.609 + 1.610 +TEST_F(MediaPipelineFilterTest, TestFilterReport0PTTruncated) { 1.611 + MediaPipelineFilter filter; 1.612 + filter.AddRemoteSSRC(16); 1.613 + const unsigned char data[] = {0x80}; 1.614 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.615 + filter.FilterRTCP(data, sizeof(data))); 1.616 +} 1.617 + 1.618 +TEST_F(MediaPipelineFilterTest, TestFilterReport0CountTruncated) { 1.619 + MediaPipelineFilter filter; 1.620 + filter.AddRemoteSSRC(16); 1.621 + const unsigned char data[] = {}; 1.622 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.623 + filter.FilterRTCP(data, sizeof(data))); 1.624 +} 1.625 + 1.626 +TEST_F(MediaPipelineFilterTest, TestFilterReport1BothMatch) { 1.627 + MediaPipelineFilter filter; 1.628 + filter.AddRemoteSSRC(16); 1.629 + filter.AddLocalSSRC(17); 1.630 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.631 + filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); 1.632 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.633 + filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); 1.634 +} 1.635 + 1.636 +TEST_F(MediaPipelineFilterTest, TestFilterReport1SSRCTruncated) { 1.637 + MediaPipelineFilter filter; 1.638 + filter.AddRemoteSSRC(16); 1.639 + filter.AddLocalSSRC(17); 1.640 + const unsigned char rr[] = { 1.641 + RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), 1.642 + SSRC(16), 1.643 + 0,0,0 1.644 + }; 1.645 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.646 + filter.FilterRTCP(rr, sizeof(rr))); 1.647 + const unsigned char sr[] = { 1.648 + RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 12), 1.649 + REPORT_FRAGMENT(16), 1.650 + 0,0,0 1.651 + }; 1.652 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.653 + filter.FilterRTCP(sr, sizeof(rr))); 1.654 +} 1.655 + 1.656 +TEST_F(MediaPipelineFilterTest, TestFilterReport1BigSSRC) { 1.657 + MediaPipelineFilter filter; 1.658 + filter.AddRemoteSSRC(0x01020304); 1.659 + filter.AddLocalSSRC(0x11121314); 1.660 + const unsigned char rr[] = { 1.661 + RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 7), 1.662 + SSRC(0x01020304), 1.663 + REPORT_FRAGMENT(0x11121314) 1.664 + }; 1.665 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.666 + filter.FilterRTCP(rr, sizeof(rr))); 1.667 + const unsigned char sr[] = { 1.668 + RTCP_TYPEINFO(1, MediaPipelineFilter::RECEIVER_REPORT_T, 12), 1.669 + SSRC(0x01020304), 1.670 + REPORT_FRAGMENT(0x11121314) 1.671 + }; 1.672 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.673 + filter.FilterRTCP(sr, sizeof(rr))); 1.674 +} 1.675 + 1.676 +TEST_F(MediaPipelineFilterTest, TestFilterReport1LocalMatch) { 1.677 + MediaPipelineFilter filter; 1.678 + filter.AddLocalSSRC(17); 1.679 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.680 + filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); 1.681 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.682 + filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); 1.683 +} 1.684 + 1.685 +TEST_F(MediaPipelineFilterTest, TestFilterReport1Inconsistent) { 1.686 + MediaPipelineFilter filter; 1.687 + filter.AddRemoteSSRC(16); 1.688 + // We assume that the filter is exactly correct in terms of local ssrcs. 1.689 + // So, when RTCP shows up with a remote SSRC that matches, and a local 1.690 + // ssrc that doesn't, we assume the other end has messed up and put ssrcs 1.691 + // from more than one m-line in the packet. 1.692 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.693 + filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); 1.694 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.695 + filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); 1.696 +} 1.697 + 1.698 +TEST_F(MediaPipelineFilterTest, TestFilterReport1NeitherMatch) { 1.699 + MediaPipelineFilter filter; 1.700 + filter.AddRemoteSSRC(17); 1.701 + filter.AddLocalSSRC(18); 1.702 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.703 + filter.FilterRTCP(rtcp_sr_s16_r17, sizeof(rtcp_sr_s16_r17))); 1.704 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.705 + filter.FilterRTCP(rtcp_rr_s16_r17, sizeof(rtcp_rr_s16_r17))); 1.706 +} 1.707 + 1.708 +TEST_F(MediaPipelineFilterTest, TestFilterReport2AllMatch) { 1.709 + MediaPipelineFilter filter; 1.710 + filter.AddRemoteSSRC(16); 1.711 + filter.AddLocalSSRC(17); 1.712 + filter.AddLocalSSRC(18); 1.713 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.714 + filter.FilterRTCP(rtcp_sr_s16_r17_18, 1.715 + sizeof(rtcp_sr_s16_r17_18))); 1.716 +} 1.717 + 1.718 +TEST_F(MediaPipelineFilterTest, TestFilterReport2LocalMatch) { 1.719 + MediaPipelineFilter filter; 1.720 + filter.AddLocalSSRC(17); 1.721 + filter.AddLocalSSRC(18); 1.722 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.723 + filter.FilterRTCP(rtcp_sr_s16_r17_18, 1.724 + sizeof(rtcp_sr_s16_r17_18))); 1.725 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.726 + filter.FilterRTCP(rtcp_rr_s16_r17_18, 1.727 + sizeof(rtcp_rr_s16_r17_18))); 1.728 +} 1.729 + 1.730 +TEST_F(MediaPipelineFilterTest, TestFilterReport2Inconsistent101) { 1.731 + MediaPipelineFilter filter; 1.732 + filter.AddRemoteSSRC(16); 1.733 + filter.AddLocalSSRC(18); 1.734 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.735 + filter.FilterRTCP(rtcp_sr_s16_r17_18, 1.736 + sizeof(rtcp_sr_s16_r17_18))); 1.737 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.738 + filter.FilterRTCP(rtcp_rr_s16_r17_18, 1.739 + sizeof(rtcp_rr_s16_r17_18))); 1.740 +} 1.741 + 1.742 +TEST_F(MediaPipelineFilterTest, TestFilterReport2Inconsistent001) { 1.743 + MediaPipelineFilter filter; 1.744 + filter.AddLocalSSRC(18); 1.745 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.746 + filter.FilterRTCP(rtcp_sr_s16_r17_18, 1.747 + sizeof(rtcp_sr_s16_r17_18))); 1.748 + ASSERT_EQ(MediaPipelineFilter::FAIL, 1.749 + filter.FilterRTCP(rtcp_rr_s16_r17_18, 1.750 + sizeof(rtcp_rr_s16_r17_18))); 1.751 +} 1.752 + 1.753 +TEST_F(MediaPipelineFilterTest, TestFilterUnknownRTCPType) { 1.754 + MediaPipelineFilter filter; 1.755 + filter.AddLocalSSRC(18); 1.756 + ASSERT_EQ(MediaPipelineFilter::UNSUPPORTED, 1.757 + filter.FilterRTCP(unknown_type, sizeof(unknown_type))); 1.758 +} 1.759 + 1.760 +TEST_F(MediaPipelineFilterTest, TestCorrelatorFilter) { 1.761 + MediaPipelineFilter filter; 1.762 + filter.SetCorrelator(7777); 1.763 + ASSERT_TRUE(Filter(filter, 7777, 16, 110)); 1.764 + ASSERT_FALSE(Filter(filter, 7778, 17, 110)); 1.765 + // This should also have resulted in the SSRC 16 being added to the filter 1.766 + ASSERT_TRUE(Filter(filter, 0, 16, 110)); 1.767 + ASSERT_FALSE(Filter(filter, 0, 17, 110)); 1.768 + 1.769 + // rtcp_sr_s16 has 16 as an SSRC 1.770 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.771 + filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); 1.772 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.773 + filter.FilterRTCP(rtcp_rr_s16, sizeof(rtcp_rr_s16))); 1.774 +} 1.775 + 1.776 +TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilter) { 1.777 + MediaPipelineFilter filter; 1.778 + filter.AddUniquePT(110); 1.779 + ASSERT_TRUE(Filter(filter, 0, 555, 110)); 1.780 + ASSERT_FALSE(Filter(filter, 0, 556, 111)); 1.781 +} 1.782 + 1.783 +TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilterSSRCUpdate) { 1.784 + MediaPipelineFilter filter; 1.785 + filter.AddUniquePT(110); 1.786 + ASSERT_TRUE(Filter(filter, 0, 16, 110)); 1.787 + 1.788 + // rtcp_sr_s16 has 16 as an SSRC 1.789 + ASSERT_EQ(MediaPipelineFilter::PASS, 1.790 + filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16))); 1.791 +} 1.792 + 1.793 +TEST_F(MediaPipelineFilterTest, TestAnswerAddsSSRCs) { 1.794 + MediaPipelineFilter filter; 1.795 + filter.SetCorrelator(7777); 1.796 + ASSERT_TRUE(Filter(filter, 7777, 555, 110)); 1.797 + ASSERT_FALSE(Filter(filter, 7778, 556, 110)); 1.798 + // This should also have resulted in the SSRC 555 being added to the filter 1.799 + ASSERT_TRUE(Filter(filter, 0, 555, 110)); 1.800 + ASSERT_FALSE(Filter(filter, 0, 556, 110)); 1.801 + 1.802 + // This sort of thing can happen when getting an answer with SSRC attrs 1.803 + // The answer will not contain the correlator. 1.804 + MediaPipelineFilter filter2; 1.805 + filter2.AddRemoteSSRC(555); 1.806 + filter2.AddRemoteSSRC(556); 1.807 + filter2.AddRemoteSSRC(557); 1.808 + 1.809 + filter.IncorporateRemoteDescription(filter2); 1.810 + 1.811 + // Ensure that the old SSRC still works. 1.812 + ASSERT_TRUE(Filter(filter, 0, 555, 110)); 1.813 + 1.814 + // Ensure that the new SSRCs work. 1.815 + ASSERT_TRUE(Filter(filter, 0, 556, 110)); 1.816 + ASSERT_TRUE(Filter(filter, 0, 557, 110)); 1.817 + 1.818 + // Ensure that the correlator continues to work 1.819 + ASSERT_TRUE(Filter(filter, 7777, 558, 110)); 1.820 +} 1.821 + 1.822 +TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithSDP) { 1.823 + MediaPipelineFilter filter; 1.824 + filter.SetCorrelator(7777); 1.825 + filter.AddUniquePT(111); 1.826 + ASSERT_TRUE(Filter(filter, 7777, 555, 110)); 1.827 + 1.828 + MediaPipelineFilter filter2; 1.829 + filter2.AddRemoteSSRC(556); 1.830 + 1.831 + filter.IncorporateRemoteDescription(filter2); 1.832 + 1.833 + // Ensure that the old SSRC has been removed. 1.834 + ASSERT_FALSE(Filter(filter, 0, 555, 110)); 1.835 + 1.836 + // Ensure that the new SSRC works. 1.837 + ASSERT_TRUE(Filter(filter, 0, 556, 110)); 1.838 + 1.839 + // Ensure that the correlator continues to work 1.840 + ASSERT_TRUE(Filter(filter, 7777, 558, 110)); 1.841 + 1.842 + // Ensure that the payload type mapping continues to work 1.843 + ASSERT_TRUE(Filter(filter, 0, 559, 111)); 1.844 +} 1.845 + 1.846 +TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithCorrelator) { 1.847 + MediaPipelineFilter filter; 1.848 + filter.SetCorrelator(7777); 1.849 + ASSERT_TRUE(Filter(filter, 7777, 555, 110)); 1.850 + ASSERT_TRUE(Filter(filter, 0, 555, 110)); 1.851 + ASSERT_FALSE(Filter(filter, 7778, 555, 110)); 1.852 + ASSERT_FALSE(Filter(filter, 0, 555, 110)); 1.853 +} 1.854 + 1.855 +TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) { 1.856 + // If the remote SDP doesn't have SSRCs, right now this is a no-op and 1.857 + // there is no point of even incorporating a filter, but we make the 1.858 + // behavior consistent to avoid confusion. 1.859 + MediaPipelineFilter filter; 1.860 + filter.SetCorrelator(7777); 1.861 + filter.AddUniquePT(111); 1.862 + ASSERT_TRUE(Filter(filter, 7777, 555, 110)); 1.863 + 1.864 + MediaPipelineFilter filter2; 1.865 + 1.866 + filter.IncorporateRemoteDescription(filter2); 1.867 + 1.868 + // Ensure that the old SSRC still works. 1.869 + ASSERT_TRUE(Filter(filter, 7777, 555, 110)); 1.870 +} 1.871 + 1.872 +TEST_F(MediaPipelineTest, TestAudioSendNoMux) { 1.873 + TestAudioSend(false); 1.874 +} 1.875 + 1.876 +TEST_F(MediaPipelineTest, TestAudioSendMux) { 1.877 + TestAudioSend(true); 1.878 +} 1.879 + 1.880 +TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndDeclined) { 1.881 + nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); 1.882 + TestAudioReceiverOffersBundle(false, filter); 1.883 +} 1.884 + 1.885 +TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndAccepted) { 1.886 + nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); 1.887 + // These durations have to be _extremely_ long to have any assurance that 1.888 + // some RTCP will be sent at all. This is because the first RTCP packet 1.889 + // is sometimes sent before the transports are ready, which causes it to 1.890 + // be dropped. 1.891 + TestAudioReceiverOffersBundle(true, 1.892 + filter, 1.893 + // We do not specify the filter for the remote description, so it will be 1.894 + // set to something sane after a short time. 1.895 + nsAutoPtr<MediaPipelineFilter>(), 1.896 + 10000, 1.897 + 10000); 1.898 + 1.899 + // Some packets should have been dropped, but not all 1.900 + ASSERT_GT(p1_.GetAudioRtpCountSent(), p2_.GetAudioRtpCountReceived()); 1.901 + ASSERT_GT(p2_.GetAudioRtpCountReceived(), 40); 1.902 + ASSERT_GT(p1_.GetAudioRtcpCountSent(), 1); 1.903 + ASSERT_GT(p1_.GetAudioRtcpCountSent(), p2_.GetAudioRtcpCountReceived()); 1.904 + ASSERT_GT(p2_.GetAudioRtcpCountReceived(), 0); 1.905 +} 1.906 + 1.907 +TEST_F(MediaPipelineTest, TestAudioSendBundleOfferedAndAcceptedEmptyFilter) { 1.908 + nsAutoPtr<MediaPipelineFilter> filter(new MediaPipelineFilter); 1.909 + nsAutoPtr<MediaPipelineFilter> bad_answer_filter(new MediaPipelineFilter); 1.910 + TestAudioReceiverOffersBundle(true, filter, bad_answer_filter); 1.911 + // Filter is empty, so should drop everything. 1.912 + ASSERT_EQ(0, p2_.GetAudioRtpCountReceived()); 1.913 + ASSERT_EQ(0, p2_.GetAudioRtcpCountReceived()); 1.914 +} 1.915 + 1.916 +} // end namespace 1.917 + 1.918 + 1.919 +int main(int argc, char **argv) { 1.920 + test_utils = new MtransportTestUtils(); 1.921 + // Start the tests 1.922 + NSS_NoDB_Init(nullptr); 1.923 + NSS_SetDomesticPolicy(); 1.924 + ::testing::InitGoogleTest(&argc, argv); 1.925 + 1.926 + int rv = RUN_ALL_TESTS(); 1.927 + delete test_utils; 1.928 + return rv; 1.929 +} 1.930 + 1.931 + 1.932 +