/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/common_types.h" #include "webrtc/modules/rtp_rtcp/include/receive_statistics.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h" #include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h" namespace webrtc { namespace { const uint64_t kTestPictureId = 12345678; const uint8_t kSliPictureId = 156; class RtcpCallback : public RtcpIntraFrameObserver { public: void SetModule(RtpRtcp* module) { _rtpRtcpModule = module; } virtual void OnRTCPPacketTimeout(const int32_t id) { } virtual void OnLipSyncUpdate(const int32_t id, const int32_t audioVideoOffset) {} virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) {} virtual void OnReceivedSLI(uint32_t ssrc, uint8_t pictureId) { EXPECT_EQ(kSliPictureId & 0x3f, pictureId); } virtual void OnReceivedRPSI(uint32_t ssrc, uint64_t pictureId) { EXPECT_EQ(kTestPictureId, pictureId); } virtual void OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {} private: RtpRtcp* _rtpRtcpModule; }; class TestRtpFeedback : public NullRtpFeedback { public: explicit TestRtpFeedback(RtpRtcp* rtp_rtcp) : rtp_rtcp_(rtp_rtcp) {} virtual ~TestRtpFeedback() {} void OnIncomingSSRCChanged(const uint32_t ssrc) override { rtp_rtcp_->SetRemoteSSRC(ssrc); } private: RtpRtcp* rtp_rtcp_; }; class RtpRtcpRtcpTest : public ::testing::Test { protected: RtpRtcpRtcpTest() : fake_clock(123456) { test_csrcs.push_back(1234); test_csrcs.push_back(2345); test_ssrc = 3456; test_timestamp = 4567; test_sequence_number = 2345; } ~RtpRtcpRtcpTest() {} virtual void SetUp() { receiver = new TestRtpReceiver(); transport1 = new LoopBackTransport(); transport2 = new LoopBackTransport(); myRTCPFeedback1 = new RtcpCallback(); myRTCPFeedback2 = new RtcpCallback(); receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock)); receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock)); RtpRtcp::Configuration configuration; configuration.audio = true; configuration.clock = &fake_clock; configuration.receive_statistics = receive_statistics1_.get(); configuration.outgoing_transport = transport1; configuration.intra_frame_callback = myRTCPFeedback1; rtp_payload_registry1_.reset(new RTPPayloadRegistry( RTPPayloadStrategy::CreateStrategy(true))); rtp_payload_registry2_.reset(new RTPPayloadRegistry( RTPPayloadStrategy::CreateStrategy(true))); module1 = RtpRtcp::CreateRtpRtcp(configuration); rtp_feedback1_.reset(new TestRtpFeedback(module1)); rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver( &fake_clock, NULL, receiver, rtp_feedback1_.get(), rtp_payload_registry1_.get())); configuration.receive_statistics = receive_statistics2_.get(); configuration.outgoing_transport = transport2; configuration.intra_frame_callback = myRTCPFeedback2; module2 = RtpRtcp::CreateRtpRtcp(configuration); rtp_feedback2_.reset(new TestRtpFeedback(module2)); rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver( &fake_clock, NULL, receiver, rtp_feedback2_.get(), rtp_payload_registry2_.get())); transport1->SetSendModule(module2, rtp_payload_registry2_.get(), rtp_receiver2_.get(), receive_statistics2_.get()); transport2->SetSendModule(module1, rtp_payload_registry1_.get(), rtp_receiver1_.get(), receive_statistics1_.get()); myRTCPFeedback1->SetModule(module1); myRTCPFeedback2->SetModule(module2); module1->SetRTCPStatus(RtcpMode::kCompound); module2->SetRTCPStatus(RtcpMode::kCompound); module2->SetSSRC(test_ssrc + 1); module1->SetSSRC(test_ssrc); module1->SetSequenceNumber(test_sequence_number); module1->SetStartTimestamp(test_timestamp); module1->SetCsrcs(test_csrcs); EXPECT_EQ(0, module1->SetCNAME("john.doe@test.test")); EXPECT_EQ(0, module1->SetSendingStatus(true)); CodecInst voice_codec; voice_codec.pltype = 96; voice_codec.plfreq = 8000; voice_codec.rate = 64000; memcpy(voice_codec.plname, "PCMU", 5); EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec)); EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload( voice_codec.plname, voice_codec.pltype, voice_codec.plfreq, voice_codec.channels, (voice_codec.rate < 0) ? 0 : voice_codec.rate)); EXPECT_EQ(0, module2->RegisterSendPayload(voice_codec)); EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload( voice_codec.plname, voice_codec.pltype, voice_codec.plfreq, voice_codec.channels, (voice_codec.rate < 0) ? 0 : voice_codec.rate)); // We need to send one RTP packet to get the RTCP packet to be accepted by // the receiving module. // send RTP packet with the data "testtest" const uint8_t test[9] = "testtest"; EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96, 0, -1, test, 8)); } virtual void TearDown() { delete module1; delete module2; delete myRTCPFeedback1; delete myRTCPFeedback2; delete transport1; delete transport2; delete receiver; } rtc::scoped_ptr rtp_feedback1_; rtc::scoped_ptr rtp_feedback2_; rtc::scoped_ptr receive_statistics1_; rtc::scoped_ptr receive_statistics2_; rtc::scoped_ptr rtp_payload_registry1_; rtc::scoped_ptr rtp_payload_registry2_; rtc::scoped_ptr rtp_receiver1_; rtc::scoped_ptr rtp_receiver2_; RtpRtcp* module1; RtpRtcp* module2; TestRtpReceiver* receiver; LoopBackTransport* transport1; LoopBackTransport* transport2; RtcpCallback* myRTCPFeedback1; RtcpCallback* myRTCPFeedback2; uint32_t test_ssrc; uint32_t test_timestamp; uint16_t test_sequence_number; std::vector test_csrcs; SimulatedClock fake_clock; }; TEST_F(RtpRtcpRtcpTest, RTCP_PLI_RPSI) { EXPECT_EQ(0, module1->SendRTCPReferencePictureSelection(kTestPictureId)); EXPECT_EQ(0, module1->SendRTCPSliceLossIndication(kSliPictureId)); } TEST_F(RtpRtcpRtcpTest, RTCP_CNAME) { uint32_t testOfCSRC[webrtc::kRtpCsrcSize]; EXPECT_EQ(2, rtp_receiver2_->CSRCs(testOfCSRC)); EXPECT_EQ(test_csrcs[0], testOfCSRC[0]); EXPECT_EQ(test_csrcs[1], testOfCSRC[1]); // Set cname of mixed. EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[0], "john@192.168.0.1")); EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2")); EXPECT_EQ(-1, module1->RemoveMixedCNAME(test_csrcs[0] + 1)); EXPECT_EQ(0, module1->RemoveMixedCNAME(test_csrcs[1])); EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2")); // send RTCP packet, triggered by timer fake_clock.AdvanceTimeMilliseconds(7500); module1->Process(); fake_clock.AdvanceTimeMilliseconds(100); module2->Process(); char cName[RTCP_CNAME_SIZE]; EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC() + 1, cName)); // Check multiple CNAME. EXPECT_EQ(0, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName)); EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE)); EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[0], cName)); EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE)); EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[1], cName)); EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE)); EXPECT_EQ(0, module1->SetSendingStatus(false)); // Test that BYE clears the CNAME EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName)); } TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) { std::vector report_blocks; EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); EXPECT_EQ(0u, report_blocks.size()); // send RTCP packet, triggered by timer fake_clock.AdvanceTimeMilliseconds(7500); module1->Process(); fake_clock.AdvanceTimeMilliseconds(100); module2->Process(); EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); ASSERT_EQ(1u, report_blocks.size()); // |test_ssrc+1| is the SSRC of module2 that send the report. EXPECT_EQ(test_ssrc+1, report_blocks[0].remoteSSRC); EXPECT_EQ(test_ssrc, report_blocks[0].sourceSSRC); EXPECT_EQ(0u, report_blocks[0].cumulativeLost); EXPECT_LT(0u, report_blocks[0].delaySinceLastSR); EXPECT_EQ(test_sequence_number, report_blocks[0].extendedHighSeqNum); EXPECT_EQ(0u, report_blocks[0].fractionLost); } } // namespace } // namespace webrtc