Per Kjellander 89870ffa95 Reland "Change CallTests to use new PacketReceiver::DeliverRtp and PacketReceiver::DeliverRtcp"
This reverts commit 3e61f881cd2ba9040a07371e0ba6dda902aa60ae.

Reason for revert: Issue fixed in https://webrtc-review.googlesource.com/c/src/+/291104

Original change's description:
> Revert "Change CallTests to use new PacketReceiver::DeliverRtp and PacketReceiver::DeliverRtcp"
>
> This reverts commit 3b96f2c770df7691df90c2cc1be40509a76ae425.
>
> Reason for revert: Seems to cause test failures and perf regressions in tests: webrtc:14833, and  CallPerfTest.Min_Bitrate_VideoAndAudio 
>
>
> Original change's description:
> > Change CallTests to use new PacketReceiver::DeliverRtp and PacketReceiver::DeliverRtcp
> >
> > PacketReceiver::DeliverRtp requires delivered packets to have extensions already mapped.
> > Therefore DirectTransport is provided with the extension mapping.
> >
> > CallTests and tests derived from CallTest create transports in different ways, this cl change CallTest to create tests in only one way to simplify how extensions are provided to the transport but at the same time still allows different network behaviour.
> >
> >
> > Change-Id: Ie8b3ad947c170be61e62c02dadf4adedbb3841f1
> > Bug: webrtc:7135, webrtc:14795
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/290980
> > Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
> > Commit-Queue: Per Kjellander <perkj@webrtc.org>
> > Reviewed-by: Erik Språng <sprang@webrtc.org>
> > Cr-Commit-Position: refs/heads/main@{#39137}
>
> Bug: webrtc:7135, webrtc:14795, webrtc:14833
> Change-Id: Ib6180a47cf7611ed2bc648acc3b9e5cfeec4d9cf
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291220
> Owners-Override: Björn Terelius <terelius@webrtc.org>
> Auto-Submit: Per Kjellander <perkj@webrtc.org>
> Reviewed-by: Björn Terelius <terelius@webrtc.org>
> Commit-Queue: Björn Terelius <terelius@webrtc.org>
> Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
> Cr-Commit-Position: refs/heads/main@{#39146}

Bug: webrtc:7135, webrtc:14795, webrtc:14833
Change-Id: I3fb0210d7a33c600ead5719ce2acb8cc68ec20bd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291222
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Owners-Override: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39157}
2023-01-20 06:32:29 +00:00

503 lines
18 KiB
C++

/*
* Copyright 2018 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 <memory>
#include "api/task_queue/task_queue_base.h"
#include "api/test/simulated_network.h"
#include "api/test/video/function_video_encoder_factory.h"
#include "call/fake_network_pipe.h"
#include "call/simulated_network.h"
#include "media/engine/internal_decoder_factory.h"
#include "modules/include/module_common_types_public.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_packet.h"
#include "modules/video_coding/codecs/vp8/include/vp8.h"
#include "rtc_base/synchronization/mutex.h"
#include "test/call_test.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/rtcp_packet_parser.h"
using ::testing::Contains;
using ::testing::Not;
namespace webrtc {
namespace {
enum : int { // The first valid value is 1.
kTransportSequenceNumberExtensionId = 1,
kVideoRotationExtensionId,
};
} // namespace
class FecEndToEndTest : public test::CallTest {
public:
FecEndToEndTest() {
RegisterRtpExtension(RtpExtension(RtpExtension::kTransportSequenceNumberUri,
kTransportSequenceNumberExtensionId));
RegisterRtpExtension(RtpExtension(RtpExtension::kVideoRotationUri,
kVideoRotationExtensionId));
}
};
TEST_F(FecEndToEndTest, ReceivesUlpfec) {
class UlpfecRenderObserver : public test::EndToEndTest,
public rtc::VideoSinkInterface<VideoFrame> {
public:
UlpfecRenderObserver()
: EndToEndTest(kDefaultTimeout),
encoder_factory_([]() { return VP8Encoder::Create(); }),
random_(0xcafef00d1),
num_packets_sent_(0) {}
private:
Action OnSendRtp(const uint8_t* packet, size_t length) override {
MutexLock lock(&mutex_);
RtpPacket rtp_packet;
EXPECT_TRUE(rtp_packet.Parse(packet, length));
EXPECT_TRUE(rtp_packet.PayloadType() == kVideoSendPayloadType ||
rtp_packet.PayloadType() == kRedPayloadType)
<< "Unknown payload type received.";
EXPECT_EQ(kVideoSendSsrcs[0], rtp_packet.Ssrc())
<< "Unknown SSRC received.";
// Parse RED header.
int encapsulated_payload_type = -1;
if (rtp_packet.PayloadType() == kRedPayloadType) {
encapsulated_payload_type = rtp_packet.payload()[0];
EXPECT_TRUE(encapsulated_payload_type == kVideoSendPayloadType ||
encapsulated_payload_type == kUlpfecPayloadType)
<< "Unknown encapsulated payload type received.";
}
// To minimize test flakiness, always let ULPFEC packets through.
if (encapsulated_payload_type == kUlpfecPayloadType) {
return SEND_PACKET;
}
// Simulate 5% video packet loss after rampup period. Record the
// corresponding timestamps that were dropped.
if (num_packets_sent_++ > 100 && random_.Rand(1, 100) <= 5) {
if (encapsulated_payload_type == kVideoSendPayloadType) {
dropped_sequence_numbers_.insert(rtp_packet.SequenceNumber());
dropped_timestamps_.insert(rtp_packet.Timestamp());
}
return DROP_PACKET;
}
return SEND_PACKET;
}
void OnFrame(const VideoFrame& video_frame) override {
MutexLock lock(&mutex_);
// Rendering frame with timestamp of packet that was dropped -> FEC
// protection worked.
auto it = dropped_timestamps_.find(video_frame.timestamp());
if (it != dropped_timestamps_.end()) {
observation_complete_.Set();
}
}
void ModifyVideoConfigs(
VideoSendStream::Config* send_config,
std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
VideoEncoderConfig* encoder_config) override {
// Use VP8 instead of FAKE, since the latter does not have PictureID
// in the packetization headers.
send_config->encoder_settings.encoder_factory = &encoder_factory_;
send_config->rtp.payload_name = "VP8";
send_config->rtp.payload_type = kVideoSendPayloadType;
encoder_config->codec_type = kVideoCodecVP8;
VideoReceiveStreamInterface::Decoder decoder =
test::CreateMatchingDecoder(*send_config);
(*receive_configs)[0].decoder_factory = &decoder_factory_;
(*receive_configs)[0].decoders.clear();
(*receive_configs)[0].decoders.push_back(decoder);
// Enable ULPFEC over RED.
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
(*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
(*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
(*receive_configs)[0].renderer = this;
}
void PerformTest() override {
EXPECT_TRUE(Wait())
<< "Timed out waiting for dropped frames to be rendered.";
}
Mutex mutex_;
std::unique_ptr<VideoEncoder> encoder_;
test::FunctionVideoEncoderFactory encoder_factory_;
InternalDecoderFactory decoder_factory_;
std::set<uint32_t> dropped_sequence_numbers_ RTC_GUARDED_BY(mutex_);
// Several packets can have the same timestamp.
std::multiset<uint32_t> dropped_timestamps_ RTC_GUARDED_BY(mutex_);
Random random_;
int num_packets_sent_ RTC_GUARDED_BY(mutex_);
} test;
RunBaseTest(&test);
}
class FlexfecRenderObserver : public test::EndToEndTest,
public rtc::VideoSinkInterface<VideoFrame> {
public:
static constexpr uint32_t kVideoLocalSsrc = 123;
static constexpr uint32_t kFlexfecLocalSsrc = 456;
explicit FlexfecRenderObserver(bool enable_nack, bool expect_flexfec_rtcp)
: test::EndToEndTest(test::CallTest::kLongTimeout),
enable_nack_(enable_nack),
expect_flexfec_rtcp_(expect_flexfec_rtcp),
received_flexfec_rtcp_(false),
random_(0xcafef00d1),
num_packets_sent_(0) {}
size_t GetNumFlexfecStreams() const override { return 1; }
private:
Action OnSendRtp(const uint8_t* packet, size_t length) override {
MutexLock lock(&mutex_);
RtpPacket rtp_packet;
EXPECT_TRUE(rtp_packet.Parse(packet, length));
EXPECT_TRUE(
rtp_packet.PayloadType() == test::CallTest::kFakeVideoSendPayloadType ||
rtp_packet.PayloadType() == test::CallTest::kFlexfecPayloadType ||
(enable_nack_ &&
rtp_packet.PayloadType() == test::CallTest::kSendRtxPayloadType))
<< "Unknown payload type received.";
EXPECT_TRUE(
rtp_packet.Ssrc() == test::CallTest::kVideoSendSsrcs[0] ||
rtp_packet.Ssrc() == test::CallTest::kFlexfecSendSsrc ||
(enable_nack_ && rtp_packet.Ssrc() == test::CallTest::kSendRtxSsrcs[0]))
<< "Unknown SSRC received.";
// To reduce test flakiness, always let FlexFEC packets through.
if (rtp_packet.PayloadType() == test::CallTest::kFlexfecPayloadType) {
EXPECT_EQ(test::CallTest::kFlexfecSendSsrc, rtp_packet.Ssrc());
return SEND_PACKET;
}
// To reduce test flakiness, always let RTX packets through.
if (rtp_packet.PayloadType() == test::CallTest::kSendRtxPayloadType) {
EXPECT_EQ(test::CallTest::kSendRtxSsrcs[0], rtp_packet.Ssrc());
if (rtp_packet.payload_size() == 0) {
// Pure padding packet.
return SEND_PACKET;
}
// Parse RTX header.
uint16_t original_sequence_number =
ByteReader<uint16_t>::ReadBigEndian(rtp_packet.payload().data());
// From the perspective of FEC, a retransmitted packet is no longer
// dropped, so remove it from list of dropped packets.
auto seq_num_it =
dropped_sequence_numbers_.find(original_sequence_number);
if (seq_num_it != dropped_sequence_numbers_.end()) {
dropped_sequence_numbers_.erase(seq_num_it);
auto ts_it = dropped_timestamps_.find(rtp_packet.Timestamp());
EXPECT_NE(ts_it, dropped_timestamps_.end());
dropped_timestamps_.erase(ts_it);
}
return SEND_PACKET;
}
// Simulate 5% video packet loss after rampup period. Record the
// corresponding timestamps that were dropped.
if (num_packets_sent_++ > 100 && random_.Rand(1, 100) <= 5) {
EXPECT_EQ(test::CallTest::kFakeVideoSendPayloadType,
rtp_packet.PayloadType());
EXPECT_EQ(test::CallTest::kVideoSendSsrcs[0], rtp_packet.Ssrc());
dropped_sequence_numbers_.insert(rtp_packet.SequenceNumber());
dropped_timestamps_.insert(rtp_packet.Timestamp());
return DROP_PACKET;
}
return SEND_PACKET;
}
Action OnReceiveRtcp(const uint8_t* data, size_t length) override {
test::RtcpPacketParser parser;
parser.Parse(data, length);
if (parser.sender_ssrc() == kFlexfecLocalSsrc) {
EXPECT_EQ(1, parser.receiver_report()->num_packets());
const std::vector<rtcp::ReportBlock>& report_blocks =
parser.receiver_report()->report_blocks();
if (!report_blocks.empty()) {
EXPECT_EQ(1U, report_blocks.size());
EXPECT_EQ(test::CallTest::kFlexfecSendSsrc,
report_blocks[0].source_ssrc());
MutexLock lock(&mutex_);
received_flexfec_rtcp_ = true;
}
}
return SEND_PACKET;
}
BuiltInNetworkBehaviorConfig GetSendTransportConfig() const override {
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
const int kNetworkDelayMs = 100;
BuiltInNetworkBehaviorConfig config;
config.queue_delay_ms = kNetworkDelayMs;
return config;
}
void OnFrame(const VideoFrame& video_frame) override {
EXPECT_EQ(kVideoRotation_90, video_frame.rotation());
MutexLock lock(&mutex_);
// Rendering frame with timestamp of packet that was dropped -> FEC
// protection worked.
auto it = dropped_timestamps_.find(video_frame.timestamp());
if (it != dropped_timestamps_.end()) {
if (!expect_flexfec_rtcp_ || received_flexfec_rtcp_) {
observation_complete_.Set();
}
}
}
void ModifyVideoConfigs(
VideoSendStream::Config* send_config,
std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
VideoEncoderConfig* encoder_config) override {
(*receive_configs)[0].rtp.local_ssrc = kVideoLocalSsrc;
(*receive_configs)[0].renderer = this;
if (enable_nack_) {
send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
send_config->rtp.rtx.ssrcs.push_back(test::CallTest::kSendRtxSsrcs[0]);
send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
(*receive_configs)[0].rtp.nack.rtp_history_ms =
test::CallTest::kNackRtpHistoryMs;
(*receive_configs)[0].rtp.rtx_ssrc = test::CallTest::kSendRtxSsrcs[0];
(*receive_configs)[0]
.rtp
.rtx_associated_payload_types[test::CallTest::kSendRtxPayloadType] =
test::CallTest::kVideoSendPayloadType;
}
}
void OnFrameGeneratorCapturerCreated(
test::FrameGeneratorCapturer* frame_generator_capturer) override {
frame_generator_capturer->SetFakeRotation(kVideoRotation_90);
}
void ModifyFlexfecConfigs(
std::vector<FlexfecReceiveStream::Config>* receive_configs) override {
(*receive_configs)[0].rtp.local_ssrc = kFlexfecLocalSsrc;
}
void PerformTest() override {
EXPECT_TRUE(Wait())
<< "Timed out waiting for dropped frames to be rendered.";
}
Mutex mutex_;
std::set<uint32_t> dropped_sequence_numbers_ RTC_GUARDED_BY(mutex_);
// Several packets can have the same timestamp.
std::multiset<uint32_t> dropped_timestamps_ RTC_GUARDED_BY(mutex_);
const bool enable_nack_;
const bool expect_flexfec_rtcp_;
bool received_flexfec_rtcp_ RTC_GUARDED_BY(mutex_);
Random random_;
int num_packets_sent_;
};
TEST_F(FecEndToEndTest, RecoversWithFlexfec) {
FlexfecRenderObserver test(false, false);
RunBaseTest(&test);
}
TEST_F(FecEndToEndTest, RecoversWithFlexfecAndNack) {
FlexfecRenderObserver test(true, false);
RunBaseTest(&test);
}
TEST_F(FecEndToEndTest, RecoversWithFlexfecAndSendsCorrespondingRtcp) {
FlexfecRenderObserver test(false, true);
RunBaseTest(&test);
}
TEST_F(FecEndToEndTest, ReceivedUlpfecPacketsNotNacked) {
class UlpfecNackObserver : public test::EndToEndTest {
public:
UlpfecNackObserver()
: EndToEndTest(kDefaultTimeout),
state_(kFirstPacket),
ulpfec_sequence_number_(0),
has_last_sequence_number_(false),
last_sequence_number_(0),
encoder_factory_([]() { return VP8Encoder::Create(); }) {}
private:
Action OnSendRtp(const uint8_t* packet, size_t length) override {
MutexLock lock_(&mutex_);
RtpPacket rtp_packet;
EXPECT_TRUE(rtp_packet.Parse(packet, length));
int encapsulated_payload_type = -1;
if (rtp_packet.PayloadType() == kRedPayloadType) {
encapsulated_payload_type = rtp_packet.payload()[0];
if (encapsulated_payload_type != kFakeVideoSendPayloadType)
EXPECT_EQ(kUlpfecPayloadType, encapsulated_payload_type);
} else {
EXPECT_EQ(kFakeVideoSendPayloadType, rtp_packet.PayloadType());
}
if (has_last_sequence_number_ &&
!IsNewerSequenceNumber(rtp_packet.SequenceNumber(),
last_sequence_number_)) {
// Drop retransmitted packets.
return DROP_PACKET;
}
last_sequence_number_ = rtp_packet.SequenceNumber();
has_last_sequence_number_ = true;
bool ulpfec_packet = encapsulated_payload_type == kUlpfecPayloadType;
switch (state_) {
case kFirstPacket:
state_ = kDropEveryOtherPacketUntilUlpfec;
break;
case kDropEveryOtherPacketUntilUlpfec:
if (ulpfec_packet) {
state_ = kDropAllMediaPacketsUntilUlpfec;
} else if (rtp_packet.SequenceNumber() % 2 == 0) {
return DROP_PACKET;
}
break;
case kDropAllMediaPacketsUntilUlpfec:
if (!ulpfec_packet)
return DROP_PACKET;
ulpfec_sequence_number_ = rtp_packet.SequenceNumber();
state_ = kDropOneMediaPacket;
break;
case kDropOneMediaPacket:
if (ulpfec_packet)
return DROP_PACKET;
state_ = kPassOneMediaPacket;
return DROP_PACKET;
case kPassOneMediaPacket:
if (ulpfec_packet)
return DROP_PACKET;
// Pass one media packet after dropped packet after last FEC,
// otherwise receiver might never see a seq_no after
// `ulpfec_sequence_number_`
state_ = kVerifyUlpfecPacketNotInNackList;
break;
case kVerifyUlpfecPacketNotInNackList:
// Continue to drop packets. Make sure no frame can be decoded.
if (ulpfec_packet || rtp_packet.SequenceNumber() % 2 == 0)
return DROP_PACKET;
break;
}
return SEND_PACKET;
}
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
MutexLock lock_(&mutex_);
if (state_ == kVerifyUlpfecPacketNotInNackList) {
test::RtcpPacketParser rtcp_parser;
rtcp_parser.Parse(packet, length);
const std::vector<uint16_t>& nacks = rtcp_parser.nack()->packet_ids();
EXPECT_THAT(nacks, Not(Contains(ulpfec_sequence_number_)))
<< "Got nack for ULPFEC packet";
if (!nacks.empty() &&
IsNewerSequenceNumber(nacks.back(), ulpfec_sequence_number_)) {
observation_complete_.Set();
}
}
return SEND_PACKET;
}
BuiltInNetworkBehaviorConfig GetSendTransportConfig() const override {
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
// Configure some network delay.
const int kNetworkDelayMs = 50;
BuiltInNetworkBehaviorConfig config;
config.queue_delay_ms = kNetworkDelayMs;
return config;
}
// TODO(holmer): Investigate why we don't send FEC packets when the bitrate
// is 10 kbps.
void ModifySenderBitrateConfig(
BitrateConstraints* bitrate_config) override {
const int kMinBitrateBps = 30000;
bitrate_config->min_bitrate_bps = kMinBitrateBps;
}
void ModifyVideoConfigs(
VideoSendStream::Config* send_config,
std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
VideoEncoderConfig* encoder_config) override {
// Configure hybrid NACK/FEC.
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
// Set codec to VP8, otherwise NACK/FEC hybrid will be disabled.
send_config->encoder_settings.encoder_factory = &encoder_factory_;
send_config->rtp.payload_name = "VP8";
send_config->rtp.payload_type = kFakeVideoSendPayloadType;
encoder_config->codec_type = kVideoCodecVP8;
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
(*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
(*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
(*receive_configs)[0].decoders.resize(1);
(*receive_configs)[0].decoders[0].payload_type =
send_config->rtp.payload_type;
(*receive_configs)[0].decoders[0].video_format =
SdpVideoFormat(send_config->rtp.payload_name);
(*receive_configs)[0].decoder_factory = &decoder_factory_;
}
void PerformTest() override {
EXPECT_TRUE(Wait())
<< "Timed out while waiting for FEC packets to be received.";
}
enum {
kFirstPacket,
kDropEveryOtherPacketUntilUlpfec,
kDropAllMediaPacketsUntilUlpfec,
kDropOneMediaPacket,
kPassOneMediaPacket,
kVerifyUlpfecPacketNotInNackList,
} state_;
Mutex mutex_;
uint16_t ulpfec_sequence_number_ RTC_GUARDED_BY(&mutex_);
bool has_last_sequence_number_;
uint16_t last_sequence_number_;
test::FunctionVideoEncoderFactory encoder_factory_;
InternalDecoderFactory decoder_factory_;
} test;
RunBaseTest(&test);
}
} // namespace webrtc