| /* |
| * Copyright (c) 2013 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 "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #include "webrtc/common_types.h" |
| #include "webrtc/modules/pacing/include/mock/mock_paced_sender.h" |
| #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" |
| #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" |
| #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h" |
| #include "webrtc/system_wrappers/interface/scoped_vector.h" |
| |
| using ::testing::_; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| |
| namespace webrtc { |
| namespace { |
| const uint32_t kSenderSsrc = 0x12345; |
| const uint32_t kReceiverSsrc = 0x23456; |
| const uint32_t kSenderRtxSsrc = 0x32345; |
| const uint32_t kOneWayNetworkDelayMs = 100; |
| |
| class RtcpRttStatsTestImpl : public RtcpRttStats { |
| public: |
| RtcpRttStatsTestImpl() : rtt_ms_(0) {} |
| virtual ~RtcpRttStatsTestImpl() {} |
| |
| virtual void OnRttUpdate(uint32_t rtt_ms) { |
| rtt_ms_ = rtt_ms; |
| } |
| virtual uint32_t LastProcessedRtt() const { |
| return rtt_ms_; |
| } |
| uint32_t rtt_ms_; |
| }; |
| |
| class SendTransport : public Transport, |
| public NullRtpData { |
| public: |
| SendTransport() : receiver_(NULL), clock_(NULL), delay_ms_(0) {} |
| |
| void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) { |
| receiver_ = receiver; |
| } |
| void SimulateNetworkDelay(uint32_t delay_ms, SimulatedClock* clock) { |
| clock_ = clock; |
| delay_ms_ = delay_ms; |
| } |
| virtual int SendPacket(int /*ch*/, const void* /*data*/, int /*len*/) { |
| return -1; |
| } |
| virtual int SendRTCPPacket(int /*ch*/, const void *data, int len) { |
| if (clock_) { |
| clock_->AdvanceTimeMilliseconds(delay_ms_); |
| } |
| EXPECT_TRUE(receiver_ != NULL); |
| EXPECT_EQ(0, receiver_->IncomingRtcpPacket( |
| static_cast<const uint8_t*>(data), len)); |
| return len; |
| } |
| ModuleRtpRtcpImpl* receiver_; |
| SimulatedClock* clock_; |
| uint32_t delay_ms_; |
| }; |
| |
| class RtpRtcpModule { |
| public: |
| RtpRtcpModule(SimulatedClock* clock) |
| : receive_statistics_(ReceiveStatistics::Create(clock)) { |
| RtpRtcp::Configuration config; |
| config.audio = false; |
| config.clock = clock; |
| config.outgoing_transport = &transport_; |
| config.receive_statistics = receive_statistics_.get(); |
| config.rtt_stats = &rtt_stats_; |
| |
| impl_.reset(new ModuleRtpRtcpImpl(config)); |
| EXPECT_EQ(0, impl_->SetRTCPStatus(kRtcpCompound)); |
| |
| transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock); |
| } |
| |
| RtcpPacketTypeCounter packets_sent_; |
| RtcpPacketTypeCounter packets_received_; |
| scoped_ptr<ReceiveStatistics> receive_statistics_; |
| SendTransport transport_; |
| RtcpRttStatsTestImpl rtt_stats_; |
| scoped_ptr<ModuleRtpRtcpImpl> impl_; |
| |
| RtcpPacketTypeCounter RtcpSent() { |
| impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_); |
| return packets_sent_; |
| } |
| RtcpPacketTypeCounter RtcpReceived() { |
| impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_); |
| return packets_received_; |
| } |
| }; |
| } // namespace |
| |
| class RtpRtcpImplTest : public ::testing::Test { |
| protected: |
| RtpRtcpImplTest() |
| : clock_(1335900000), |
| sender_(&clock_), |
| receiver_(&clock_) { |
| // Send module. |
| EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true)); |
| sender_.impl_->SetSSRC(kSenderSsrc); |
| sender_.impl_->SetRemoteSSRC(kReceiverSsrc); |
| // Receive module. |
| EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false)); |
| receiver_.impl_->SetSSRC(kReceiverSsrc); |
| receiver_.impl_->SetRemoteSSRC(kSenderSsrc); |
| // Transport settings. |
| sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get()); |
| receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get()); |
| } |
| SimulatedClock clock_; |
| RtpRtcpModule sender_; |
| RtpRtcpModule receiver_; |
| }; |
| |
| TEST_F(RtpRtcpImplTest, Rtt) { |
| RTPHeader header; |
| header.timestamp = 1; |
| header.sequenceNumber = 123; |
| header.ssrc = kSenderSsrc; |
| header.headerLength = 12; |
| receiver_.receive_statistics_->IncomingPacket(header, 100, false); |
| |
| // Sender module should send a SR. |
| EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); |
| |
| // Receiver module should send a RR with a response to the last received SR. |
| clock_.AdvanceTimeMilliseconds(1000); |
| EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); |
| |
| // Verify RTT. |
| uint16_t rtt; |
| uint16_t avg_rtt; |
| uint16_t min_rtt; |
| uint16_t max_rtt; |
| EXPECT_EQ(0, |
| sender_.impl_->RTT(kReceiverSsrc, &rtt, &avg_rtt, &min_rtt, &max_rtt)); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, rtt); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, avg_rtt); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, min_rtt); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, max_rtt); |
| |
| // No RTT from other ssrc. |
| EXPECT_EQ(-1, |
| sender_.impl_->RTT(kReceiverSsrc+1, &rtt, &avg_rtt, &min_rtt, &max_rtt)); |
| |
| // Verify RTT from rtt_stats config. |
| EXPECT_EQ(0U, sender_.rtt_stats_.LastProcessedRtt()); |
| EXPECT_EQ(0U, sender_.impl_->rtt_ms()); |
| sender_.impl_->Process(); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, sender_.rtt_stats_.LastProcessedRtt()); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, sender_.impl_->rtt_ms()); |
| } |
| |
| TEST_F(RtpRtcpImplTest, SetRtcpXrRrtrStatus) { |
| EXPECT_FALSE(receiver_.impl_->RtcpXrRrtrStatus()); |
| receiver_.impl_->SetRtcpXrRrtrStatus(true); |
| EXPECT_TRUE(receiver_.impl_->RtcpXrRrtrStatus()); |
| } |
| |
| TEST_F(RtpRtcpImplTest, RttForReceiverOnly) { |
| receiver_.impl_->SetRtcpXrRrtrStatus(true); |
| |
| // Receiver module should send a Receiver time reference report (RTRR). |
| EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); |
| |
| // Sender module should send a response to the last received RTRR (DLRR). |
| clock_.AdvanceTimeMilliseconds(1000); |
| EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); |
| |
| // Verify RTT. |
| EXPECT_EQ(0U, receiver_.rtt_stats_.LastProcessedRtt()); |
| EXPECT_EQ(0U, receiver_.impl_->rtt_ms()); |
| receiver_.impl_->Process(); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.rtt_stats_.LastProcessedRtt()); |
| EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms()); |
| } |
| |
| TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) { |
| EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets); |
| EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets); |
| // Receive module sends a NACK. |
| const uint16_t kNackLength = 1; |
| uint16_t nack_list[kNackLength] = {123}; |
| EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength)); |
| EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets); |
| |
| // Send module receives the NACK. |
| EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets); |
| } |
| |
| TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) { |
| EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets); |
| EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets); |
| // Receive module sends a FIR. |
| EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir)); |
| EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets); |
| // Send module receives the FIR. |
| EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets); |
| |
| // Receive module sends a FIR and PLI. |
| EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir | kRtcpPli)); |
| EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets); |
| EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets); |
| // Send module receives the FIR and PLI. |
| EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets); |
| EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets); |
| } |
| |
| class RtpSendingTestTransport : public Transport { |
| public: |
| void ResetCounters() { bytes_received_.clear(); } |
| |
| virtual int SendPacket(int channel, const void* data, int length) { |
| RTPHeader header; |
| scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); |
| EXPECT_TRUE(parser->Parse(static_cast<const uint8_t*>(data), |
| static_cast<size_t>(length), |
| &header)); |
| bytes_received_[header.ssrc] += length; |
| ++packets_received_[header.ssrc]; |
| return length; |
| } |
| |
| virtual int SendRTCPPacket(int channel, const void* data, int length) { |
| return length; |
| } |
| |
| int GetPacketsReceived(uint32_t ssrc) const { |
| std::map<uint32_t, int>::const_iterator it = packets_received_.find(ssrc); |
| if (it == packets_received_.end()) |
| return 0; |
| return it->second; |
| } |
| |
| int GetBytesReceived(uint32_t ssrc) const { |
| std::map<uint32_t, int>::const_iterator it = bytes_received_.find(ssrc); |
| if (it == bytes_received_.end()) |
| return 0; |
| return it->second; |
| } |
| |
| int GetTotalBytesReceived() const { |
| int sum = 0; |
| for (std::map<uint32_t, int>::const_iterator it = bytes_received_.begin(); |
| it != bytes_received_.end(); |
| ++it) { |
| sum += it->second; |
| } |
| return sum; |
| } |
| |
| private: |
| std::map<uint32_t, int> bytes_received_; |
| std::map<uint32_t, int> packets_received_; |
| }; |
| |
| class RtpSendingTest : public ::testing::Test { |
| protected: |
| // Map from SSRC to number of received packets and bytes. |
| typedef std::map<uint32_t, std::pair<int, int> > PaddingMap; |
| |
| RtpSendingTest() { |
| // Send module. |
| RtpRtcp::Configuration config; |
| config.audio = false; |
| config.clock = Clock::GetRealTimeClock(); |
| config.outgoing_transport = &transport_; |
| config.receive_statistics = receive_statistics_.get(); |
| config.rtt_stats = &rtt_stats_; |
| config.paced_sender = &pacer_; |
| memset(&codec_, 0, sizeof(VideoCodec)); |
| codec_.plType = 100; |
| strncpy(codec_.plName, "VP8", 3); |
| codec_.numberOfSimulcastStreams = 3; |
| codec_.simulcastStream[0].width = 320; |
| codec_.simulcastStream[0].height = 180; |
| codec_.simulcastStream[0].maxBitrate = 300; |
| codec_.simulcastStream[1].width = 640; |
| codec_.simulcastStream[1].height = 360; |
| codec_.simulcastStream[1].maxBitrate = 600; |
| codec_.simulcastStream[2].width = 1280; |
| codec_.simulcastStream[2].height = 720; |
| codec_.simulcastStream[2].maxBitrate = 1200; |
| // We need numberOfSimulcastStreams + 1 RTP modules since we need one |
| // default module. |
| for (int i = 0; i < codec_.numberOfSimulcastStreams + 1; ++i) { |
| RtpRtcp* sender = RtpRtcp::CreateRtpRtcp(config); |
| EXPECT_EQ(0, sender->RegisterSendPayload(codec_)); |
| EXPECT_EQ(0, sender->SetSendingStatus(true)); |
| EXPECT_EQ(0, sender->SetSendingMediaStatus(true)); |
| sender->SetSSRC(kSenderSsrc + i); |
| sender->SetRemoteSSRC(kReceiverSsrc + i); |
| senders_.push_back(sender); |
| config.default_module = senders_[0]; |
| } |
| std::vector<uint32_t> bitrates; |
| bitrates.push_back(codec_.simulcastStream[0].maxBitrate); |
| bitrates.push_back(codec_.simulcastStream[1].maxBitrate); |
| bitrates.push_back(codec_.simulcastStream[2].maxBitrate); |
| senders_[0]->SetTargetSendBitrate(bitrates); |
| } |
| |
| ~RtpSendingTest() { |
| for (int i = senders_.size() - 1; i >= 0; --i) { |
| delete senders_[i]; |
| } |
| } |
| |
| void SendFrameOnSender(int sender_index, |
| const uint8_t* payload, |
| size_t length) { |
| RTPVideoHeader rtp_video_header = { |
| codec_.simulcastStream[sender_index].width, |
| codec_.simulcastStream[sender_index].height, |
| true, |
| 0, |
| kRtpVideoVp8, |
| {}}; |
| uint32_t seq_num = 0; |
| uint32_t ssrc = 0; |
| int64_t capture_time_ms = 0; |
| bool retransmission = false; |
| EXPECT_CALL(pacer_, SendPacket(_, _, _, _, _, _)) |
| .WillRepeatedly(DoAll(SaveArg<1>(&ssrc), |
| SaveArg<2>(&seq_num), |
| SaveArg<3>(&capture_time_ms), |
| SaveArg<5>(&retransmission), |
| Return(true))); |
| EXPECT_EQ(0, |
| senders_[sender_index]->SendOutgoingData(kVideoFrameKey, |
| codec_.plType, |
| 0, |
| 0, |
| payload, |
| length, |
| NULL, |
| &rtp_video_header)); |
| EXPECT_TRUE(senders_[sender_index]->TimeToSendPacket( |
| ssrc, seq_num, capture_time_ms, retransmission)); |
| } |
| |
| void ExpectPadding(const PaddingMap& expected_padding) { |
| int expected_total_bytes = 0; |
| for (PaddingMap::const_iterator it = expected_padding.begin(); |
| it != expected_padding.end(); |
| ++it) { |
| int packets_received = transport_.GetBytesReceived(it->first); |
| if (it->second.first > 0) { |
| EXPECT_GE(packets_received, it->second.first) |
| << "On SSRC: " << it->first; |
| } |
| int bytes_received = transport_.GetBytesReceived(it->first); |
| expected_total_bytes += bytes_received; |
| if (it->second.second > 0) { |
| EXPECT_GE(bytes_received, it->second.second) |
| << "On SSRC: " << it->first; |
| } else { |
| EXPECT_EQ(0, bytes_received) << "On SSRC: " << it->first; |
| } |
| } |
| EXPECT_EQ(expected_total_bytes, transport_.GetTotalBytesReceived()); |
| } |
| |
| scoped_ptr<ReceiveStatistics> receive_statistics_; |
| RtcpRttStatsTestImpl rtt_stats_; |
| std::vector<RtpRtcp*> senders_; |
| RtpSendingTestTransport transport_; |
| NiceMock<MockPacedSender> pacer_; |
| VideoCodec codec_; |
| }; |
| |
| TEST_F(RtpSendingTest, DISABLED_RoundRobinPadding) { |
| // We have to send on an SSRC to be allowed to pad, since a marker bit must |
| // be sent prior to padding packets. |
| const uint8_t payload[200] = {0}; |
| for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) { |
| SendFrameOnSender(i + 1, payload, sizeof(payload)); |
| } |
| transport_.ResetCounters(); |
| senders_[0]->TimeToSendPadding(500); |
| PaddingMap expected_padding; |
| expected_padding[kSenderSsrc + 1] = std::make_pair(2, 500); |
| expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0); |
| expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1000); |
| expected_padding[kSenderSsrc + 2] = std::make_pair(4, 1000); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1500); |
| expected_padding[kSenderSsrc + 3] = std::make_pair(6, 1500); |
| ExpectPadding(expected_padding); |
| } |
| |
| TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtx) { |
| // Enable RTX to allow padding to be sent prior to media. |
| for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) { |
| // Abs-send-time is needed to be allowed to send padding prior to media, |
| // as otherwise the timestmap used for BWE will be broken. |
| senders_[i]->RegisterSendRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, |
| 1); |
| senders_[i]->SetRtxSendPayloadType(96); |
| senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i); |
| senders_[i]->SetRTXSendStatus(kRtxRetransmitted); |
| } |
| transport_.ResetCounters(); |
| senders_[0]->TimeToSendPadding(500); |
| PaddingMap expected_padding; |
| expected_padding[kSenderSsrc + 1] = std::make_pair(0, 0); |
| expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0); |
| expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0); |
| expected_padding[kSenderRtxSsrc + 1] = std::make_pair(2, 500); |
| expected_padding[kSenderRtxSsrc + 2] = std::make_pair(0, 0); |
| expected_padding[kSenderRtxSsrc + 3] = std::make_pair(0, 0); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1000); |
| expected_padding[kSenderRtxSsrc + 2] = std::make_pair(4, 500); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1500); |
| |
| expected_padding[kSenderRtxSsrc + 3] = std::make_pair(6, 500); |
| ExpectPadding(expected_padding); |
| } |
| |
| TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtxRedundantPayloads) { |
| for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) { |
| senders_[i]->SetRtxSendPayloadType(96); |
| senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i); |
| senders_[i]->SetRTXSendStatus(kRtxRetransmitted | kRtxRedundantPayloads); |
| senders_[i]->SetStorePacketsStatus(true, 100); |
| } |
| // First send payloads so that we have something to retransmit. |
| const size_t kPayloadSize = 500; |
| const uint8_t payload[kPayloadSize] = {0}; |
| for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) { |
| SendFrameOnSender(i + 1, payload, sizeof(payload)); |
| } |
| transport_.ResetCounters(); |
| senders_[0]->TimeToSendPadding(500); |
| PaddingMap expected_padding; |
| expected_padding[kSenderSsrc + 1] = std::make_pair<int, int>(0, 0); |
| expected_padding[kSenderSsrc + 2] = std::make_pair<int, int>(0, 0); |
| expected_padding[kSenderSsrc + 3] = std::make_pair<int, int>(0, 0); |
| expected_padding[kSenderRtxSsrc + 1] = std::make_pair<int, int>(1, 500); |
| expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(0, 0); |
| expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(0, 0); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1000); |
| expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(2, 1000); |
| ExpectPadding(expected_padding); |
| senders_[0]->TimeToSendPadding(1500); |
| expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(3, 1500); |
| ExpectPadding(expected_padding); |
| } |
| } // namespace webrtc |