mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

This is search and replace change: find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataSize::Bytes<\(.*\)>()/DataSize::Bytes(\1)/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataSize::bytes/DataSize::Bytes/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataRate::BitsPerSec<\(.*\)>()/DataRate::BitsPerSec(\1)/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataRate::BytesPerSec<\(.*\)>()/DataRate::BytesPerSec(\1)/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataRate::KilobitsPerSec<\(.*\)>()/DataRate::KilobitsPerSec(\1)/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataRate::bps/DataRate::BitsPerSec/g" find . -type f \( -name "*.h" -o -name "*.cc" \) | xargs sed -i -e "s/DataRate::kbps/DataRate::KilobitsPerSec/g" git cl format Bug: webrtc:9709 Change-Id: I65aaca69474ba038c1fe2dd8dc30d3f8e7b94c29 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168647 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#30545}
414 lines
16 KiB
C++
414 lines
16 KiB
C++
/*
|
|
* 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 "modules/congestion_controller/rtp/transport_feedback_adapter.h"
|
|
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/numerics/safe_conversions.h"
|
|
#include "system_wrappers/include/clock.h"
|
|
#include "test/field_trial.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
using ::testing::_;
|
|
using ::testing::Invoke;
|
|
|
|
namespace webrtc {
|
|
namespace webrtc_cc {
|
|
|
|
namespace {
|
|
const PacedPacketInfo kPacingInfo0(0, 5, 2000);
|
|
const PacedPacketInfo kPacingInfo1(1, 8, 4000);
|
|
const PacedPacketInfo kPacingInfo2(2, 14, 7000);
|
|
const PacedPacketInfo kPacingInfo3(3, 20, 10000);
|
|
const PacedPacketInfo kPacingInfo4(4, 22, 10000);
|
|
|
|
void ComparePacketFeedbackVectors(const std::vector<PacketResult>& truth,
|
|
const std::vector<PacketResult>& input) {
|
|
ASSERT_EQ(truth.size(), input.size());
|
|
size_t len = truth.size();
|
|
// truth contains the input data for the test, and input is what will be
|
|
// sent to the bandwidth estimator. truth.arrival_tims_ms is used to
|
|
// populate the transport feedback messages. As these times may be changed
|
|
// (because of resolution limits in the packets, and because of the time
|
|
// base adjustment performed by the TransportFeedbackAdapter at the first
|
|
// packet, the truth[x].arrival_time and input[x].arrival_time may not be
|
|
// equal. However, the difference must be the same for all x.
|
|
TimeDelta arrival_time_delta = truth[0].receive_time - input[0].receive_time;
|
|
for (size_t i = 0; i < len; ++i) {
|
|
RTC_CHECK(truth[i].receive_time.IsFinite());
|
|
if (input[i].receive_time.IsFinite()) {
|
|
EXPECT_EQ(truth[i].receive_time - input[i].receive_time,
|
|
arrival_time_delta);
|
|
}
|
|
EXPECT_EQ(truth[i].sent_packet.send_time, input[i].sent_packet.send_time);
|
|
EXPECT_EQ(truth[i].sent_packet.sequence_number,
|
|
input[i].sent_packet.sequence_number);
|
|
EXPECT_EQ(truth[i].sent_packet.size, input[i].sent_packet.size);
|
|
EXPECT_EQ(truth[i].sent_packet.pacing_info,
|
|
input[i].sent_packet.pacing_info);
|
|
}
|
|
}
|
|
|
|
PacketResult CreatePacket(int64_t receive_time_ms,
|
|
int64_t send_time_ms,
|
|
int64_t sequence_number,
|
|
size_t payload_size,
|
|
const PacedPacketInfo& pacing_info) {
|
|
PacketResult res;
|
|
res.receive_time = Timestamp::Millis(receive_time_ms);
|
|
res.sent_packet.send_time = Timestamp::Millis(send_time_ms);
|
|
res.sent_packet.sequence_number = sequence_number;
|
|
res.sent_packet.size = DataSize::Bytes(payload_size);
|
|
res.sent_packet.pacing_info = pacing_info;
|
|
return res;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace test {
|
|
|
|
class MockStreamFeedbackObserver : public webrtc::StreamFeedbackObserver {
|
|
public:
|
|
MOCK_METHOD1(OnPacketFeedbackVector,
|
|
void(std::vector<StreamPacketInfo> packet_feedback_vector));
|
|
};
|
|
|
|
class TransportFeedbackAdapterTest : public ::testing::Test {
|
|
public:
|
|
TransportFeedbackAdapterTest() : clock_(0) {}
|
|
|
|
virtual ~TransportFeedbackAdapterTest() {}
|
|
|
|
virtual void SetUp() { adapter_.reset(new TransportFeedbackAdapter()); }
|
|
|
|
virtual void TearDown() { adapter_.reset(); }
|
|
|
|
protected:
|
|
void OnReceivedEstimatedBitrate(uint32_t bitrate) {}
|
|
|
|
void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
|
|
int64_t rtt,
|
|
int64_t now_ms) {}
|
|
|
|
void OnSentPacket(const PacketResult& packet_feedback) {
|
|
RtpPacketSendInfo packet_info;
|
|
packet_info.ssrc = kSsrc;
|
|
packet_info.transport_sequence_number =
|
|
packet_feedback.sent_packet.sequence_number;
|
|
packet_info.rtp_sequence_number = 0;
|
|
packet_info.has_rtp_sequence_number = true;
|
|
packet_info.length = packet_feedback.sent_packet.size.bytes();
|
|
packet_info.pacing_info = packet_feedback.sent_packet.pacing_info;
|
|
adapter_->AddPacket(RtpPacketSendInfo(packet_info), 0u,
|
|
clock_.CurrentTime());
|
|
adapter_->ProcessSentPacket(rtc::SentPacket(
|
|
packet_feedback.sent_packet.sequence_number,
|
|
packet_feedback.sent_packet.send_time.ms(), rtc::PacketInfo()));
|
|
}
|
|
|
|
static constexpr uint32_t kSsrc = 8492;
|
|
|
|
SimulatedClock clock_;
|
|
std::unique_ptr<TransportFeedbackAdapter> adapter_;
|
|
};
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) {
|
|
std::vector<PacketResult> packets;
|
|
packets.push_back(CreatePacket(100, 200, 0, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(120, 220, 2, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(130, 230, 3, 1500, kPacingInfo1));
|
|
packets.push_back(CreatePacket(140, 240, 4, 1500, kPacingInfo1));
|
|
|
|
for (const auto& packet : packets)
|
|
OnSentPacket(packet);
|
|
|
|
rtcp::TransportFeedback feedback;
|
|
feedback.SetBase(packets[0].sent_packet.sequence_number,
|
|
packets[0].receive_time.us());
|
|
|
|
for (const auto& packet : packets) {
|
|
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sent_packet.sequence_number,
|
|
packet.receive_time.us()));
|
|
}
|
|
|
|
feedback.Build();
|
|
|
|
auto result =
|
|
adapter_->ProcessTransportFeedback(feedback, clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(packets, result->packet_feedbacks);
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, FeedbackVectorReportsUnreceived) {
|
|
std::vector<PacketResult> sent_packets = {
|
|
CreatePacket(100, 220, 0, 1500, kPacingInfo0),
|
|
CreatePacket(110, 210, 1, 1500, kPacingInfo0),
|
|
CreatePacket(120, 220, 2, 1500, kPacingInfo0),
|
|
CreatePacket(130, 230, 3, 1500, kPacingInfo0),
|
|
CreatePacket(140, 240, 4, 1500, kPacingInfo0),
|
|
CreatePacket(150, 250, 5, 1500, kPacingInfo0),
|
|
CreatePacket(160, 260, 6, 1500, kPacingInfo0)};
|
|
|
|
for (const auto& packet : sent_packets)
|
|
OnSentPacket(packet);
|
|
|
|
// Note: Important to include the last packet, as only unreceived packets in
|
|
// between received packets can be inferred.
|
|
std::vector<PacketResult> received_packets = {
|
|
sent_packets[0], sent_packets[2], sent_packets[6]};
|
|
|
|
rtcp::TransportFeedback feedback;
|
|
feedback.SetBase(received_packets[0].sent_packet.sequence_number,
|
|
received_packets[0].receive_time.us());
|
|
|
|
for (const auto& packet : received_packets) {
|
|
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sent_packet.sequence_number,
|
|
packet.receive_time.us()));
|
|
}
|
|
|
|
feedback.Build();
|
|
|
|
auto res = adapter_->ProcessTransportFeedback(feedback, clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(sent_packets, res->packet_feedbacks);
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, HandlesDroppedPackets) {
|
|
std::vector<PacketResult> packets;
|
|
packets.push_back(CreatePacket(100, 200, 0, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo1));
|
|
packets.push_back(CreatePacket(120, 220, 2, 1500, kPacingInfo2));
|
|
packets.push_back(CreatePacket(130, 230, 3, 1500, kPacingInfo3));
|
|
packets.push_back(CreatePacket(140, 240, 4, 1500, kPacingInfo4));
|
|
|
|
const uint16_t kSendSideDropBefore = 1;
|
|
const uint16_t kReceiveSideDropAfter = 3;
|
|
|
|
for (const auto& packet : packets) {
|
|
if (packet.sent_packet.sequence_number >= kSendSideDropBefore)
|
|
OnSentPacket(packet);
|
|
}
|
|
|
|
rtcp::TransportFeedback feedback;
|
|
feedback.SetBase(packets[0].sent_packet.sequence_number,
|
|
packets[0].receive_time.us());
|
|
|
|
for (const auto& packet : packets) {
|
|
if (packet.sent_packet.sequence_number <= kReceiveSideDropAfter) {
|
|
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sent_packet.sequence_number,
|
|
packet.receive_time.us()));
|
|
}
|
|
}
|
|
|
|
feedback.Build();
|
|
|
|
std::vector<PacketResult> expected_packets(
|
|
packets.begin() + kSendSideDropBefore,
|
|
packets.begin() + kReceiveSideDropAfter + 1);
|
|
// Packets that have timed out on the send-side have lost the
|
|
// information stored on the send-side. And they will not be reported to
|
|
// observers since we won't know that they come from the same networks.
|
|
|
|
auto res = adapter_->ProcessTransportFeedback(feedback, clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(expected_packets, res->packet_feedbacks);
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, SendTimeWrapsBothWays) {
|
|
int64_t kHighArrivalTimeMs = rtcp::TransportFeedback::kDeltaScaleFactor *
|
|
static_cast<int64_t>(1 << 8) *
|
|
static_cast<int64_t>((1 << 23) - 1) / 1000;
|
|
std::vector<PacketResult> packets;
|
|
packets.push_back(
|
|
CreatePacket(kHighArrivalTimeMs + 64, 210, 0, 1500, PacedPacketInfo()));
|
|
packets.push_back(
|
|
CreatePacket(kHighArrivalTimeMs - 64, 210, 1, 1500, PacedPacketInfo()));
|
|
packets.push_back(
|
|
CreatePacket(kHighArrivalTimeMs, 220, 2, 1500, PacedPacketInfo()));
|
|
|
|
for (const auto& packet : packets)
|
|
OnSentPacket(packet);
|
|
|
|
for (size_t i = 0; i < packets.size(); ++i) {
|
|
std::unique_ptr<rtcp::TransportFeedback> feedback(
|
|
new rtcp::TransportFeedback());
|
|
feedback->SetBase(packets[i].sent_packet.sequence_number,
|
|
packets[i].receive_time.us());
|
|
|
|
EXPECT_TRUE(feedback->AddReceivedPacket(
|
|
packets[i].sent_packet.sequence_number, packets[i].receive_time.us()));
|
|
|
|
rtc::Buffer raw_packet = feedback->Build();
|
|
feedback = rtcp::TransportFeedback::ParseFrom(raw_packet.data(),
|
|
raw_packet.size());
|
|
|
|
std::vector<PacketResult> expected_packets;
|
|
expected_packets.push_back(packets[i]);
|
|
|
|
auto res = adapter_->ProcessTransportFeedback(*feedback.get(),
|
|
clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(expected_packets, res->packet_feedbacks);
|
|
}
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, HandlesArrivalReordering) {
|
|
std::vector<PacketResult> packets;
|
|
packets.push_back(CreatePacket(120, 200, 0, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo0));
|
|
packets.push_back(CreatePacket(100, 220, 2, 1500, kPacingInfo0));
|
|
|
|
for (const auto& packet : packets)
|
|
OnSentPacket(packet);
|
|
|
|
rtcp::TransportFeedback feedback;
|
|
feedback.SetBase(packets[0].sent_packet.sequence_number,
|
|
packets[0].receive_time.us());
|
|
|
|
for (const auto& packet : packets) {
|
|
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sent_packet.sequence_number,
|
|
packet.receive_time.us()));
|
|
}
|
|
|
|
feedback.Build();
|
|
|
|
// Adapter keeps the packets ordered by sequence number (which is itself
|
|
// assigned by the order of transmission). Reordering by some other criteria,
|
|
// eg. arrival time, is up to the observers.
|
|
auto res = adapter_->ProcessTransportFeedback(feedback, clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(packets, res->packet_feedbacks);
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, TimestampDeltas) {
|
|
std::vector<PacketResult> sent_packets;
|
|
// TODO(srte): Consider using us resolution in the constants.
|
|
const TimeDelta kSmallDelta =
|
|
TimeDelta::Micros(rtcp::TransportFeedback::kDeltaScaleFactor * 0xFF)
|
|
.RoundDownTo(TimeDelta::Millis(1));
|
|
const TimeDelta kLargePositiveDelta =
|
|
TimeDelta::Micros(rtcp::TransportFeedback::kDeltaScaleFactor *
|
|
std::numeric_limits<int16_t>::max())
|
|
.RoundDownTo(TimeDelta::Millis(1));
|
|
const TimeDelta kLargeNegativeDelta =
|
|
TimeDelta::Micros(rtcp::TransportFeedback::kDeltaScaleFactor *
|
|
std::numeric_limits<int16_t>::min())
|
|
.RoundDownTo(TimeDelta::Millis(1));
|
|
|
|
PacketResult packet_feedback;
|
|
packet_feedback.sent_packet.sequence_number = 1;
|
|
packet_feedback.sent_packet.send_time = Timestamp::Millis(100);
|
|
packet_feedback.receive_time = Timestamp::Millis(200);
|
|
packet_feedback.sent_packet.size = DataSize::Bytes(1500);
|
|
sent_packets.push_back(packet_feedback);
|
|
|
|
// TODO(srte): This rounding maintains previous behavior, but should ot be
|
|
// required.
|
|
packet_feedback.sent_packet.send_time += kSmallDelta;
|
|
packet_feedback.receive_time += kSmallDelta;
|
|
++packet_feedback.sent_packet.sequence_number;
|
|
sent_packets.push_back(packet_feedback);
|
|
|
|
packet_feedback.sent_packet.send_time += kLargePositiveDelta;
|
|
packet_feedback.receive_time += kLargePositiveDelta;
|
|
++packet_feedback.sent_packet.sequence_number;
|
|
sent_packets.push_back(packet_feedback);
|
|
|
|
packet_feedback.sent_packet.send_time += kLargeNegativeDelta;
|
|
packet_feedback.receive_time += kLargeNegativeDelta;
|
|
++packet_feedback.sent_packet.sequence_number;
|
|
sent_packets.push_back(packet_feedback);
|
|
|
|
// Too large, delta - will need two feedback messages.
|
|
packet_feedback.sent_packet.send_time +=
|
|
kLargePositiveDelta + TimeDelta::Millis(1);
|
|
packet_feedback.receive_time += kLargePositiveDelta + TimeDelta::Millis(1);
|
|
++packet_feedback.sent_packet.sequence_number;
|
|
|
|
// Packets will be added to send history.
|
|
for (const auto& packet : sent_packets)
|
|
OnSentPacket(packet);
|
|
OnSentPacket(packet_feedback);
|
|
|
|
// Create expected feedback and send into adapter.
|
|
std::unique_ptr<rtcp::TransportFeedback> feedback(
|
|
new rtcp::TransportFeedback());
|
|
feedback->SetBase(sent_packets[0].sent_packet.sequence_number,
|
|
sent_packets[0].receive_time.us());
|
|
|
|
for (const auto& packet : sent_packets) {
|
|
EXPECT_TRUE(feedback->AddReceivedPacket(packet.sent_packet.sequence_number,
|
|
packet.receive_time.us()));
|
|
}
|
|
EXPECT_FALSE(
|
|
feedback->AddReceivedPacket(packet_feedback.sent_packet.sequence_number,
|
|
packet_feedback.receive_time.us()));
|
|
|
|
rtc::Buffer raw_packet = feedback->Build();
|
|
feedback =
|
|
rtcp::TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
|
|
|
|
std::vector<PacketResult> received_feedback;
|
|
|
|
EXPECT_TRUE(feedback.get() != nullptr);
|
|
auto res =
|
|
adapter_->ProcessTransportFeedback(*feedback.get(), clock_.CurrentTime());
|
|
ComparePacketFeedbackVectors(sent_packets, res->packet_feedbacks);
|
|
|
|
// Create a new feedback message and add the trailing item.
|
|
feedback.reset(new rtcp::TransportFeedback());
|
|
feedback->SetBase(packet_feedback.sent_packet.sequence_number,
|
|
packet_feedback.receive_time.us());
|
|
EXPECT_TRUE(
|
|
feedback->AddReceivedPacket(packet_feedback.sent_packet.sequence_number,
|
|
packet_feedback.receive_time.us()));
|
|
raw_packet = feedback->Build();
|
|
feedback =
|
|
rtcp::TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
|
|
|
|
EXPECT_TRUE(feedback.get() != nullptr);
|
|
{
|
|
auto res = adapter_->ProcessTransportFeedback(*feedback.get(),
|
|
clock_.CurrentTime());
|
|
std::vector<PacketResult> expected_packets;
|
|
expected_packets.push_back(packet_feedback);
|
|
ComparePacketFeedbackVectors(expected_packets, res->packet_feedbacks);
|
|
}
|
|
}
|
|
|
|
TEST_F(TransportFeedbackAdapterTest, IgnoreDuplicatePacketSentCalls) {
|
|
auto packet = CreatePacket(100, 200, 0, 1500, kPacingInfo0);
|
|
|
|
// Add a packet and then mark it as sent.
|
|
RtpPacketSendInfo packet_info;
|
|
packet_info.ssrc = kSsrc;
|
|
packet_info.transport_sequence_number = packet.sent_packet.sequence_number;
|
|
packet_info.length = packet.sent_packet.size.bytes();
|
|
packet_info.pacing_info = packet.sent_packet.pacing_info;
|
|
adapter_->AddPacket(packet_info, 0u, clock_.CurrentTime());
|
|
absl::optional<SentPacket> sent_packet = adapter_->ProcessSentPacket(
|
|
rtc::SentPacket(packet.sent_packet.sequence_number,
|
|
packet.sent_packet.send_time.ms(), rtc::PacketInfo()));
|
|
EXPECT_TRUE(sent_packet.has_value());
|
|
|
|
// Call ProcessSentPacket() again with the same sequence number. This packet
|
|
// has already been marked as sent and the call should be ignored.
|
|
absl::optional<SentPacket> duplicate_packet = adapter_->ProcessSentPacket(
|
|
rtc::SentPacket(packet.sent_packet.sequence_number,
|
|
packet.sent_packet.send_time.ms(), rtc::PacketInfo()));
|
|
EXPECT_FALSE(duplicate_packet.has_value());
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace webrtc_cc
|
|
} // namespace webrtc
|