mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 23:01:21 +01:00
Negotiate use of RTCP loss notification feedback (LNTF)
When the LossNotifications field trial is in effect, LNTF should be offered/accepted in the SDP message, not assumed to be configured on both sides equally. Bug: webrtc:10662 Change-Id: Ibd827779bd301821cbb4196857f6baebfc9e7dc2 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138079 Commit-Queue: Elad Alon <eladalon@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28056}
This commit is contained in:
parent
815b1a6f53
commit
fadb1811a8
29 changed files with 297 additions and 82 deletions
api
call
media
base
engine
modules/rtp_rtcp/source
pc
sdk/objc/unittests
test
video
|
@ -50,6 +50,7 @@ enum class FecMechanism {
|
||||||
// Used in RtcpFeedback struct.
|
// Used in RtcpFeedback struct.
|
||||||
enum class RtcpFeedbackType {
|
enum class RtcpFeedbackType {
|
||||||
CCM,
|
CCM,
|
||||||
|
LNTF, // "goog-lntf"
|
||||||
NACK,
|
NACK,
|
||||||
REMB, // "goog-remb"
|
REMB, // "goog-remb"
|
||||||
TRANSPORT_CC,
|
TRANSPORT_CC,
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
std::string LntfConfig::ToString() const {
|
||||||
|
return enabled ? "{enabled: true}" : "{enabled: false}";
|
||||||
|
}
|
||||||
|
|
||||||
std::string NackConfig::ToString() const {
|
std::string NackConfig::ToString() const {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
rtc::SimpleStringBuilder ss(buf);
|
rtc::SimpleStringBuilder ss(buf);
|
||||||
|
@ -72,6 +76,7 @@ std::string RtpConfig::ToString() const {
|
||||||
}
|
}
|
||||||
ss << ']';
|
ss << ']';
|
||||||
|
|
||||||
|
ss << ", lntf: " << lntf.ToString();
|
||||||
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
||||||
ss << ", ulpfec: " << ulpfec.ToString();
|
ss << ", ulpfec: " << ulpfec.ToString();
|
||||||
ss << ", payload_name: " << payload_name;
|
ss << ", payload_name: " << payload_name;
|
||||||
|
|
|
@ -26,6 +26,14 @@ struct RtpPayloadState {
|
||||||
uint8_t tl0_pic_idx = 0;
|
uint8_t tl0_pic_idx = 0;
|
||||||
int64_t shared_frame_id = 0;
|
int64_t shared_frame_id = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Settings for LNTF (LossNotification). Still highly experimental.
|
||||||
|
struct LntfConfig {
|
||||||
|
std::string ToString() const;
|
||||||
|
|
||||||
|
bool enabled{false}; // TODO(bugs.webrtc.org/10662): Consume this flag.
|
||||||
|
};
|
||||||
|
|
||||||
// Settings for NACK, see RFC 4585 for details.
|
// Settings for NACK, see RFC 4585 for details.
|
||||||
struct NackConfig {
|
struct NackConfig {
|
||||||
NackConfig() : rtp_history_ms(0) {}
|
NackConfig() : rtp_history_ms(0) {}
|
||||||
|
@ -104,6 +112,9 @@ struct RtpConfig {
|
||||||
// frame descriptor RTP header extension).
|
// frame descriptor RTP header extension).
|
||||||
bool raw_payload = false;
|
bool raw_payload = false;
|
||||||
|
|
||||||
|
// See LntfConfig for description.
|
||||||
|
LntfConfig lntf;
|
||||||
|
|
||||||
// See NackConfig for description.
|
// See NackConfig for description.
|
||||||
NackConfig nack;
|
NackConfig nack;
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ std::string VideoReceiveStream::Config::Rtp::ToString() const {
|
||||||
ss << '}';
|
ss << '}';
|
||||||
ss << ", remb: " << (remb ? "on" : "off");
|
ss << ", remb: " << (remb ? "on" : "off");
|
||||||
ss << ", transport_cc: " << (transport_cc ? "on" : "off");
|
ss << ", transport_cc: " << (transport_cc ? "on" : "off");
|
||||||
|
ss << ", lntf: {enabled: " << (lntf.enabled ? "true" : "false") << '}';
|
||||||
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
||||||
ss << ", ulpfec_payload_type: " << ulpfec_payload_type;
|
ss << ", ulpfec_payload_type: " << ulpfec_payload_type;
|
||||||
ss << ", red_type: " << red_payload_type;
|
ss << ", red_type: " << red_payload_type;
|
||||||
|
|
|
@ -179,6 +179,9 @@ class VideoReceiveStream {
|
||||||
// See draft-holmer-rmcat-transport-wide-cc-extensions for details.
|
// See draft-holmer-rmcat-transport-wide-cc-extensions for details.
|
||||||
bool transport_cc = false;
|
bool transport_cc = false;
|
||||||
|
|
||||||
|
// See LntfConfig for description.
|
||||||
|
LntfConfig lntf;
|
||||||
|
|
||||||
// See NackConfig for description.
|
// See NackConfig for description.
|
||||||
NackConfig nack;
|
NackConfig nack;
|
||||||
|
|
||||||
|
|
|
@ -353,6 +353,11 @@ std::string RtpDataCodec::ToString() const {
|
||||||
return sb.str();
|
return sb.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasLntf(const Codec& codec) {
|
||||||
|
return codec.HasFeedbackParam(
|
||||||
|
FeedbackParam(kRtcpFbParamLntf, kParamValueEmpty));
|
||||||
|
}
|
||||||
|
|
||||||
bool HasNack(const Codec& codec) {
|
bool HasNack(const Codec& codec) {
|
||||||
return codec.HasFeedbackParam(
|
return codec.HasFeedbackParam(
|
||||||
FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
|
FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
|
||||||
|
|
|
@ -220,6 +220,7 @@ const Codec* FindCodecById(const std::vector<Codec>& codecs, int payload_type) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasLntf(const Codec& codec);
|
||||||
bool HasNack(const Codec& codec);
|
bool HasNack(const Codec& codec);
|
||||||
bool HasRemb(const Codec& codec);
|
bool HasRemb(const Codec& codec);
|
||||||
bool HasRrtr(const Codec& codec);
|
bool HasRrtr(const Codec& codec);
|
||||||
|
|
|
@ -77,6 +77,7 @@ const int kPreferredSPropStereo = 0;
|
||||||
const int kPreferredStereo = 0;
|
const int kPreferredStereo = 0;
|
||||||
const int kPreferredUseInbandFec = 0;
|
const int kPreferredUseInbandFec = 0;
|
||||||
|
|
||||||
|
const char kRtcpFbParamLntf[] = "goog-lntf";
|
||||||
const char kRtcpFbParamNack[] = "nack";
|
const char kRtcpFbParamNack[] = "nack";
|
||||||
const char kRtcpFbNackParamPli[] = "pli";
|
const char kRtcpFbNackParamPli[] = "pli";
|
||||||
const char kRtcpFbParamRemb[] = "goog-remb";
|
const char kRtcpFbParamRemb[] = "goog-remb";
|
||||||
|
|
|
@ -91,6 +91,8 @@ extern const int kPreferredSPropStereo;
|
||||||
extern const int kPreferredStereo;
|
extern const int kPreferredStereo;
|
||||||
extern const int kPreferredUseInbandFec;
|
extern const int kPreferredUseInbandFec;
|
||||||
|
|
||||||
|
// rtcp-fb message in its first experimental stages. Documentation pending.
|
||||||
|
extern const char kRtcpFbParamLntf[];
|
||||||
// rtcp-fb messages according to RFC 4585
|
// rtcp-fb messages according to RFC 4585
|
||||||
extern const char kRtcpFbParamNack[];
|
extern const char kRtcpFbParamNack[];
|
||||||
extern const char kRtcpFbNackParamPli[];
|
extern const char kRtcpFbNackParamPli[];
|
||||||
|
|
|
@ -72,6 +72,10 @@ void AddDefaultFeedbackParams(VideoCodec* codec) {
|
||||||
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
|
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
|
||||||
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
|
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
|
||||||
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli));
|
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli));
|
||||||
|
if (codec->name == kVp8CodecName &&
|
||||||
|
webrtc::field_trial::IsEnabled("WebRTC-RtcpLossNotification")) {
|
||||||
|
codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamLntf, kParamValueEmpty));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will assign dynamic payload types (in the range [96, 127]) to
|
// This function will assign dynamic payload types (in the range [96, 127]) to
|
||||||
|
@ -766,8 +770,8 @@ bool WebRtcVideoChannel::SetSendParameters(const VideoSendParameters& params) {
|
||||||
for (auto& kv : receive_streams_) {
|
for (auto& kv : receive_streams_) {
|
||||||
RTC_DCHECK(kv.second != nullptr);
|
RTC_DCHECK(kv.second != nullptr);
|
||||||
kv.second->SetFeedbackParameters(
|
kv.second->SetFeedbackParameters(
|
||||||
HasNack(send_codec_->codec), HasRemb(send_codec_->codec),
|
HasLntf(send_codec_->codec), HasNack(send_codec_->codec),
|
||||||
HasTransportCc(send_codec_->codec),
|
HasRemb(send_codec_->codec), HasTransportCc(send_codec_->codec),
|
||||||
params.rtcp.reduced_size ? webrtc::RtcpMode::kReducedSize
|
params.rtcp.reduced_size ? webrtc::RtcpMode::kReducedSize
|
||||||
: webrtc::RtcpMode::kCompound);
|
: webrtc::RtcpMode::kCompound);
|
||||||
}
|
}
|
||||||
|
@ -1889,6 +1893,8 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetCodec(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameters_.config.rtp.lntf.enabled = HasLntf(codec_settings.codec);
|
||||||
|
|
||||||
parameters_.config.rtp.nack.rtp_history_ms =
|
parameters_.config.rtp.nack.rtp_history_ms =
|
||||||
HasNack(codec_settings.codec) ? kNackHistoryMs : 0;
|
HasNack(codec_settings.codec) ? kNackHistoryMs : 0;
|
||||||
|
|
||||||
|
@ -2470,6 +2476,7 @@ void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
|
||||||
config_.rtp.ulpfec_payload_type = codec.ulpfec.ulpfec_payload_type;
|
config_.rtp.ulpfec_payload_type = codec.ulpfec.ulpfec_payload_type;
|
||||||
config_.rtp.red_payload_type = codec.ulpfec.red_payload_type;
|
config_.rtp.red_payload_type = codec.ulpfec.red_payload_type;
|
||||||
|
|
||||||
|
config_.rtp.lntf.enabled = HasLntf(codec.codec);
|
||||||
config_.rtp.nack.rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
|
config_.rtp.nack.rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
|
||||||
config_.rtp.rtcp_xr.receiver_reference_time_report = HasRrtr(codec.codec);
|
config_.rtp.rtcp_xr.receiver_reference_time_report = HasRrtr(codec.codec);
|
||||||
if (codec.ulpfec.red_rtx_payload_type != -1) {
|
if (codec.ulpfec.red_rtx_payload_type != -1) {
|
||||||
|
@ -2507,23 +2514,27 @@ void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetLocalSsrc(
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFeedbackParameters(
|
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFeedbackParameters(
|
||||||
|
bool lntf_enabled,
|
||||||
bool nack_enabled,
|
bool nack_enabled,
|
||||||
bool remb_enabled,
|
bool remb_enabled,
|
||||||
bool transport_cc_enabled,
|
bool transport_cc_enabled,
|
||||||
webrtc::RtcpMode rtcp_mode) {
|
webrtc::RtcpMode rtcp_mode) {
|
||||||
int nack_history_ms = nack_enabled ? kNackHistoryMs : 0;
|
int nack_history_ms = nack_enabled ? kNackHistoryMs : 0;
|
||||||
if (config_.rtp.nack.rtp_history_ms == nack_history_ms &&
|
if (config_.rtp.lntf.enabled == lntf_enabled &&
|
||||||
|
config_.rtp.nack.rtp_history_ms == nack_history_ms &&
|
||||||
config_.rtp.remb == remb_enabled &&
|
config_.rtp.remb == remb_enabled &&
|
||||||
config_.rtp.transport_cc == transport_cc_enabled &&
|
config_.rtp.transport_cc == transport_cc_enabled &&
|
||||||
config_.rtp.rtcp_mode == rtcp_mode) {
|
config_.rtp.rtcp_mode == rtcp_mode) {
|
||||||
RTC_LOG(LS_INFO)
|
RTC_LOG(LS_INFO)
|
||||||
<< "Ignoring call to SetFeedbackParameters because parameters are "
|
<< "Ignoring call to SetFeedbackParameters because parameters are "
|
||||||
"unchanged; nack="
|
"unchanged; lntf="
|
||||||
<< nack_enabled << ", remb=" << remb_enabled
|
<< lntf_enabled << ", nack=" << nack_enabled
|
||||||
|
<< ", remb=" << remb_enabled
|
||||||
<< ", transport_cc=" << transport_cc_enabled;
|
<< ", transport_cc=" << transport_cc_enabled;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
config_.rtp.remb = remb_enabled;
|
config_.rtp.remb = remb_enabled;
|
||||||
|
config_.rtp.lntf.enabled = lntf_enabled;
|
||||||
config_.rtp.nack.rtp_history_ms = nack_history_ms;
|
config_.rtp.nack.rtp_history_ms = nack_history_ms;
|
||||||
config_.rtp.transport_cc = transport_cc_enabled;
|
config_.rtp.transport_cc = transport_cc_enabled;
|
||||||
config_.rtp.rtcp_mode = rtcp_mode;
|
config_.rtp.rtcp_mode = rtcp_mode;
|
||||||
|
@ -2743,6 +2754,7 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
|
||||||
info.firs_sent = stats.rtcp_packet_type_counts.fir_packets;
|
info.firs_sent = stats.rtcp_packet_type_counts.fir_packets;
|
||||||
info.plis_sent = stats.rtcp_packet_type_counts.pli_packets;
|
info.plis_sent = stats.rtcp_packet_type_counts.pli_packets;
|
||||||
info.nacks_sent = stats.rtcp_packet_type_counts.nack_packets;
|
info.nacks_sent = stats.rtcp_packet_type_counts.nack_packets;
|
||||||
|
// TODO(bugs.webrtc.org/10662): Add stats for LNTF.
|
||||||
|
|
||||||
info.timing_frame_info = stats.timing_frame_info;
|
info.timing_frame_info = stats.timing_frame_info;
|
||||||
|
|
||||||
|
|
|
@ -400,7 +400,8 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||||
|
|
||||||
void SetLocalSsrc(uint32_t local_ssrc);
|
void SetLocalSsrc(uint32_t local_ssrc);
|
||||||
// TODO(deadbeef): Move these feedback parameters into the recv parameters.
|
// TODO(deadbeef): Move these feedback parameters into the recv parameters.
|
||||||
void SetFeedbackParameters(bool nack_enabled,
|
void SetFeedbackParameters(bool lntf_enabled,
|
||||||
|
bool nack_enabled,
|
||||||
bool remb_enabled,
|
bool remb_enabled,
|
||||||
bool transport_cc_enabled,
|
bool transport_cc_enabled,
|
||||||
webrtc::RtcpMode rtcp_mode);
|
webrtc::RtcpMode rtcp_mode);
|
||||||
|
|
|
@ -91,7 +91,11 @@ cricket::VideoCodec RemoveFeedbackParams(cricket::VideoCodec&& codec) {
|
||||||
return std::move(codec);
|
return std::move(codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyCodecHasDefaultFeedbackParams(const cricket::VideoCodec& codec) {
|
void VerifyCodecHasDefaultFeedbackParams(const cricket::VideoCodec& codec,
|
||||||
|
bool lntf_expected) {
|
||||||
|
EXPECT_EQ(lntf_expected,
|
||||||
|
codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
|
cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
|
||||||
EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
||||||
EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
|
@ -1104,7 +1108,8 @@ TEST(WebRtcVideoEngineNewVideoCodecFactoryTest, Vp8) {
|
||||||
cricket::kCodecParamAssociatedPayloadType, &associated_payload_type));
|
cricket::kCodecParamAssociatedPayloadType, &associated_payload_type));
|
||||||
EXPECT_EQ(engine_codecs.at(0).id, associated_payload_type);
|
EXPECT_EQ(engine_codecs.at(0).id, associated_payload_type);
|
||||||
// Verify default parameters has been added to the VP8 codec.
|
// Verify default parameters has been added to the VP8 codec.
|
||||||
VerifyCodecHasDefaultFeedbackParams(engine_codecs.at(0));
|
VerifyCodecHasDefaultFeedbackParams(engine_codecs.at(0),
|
||||||
|
/*lntf_expected=*/false);
|
||||||
|
|
||||||
// Mock encoder creation. |engine| take ownership of the encoder.
|
// Mock encoder creation. |engine| take ownership of the encoder.
|
||||||
webrtc::VideoEncoderFactory::CodecInfo codec_info;
|
webrtc::VideoEncoderFactory::CodecInfo codec_info;
|
||||||
|
@ -2262,6 +2267,26 @@ class WebRtcVideoChannelTest : public WebRtcVideoEngineTest {
|
||||||
EXPECT_EQ(ext_uri, recv_stream->GetConfig().rtp.extensions[0].uri);
|
EXPECT_EQ(ext_uri, recv_stream->GetConfig().rtp.extensions[0].uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestLossNotificationState(bool expect_lntf_enabled) {
|
||||||
|
AssignDefaultCodec();
|
||||||
|
VerifyCodecHasDefaultFeedbackParams(default_codec_, expect_lntf_enabled);
|
||||||
|
|
||||||
|
cricket::VideoSendParameters parameters;
|
||||||
|
parameters.codecs = engine_.codecs();
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
EXPECT_TRUE(channel_->SetSend(true));
|
||||||
|
|
||||||
|
// Send side.
|
||||||
|
FakeVideoSendStream* send_stream =
|
||||||
|
AddSendStream(cricket::StreamParams::CreateLegacy(1));
|
||||||
|
EXPECT_EQ(send_stream->GetConfig().rtp.lntf.enabled, expect_lntf_enabled);
|
||||||
|
|
||||||
|
// Receiver side.
|
||||||
|
FakeVideoReceiveStream* recv_stream =
|
||||||
|
AddRecvStream(cricket::StreamParams::CreateLegacy(1));
|
||||||
|
EXPECT_EQ(recv_stream->GetConfig().rtp.lntf.enabled, expect_lntf_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void TestExtensionFilter(const std::vector<std::string>& extensions,
|
void TestExtensionFilter(const std::vector<std::string>& extensions,
|
||||||
const std::string& expected_extension) {
|
const std::string& expected_extension) {
|
||||||
cricket::VideoSendParameters parameters = send_parameters_;
|
cricket::VideoSendParameters parameters = send_parameters_;
|
||||||
|
@ -2734,9 +2759,64 @@ TEST_F(WebRtcVideoChannelTest, TransportCcCanBeEnabledAndDisabled) {
|
||||||
EXPECT_TRUE(stream->GetConfig().rtp.transport_cc);
|
EXPECT_TRUE(stream->GetConfig().rtp.transport_cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannelTest, LossNotificationIsDisabledByDefault) {
|
||||||
|
TestLossNotificationState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannelTest, LossNotificationIsEnabledByFieldTrial) {
|
||||||
|
RTC_DCHECK(!override_field_trials_);
|
||||||
|
override_field_trials_ = absl::make_unique<webrtc::test::ScopedFieldTrials>(
|
||||||
|
"WebRTC-RtcpLossNotification/Enabled/");
|
||||||
|
SetUp();
|
||||||
|
TestLossNotificationState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannelTest, LossNotificationCanBeEnabledAndDisabled) {
|
||||||
|
RTC_DCHECK(!override_field_trials_);
|
||||||
|
override_field_trials_ = absl::make_unique<webrtc::test::ScopedFieldTrials>(
|
||||||
|
"WebRTC-RtcpLossNotification/Enabled/");
|
||||||
|
SetUp();
|
||||||
|
|
||||||
|
AssignDefaultCodec();
|
||||||
|
VerifyCodecHasDefaultFeedbackParams(default_codec_, true);
|
||||||
|
|
||||||
|
{
|
||||||
|
cricket::VideoSendParameters parameters;
|
||||||
|
parameters.codecs = engine_.codecs();
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
EXPECT_TRUE(channel_->SetSend(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with LNTF enabled.
|
||||||
|
FakeVideoSendStream* send_stream =
|
||||||
|
AddSendStream(cricket::StreamParams::CreateLegacy(1));
|
||||||
|
ASSERT_TRUE(send_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
FakeVideoReceiveStream* recv_stream =
|
||||||
|
AddRecvStream(cricket::StreamParams::CreateLegacy(1));
|
||||||
|
ASSERT_TRUE(recv_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
|
||||||
|
// Verify that LNTF is turned off when send(!) codecs without LNTF are set.
|
||||||
|
cricket::VideoSendParameters parameters;
|
||||||
|
parameters.codecs.push_back(RemoveFeedbackParams(GetEngineCodec("VP8")));
|
||||||
|
EXPECT_TRUE(parameters.codecs[0].feedback_params.params().empty());
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
||||||
|
EXPECT_FALSE(recv_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
send_stream = fake_call_->GetVideoSendStreams()[0];
|
||||||
|
EXPECT_FALSE(send_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
|
||||||
|
// Setting the default codecs again, including VP8, turns LNTF back on.
|
||||||
|
parameters.codecs = engine_.codecs();
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
||||||
|
EXPECT_TRUE(recv_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
send_stream = fake_call_->GetVideoSendStreams()[0];
|
||||||
|
EXPECT_TRUE(send_stream->GetConfig().rtp.lntf.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannelTest, NackIsEnabledByDefault) {
|
TEST_F(WebRtcVideoChannelTest, NackIsEnabledByDefault) {
|
||||||
AssignDefaultCodec();
|
AssignDefaultCodec();
|
||||||
VerifyCodecHasDefaultFeedbackParams(default_codec_);
|
VerifyCodecHasDefaultFeedbackParams(default_codec_, false);
|
||||||
|
|
||||||
cricket::VideoSendParameters parameters;
|
cricket::VideoSendParameters parameters;
|
||||||
parameters.codecs = engine_.codecs();
|
parameters.codecs = engine_.codecs();
|
||||||
|
|
|
@ -195,8 +195,9 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock,
|
||||||
last_rotation_(kVideoRotation_0),
|
last_rotation_(kVideoRotation_0),
|
||||||
transmit_color_space_next_frame_(false),
|
transmit_color_space_next_frame_(false),
|
||||||
playout_delay_oracle_(playout_delay_oracle),
|
playout_delay_oracle_(playout_delay_oracle),
|
||||||
// TODO(eladalon): Choose whether to instantiate rtp_sequence_number_map_
|
// TODO(bugs.webrtc.org/10662): Choose whether to instantiate
|
||||||
// according to the negotiation of the RTCP message.
|
// |rtp_sequence_number_map_| according to the negotiation of the
|
||||||
|
// LNTF (loss notification) rtcp-fb message.
|
||||||
rtp_sequence_number_map_(
|
rtp_sequence_number_map_(
|
||||||
field_trials.Lookup("WebRTC-RtcpLossNotification").find("Enabled") !=
|
field_trials.Lookup("WebRTC-RtcpLossNotification").find("Enabled") !=
|
||||||
std::string::npos
|
std::string::npos
|
||||||
|
|
|
@ -39,6 +39,13 @@ RTCErrorOr<cricket::FeedbackParam> ToCricketFeedbackParam(
|
||||||
}
|
}
|
||||||
return cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
|
return cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
|
||||||
cricket::kRtcpFbCcmParamFir);
|
cricket::kRtcpFbCcmParamFir);
|
||||||
|
case RtcpFeedbackType::LNTF:
|
||||||
|
if (feedback.message_type) {
|
||||||
|
LOG_AND_RETURN_ERROR(
|
||||||
|
RTCErrorType::INVALID_PARAMETER,
|
||||||
|
"Didn't expect message type in LNTF RtcpFeedback.");
|
||||||
|
}
|
||||||
|
return cricket::FeedbackParam(cricket::kRtcpFbParamLntf);
|
||||||
case RtcpFeedbackType::NACK:
|
case RtcpFeedbackType::NACK:
|
||||||
if (!feedback.message_type) {
|
if (!feedback.message_type) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
|
||||||
|
@ -253,6 +260,14 @@ absl::optional<RtcpFeedback> ToRtcpFeedback(
|
||||||
<< cricket_feedback.param();
|
<< cricket_feedback.param();
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
|
} else if (cricket_feedback.id() == cricket::kRtcpFbParamLntf) {
|
||||||
|
if (cricket_feedback.param().empty()) {
|
||||||
|
return RtcpFeedback(RtcpFeedbackType::LNTF);
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_WARNING) << "Unsupported parameter for LNTF RTCP feedback: "
|
||||||
|
<< cricket_feedback.param();
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
} else if (cricket_feedback.id() == cricket::kRtcpFbParamNack) {
|
} else if (cricket_feedback.id() == cricket::kRtcpFbParamNack) {
|
||||||
if (cricket_feedback.param().empty()) {
|
if (cricket_feedback.param().empty()) {
|
||||||
return RtcpFeedback(RtcpFeedbackType::NACK,
|
return RtcpFeedback(RtcpFeedbackType::NACK,
|
||||||
|
|
|
@ -22,14 +22,21 @@ TEST(RtpParametersConversionTest, ToCricketFeedbackParam) {
|
||||||
auto result = ToCricketFeedbackParam(
|
auto result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR});
|
{RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR});
|
||||||
EXPECT_EQ(cricket::FeedbackParam("ccm", "fir"), result.value());
|
EXPECT_EQ(cricket::FeedbackParam("ccm", "fir"), result.value());
|
||||||
|
|
||||||
|
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::LNTF));
|
||||||
|
EXPECT_EQ(cricket::FeedbackParam("goog-lntf"), result.value());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::GENERIC_NACK});
|
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::GENERIC_NACK});
|
||||||
EXPECT_EQ(cricket::FeedbackParam("nack"), result.value());
|
EXPECT_EQ(cricket::FeedbackParam("nack"), result.value());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI});
|
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI});
|
||||||
EXPECT_EQ(cricket::FeedbackParam("nack", "pli"), result.value());
|
EXPECT_EQ(cricket::FeedbackParam("nack", "pli"), result.value());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::REMB));
|
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::REMB));
|
||||||
EXPECT_EQ(cricket::FeedbackParam("goog-remb"), result.value());
|
EXPECT_EQ(cricket::FeedbackParam("goog-remb"), result.value());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC));
|
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC));
|
||||||
EXPECT_EQ(cricket::FeedbackParam("transport-cc"), result.value());
|
EXPECT_EQ(cricket::FeedbackParam("transport-cc"), result.value());
|
||||||
}
|
}
|
||||||
|
@ -38,19 +45,29 @@ TEST(RtpParametersConversionTest, ToCricketFeedbackParamErrors) {
|
||||||
// CCM with missing or invalid message type.
|
// CCM with missing or invalid message type.
|
||||||
auto result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::CCM));
|
auto result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::CCM));
|
||||||
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::CCM, RtcpFeedbackMessageType::PLI});
|
{RtcpFeedbackType::CCM, RtcpFeedbackMessageType::PLI});
|
||||||
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
|
// LNTF with message type (should be left empty).
|
||||||
|
result = ToCricketFeedbackParam(
|
||||||
|
{RtcpFeedbackType::LNTF, RtcpFeedbackMessageType::GENERIC_NACK});
|
||||||
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
// NACK with missing or invalid message type.
|
// NACK with missing or invalid message type.
|
||||||
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::NACK));
|
result = ToCricketFeedbackParam(RtcpFeedback(RtcpFeedbackType::NACK));
|
||||||
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::FIR});
|
{RtcpFeedbackType::NACK, RtcpFeedbackMessageType::FIR});
|
||||||
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
// REMB with message type (should be left empty).
|
// REMB with message type (should be left empty).
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::REMB, RtcpFeedbackMessageType::GENERIC_NACK});
|
{RtcpFeedbackType::REMB, RtcpFeedbackMessageType::GENERIC_NACK});
|
||||||
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
|
||||||
|
|
||||||
// TRANSPORT_CC with message type (should be left empty).
|
// TRANSPORT_CC with message type (should be left empty).
|
||||||
result = ToCricketFeedbackParam(
|
result = ToCricketFeedbackParam(
|
||||||
{RtcpFeedbackType::TRANSPORT_CC, RtcpFeedbackMessageType::FIR});
|
{RtcpFeedbackType::TRANSPORT_CC, RtcpFeedbackMessageType::FIR});
|
||||||
|
@ -88,6 +105,7 @@ TEST(RtpParametersConversionTest, ToVideoCodec) {
|
||||||
codec.clock_rate.emplace(90000);
|
codec.clock_rate.emplace(90000);
|
||||||
codec.parameters["foo"] = "bar";
|
codec.parameters["foo"] = "bar";
|
||||||
codec.parameters["PING"] = "PONG";
|
codec.parameters["PING"] = "PONG";
|
||||||
|
codec.rtcp_feedback.emplace_back(RtcpFeedbackType::LNTF);
|
||||||
codec.rtcp_feedback.emplace_back(RtcpFeedbackType::TRANSPORT_CC);
|
codec.rtcp_feedback.emplace_back(RtcpFeedbackType::TRANSPORT_CC);
|
||||||
codec.rtcp_feedback.emplace_back(RtcpFeedbackType::NACK,
|
codec.rtcp_feedback.emplace_back(RtcpFeedbackType::NACK,
|
||||||
RtcpFeedbackMessageType::PLI);
|
RtcpFeedbackMessageType::PLI);
|
||||||
|
@ -100,7 +118,9 @@ TEST(RtpParametersConversionTest, ToVideoCodec) {
|
||||||
ASSERT_EQ(2u, result.value().params.size());
|
ASSERT_EQ(2u, result.value().params.size());
|
||||||
EXPECT_EQ("bar", result.value().params["foo"]);
|
EXPECT_EQ("bar", result.value().params["foo"]);
|
||||||
EXPECT_EQ("PONG", result.value().params["PING"]);
|
EXPECT_EQ("PONG", result.value().params["PING"]);
|
||||||
EXPECT_EQ(2u, result.value().feedback_params.params().size());
|
EXPECT_EQ(3u, result.value().feedback_params.params().size());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
result.value().feedback_params.Has(cricket::FeedbackParam("goog-lntf")));
|
||||||
EXPECT_TRUE(result.value().feedback_params.Has(
|
EXPECT_TRUE(result.value().feedback_params.Has(
|
||||||
cricket::FeedbackParam("transport-cc")));
|
cricket::FeedbackParam("transport-cc")));
|
||||||
EXPECT_TRUE(result.value().feedback_params.Has(
|
EXPECT_TRUE(result.value().feedback_params.Has(
|
||||||
|
@ -382,15 +402,22 @@ TEST(RtpParametersConversionTest, ToRtcpFeedback) {
|
||||||
absl::optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "fir"});
|
absl::optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "fir"});
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::CCM, RtcpFeedbackMessageType::FIR),
|
||||||
*result);
|
*result);
|
||||||
|
|
||||||
|
result = ToRtcpFeedback(cricket::FeedbackParam("goog-lntf"));
|
||||||
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::LNTF), *result);
|
||||||
|
|
||||||
result = ToRtcpFeedback(cricket::FeedbackParam("nack"));
|
result = ToRtcpFeedback(cricket::FeedbackParam("nack"));
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK,
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK,
|
||||||
RtcpFeedbackMessageType::GENERIC_NACK),
|
RtcpFeedbackMessageType::GENERIC_NACK),
|
||||||
*result);
|
*result);
|
||||||
|
|
||||||
result = ToRtcpFeedback({"nack", "pli"});
|
result = ToRtcpFeedback({"nack", "pli"});
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
||||||
*result);
|
*result);
|
||||||
|
|
||||||
result = ToRtcpFeedback(cricket::FeedbackParam("goog-remb"));
|
result = ToRtcpFeedback(cricket::FeedbackParam("goog-remb"));
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::REMB), *result);
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::REMB), *result);
|
||||||
|
|
||||||
result = ToRtcpFeedback(cricket::FeedbackParam("transport-cc"));
|
result = ToRtcpFeedback(cricket::FeedbackParam("transport-cc"));
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), *result);
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC), *result);
|
||||||
}
|
}
|
||||||
|
@ -399,17 +426,26 @@ TEST(RtpParametersConversionTest, ToRtcpFeedbackErrors) {
|
||||||
// CCM with missing or invalid message type.
|
// CCM with missing or invalid message type.
|
||||||
absl::optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "pli"});
|
absl::optional<RtcpFeedback> result = ToRtcpFeedback({"ccm", "pli"});
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
result = ToRtcpFeedback(cricket::FeedbackParam("ccm"));
|
result = ToRtcpFeedback(cricket::FeedbackParam("ccm"));
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
|
// LNTF with message type (should be left empty).
|
||||||
|
result = ToRtcpFeedback({"goog-lntf", "pli"});
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
// NACK with missing or invalid message type.
|
// NACK with missing or invalid message type.
|
||||||
result = ToRtcpFeedback({"nack", "fir"});
|
result = ToRtcpFeedback({"nack", "fir"});
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
// REMB with message type (should be left empty).
|
// REMB with message type (should be left empty).
|
||||||
result = ToRtcpFeedback({"goog-remb", "pli"});
|
result = ToRtcpFeedback({"goog-remb", "pli"});
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
// TRANSPORT_CC with message type (should be left empty).
|
// TRANSPORT_CC with message type (should be left empty).
|
||||||
result = ToRtcpFeedback({"transport-cc", "fir"});
|
result = ToRtcpFeedback({"transport-cc", "fir"});
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
// Unknown message type.
|
// Unknown message type.
|
||||||
result = ToRtcpFeedback(cricket::FeedbackParam("foo"));
|
result = ToRtcpFeedback(cricket::FeedbackParam("foo"));
|
||||||
EXPECT_FALSE(result);
|
EXPECT_FALSE(result);
|
||||||
|
@ -445,6 +481,7 @@ TEST(RtpParametersConversionTest, ToVideoRtpCodecCapability) {
|
||||||
cricket_codec.params["foo"] = "bar";
|
cricket_codec.params["foo"] = "bar";
|
||||||
cricket_codec.params["ANOTHER"] = "param";
|
cricket_codec.params["ANOTHER"] = "param";
|
||||||
cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc"));
|
cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc"));
|
||||||
|
cricket_codec.feedback_params.Add(cricket::FeedbackParam("goog-lntf"));
|
||||||
cricket_codec.feedback_params.Add({"nack", "pli"});
|
cricket_codec.feedback_params.Add({"nack", "pli"});
|
||||||
RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec);
|
RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec);
|
||||||
|
|
||||||
|
@ -455,11 +492,12 @@ TEST(RtpParametersConversionTest, ToVideoRtpCodecCapability) {
|
||||||
ASSERT_EQ(2u, codec.parameters.size());
|
ASSERT_EQ(2u, codec.parameters.size());
|
||||||
EXPECT_EQ("bar", codec.parameters["foo"]);
|
EXPECT_EQ("bar", codec.parameters["foo"]);
|
||||||
EXPECT_EQ("param", codec.parameters["ANOTHER"]);
|
EXPECT_EQ("param", codec.parameters["ANOTHER"]);
|
||||||
EXPECT_EQ(2u, codec.rtcp_feedback.size());
|
EXPECT_EQ(3u, codec.rtcp_feedback.size());
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC),
|
||||||
codec.rtcp_feedback[0]);
|
codec.rtcp_feedback[0]);
|
||||||
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::LNTF), codec.rtcp_feedback[1]);
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
||||||
codec.rtcp_feedback[1]);
|
codec.rtcp_feedback[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RtpParametersConversionTest, ToRtpEncodingsWithEmptyStreamParamsVec) {
|
TEST(RtpParametersConversionTest, ToRtpEncodingsWithEmptyStreamParamsVec) {
|
||||||
|
@ -519,6 +557,7 @@ TEST(RtpParametersConversionTest, ToVideoRtpCodecParameters) {
|
||||||
cricket_codec.params["foo"] = "bar";
|
cricket_codec.params["foo"] = "bar";
|
||||||
cricket_codec.params["ANOTHER"] = "param";
|
cricket_codec.params["ANOTHER"] = "param";
|
||||||
cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc"));
|
cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc"));
|
||||||
|
cricket_codec.feedback_params.Add(cricket::FeedbackParam("goog-lntf"));
|
||||||
cricket_codec.feedback_params.Add({"nack", "pli"});
|
cricket_codec.feedback_params.Add({"nack", "pli"});
|
||||||
RtpCodecParameters codec = ToRtpCodecParameters(cricket_codec);
|
RtpCodecParameters codec = ToRtpCodecParameters(cricket_codec);
|
||||||
|
|
||||||
|
@ -529,11 +568,12 @@ TEST(RtpParametersConversionTest, ToVideoRtpCodecParameters) {
|
||||||
ASSERT_EQ(2u, codec.parameters.size());
|
ASSERT_EQ(2u, codec.parameters.size());
|
||||||
EXPECT_EQ("bar", codec.parameters["foo"]);
|
EXPECT_EQ("bar", codec.parameters["foo"]);
|
||||||
EXPECT_EQ("param", codec.parameters["ANOTHER"]);
|
EXPECT_EQ("param", codec.parameters["ANOTHER"]);
|
||||||
EXPECT_EQ(2u, codec.rtcp_feedback.size());
|
EXPECT_EQ(3u, codec.rtcp_feedback.size());
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::TRANSPORT_CC),
|
||||||
codec.rtcp_feedback[0]);
|
codec.rtcp_feedback[0]);
|
||||||
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::LNTF), codec.rtcp_feedback[1]);
|
||||||
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
EXPECT_EQ(RtcpFeedback(RtcpFeedbackType::NACK, RtcpFeedbackMessageType::PLI),
|
||||||
codec.rtcp_feedback[1]);
|
codec.rtcp_feedback[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// An unknown feedback param should just be ignored.
|
// An unknown feedback param should just be ignored.
|
||||||
|
|
|
@ -1993,6 +1993,7 @@ class WebRtcSdpTest : public ::testing::Test {
|
||||||
std::string sdp_video =
|
std::string sdp_video =
|
||||||
"m=video 3457 RTP/SAVPF 101\r\n"
|
"m=video 3457 RTP/SAVPF 101\r\n"
|
||||||
"a=rtpmap:101 VP8/90000\r\n"
|
"a=rtpmap:101 VP8/90000\r\n"
|
||||||
|
"a=rtcp-fb:101 goog-lntf\r\n"
|
||||||
"a=rtcp-fb:101 nack\r\n"
|
"a=rtcp-fb:101 nack\r\n"
|
||||||
"a=rtcp-fb:101 nack pli\r\n"
|
"a=rtcp-fb:101 nack pli\r\n"
|
||||||
"a=rtcp-fb:101 goog-remb\r\n";
|
"a=rtcp-fb:101 goog-remb\r\n";
|
||||||
|
@ -2022,6 +2023,8 @@ class WebRtcSdpTest : public ::testing::Test {
|
||||||
EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
|
EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
|
||||||
vp8.name.c_str());
|
vp8.name.c_str());
|
||||||
EXPECT_EQ(101, vp8.id);
|
EXPECT_EQ(101, vp8.id);
|
||||||
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
|
cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
|
||||||
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
||||||
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
"a=rtcp-mux\r\n"
|
"a=rtcp-mux\r\n"
|
||||||
"a=rtpmap:100 VP8/90000\r\n"
|
"a=rtpmap:100 VP8/90000\r\n"
|
||||||
"a=rtcp-fb:100 ccm fir\r\n"
|
"a=rtcp-fb:100 ccm fir\r\n"
|
||||||
|
"a=rtcp-fb:100 goog-lntf\r\n"
|
||||||
"a=rtcp-fb:100 nack\r\n"
|
"a=rtcp-fb:100 nack\r\n"
|
||||||
"a=rtcp-fb:100 nack pli\r\n"
|
"a=rtcp-fb:100 nack pli\r\n"
|
||||||
"a=rtcp-fb:100 goog-remb\r\n"
|
"a=rtcp-fb:100 goog-remb\r\n"
|
||||||
|
|
|
@ -45,6 +45,7 @@ VideoReceiveStream::Config ParseVideoReceiveStreamJsonConfig(
|
||||||
: RtcpMode::kReducedSize;
|
: RtcpMode::kReducedSize;
|
||||||
receive_config.rtp.remb = json["rtp"]["remb"].asBool();
|
receive_config.rtp.remb = json["rtp"]["remb"].asBool();
|
||||||
receive_config.rtp.transport_cc = json["rtp"]["transport_cc"].asBool();
|
receive_config.rtp.transport_cc = json["rtp"]["transport_cc"].asBool();
|
||||||
|
receive_config.rtp.lntf.enabled = json["rtp"]["lntf"]["enabled"].asInt64();
|
||||||
receive_config.rtp.nack.rtp_history_ms =
|
receive_config.rtp.nack.rtp_history_ms =
|
||||||
json["rtp"]["nack"]["rtp_history_ms"].asInt64();
|
json["rtp"]["nack"]["rtp_history_ms"].asInt64();
|
||||||
receive_config.rtp.ulpfec_payload_type =
|
receive_config.rtp.ulpfec_payload_type =
|
||||||
|
@ -94,6 +95,7 @@ Json::Value GenerateVideoReceiveStreamJsonConfig(
|
||||||
: "RtcpMode::kReducedSize";
|
: "RtcpMode::kReducedSize";
|
||||||
rtp_json["remb"] = config.rtp.remb;
|
rtp_json["remb"] = config.rtp.remb;
|
||||||
rtp_json["transport_cc"] = config.rtp.transport_cc;
|
rtp_json["transport_cc"] = config.rtp.transport_cc;
|
||||||
|
rtp_json["lntf"]["enabled"] = config.rtp.lntf.enabled;
|
||||||
rtp_json["nack"]["rtp_history_ms"] = config.rtp.nack.rtp_history_ms;
|
rtp_json["nack"]["rtp_history_ms"] = config.rtp.nack.rtp_history_ms;
|
||||||
rtp_json["ulpfec_payload_type"] = config.rtp.ulpfec_payload_type;
|
rtp_json["ulpfec_payload_type"] = config.rtp.ulpfec_payload_type;
|
||||||
rtp_json["red_payload_type"] = config.rtp.red_payload_type;
|
rtp_json["red_payload_type"] = config.rtp.red_payload_type;
|
||||||
|
|
|
@ -31,6 +31,7 @@ TEST(CallConfigUtils, MarshalUnmarshalProcessSameObject) {
|
||||||
recv_config.rtp.rtcp_mode = RtcpMode::kCompound;
|
recv_config.rtp.rtcp_mode = RtcpMode::kCompound;
|
||||||
recv_config.rtp.remb = false;
|
recv_config.rtp.remb = false;
|
||||||
recv_config.rtp.transport_cc = false;
|
recv_config.rtp.transport_cc = false;
|
||||||
|
recv_config.rtp.lntf.enabled = false;
|
||||||
recv_config.rtp.nack.rtp_history_ms = 150;
|
recv_config.rtp.nack.rtp_history_ms = 150;
|
||||||
recv_config.rtp.red_payload_type = 50;
|
recv_config.rtp.red_payload_type = 50;
|
||||||
recv_config.rtp.rtx_ssrc = 1000;
|
recv_config.rtp.rtx_ssrc = 1000;
|
||||||
|
@ -54,6 +55,7 @@ TEST(CallConfigUtils, MarshalUnmarshalProcessSameObject) {
|
||||||
EXPECT_EQ(recv_config.rtp.rtcp_mode, unmarshaled_config.rtp.rtcp_mode);
|
EXPECT_EQ(recv_config.rtp.rtcp_mode, unmarshaled_config.rtp.rtcp_mode);
|
||||||
EXPECT_EQ(recv_config.rtp.remb, unmarshaled_config.rtp.remb);
|
EXPECT_EQ(recv_config.rtp.remb, unmarshaled_config.rtp.remb);
|
||||||
EXPECT_EQ(recv_config.rtp.transport_cc, unmarshaled_config.rtp.transport_cc);
|
EXPECT_EQ(recv_config.rtp.transport_cc, unmarshaled_config.rtp.transport_cc);
|
||||||
|
EXPECT_EQ(recv_config.rtp.lntf.enabled, unmarshaled_config.rtp.lntf.enabled);
|
||||||
EXPECT_EQ(recv_config.rtp.nack.rtp_history_ms,
|
EXPECT_EQ(recv_config.rtp.nack.rtp_history_ms,
|
||||||
unmarshaled_config.rtp.nack.rtp_history_ms);
|
unmarshaled_config.rtp.nack.rtp_history_ms);
|
||||||
EXPECT_EQ(recv_config.rtp.red_payload_type,
|
EXPECT_EQ(recv_config.rtp.red_payload_type,
|
||||||
|
|
|
@ -112,6 +112,9 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"local_ssrc" : 1,
|
"local_ssrc" : 1,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
"rtp" : {
|
"rtp" : {
|
||||||
"extensions" : [],
|
"extensions" : [],
|
||||||
"local_ssrc" : 1,
|
"local_ssrc" : 1,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
"rtp" : {
|
"rtp" : {
|
||||||
"extensions" : [],
|
"extensions" : [],
|
||||||
"local_ssrc" : 1,
|
"local_ssrc" : 1,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
"rtp" : {
|
"rtp" : {
|
||||||
"extensions" : [],
|
"extensions" : [],
|
||||||
"local_ssrc" : 7331,
|
"local_ssrc" : 7331,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"local_ssrc" : 1,
|
"local_ssrc" : 1,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
"rtp" : {
|
"rtp" : {
|
||||||
"extensions" : [],
|
"extensions" : [],
|
||||||
"local_ssrc" : 7331,
|
"local_ssrc" : 7331,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,6 +52,9 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"local_ssrc" : 1,
|
"local_ssrc" : 1,
|
||||||
|
"lntf" : {
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
"nack" : {
|
"nack" : {
|
||||||
"rtp_history_ms" : 1000
|
"rtp_history_ms" : 1000
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,6 +31,7 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
|
||||||
vp8_config.rtp.transport_cc = true;
|
vp8_config.rtp.transport_cc = true;
|
||||||
vp8_config.rtp.remb = true;
|
vp8_config.rtp.remb = true;
|
||||||
vp8_config.rtp.nack.rtp_history_ms = 1000;
|
vp8_config.rtp.nack.rtp_history_ms = 1000;
|
||||||
|
vp8_config.rtp.lntf.enabled = true;
|
||||||
|
|
||||||
std::vector<VideoReceiveStream::Config> replay_configs;
|
std::vector<VideoReceiveStream::Config> replay_configs;
|
||||||
replay_configs.push_back(std::move(vp8_config));
|
replay_configs.push_back(std::move(vp8_config));
|
||||||
|
|
|
@ -52,6 +52,8 @@ void VerifyEmptyFlexfecConfig(const RtpConfig::Flexfec& config) {
|
||||||
|
|
||||||
TEST_F(ConfigEndToEndTest, VerifyDefaultSendConfigParameters) {
|
TEST_F(ConfigEndToEndTest, VerifyDefaultSendConfigParameters) {
|
||||||
VideoSendStream::Config default_send_config(nullptr);
|
VideoSendStream::Config default_send_config(nullptr);
|
||||||
|
EXPECT_FALSE(default_send_config.rtp.lntf.enabled)
|
||||||
|
<< "Enabling LNTF require rtcp-fb: goog-lntf negotiation.";
|
||||||
EXPECT_EQ(0, default_send_config.rtp.nack.rtp_history_ms)
|
EXPECT_EQ(0, default_send_config.rtp.nack.rtp_history_ms)
|
||||||
<< "Enabling NACK require rtcp-fb: nack negotiation.";
|
<< "Enabling NACK require rtcp-fb: nack negotiation.";
|
||||||
EXPECT_TRUE(default_send_config.rtp.rtx.ssrcs.empty())
|
EXPECT_TRUE(default_send_config.rtp.rtx.ssrcs.empty())
|
||||||
|
@ -74,6 +76,8 @@ TEST_F(ConfigEndToEndTest, VerifyDefaultVideoReceiveConfigParameters) {
|
||||||
VideoReceiveStream::Config default_receive_config(nullptr);
|
VideoReceiveStream::Config default_receive_config(nullptr);
|
||||||
EXPECT_EQ(RtcpMode::kCompound, default_receive_config.rtp.rtcp_mode)
|
EXPECT_EQ(RtcpMode::kCompound, default_receive_config.rtp.rtcp_mode)
|
||||||
<< "Reduced-size RTCP require rtcp-rsize to be negotiated.";
|
<< "Reduced-size RTCP require rtcp-rsize to be negotiated.";
|
||||||
|
EXPECT_FALSE(default_receive_config.rtp.lntf.enabled)
|
||||||
|
<< "Enabling LNTF require rtcp-fb: goog-lntf negotiation.";
|
||||||
EXPECT_FALSE(default_receive_config.rtp.remb)
|
EXPECT_FALSE(default_receive_config.rtp.remb)
|
||||||
<< "REMB require rtcp-fb: goog-remb to be negotiated.";
|
<< "REMB require rtcp-fb: goog-remb to be negotiated.";
|
||||||
EXPECT_FALSE(
|
EXPECT_FALSE(
|
||||||
|
|
|
@ -158,7 +158,8 @@ RtpVideoStreamReceiver::RtpVideoStreamReceiver(
|
||||||
|
|
||||||
process_thread_->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE);
|
process_thread_->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE);
|
||||||
|
|
||||||
if (webrtc::field_trial::IsEnabled("WebRTC-RtcpLossNotification")) {
|
// TODO(bugs.webrtc.org/10662): NACK and LNTF shouldn't be mutually exclusive.
|
||||||
|
if (config_.rtp.lntf.enabled) {
|
||||||
loss_notification_controller_ =
|
loss_notification_controller_ =
|
||||||
absl::make_unique<LossNotificationController>(this, this);
|
absl::make_unique<LossNotificationController>(this, this);
|
||||||
} else if (config_.rtp.nack.rtp_history_ms != 0) {
|
} else if (config_.rtp.nack.rtp_history_ms != 0) {
|
||||||
|
@ -395,6 +396,7 @@ void RtpVideoStreamReceiver::SendLossNotification(
|
||||||
uint16_t last_decoded_seq_num,
|
uint16_t last_decoded_seq_num,
|
||||||
uint16_t last_received_seq_num,
|
uint16_t last_received_seq_num,
|
||||||
bool decodability_flag) {
|
bool decodability_flag) {
|
||||||
|
RTC_DCHECK(config_.rtp.lntf.enabled);
|
||||||
rtp_rtcp_->SendLossNotification(last_decoded_seq_num, last_received_seq_num,
|
rtp_rtcp_->SendLossNotification(last_decoded_seq_num, last_received_seq_num,
|
||||||
decodability_flag);
|
decodability_flag);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue