Potential fix for rtx/red issue where red is removed only from the remote description.
BUG=5675
R=pbos@webrtc.org
Review URL: https://codereview.webrtc.org/1964473002 .
Cr-Commit-Position: refs/heads/master@{#12776}
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index d4360b8..d81c849 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -263,39 +263,6 @@
return false;
}
-// Merges two fec configs and logs an error if a conflict arises
-// such that merging in different order would trigger a different output.
-static void MergeFecConfig(const webrtc::FecConfig& other,
- webrtc::FecConfig* output) {
- if (other.ulpfec_payload_type != -1) {
- if (output->ulpfec_payload_type != -1 &&
- output->ulpfec_payload_type != other.ulpfec_payload_type) {
- LOG(LS_WARNING) << "Conflict merging ulpfec_payload_type configs: "
- << output->ulpfec_payload_type << " and "
- << other.ulpfec_payload_type;
- }
- output->ulpfec_payload_type = other.ulpfec_payload_type;
- }
- if (other.red_payload_type != -1) {
- if (output->red_payload_type != -1 &&
- output->red_payload_type != other.red_payload_type) {
- LOG(LS_WARNING) << "Conflict merging red_payload_type configs: "
- << output->red_payload_type << " and "
- << other.red_payload_type;
- }
- output->red_payload_type = other.red_payload_type;
- }
- if (other.red_rtx_payload_type != -1) {
- if (output->red_rtx_payload_type != -1 &&
- output->red_rtx_payload_type != other.red_rtx_payload_type) {
- LOG(LS_WARNING) << "Conflict merging red_rtx_payload_type configs: "
- << output->red_rtx_payload_type << " and "
- << other.red_rtx_payload_type;
- }
- output->red_rtx_payload_type = other.red_rtx_payload_type;
- }
-}
-
// Returns true if the given codec is disallowed from doing simulcast.
bool IsCodecBlacklistedForSimulcast(const std::string& codec_name) {
return CodecNamesEq(codec_name, kH264CodecName) ||
@@ -682,7 +649,8 @@
video_config_(config.video),
external_encoder_factory_(external_encoder_factory),
external_decoder_factory_(external_decoder_factory),
- default_send_options_(options) {
+ default_send_options_(options),
+ red_disabled_by_remote_side_(false) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
@@ -872,6 +840,19 @@
: webrtc::RtcpMode::kCompound);
}
}
+ if (changed_params.codec) {
+ bool red_was_disabled = red_disabled_by_remote_side_;
+ red_disabled_by_remote_side_ =
+ changed_params.codec->fec.red_payload_type == -1;
+ if (red_was_disabled != red_disabled_by_remote_side_) {
+ for (auto& kv : receive_streams_) {
+ // In practice VideoChannel::SetRemoteContent appears to most of the
+ // time also call UpdateRemoteStreams, which recreates the receive
+ // streams. If that's always true this call isn't needed.
+ kv.second->SetFecDisabledRemotely(red_disabled_by_remote_side_);
+ }
+ }
+ }
}
send_params_ = params;
return true;
@@ -1237,7 +1218,7 @@
receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
call_, sp, config, external_decoder_factory_, default_stream,
- recv_codecs_);
+ recv_codecs_, red_disabled_by_remote_side_);
return true;
}
@@ -1273,10 +1254,6 @@
}
for (size_t i = 0; i < recv_codecs_.size(); ++i) {
- MergeFecConfig(recv_codecs_[i].fec, &config->rtp.fec);
- }
-
- 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)) {
@@ -2239,13 +2216,15 @@
const webrtc::VideoReceiveStream::Config& config,
WebRtcVideoDecoderFactory* external_decoder_factory,
bool default_stream,
- const std::vector<VideoCodecSettings>& recv_codecs)
+ const std::vector<VideoCodecSettings>& recv_codecs,
+ bool red_disabled_by_remote_side)
: call_(call),
ssrcs_(sp.ssrcs),
ssrc_groups_(sp.ssrc_groups),
stream_(NULL),
default_stream_(default_stream),
config_(config),
+ red_disabled_by_remote_side_(red_disabled_by_remote_side),
external_decoder_factory_(external_decoder_factory),
sink_(NULL),
last_width_(-1),
@@ -2421,7 +2400,13 @@
if (stream_ != NULL) {
call_->DestroyVideoReceiveStream(stream_);
}
- stream_ = call_->CreateVideoReceiveStream(config_);
+ webrtc::VideoReceiveStream::Config config = config_;
+ if (red_disabled_by_remote_side_) {
+ config.rtp.fec.red_payload_type = -1;
+ config.rtp.fec.ulpfec_payload_type = -1;
+ config.rtp.fec.red_rtx_payload_type = -1;
+ }
+ stream_ = call_->CreateVideoReceiveStream(config);
stream_->Start();
}
@@ -2529,6 +2514,12 @@
return info;
}
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetFecDisabledRemotely(
+ bool disable) {
+ red_disabled_by_remote_side_ = disable;
+ RecreateWebRtcStream();
+}
+
WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings()
: rtx_payload_type(-1) {}
diff --git a/webrtc/media/engine/webrtcvideoengine2.h b/webrtc/media/engine/webrtcvideoengine2.h
index f6dd938..2d1b192 100644
--- a/webrtc/media/engine/webrtcvideoengine2.h
+++ b/webrtc/media/engine/webrtcvideoengine2.h
@@ -422,7 +422,8 @@
const webrtc::VideoReceiveStream::Config& config,
WebRtcVideoDecoderFactory* external_decoder_factory,
bool default_stream,
- const std::vector<VideoCodecSettings>& recv_codecs);
+ const std::vector<VideoCodecSettings>& recv_codecs,
+ bool red_disabled_by_remote_side);
~WebRtcVideoReceiveStream();
const std::vector<uint32_t>& GetSsrcs() const;
@@ -442,6 +443,14 @@
VideoReceiverInfo GetVideoReceiverInfo();
+ // Used to disable RED/FEC when the remote description doesn't contain those
+ // codecs. This is needed to be able to work around an RTX bug which is only
+ // happening if the remote side doesn't send RED, but the local side is
+ // configured to receive RED.
+ // TODO(holmer): Remove this after a couple of Chrome versions, M53-54
+ // time frame.
+ void SetFecDisabledRemotely(bool disable);
+
private:
struct AllocatedDecoder {
AllocatedDecoder(webrtc::VideoDecoder* decoder,
@@ -472,6 +481,7 @@
webrtc::VideoReceiveStream* stream_;
const bool default_stream_;
webrtc::VideoReceiveStream::Config config_;
+ bool red_disabled_by_remote_side_;
WebRtcVideoDecoderFactory* const external_decoder_factory_;
std::vector<AllocatedDecoder> allocated_decoders_;
@@ -542,6 +552,7 @@
VideoSendParameters send_params_;
VideoOptions default_send_options_;
VideoRecvParameters recv_params_;
+ bool red_disabled_by_remote_side_;
};
} // namespace cricket
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
index db34dd1..fd7a646 100644
--- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc
+++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -2678,6 +2678,7 @@
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithoutFecDisablesFec) {
cricket::VideoSendParameters send_parameters;
send_parameters.codecs.push_back(kVp8Codec);
+ send_parameters.codecs.push_back(kRedCodec);
send_parameters.codecs.push_back(kUlpfecCodec);
ASSERT_TRUE(channel_->SetSendParameters(send_parameters));
@@ -2696,6 +2697,41 @@
<< "SetSendCodec without FEC should disable current FEC.";
}
+TEST_F(WebRtcVideoChannel2Test, SetSendParamsWithoutFecDisablesReceivingFec) {
+ FakeVideoReceiveStream* stream = AddRecvStream();
+ webrtc::VideoReceiveStream::Config config = stream->GetConfig();
+
+ EXPECT_EQ(kUlpfecCodec.id, config.rtp.fec.ulpfec_payload_type);
+
+ cricket::VideoRecvParameters recv_parameters;
+ recv_parameters.codecs.push_back(kVp8Codec);
+ recv_parameters.codecs.push_back(kRedCodec);
+ recv_parameters.codecs.push_back(kUlpfecCodec);
+ ASSERT_TRUE(channel_->SetRecvParameters(recv_parameters));
+ stream = fake_call_->GetVideoReceiveStreams()[0];
+ ASSERT_TRUE(stream != NULL);
+ config = stream->GetConfig();
+ EXPECT_EQ(kUlpfecCodec.id, config.rtp.fec.ulpfec_payload_type)
+ << "FEC should be enabled on the recieve stream.";
+
+ cricket::VideoSendParameters send_parameters;
+ send_parameters.codecs.push_back(kVp8Codec);
+ ASSERT_TRUE(channel_->SetSendParameters(send_parameters));
+ stream = fake_call_->GetVideoReceiveStreams()[0];
+ config = stream->GetConfig();
+ EXPECT_EQ(-1, config.rtp.fec.ulpfec_payload_type)
+ << "FEC should have been disabled when we know the other side won't do "
+ "FEC.";
+
+ send_parameters.codecs.push_back(kRedCodec);
+ send_parameters.codecs.push_back(kUlpfecCodec);
+ ASSERT_TRUE(channel_->SetSendParameters(send_parameters));
+ stream = fake_call_->GetVideoReceiveStreams()[0];
+ config = stream->GetConfig();
+ EXPECT_EQ(kUlpfecCodec.id, config.rtp.fec.ulpfec_payload_type)
+ << "FEC should be enabled on the recieve stream.";
+}
+
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectDuplicateFecPayloads) {
cricket::VideoRecvParameters parameters;
parameters.codecs.push_back(kVp8Codec);