Introduce SimulatedNetworkReceiverInterface and switch DirectTransport on this interface. Also switch part of related users on DefaultNetworkSimulationConfig. This two changes united into single CL to prevent work duplication. Most changes were done because of stop including fake_network_pipe.h into direct_transport.h, so splitting this into 2 CLs will require first fix all imports of fake_network_pipe.h and then replace them on new API imports again. Bug: webrtc:9630 Change-Id: I87d4a6ff1bab72d04a9871a40441f4fbe028f4e6 Reviewed-on: https://webrtc-review.googlesource.com/94762 Commit-Queue: Patrik Höglund <phoglund@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Patrik Höglund <phoglund@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24336}
570 lines
21 KiB
C++
570 lines
21 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 "api/test/simulated_network.h"
|
|
#include "modules/video_coding/codecs/vp8/include/vp8.h"
|
|
#include "test/call_test.h"
|
|
#include "test/gtest.h"
|
|
#include "test/rtcp_packet_parser.h"
|
|
|
|
namespace webrtc {
|
|
|
|
class RtpRtcpEndToEndTest : public test::CallTest {
|
|
protected:
|
|
void RespectsRtcpMode(RtcpMode rtcp_mode);
|
|
void TestRtpStatePreservation(bool use_rtx, bool provoke_rtcpsr_before_rtp);
|
|
};
|
|
|
|
void RtpRtcpEndToEndTest::RespectsRtcpMode(RtcpMode rtcp_mode) {
|
|
static const int kNumCompoundRtcpPacketsToObserve = 10;
|
|
class RtcpModeObserver : public test::EndToEndTest {
|
|
public:
|
|
explicit RtcpModeObserver(RtcpMode rtcp_mode)
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
rtcp_mode_(rtcp_mode),
|
|
sent_rtp_(0),
|
|
sent_rtcp_(0) {}
|
|
|
|
private:
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
rtc::CritScope lock(&crit_);
|
|
if (++sent_rtp_ % 3 == 0)
|
|
return DROP_PACKET;
|
|
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
|
rtc::CritScope lock(&crit_);
|
|
++sent_rtcp_;
|
|
test::RtcpPacketParser parser;
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
EXPECT_EQ(0, parser.sender_report()->num_packets());
|
|
|
|
switch (rtcp_mode_) {
|
|
case RtcpMode::kCompound:
|
|
// TODO(holmer): We shouldn't send transport feedback alone if
|
|
// compound RTCP is negotiated.
|
|
if (parser.receiver_report()->num_packets() == 0 &&
|
|
parser.transport_feedback()->num_packets() == 0) {
|
|
ADD_FAILURE() << "Received RTCP packet without receiver report for "
|
|
"RtcpMode::kCompound.";
|
|
observation_complete_.Set();
|
|
}
|
|
|
|
if (sent_rtcp_ >= kNumCompoundRtcpPacketsToObserve)
|
|
observation_complete_.Set();
|
|
|
|
break;
|
|
case RtcpMode::kReducedSize:
|
|
if (parser.receiver_report()->num_packets() == 0)
|
|
observation_complete_.Set();
|
|
break;
|
|
case RtcpMode::kOff:
|
|
RTC_NOTREACHED();
|
|
break;
|
|
}
|
|
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
void ModifyVideoConfigs(
|
|
VideoSendStream::Config* send_config,
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
VideoEncoderConfig* encoder_config) override {
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
(*receive_configs)[0].rtp.rtcp_mode = rtcp_mode_;
|
|
}
|
|
|
|
void PerformTest() override {
|
|
EXPECT_TRUE(Wait())
|
|
<< (rtcp_mode_ == RtcpMode::kCompound
|
|
? "Timed out before observing enough compound packets."
|
|
: "Timed out before receiving a non-compound RTCP packet.");
|
|
}
|
|
|
|
RtcpMode rtcp_mode_;
|
|
rtc::CriticalSection crit_;
|
|
// Must be protected since RTCP can be sent by both the process thread
|
|
// and the pacer thread.
|
|
int sent_rtp_ RTC_GUARDED_BY(&crit_);
|
|
int sent_rtcp_ RTC_GUARDED_BY(&crit_);
|
|
} test(rtcp_mode);
|
|
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest, UsesRtcpCompoundMode) {
|
|
RespectsRtcpMode(RtcpMode::kCompound);
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest, UsesRtcpReducedSizeMode) {
|
|
RespectsRtcpMode(RtcpMode::kReducedSize);
|
|
}
|
|
|
|
void RtpRtcpEndToEndTest::TestRtpStatePreservation(
|
|
bool use_rtx,
|
|
bool provoke_rtcpsr_before_rtp) {
|
|
// This test uses other VideoStream settings than the the default settings
|
|
// implemented in DefaultVideoStreamFactory. Therefore this test implements
|
|
// its own VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
// in ModifyVideoConfigs.
|
|
class VideoStreamFactory
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
public:
|
|
VideoStreamFactory() {}
|
|
|
|
private:
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
int width,
|
|
int height,
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
std::vector<VideoStream> streams =
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
|
|
|
if (encoder_config.number_of_streams > 1) {
|
|
// Lower bitrates so that all streams send initially.
|
|
RTC_DCHECK_EQ(3, encoder_config.number_of_streams);
|
|
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
|
streams[i].min_bitrate_bps = 10000;
|
|
streams[i].target_bitrate_bps = 15000;
|
|
streams[i].max_bitrate_bps = 20000;
|
|
}
|
|
} else {
|
|
// Use the same total bitrates when sending a single stream to avoid
|
|
// lowering
|
|
// the bitrate estimate and requiring a subsequent rampup.
|
|
streams[0].min_bitrate_bps = 3 * 10000;
|
|
streams[0].target_bitrate_bps = 3 * 15000;
|
|
streams[0].max_bitrate_bps = 3 * 20000;
|
|
}
|
|
return streams;
|
|
}
|
|
};
|
|
|
|
class RtpSequenceObserver : public test::RtpRtcpObserver {
|
|
public:
|
|
explicit RtpSequenceObserver(bool use_rtx)
|
|
: test::RtpRtcpObserver(kDefaultTimeoutMs),
|
|
ssrcs_to_observe_(kNumSimulcastStreams) {
|
|
for (size_t i = 0; i < kNumSimulcastStreams; ++i) {
|
|
ssrc_is_rtx_[kVideoSendSsrcs[i]] = false;
|
|
if (use_rtx)
|
|
ssrc_is_rtx_[kSendRtxSsrcs[i]] = true;
|
|
}
|
|
}
|
|
|
|
void ResetExpectedSsrcs(size_t num_expected_ssrcs) {
|
|
rtc::CritScope lock(&crit_);
|
|
ssrc_observed_.clear();
|
|
ssrcs_to_observe_ = num_expected_ssrcs;
|
|
}
|
|
|
|
private:
|
|
void ValidateTimestampGap(uint32_t ssrc,
|
|
uint32_t timestamp,
|
|
bool only_padding)
|
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) {
|
|
static const int32_t kMaxTimestampGap = kDefaultTimeoutMs * 90;
|
|
auto timestamp_it = last_observed_timestamp_.find(ssrc);
|
|
if (timestamp_it == last_observed_timestamp_.end()) {
|
|
EXPECT_FALSE(only_padding);
|
|
last_observed_timestamp_[ssrc] = timestamp;
|
|
} else {
|
|
// Verify timestamps are reasonably close.
|
|
uint32_t latest_observed = timestamp_it->second;
|
|
// Wraparound handling is unnecessary here as long as an int variable
|
|
// is used to store the result.
|
|
int32_t timestamp_gap = timestamp - latest_observed;
|
|
EXPECT_LE(std::abs(timestamp_gap), kMaxTimestampGap)
|
|
<< "Gap in timestamps (" << latest_observed << " -> " << timestamp
|
|
<< ") too large for SSRC: " << ssrc << ".";
|
|
timestamp_it->second = timestamp;
|
|
}
|
|
}
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
RTPHeader header;
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
const uint32_t ssrc = header.ssrc;
|
|
const int64_t sequence_number =
|
|
seq_numbers_unwrapper_.Unwrap(header.sequenceNumber);
|
|
const uint32_t timestamp = header.timestamp;
|
|
const bool only_padding =
|
|
header.headerLength + header.paddingLength == length;
|
|
|
|
EXPECT_TRUE(ssrc_is_rtx_.find(ssrc) != ssrc_is_rtx_.end())
|
|
<< "Received SSRC that wasn't configured: " << ssrc;
|
|
|
|
static const int64_t kMaxSequenceNumberGap = 100;
|
|
std::list<int64_t>* seq_numbers = &last_observed_seq_numbers_[ssrc];
|
|
if (seq_numbers->empty()) {
|
|
seq_numbers->push_back(sequence_number);
|
|
} else {
|
|
// We shouldn't get replays of previous sequence numbers.
|
|
for (int64_t observed : *seq_numbers) {
|
|
EXPECT_NE(observed, sequence_number)
|
|
<< "Received sequence number " << sequence_number << " for SSRC "
|
|
<< ssrc << " 2nd time.";
|
|
}
|
|
// Verify sequence numbers are reasonably close.
|
|
int64_t latest_observed = seq_numbers->back();
|
|
int64_t sequence_number_gap = sequence_number - latest_observed;
|
|
EXPECT_LE(std::abs(sequence_number_gap), kMaxSequenceNumberGap)
|
|
<< "Gap in sequence numbers (" << latest_observed << " -> "
|
|
<< sequence_number << ") too large for SSRC: " << ssrc << ".";
|
|
seq_numbers->push_back(sequence_number);
|
|
if (seq_numbers->size() >= kMaxSequenceNumberGap) {
|
|
seq_numbers->pop_front();
|
|
}
|
|
}
|
|
|
|
if (!ssrc_is_rtx_[ssrc]) {
|
|
rtc::CritScope lock(&crit_);
|
|
ValidateTimestampGap(ssrc, timestamp, only_padding);
|
|
|
|
// Wait for media packets on all ssrcs.
|
|
if (!ssrc_observed_[ssrc] && !only_padding) {
|
|
ssrc_observed_[ssrc] = true;
|
|
if (--ssrcs_to_observe_ == 0)
|
|
observation_complete_.Set();
|
|
}
|
|
}
|
|
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
Action OnSendRtcp(const uint8_t* packet, size_t length) override {
|
|
test::RtcpPacketParser rtcp_parser;
|
|
rtcp_parser.Parse(packet, length);
|
|
if (rtcp_parser.sender_report()->num_packets() > 0) {
|
|
uint32_t ssrc = rtcp_parser.sender_report()->sender_ssrc();
|
|
uint32_t rtcp_timestamp = rtcp_parser.sender_report()->rtp_timestamp();
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
ValidateTimestampGap(ssrc, rtcp_timestamp, false);
|
|
}
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
SequenceNumberUnwrapper seq_numbers_unwrapper_;
|
|
std::map<uint32_t, std::list<int64_t>> last_observed_seq_numbers_;
|
|
std::map<uint32_t, uint32_t> last_observed_timestamp_;
|
|
std::map<uint32_t, bool> ssrc_is_rtx_;
|
|
|
|
rtc::CriticalSection crit_;
|
|
size_t ssrcs_to_observe_ RTC_GUARDED_BY(crit_);
|
|
std::map<uint32_t, bool> ssrc_observed_ RTC_GUARDED_BY(crit_);
|
|
} observer(use_rtx);
|
|
|
|
std::unique_ptr<test::PacketTransport> send_transport;
|
|
std::unique_ptr<test::PacketTransport> receive_transport;
|
|
|
|
VideoEncoderConfig one_stream;
|
|
|
|
task_queue_.SendTask([this, &observer, &send_transport, &receive_transport,
|
|
&one_stream, use_rtx]() {
|
|
CreateCalls();
|
|
|
|
send_transport = absl::make_unique<test::PacketTransport>(
|
|
&task_queue_, sender_call_.get(), &observer,
|
|
test::PacketTransport::kSender, payload_type_map_,
|
|
DefaultNetworkSimulationConfig());
|
|
receive_transport = absl::make_unique<test::PacketTransport>(
|
|
&task_queue_, nullptr, &observer, test::PacketTransport::kReceiver,
|
|
payload_type_map_, DefaultNetworkSimulationConfig());
|
|
send_transport->SetReceiver(receiver_call_->Receiver());
|
|
receive_transport->SetReceiver(sender_call_->Receiver());
|
|
|
|
CreateSendConfig(kNumSimulcastStreams, 0, 0, send_transport.get());
|
|
|
|
if (use_rtx) {
|
|
for (size_t i = 0; i < kNumSimulcastStreams; ++i) {
|
|
GetVideoSendConfig()->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
|
|
}
|
|
GetVideoSendConfig()->rtp.rtx.payload_type = kSendRtxPayloadType;
|
|
}
|
|
|
|
GetVideoEncoderConfig()->video_stream_factory =
|
|
new rtc::RefCountedObject<VideoStreamFactory>();
|
|
// Use the same total bitrates when sending a single stream to avoid
|
|
// lowering the bitrate estimate and requiring a subsequent rampup.
|
|
one_stream = GetVideoEncoderConfig()->Copy();
|
|
// one_stream.streams.resize(1);
|
|
one_stream.number_of_streams = 1;
|
|
CreateMatchingReceiveConfigs(receive_transport.get());
|
|
|
|
CreateVideoStreams();
|
|
CreateFrameGeneratorCapturer(30, 1280, 720);
|
|
|
|
Start();
|
|
});
|
|
|
|
EXPECT_TRUE(observer.Wait())
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
|
|
// Test stream resetting more than once to make sure that the state doesn't
|
|
// get set once (this could be due to using std::map::insert for instance).
|
|
for (size_t i = 0; i < 3; ++i) {
|
|
task_queue_.SendTask([&]() {
|
|
frame_generator_capturer_->Stop();
|
|
DestroyVideoSendStreams();
|
|
|
|
// Re-create VideoSendStream with only one stream.
|
|
CreateVideoSendStream(one_stream);
|
|
GetVideoSendStream()->Start();
|
|
if (provoke_rtcpsr_before_rtp) {
|
|
// Rapid Resync Request forces sending RTCP Sender Report back.
|
|
// Using this request speeds up this test because then there is no need
|
|
// to wait for a second for periodic Sender Report.
|
|
rtcp::RapidResyncRequest force_send_sr_back_request;
|
|
rtc::Buffer packet = force_send_sr_back_request.Build();
|
|
static_cast<webrtc::test::DirectTransport*>(receive_transport.get())
|
|
->SendRtcp(packet.data(), packet.size());
|
|
}
|
|
CreateFrameGeneratorCapturer(30, 1280, 720);
|
|
frame_generator_capturer_->Start();
|
|
});
|
|
|
|
observer.ResetExpectedSsrcs(1);
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for single RTP packet.";
|
|
|
|
// Reconfigure back to use all streams.
|
|
task_queue_.SendTask([this]() {
|
|
GetVideoSendStream()->ReconfigureVideoEncoder(
|
|
GetVideoEncoderConfig()->Copy());
|
|
});
|
|
observer.ResetExpectedSsrcs(kNumSimulcastStreams);
|
|
EXPECT_TRUE(observer.Wait())
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
|
|
// Reconfigure down to one stream.
|
|
task_queue_.SendTask([this, &one_stream]() {
|
|
GetVideoSendStream()->ReconfigureVideoEncoder(one_stream.Copy());
|
|
});
|
|
observer.ResetExpectedSsrcs(1);
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for single RTP packet.";
|
|
|
|
// Reconfigure back to use all streams.
|
|
task_queue_.SendTask([this]() {
|
|
GetVideoSendStream()->ReconfigureVideoEncoder(
|
|
GetVideoEncoderConfig()->Copy());
|
|
});
|
|
observer.ResetExpectedSsrcs(kNumSimulcastStreams);
|
|
EXPECT_TRUE(observer.Wait())
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
}
|
|
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport]() {
|
|
Stop();
|
|
DestroyStreams();
|
|
send_transport.reset();
|
|
receive_transport.reset();
|
|
DestroyCalls();
|
|
});
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest, RestartingSendStreamPreservesRtpState) {
|
|
TestRtpStatePreservation(false, false);
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest, RestartingSendStreamPreservesRtpStatesWithRtx) {
|
|
TestRtpStatePreservation(true, false);
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest,
|
|
RestartingSendStreamKeepsRtpAndRtcpTimestampsSynced) {
|
|
TestRtpStatePreservation(true, true);
|
|
}
|
|
|
|
TEST_F(RtpRtcpEndToEndTest, TestFlexfecRtpStatePreservation) {
|
|
class RtpSequenceObserver : public test::RtpRtcpObserver {
|
|
public:
|
|
RtpSequenceObserver()
|
|
: test::RtpRtcpObserver(kDefaultTimeoutMs),
|
|
num_flexfec_packets_sent_(0) {}
|
|
|
|
void ResetPacketCount() {
|
|
rtc::CritScope lock(&crit_);
|
|
num_flexfec_packets_sent_ = 0;
|
|
}
|
|
|
|
private:
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
RTPHeader header;
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
const uint16_t sequence_number = header.sequenceNumber;
|
|
const uint32_t timestamp = header.timestamp;
|
|
const uint32_t ssrc = header.ssrc;
|
|
|
|
if (ssrc == kVideoSendSsrcs[0] || ssrc == kSendRtxSsrcs[0]) {
|
|
return SEND_PACKET;
|
|
}
|
|
EXPECT_EQ(kFlexfecSendSsrc, ssrc) << "Unknown SSRC sent.";
|
|
|
|
++num_flexfec_packets_sent_;
|
|
|
|
// If this is the first packet, we have nothing to compare to.
|
|
if (!last_observed_sequence_number_) {
|
|
last_observed_sequence_number_.emplace(sequence_number);
|
|
last_observed_timestamp_.emplace(timestamp);
|
|
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
// Verify continuity and monotonicity of RTP sequence numbers.
|
|
EXPECT_EQ(static_cast<uint16_t>(*last_observed_sequence_number_ + 1),
|
|
sequence_number);
|
|
last_observed_sequence_number_.emplace(sequence_number);
|
|
|
|
// Timestamps should be non-decreasing...
|
|
const bool timestamp_is_same_or_newer =
|
|
timestamp == *last_observed_timestamp_ ||
|
|
IsNewerTimestamp(timestamp, *last_observed_timestamp_);
|
|
EXPECT_TRUE(timestamp_is_same_or_newer);
|
|
// ...but reasonably close in time.
|
|
const int k10SecondsInRtpTimestampBase = 10 * kVideoPayloadTypeFrequency;
|
|
EXPECT_TRUE(IsNewerTimestamp(
|
|
*last_observed_timestamp_ + k10SecondsInRtpTimestampBase, timestamp));
|
|
last_observed_timestamp_.emplace(timestamp);
|
|
|
|
// Pass test when enough packets have been let through.
|
|
if (num_flexfec_packets_sent_ >= 10) {
|
|
observation_complete_.Set();
|
|
}
|
|
|
|
return SEND_PACKET;
|
|
}
|
|
|
|
absl::optional<uint16_t> last_observed_sequence_number_
|
|
RTC_GUARDED_BY(crit_);
|
|
absl::optional<uint32_t> last_observed_timestamp_ RTC_GUARDED_BY(crit_);
|
|
size_t num_flexfec_packets_sent_ RTC_GUARDED_BY(crit_);
|
|
rtc::CriticalSection crit_;
|
|
} observer;
|
|
|
|
static constexpr int kFrameMaxWidth = 320;
|
|
static constexpr int kFrameMaxHeight = 180;
|
|
static constexpr int kFrameRate = 15;
|
|
|
|
std::unique_ptr<test::PacketTransport> send_transport;
|
|
std::unique_ptr<test::PacketTransport> receive_transport;
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return VP8Encoder::Create(); });
|
|
|
|
task_queue_.SendTask([&]() {
|
|
CreateCalls();
|
|
|
|
DefaultNetworkSimulationConfig lossy_delayed_link;
|
|
lossy_delayed_link.loss_percent = 2;
|
|
lossy_delayed_link.queue_delay_ms = 50;
|
|
|
|
send_transport = absl::make_unique<test::PacketTransport>(
|
|
&task_queue_, sender_call_.get(), &observer,
|
|
test::PacketTransport::kSender, payload_type_map_, lossy_delayed_link);
|
|
send_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
DefaultNetworkSimulationConfig flawless_link;
|
|
receive_transport = absl::make_unique<test::PacketTransport>(
|
|
&task_queue_, nullptr, &observer, test::PacketTransport::kReceiver,
|
|
payload_type_map_, flawless_link);
|
|
receive_transport->SetReceiver(sender_call_->Receiver());
|
|
|
|
// For reduced flakyness, we use a real VP8 encoder together with NACK
|
|
// and RTX.
|
|
const int kNumVideoStreams = 1;
|
|
const int kNumFlexfecStreams = 1;
|
|
CreateSendConfig(kNumVideoStreams, 0, kNumFlexfecStreams,
|
|
send_transport.get());
|
|
|
|
GetVideoSendConfig()->encoder_settings.encoder_factory = &encoder_factory;
|
|
GetVideoSendConfig()->rtp.payload_name = "VP8";
|
|
GetVideoSendConfig()->rtp.payload_type = kVideoSendPayloadType;
|
|
GetVideoSendConfig()->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
GetVideoSendConfig()->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
|
GetVideoSendConfig()->rtp.rtx.payload_type = kSendRtxPayloadType;
|
|
GetVideoEncoderConfig()->codec_type = kVideoCodecVP8;
|
|
|
|
CreateMatchingReceiveConfigs(receive_transport.get());
|
|
video_receive_configs_[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
video_receive_configs_[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
|
video_receive_configs_[0]
|
|
.rtp.rtx_associated_payload_types[kSendRtxPayloadType] =
|
|
kVideoSendPayloadType;
|
|
|
|
// The matching FlexFEC receive config is not created by
|
|
// CreateMatchingReceiveConfigs since this is not a test::BaseTest.
|
|
// Set up the receive config manually instead.
|
|
FlexfecReceiveStream::Config flexfec_receive_config(
|
|
receive_transport.get());
|
|
flexfec_receive_config.payload_type =
|
|
GetVideoSendConfig()->rtp.flexfec.payload_type;
|
|
flexfec_receive_config.remote_ssrc = GetVideoSendConfig()->rtp.flexfec.ssrc;
|
|
flexfec_receive_config.protected_media_ssrcs =
|
|
GetVideoSendConfig()->rtp.flexfec.protected_media_ssrcs;
|
|
flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc;
|
|
flexfec_receive_config.transport_cc = true;
|
|
flexfec_receive_config.rtp_header_extensions.emplace_back(
|
|
RtpExtension::kTransportSequenceNumberUri,
|
|
test::kTransportSequenceNumberExtensionId);
|
|
flexfec_receive_configs_.push_back(flexfec_receive_config);
|
|
|
|
CreateFlexfecStreams();
|
|
CreateVideoStreams();
|
|
|
|
// RTCP might be disabled if the network is "down".
|
|
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
|
|
|
Start();
|
|
});
|
|
|
|
// Initial test.
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
task_queue_.SendTask([this, &observer]() {
|
|
// Ensure monotonicity when the VideoSendStream is restarted.
|
|
Stop();
|
|
observer.ResetPacketCount();
|
|
Start();
|
|
});
|
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
task_queue_.SendTask([this, &observer]() {
|
|
// Ensure monotonicity when the VideoSendStream is recreated.
|
|
frame_generator_capturer_->Stop();
|
|
DestroyVideoSendStreams();
|
|
observer.ResetPacketCount();
|
|
CreateVideoSendStreams();
|
|
GetVideoSendStream()->Start();
|
|
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
|
frame_generator_capturer_->Start();
|
|
});
|
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
// Cleanup.
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport]() {
|
|
Stop();
|
|
DestroyStreams();
|
|
send_transport.reset();
|
|
receive_transport.reset();
|
|
DestroyCalls();
|
|
});
|
|
}
|
|
} // namespace webrtc
|