Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters.

Prior to this CL, received RTX (associated) payload types were only configured
when WebRtcVideoChannel2::AddRecvStream was called. In the same method, the RTX
SSRC was set up.

After this CL, the RTX (associated) payload types are set in
WebRtcVideoChannel2::SetRecvParameters, which is the appropriate place to set
them. The RTX SSRC is still set in WebRtcVideoChannel2::AddRecvStream, since
that is the code path that sets other SSRCs.

As part of this fix, the VideoReceiveStream::Config::Rtp struct is changed.
We remove the possibility for each video payload type to have an associated
specific RTX SSRC. Although the config previously allowed for this, all payload
types always had the same RTX SSRC set, and the underlying RtpPayloadRegistry
did not support multiple SSRCs. This change to the config struct should thus not
have any functional impact. The change does however affect the RtcEventLog, since
that is used for storing the VideoReceiveStream::Configs. For simplicity,
this CL does not change the event log proto definitions, instead duplicating
the serialized RTX SSRCs such that they fit in the existing proto definition.

BUG=webrtc:7011

Review-Url: https://codereview.webrtc.org/2646073004
Cr-Commit-Position: refs/heads/master@{#16302}
This commit is contained in:
brandtr 2017-01-26 08:03:58 -08:00 committed by Commit bot
parent 4703741e49
commit fe2bef39cd
15 changed files with 178 additions and 104 deletions

View File

@ -649,11 +649,8 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
video_receive_ssrcs_.end());
video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
// TODO(pbos): Configure different RTX payloads per receive payload.
VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it =
config.rtp.rtx.begin();
if (it != config.rtp.rtx.end())
video_receive_ssrcs_[it->second.ssrc] = receive_stream;
if (config.rtp.rtx_ssrc)
video_receive_ssrcs_[config.rtp.rtx_ssrc] = receive_stream;
video_receive_streams_.insert(receive_stream);
ConfigureSync(config.sync_group);
}

View File

@ -199,10 +199,10 @@ void RampUpTester::ModifyVideoConfigs(
}
if (rtx_) {
recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc =
video_rtx_ssrcs_[i];
recv_config.rtp.rtx[send_config->encoder_settings.payload_type]
.payload_type = send_config->rtp.rtx.payload_type;
recv_config.rtp.rtx_ssrc = video_rtx_ssrcs_[i];
recv_config.rtp
.rtx_payload_types[send_config->encoder_settings.payload_type] =
send_config->rtp.rtx.payload_type;
}
++i;
}

View File

@ -242,11 +242,11 @@ void RtcEventLogImpl::LogVideoReceiveStreamConfig(
receiver_config->set_rtcp_mode(ConvertRtcpMode(config.rtp.rtcp_mode));
receiver_config->set_remb(config.rtp.remb);
for (const auto& kv : config.rtp.rtx) {
for (const auto& kv : config.rtp.rtx_payload_types) {
rtclog::RtxMap* rtx = receiver_config->add_rtx_map();
rtx->set_payload_type(kv.first);
rtx->mutable_config()->set_rtx_ssrc(kv.second.ssrc);
rtx->mutable_config()->set_rtx_payload_type(kv.second.payload_type);
rtx->mutable_config()->set_rtx_ssrc(config.rtp.rtx_ssrc);
rtx->mutable_config()->set_rtx_payload_type(kv.second);
}
for (const auto& e : config.rtp.extensions) {

View File

@ -10,8 +10,10 @@
#include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h"
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include <fstream>
#include <istream>
#include <utility>
@ -314,17 +316,30 @@ void ParsedRtcEventLog::GetVideoReceiveConfig(
RTC_CHECK(receiver_config.has_remb());
config->rtp.remb = receiver_config.remb();
// Get RTX map.
config->rtp.rtx.clear();
std::vector<uint32_t> rtx_ssrcs(receiver_config.rtx_map_size());
config->rtp.rtx_payload_types.clear();
for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
const rtclog::RtxMap& map = receiver_config.rtx_map(i);
RTC_CHECK(map.has_payload_type());
RTC_CHECK(map.has_config());
RTC_CHECK(map.config().has_rtx_ssrc());
rtx_ssrcs[i] = map.config().rtx_ssrc();
RTC_CHECK(map.config().has_rtx_payload_type());
webrtc::VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
rtx_pair.ssrc = map.config().rtx_ssrc();
rtx_pair.payload_type = map.config().rtx_payload_type();
config->rtp.rtx.insert(std::make_pair(map.payload_type(), rtx_pair));
config->rtp.rtx_payload_types.insert(
std::make_pair(map.payload_type(), map.config().rtx_payload_type()));
}
if (!rtx_ssrcs.empty()) {
config->rtp.rtx_ssrc = rtx_ssrcs[0];
auto pred = [&config](uint32_t ssrc) {
return ssrc == config->rtp.rtx_ssrc;
};
if (!std::all_of(rtx_ssrcs.cbegin(), rtx_ssrcs.cend(), pred)) {
LOG(LS_WARNING) << "RtcEventLog protobuf contained different SSRCs for "
"different received RTX payload types. Will only use "
"rtx_ssrc = "
<< config->rtp.rtx_ssrc << ".";
}
}
// Get header extensions.
GetHeaderExtensions(&config->rtp.extensions,

View File

@ -165,11 +165,10 @@ void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
config->rtp.rtcp_mode =
prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize;
config->rtp.remb = prng->Rand<bool>();
// Add a map from a payload type to a new ssrc and a new payload type for RTX.
VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
rtx_pair.ssrc = prng->Rand<uint32_t>();
rtx_pair.payload_type = prng->Rand(0, 127);
config->rtp.rtx.insert(std::make_pair(prng->Rand(0, 127), rtx_pair));
config->rtp.rtx_ssrc = prng->Rand<uint32_t>();
// Add a map from a payload type to a new payload type for RTX.
config->rtp.rtx_payload_types.insert(
std::make_pair(prng->Rand(0, 127), prng->Rand(0, 127)));
// Add header extensions.
for (unsigned i = 0; i < kNumExtensions; i++) {
if (extensions_bitvector & (1u << i)) {

View File

@ -127,19 +127,18 @@ void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(
ASSERT_TRUE(receiver_config.has_remb());
EXPECT_EQ(config.rtp.remb, receiver_config.remb());
// Check RTX map.
ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()),
ASSERT_EQ(static_cast<int>(config.rtp.rtx_payload_types.size()),
receiver_config.rtx_map_size());
for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) {
ASSERT_TRUE(rtx_map.has_payload_type());
ASSERT_TRUE(rtx_map.has_config());
EXPECT_EQ(1u, config.rtp.rtx.count(rtx_map.payload_type()));
EXPECT_EQ(1u, config.rtp.rtx_payload_types.count(rtx_map.payload_type()));
const rtclog::RtxConfig& rtx_config = rtx_map.config();
const VideoReceiveStream::Config::Rtp::Rtx& rtx =
config.rtp.rtx.at(rtx_map.payload_type());
ASSERT_TRUE(rtx_config.has_rtx_ssrc());
ASSERT_TRUE(rtx_config.has_rtx_payload_type());
EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc());
EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type());
EXPECT_EQ(config.rtp.rtx_ssrc, rtx_config.rtx_ssrc());
EXPECT_EQ(config.rtp.rtx_payload_types.at(rtx_map.payload_type()),
rtx_config.rtx_payload_type());
}
// Check header extensions.
ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
@ -173,12 +172,13 @@ void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(
EXPECT_EQ(config.rtp.rtcp_mode, parsed_config.rtp.rtcp_mode);
EXPECT_EQ(config.rtp.remb, parsed_config.rtp.remb);
// Check RTX map.
EXPECT_EQ(config.rtp.rtx.size(), parsed_config.rtp.rtx.size());
for (const auto& kv : config.rtp.rtx) {
auto parsed_kv = parsed_config.rtp.rtx.find(kv.first);
EXPECT_EQ(config.rtp.rtx_ssrc, parsed_config.rtp.rtx_ssrc);
EXPECT_EQ(config.rtp.rtx_payload_types.size(),
parsed_config.rtp.rtx_payload_types.size());
for (const auto& kv : config.rtp.rtx_payload_types) {
auto parsed_kv = parsed_config.rtp.rtx_payload_types.find(kv.first);
EXPECT_EQ(kv.first, parsed_kv->first);
EXPECT_EQ(kv.second.ssrc, parsed_kv->second.ssrc);
EXPECT_EQ(kv.second.payload_type, parsed_kv->second.payload_type);
EXPECT_EQ(kv.second, parsed_kv->second);
}
// Check header extensions.
EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());

View File

@ -1233,16 +1233,7 @@ void WebRtcVideoChannel2::ConfigureReceiverRtp(
flexfec_config->rtp_header_extensions = config->rtp.extensions;
}
for (size_t i = 0; i < recv_codecs_.size(); ++i) {
uint32_t rtx_ssrc;
if (recv_codecs_[i].rtx_payload_type != -1 &&
sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
webrtc::VideoReceiveStream::Config::Rtp::Rtx& rtx =
config->rtp.rtx[recv_codecs_[i].codec.id];
rtx.ssrc = rtx_ssrc;
rtx.payload_type = recv_codecs_[i].rtx_payload_type;
}
}
sp.GetFidSsrc(ssrc, &config->rtp.rtx_ssrc);
config->rtp.extensions = recv_rtp_extensions_;
}
@ -2205,7 +2196,12 @@ void WebRtcVideoChannel2::WebRtcVideoReceiveStream::ConfigureCodecs(
config_.decoders.push_back(decoder);
}
// TODO(pbos): Reconfigure RTX based on incoming recv_codecs.
config_.rtp.rtx_payload_types.clear();
for (const VideoCodecSettings& recv_codec : recv_codecs) {
config_.rtp.rtx_payload_types[recv_codec.codec.id] =
recv_codec.rtx_payload_type;
}
config_.rtp.ulpfec = recv_codecs.front().ulpfec;
flexfec_config_.payload_type = recv_codecs.front().flexfec_payload_type;

View File

@ -1228,13 +1228,11 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamWithSimAndRtx) {
// Receiver side.
FakeVideoReceiveStream* recv_stream = AddRecvStream(
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx.empty());
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx_payload_types.empty());
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
recv_stream->GetConfig().rtp.rtx.size())
recv_stream->GetConfig().rtp.rtx_payload_types.size())
<< "RTX should be mapped for all decoders/payload types.";
for (const auto& kv : recv_stream->GetConfig().rtp.rtx) {
EXPECT_EQ(rtx_ssrcs[0], kv.second.ssrc);
}
EXPECT_EQ(rtx_ssrcs[0], recv_stream->GetConfig().rtp.rtx_ssrc);
}
TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
@ -1243,8 +1241,7 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
EXPECT_EQ(kRtxSsrcs1[0],
recv_stream->GetConfig().rtp.rtx.begin()->second.ssrc);
EXPECT_EQ(kRtxSsrcs1[0], recv_stream->GetConfig().rtp.rtx_ssrc);
}
TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
@ -1252,7 +1249,7 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
ASSERT_TRUE(recv_stream->GetConfig().rtp.rtx.empty());
ASSERT_EQ(0U, recv_stream->GetConfig().rtp.rtx_ssrc);
}
TEST_F(WebRtcVideoChannel2Test, NoHeaderExtesionsByDefault) {
@ -2482,6 +2479,43 @@ TEST_F(WebRtcVideoChannel2Test,
}
}
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithChangedRtxPayloadType) {
const int kUnusedPayloadType1 = 126;
const int kUnusedPayloadType2 = 127;
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType1));
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType2));
// SSRCs for RTX.
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
AddSendStream(params);
// Original payload type for RTX.
cricket::VideoSendParameters parameters;
parameters.codecs.push_back(GetEngineCodec("VP8"));
cricket::VideoCodec rtx_codec(kUnusedPayloadType1, "rtx");
rtx_codec.SetParam("apt", GetEngineCodec("VP8").id);
parameters.codecs.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetSendParameters(parameters));
ASSERT_EQ(1U, fake_call_->GetVideoSendStreams().size());
const webrtc::VideoSendStream::Config& config_before =
fake_call_->GetVideoSendStreams()[0]->GetConfig();
EXPECT_EQ(kUnusedPayloadType1, config_before.rtp.rtx.payload_type);
ASSERT_EQ(1U, config_before.rtp.rtx.ssrcs.size());
EXPECT_EQ(kRtxSsrcs1[0], config_before.rtp.rtx.ssrcs[0]);
// Change payload type for RTX.
parameters.codecs[1].id = kUnusedPayloadType2;
EXPECT_TRUE(channel_->SetSendParameters(parameters));
ASSERT_EQ(1U, fake_call_->GetVideoSendStreams().size());
const webrtc::VideoSendStream::Config& config_after =
fake_call_->GetVideoSendStreams()[0]->GetConfig();
EXPECT_EQ(kUnusedPayloadType2, config_after.rtp.rtx.payload_type);
ASSERT_EQ(1U, config_after.rtp.rtx.ssrcs.size());
EXPECT_EQ(kRtxSsrcs1[0], config_after.rtp.rtx.ssrcs[0]);
}
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithoutFecDisablesFec) {
cricket::VideoSendParameters parameters;
parameters.codecs.push_back(GetEngineCodec("VP8"));
@ -2812,6 +2846,49 @@ TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithRtx) {
"rejected.";
}
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithChangedRtxPayloadType) {
const int kUnusedPayloadType1 = 126;
const int kUnusedPayloadType2 = 127;
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType1));
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType2));
// SSRCs for RTX.
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
AddRecvStream(params);
// Original payload type for RTX.
cricket::VideoRecvParameters parameters;
parameters.codecs.push_back(GetEngineCodec("VP8"));
cricket::VideoCodec rtx_codec(kUnusedPayloadType1, "rtx");
rtx_codec.SetParam("apt", GetEngineCodec("VP8").id);
parameters.codecs.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
ASSERT_EQ(1U, fake_call_->GetVideoReceiveStreams().size());
const webrtc::VideoReceiveStream::Config& config_before =
fake_call_->GetVideoReceiveStreams()[0]->GetConfig();
EXPECT_EQ(1U, config_before.rtp.rtx_payload_types.size());
auto it_before =
config_before.rtp.rtx_payload_types.find(GetEngineCodec("VP8").id);
ASSERT_NE(it_before, config_before.rtp.rtx_payload_types.end());
EXPECT_EQ(kUnusedPayloadType1, it_before->second);
EXPECT_EQ(kRtxSsrcs1[0], config_before.rtp.rtx_ssrc);
// Change payload type for RTX.
parameters.codecs[1].id = kUnusedPayloadType2;
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
ASSERT_EQ(1U, fake_call_->GetVideoReceiveStreams().size());
const webrtc::VideoReceiveStream::Config& config_after =
fake_call_->GetVideoReceiveStreams()[0]->GetConfig();
EXPECT_EQ(1U, config_after.rtp.rtx_payload_types.size());
auto it_after =
config_after.rtp.rtx_payload_types.find(GetEngineCodec("VP8").id);
ASSERT_NE(it_after, config_after.rtp.rtx_payload_types.end());
EXPECT_EQ(kUnusedPayloadType2, it_after->second);
EXPECT_EQ(kRtxSsrcs1[0], config_after.rtp.rtx_ssrc);
}
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsDifferentPayloadType) {
cricket::VideoRecvParameters parameters;
parameters.codecs.push_back(GetEngineCodec("VP8"));
@ -3441,21 +3518,19 @@ TEST_F(WebRtcVideoChannel2Test, DefaultReceiveStreamReconfiguresToUseRtx) {
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
<< "No default receive stream created.";
FakeVideoReceiveStream* recv_stream = fake_call_->GetVideoReceiveStreams()[0];
EXPECT_TRUE(recv_stream->GetConfig().rtp.rtx.empty())
EXPECT_EQ(0u, recv_stream->GetConfig().rtp.rtx_ssrc)
<< "Default receive stream should not have configured RTX";
EXPECT_TRUE(channel_->AddRecvStream(
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs)));
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
<< "AddRecvStream should've reconfigured, not added a new receiver.";
<< "AddRecvStream should have reconfigured, not added a new receiver.";
recv_stream = fake_call_->GetVideoReceiveStreams()[0];
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx.empty());
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx_payload_types.empty());
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
recv_stream->GetConfig().rtp.rtx.size())
recv_stream->GetConfig().rtp.rtx_payload_types.size())
<< "RTX should be mapped for all decoders/payload types.";
for (const auto& kv : recv_stream->GetConfig().rtp.rtx) {
EXPECT_EQ(rtx_ssrcs[0], kv.second.ssrc);
}
EXPECT_EQ(rtx_ssrcs[0], recv_stream->GetConfig().rtp.rtx_ssrc);
}
TEST_F(WebRtcVideoChannel2Test, RejectsAddingStreamsWithMissingSsrcsForRtx) {

View File

@ -311,13 +311,11 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
StreamId stream(config.rtp.remote_ssrc, kIncomingPacket);
extension_maps[stream] = RtpHeaderExtensionMap(config.rtp.extensions);
video_ssrcs_.insert(stream);
for (auto kv : config.rtp.rtx) {
StreamId rtx_stream(kv.second.ssrc, kIncomingPacket);
extension_maps[rtx_stream] =
RtpHeaderExtensionMap(config.rtp.extensions);
video_ssrcs_.insert(rtx_stream);
rtx_ssrcs_.insert(rtx_stream);
}
StreamId rtx_stream(config.rtp.rtx_ssrc, kIncomingPacket);
extension_maps[rtx_stream] =
RtpHeaderExtensionMap(config.rtp.extensions);
video_ssrcs_.insert(rtx_stream);
rtx_ssrcs_.insert(rtx_stream);
break;
}
case ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: {

View File

@ -1091,8 +1091,8 @@ void EndToEndTest::DecodesRetransmittedFrame(bool enable_rtx, bool enable_red) {
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
(*receive_configs)[0].rtp.rtx[payload_type_].ssrc = kSendRtxSsrcs[0];
(*receive_configs)[0].rtp.rtx[payload_type_].payload_type =
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
(*receive_configs)[0].rtp.rtx_payload_types[payload_type_] =
kSendRtxPayloadType;
}
// Configure encoding and decoding with VP8, since generic packetization
@ -2331,9 +2331,8 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx,
if (use_rtx_) {
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
(*receive_configs)[0].rtp.rtx[kFakeVideoSendPayloadType].ssrc =
kSendRtxSsrcs[0];
(*receive_configs)[0].rtp.rtx[kFakeVideoSendPayloadType].payload_type =
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
(*receive_configs)[0].rtp.rtx_payload_types[kFakeVideoSendPayloadType] =
kSendRtxPayloadType;
}
// RTT needed for RemoteNtpTimeEstimator for the receive stream.
@ -2953,9 +2952,8 @@ TEST_P(EndToEndTest, GetStats) {
(*receive_configs)[i].renderer = &receive_stream_renderer_;
(*receive_configs)[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
(*receive_configs)[i].rtp.rtx[kFakeVideoSendPayloadType].ssrc =
kSendRtxSsrcs[i];
(*receive_configs)[i].rtp.rtx[kFakeVideoSendPayloadType].payload_type =
(*receive_configs)[i].rtp.rtx_ssrc = kSendRtxSsrcs[i];
(*receive_configs)[i].rtp.rtx_payload_types[kFakeVideoSendPayloadType] =
kSendRtxPayloadType;
}
@ -3939,7 +3937,9 @@ TEST_P(EndToEndTest, VerifyDefaultVideoReceiveConfigParameters) {
EXPECT_FALSE(
default_receive_config.rtp.rtcp_xr.receiver_reference_time_report)
<< "RTCP XR settings require rtcp-xr to be negotiated.";
EXPECT_TRUE(default_receive_config.rtp.rtx.empty())
EXPECT_EQ(0U, default_receive_config.rtp.rtx_ssrc)
<< "Enabling RTX requires ssrc-group: FID negotiation";
EXPECT_TRUE(default_receive_config.rtp.rtx_payload_types.empty())
<< "Enabling RTX requires rtpmap: rtx negotiation.";
EXPECT_TRUE(default_receive_config.rtp.extensions.empty())
<< "Enabling RTP extensions require negotiation.";

View File

@ -78,8 +78,11 @@ ReceiveStatisticsProxy::ReceiveStatisticsProxy(
avg_rtt_ms_(0),
frame_window_accumulated_bytes_(0) {
stats_.ssrc = config_.rtp.remote_ssrc;
for (auto it : config_.rtp.rtx)
rtx_stats_[it.second.ssrc] = StreamDataCounters();
// TODO(brandtr): Replace |rtx_stats_| with a single instance of
// StreamDataCounters.
if (config_.rtp.rtx_ssrc) {
rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters();
}
}
ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {

View File

@ -150,14 +150,13 @@ RtpStreamReceiver::RtpStreamReceiver(
: kDefaultMaxReorderingThreshold;
rtp_receive_statistics_->SetMaxReorderingThreshold(max_reordering_threshold);
// TODO(pbos): Support multiple RTX, per video payload.
for (const auto& kv : config_.rtp.rtx) {
RTC_DCHECK(kv.second.ssrc != 0);
RTC_DCHECK(kv.second.payload_type != 0);
if (config_.rtp.rtx_ssrc) {
rtp_payload_registry_.SetRtxSsrc(config_.rtp.rtx_ssrc);
rtp_payload_registry_.SetRtxSsrc(kv.second.ssrc);
rtp_payload_registry_.SetRtxPayloadType(kv.second.payload_type,
kv.first);
for (const auto& kv : config_.rtp.rtx_payload_types) {
RTC_DCHECK(kv.second != 0);
rtp_payload_registry_.SetRtxPayloadType(kv.second, kv.first);
}
}
if (IsUlpfecEnabled()) {

View File

@ -1124,8 +1124,8 @@ void VideoQualityTest::SetupVideo(Transport* send_transport,
for (size_t i = 0; i < num_video_streams; ++i) {
video_receive_configs_[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
video_receive_configs_[i].rtp.rtx[payload_type].ssrc = kSendRtxSsrcs[i];
video_receive_configs_[i].rtp.rtx[payload_type].payload_type =
video_receive_configs_[i].rtp.rtx_ssrc = kSendRtxSsrcs[i];
video_receive_configs_[i].rtp.rtx_payload_types[payload_type] =
kSendRtxPayloadType;
video_receive_configs_[i].rtp.transport_cc = params_.call.send_side_bwe;
}

View File

@ -100,12 +100,10 @@ std::string VideoReceiveStream::Config::Rtp::ToString() const {
ss << ", transport_cc: " << (transport_cc ? "on" : "off");
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
ss << ", ulpfec: " << ulpfec.ToString();
ss << ", rtx: {";
for (auto& kv : rtx) {
ss << kv.first << " -> ";
ss << "{ssrc: " << kv.second.ssrc;
ss << ", payload_type: " << kv.second.payload_type;
ss << '}';
ss << ", rtx_ssrc: " << rtx_ssrc;
ss << ", rtx_payload_types: {";
for (auto& kv : rtx_payload_types) {
ss << kv.first << " (apt) -> " << kv.second << " (pt), ";
}
ss << '}';
ss << ", extensions: [";

View File

@ -117,6 +117,7 @@ class VideoReceiveStream {
// Synchronization source (stream identifier) to be received.
uint32_t remote_ssrc = 0;
// Sender SSRC used for sending RTCP (such as receiver reports).
uint32_t local_ssrc = 0;
@ -142,19 +143,12 @@ class VideoReceiveStream {
// See UlpfecConfig for description.
UlpfecConfig ulpfec;
// RTX settings for incoming video payloads that may be received. RTX is
// disabled if there's no config present.
struct Rtx {
// SSRCs to use for the RTX streams.
uint32_t ssrc = 0;
// SSRC for retransmissions.
uint32_t rtx_ssrc = 0;
// Payload type to use for the RTX stream.
int payload_type = 0;
};
// Map from video RTP payload type -> RTX config.
typedef std::map<int, Rtx> RtxMap;
RtxMap rtx;
// Map from video payload type (apt) -> RTX payload type (pt).
// For RTX to be enabled, both an SSRC and this mapping are needed.
std::map<int, int> rtx_payload_types;
// RTP header extensions used for the received stream.
std::vector<RtpExtension> extensions;