Chromium Code Reviews| Index: webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc |
| diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5d63b899a35ea0069fcda55cb7fe9deb9e4c42ba |
| --- /dev/null |
| +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc |
| @@ -0,0 +1,222 @@ |
| +/* |
| + * Copyright (c) 2015 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 <vector> |
| + |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +#include "webrtc/base/checks.h" |
| +#include "webrtc/base/scoped_ptr.h" |
| +#include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h" |
| +#include "webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h" |
| +#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" |
| +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" |
| +#include "webrtc/modules/utility/interface/mock/mock_process_thread.h" |
| +#include "webrtc/system_wrappers/interface/clock.h" |
| + |
| +using ::testing::_; |
| +using ::testing::Invoke; |
| + |
| +namespace webrtc { |
| +namespace test { |
| + |
| +class TransportFeedbackAdapterTest : public ::testing::Test { |
| + public: |
| + TransportFeedbackAdapterTest() |
| + : clock_(0), |
| + bitrate_estimator_(nullptr), |
| + receiver_estimated_bitrate_(0) {} |
| + |
| + virtual ~TransportFeedbackAdapterTest() {} |
| + |
| + virtual void SetUp() { |
| + adapter_.reset(new TransportFeedbackAdapter( |
| + new RtcpBandwidthObserverAdapter(this), &clock_, &process_thread_)); |
| + |
| + bitrate_estimator_ = new MockRemoteBitrateEstimator(); |
| + EXPECT_CALL(process_thread_, RegisterModule(bitrate_estimator_)).Times(1); |
| + adapter_->SetBitrateEstimator(bitrate_estimator_); |
| + } |
| + |
| + virtual void TearDown() { |
| + EXPECT_CALL(process_thread_, DeRegisterModule(bitrate_estimator_)).Times(1); |
| + adapter_.reset(); |
| + } |
| + |
| + protected: |
| + // Proxy class used since TransportFeedbackAdapter will own the instance |
| + // passed at construction. |
| + class RtcpBandwidthObserverAdapter : public RtcpBandwidthObserver { |
| + public: |
| + explicit RtcpBandwidthObserverAdapter(TransportFeedbackAdapterTest* owner) |
| + : owner_(owner) {} |
| + |
| + void OnReceivedEstimatedBitrate(uint32_t bitrate) override { |
| + owner_->receiver_estimated_bitrate_ = bitrate; |
| + } |
| + |
| + void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks, |
| + int64_t rtt, |
| + int64_t now_ms) override { |
| + RTC_NOTREACHED(); |
| + } |
| + |
| + TransportFeedbackAdapterTest* const owner_; |
| + }; |
| + |
| + void OnReceivedEstimatedBitrate(uint32_t bitrate) {} |
| + |
| + void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks, |
| + int64_t rtt, |
| + int64_t now_ms) {} |
| + |
| + void ComparePacketVectors(const std::vector<PacketInfo>& truth, |
| + const std::vector<PacketInfo>& input) { |
| + ASSERT_EQ(truth.size(), input.size()); |
| + size_t len = truth.size(); |
| + int64_t arrival_time_delta = |
| + truth[0].arrival_time_ms - input[0].arrival_time_ms; |
|
stefan-webrtc
2015/09/11 08:15:12
Just from reading this code I don't fully understa
sprang_webrtc
2015/09/11 12:33:47
Done.
|
| + for (size_t i = 0; i < len; ++i) { |
| + EXPECT_EQ(truth[i].arrival_time_ms, |
| + input[i].arrival_time_ms + arrival_time_delta); |
| + EXPECT_EQ(truth[i].send_time_ms, input[i].send_time_ms); |
| + EXPECT_EQ(truth[i].sequence_number, input[i].sequence_number); |
| + EXPECT_EQ(truth[i].payload_size, input[i].payload_size); |
| + EXPECT_EQ(truth[i].was_paced, input[i].was_paced); |
| + } |
| + } |
| + |
| + SimulatedClock clock_; |
| + MockProcessThread process_thread_; |
| + MockRemoteBitrateEstimator* bitrate_estimator_; |
|
stefan-webrtc
2015/09/11 08:15:12
Do you have to allocate it on the heap? Would save
sprang_webrtc
2015/09/11 12:33:48
Yes, the instance will be owned by TransportFeedba
|
| + rtc::scoped_ptr<TransportFeedbackAdapter> adapter_; |
| + |
| + uint32_t receiver_estimated_bitrate_; |
| +}; |
| + |
| +TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) { |
| + std::vector<PacketInfo> packets; |
| + packets.push_back(PacketInfo(100, 200, 0, 1500, true)); |
| + packets.push_back(PacketInfo(110, 210, 1, 1500, true)); |
| + packets.push_back(PacketInfo(120, 220, 2, 1500, true)); |
| + packets.push_back(PacketInfo(130, 230, 3, 1500, true)); |
| + packets.push_back(PacketInfo(140, 240, 4, 1500, true)); |
| + |
| + for (const PacketInfo& packet : packets) { |
| + adapter_->OnPacketSent(packet.sequence_number, packet.send_time_ms, |
| + packet.payload_size, packet.was_paced); |
|
stefan-webrtc
2015/09/11 08:15:12
Makes me wonder why we don't pass in a PacketInfo
sprang_webrtc
2015/09/11 12:33:47
Done.
|
| + } |
| + |
| + rtcp::TransportFeedback feedback; |
| + feedback.WithBase(packets[0].sequence_number, |
| + packets[0].arrival_time_ms * 1000); |
| + |
| + for (const PacketInfo& packet : packets) { |
| + EXPECT_TRUE(feedback.WithReceivedPacket(packet.sequence_number, |
| + packet.arrival_time_ms * 1000)); |
| + } |
| + |
| + feedback.Build(); |
| + |
| + EXPECT_CALL(*bitrate_estimator_, IncomingPacketFeedbackVector(_)) |
| + .Times(1) |
| + .WillOnce(Invoke( |
| + [packets, this](const std::vector<PacketInfo>& feedback_vector) { |
| + ComparePacketVectors(packets, feedback_vector); |
| + })); |
| + adapter_->OnTransportFeedback(feedback); |
| +} |
| + |
| +TEST_F(TransportFeedbackAdapterTest, HandlesDroppedPackets) { |
| + std::vector<PacketInfo> packets; |
| + packets.push_back(PacketInfo(100, 200, 0, 1500, true)); |
| + packets.push_back(PacketInfo(110, 210, 1, 1500, true)); |
| + packets.push_back(PacketInfo(120, 220, 2, 1500, true)); |
| + packets.push_back(PacketInfo(130, 230, 3, 1500, true)); |
| + packets.push_back(PacketInfo(140, 240, 4, 1500, true)); |
| + |
| + const uint16_t kSendSideDropBefore = 1; |
| + const uint16_t kReceiveSideDropAfter = 3; |
| + |
| + for (const PacketInfo& packet : packets) { |
| + if (packet.sequence_number >= kSendSideDropBefore) { |
| + adapter_->OnPacketSent(packet.sequence_number, packet.send_time_ms, |
| + packet.payload_size, packet.was_paced); |
| + } |
| + } |
| + |
| + rtcp::TransportFeedback feedback; |
| + feedback.WithBase(packets[0].sequence_number, |
| + packets[0].arrival_time_ms * 1000); |
| + |
| + for (const PacketInfo& packet : packets) { |
| + if (packet.sequence_number <= kReceiveSideDropAfter) { |
| + EXPECT_TRUE(feedback.WithReceivedPacket(packet.sequence_number, |
| + packet.arrival_time_ms * 1000)); |
| + } |
| + } |
| + |
| + feedback.Build(); |
| + |
| + std::vector<PacketInfo> expected_packets( |
| + packets.begin() + kSendSideDropBefore, |
| + packets.begin() + kReceiveSideDropAfter + 1); |
| + |
| + EXPECT_CALL(*bitrate_estimator_, IncomingPacketFeedbackVector(_)) |
| + .Times(1) |
| + .WillOnce(Invoke([expected_packets, |
| + this](const std::vector<PacketInfo>& feedback_vector) { |
| + ComparePacketVectors(expected_packets, feedback_vector); |
| + })); |
| + adapter_->OnTransportFeedback(feedback); |
| +} |
| + |
| +TEST_F(TransportFeedbackAdapterTest, SendTimeWrapsBothWays) { |
| + int64_t kHighArrivalTimeMs = rtcp::TransportFeedback::kDeltaScaleFactor * |
| + (1L << 8) * ((1L << 23) - 1) / 1000; |
| + std::vector<PacketInfo> packets; |
| + packets.push_back(PacketInfo(kHighArrivalTimeMs - 64, 200, 0, 1500, true)); |
| + packets.push_back(PacketInfo(kHighArrivalTimeMs + 64, 210, 1, 1500, true)); |
| + packets.push_back(PacketInfo(kHighArrivalTimeMs, 220, 2, 1500, true)); |
| + |
| + for (const PacketInfo& packet : packets) { |
| + adapter_->OnPacketSent(packet.sequence_number, packet.send_time_ms, |
| + packet.payload_size, packet.was_paced); |
| + } |
| + |
| + for (size_t i = 0; i < packets.size(); ++i) { |
| + rtc::scoped_ptr<rtcp::TransportFeedback> feedback( |
| + new rtcp::TransportFeedback()); |
| + feedback->WithBase(packets[i].sequence_number, |
| + packets[i].arrival_time_ms * 1000); |
| + |
| + EXPECT_TRUE(feedback->WithReceivedPacket( |
| + packets[i].sequence_number, packets[i].arrival_time_ms * 1000)); |
| + |
| + rtc::scoped_ptr<rtcp::RawPacket> raw_packet = feedback->Build(); |
| + feedback = rtcp::TransportFeedback::ParseFrom(raw_packet->Buffer(), |
| + raw_packet->Length()); |
| + |
| + std::vector<PacketInfo> expected_packets; |
| + expected_packets.push_back(packets[i]); |
| + |
| + EXPECT_CALL(*bitrate_estimator_, IncomingPacketFeedbackVector(_)) |
| + .Times(1) |
| + .WillOnce(Invoke([expected_packets, this]( |
| + const std::vector<PacketInfo>& feedback_vector) { |
| + ComparePacketVectors(expected_packets, feedback_vector); |
| + })); |
| + adapter_->OnTransportFeedback(*feedback.get()); |
| + } |
| +} |
| + |
|
stefan-webrtc
2015/09/11 08:15:12
Should we have a test for the limit on time deltas
sprang_webrtc
2015/09/11 12:33:48
Done.
|
| +} // namespace test |
| +} // namespace webrtc |