negotiate RED codec for audio
negotiates the RED codec for opus audio behind a field trial WebRTC-Audio-Redundancy This adds the following line to the SDP: a=rtpmap:someid RED/48000/2 To test start Chrome with --force-fieldtrials=WebRTC-Audio-Red-For-Opus/Enabled BUG=webrtc:11640 Change-Id: I8fa9fb07d03db5f90cdb08765baaa03d3d0458cc Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/176372 Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31562}
This commit is contained in:
parent
afdbf8e6f8
commit
edcd9665b8
@ -71,6 +71,7 @@ rtc_library("audio") {
|
|||||||
"../modules/audio_coding:audio_coding_module_typedefs",
|
"../modules/audio_coding:audio_coding_module_typedefs",
|
||||||
"../modules/audio_coding:audio_encoder_cng",
|
"../modules/audio_coding:audio_encoder_cng",
|
||||||
"../modules/audio_coding:audio_network_adaptor_config",
|
"../modules/audio_coding:audio_network_adaptor_config",
|
||||||
|
"../modules/audio_coding:red",
|
||||||
"../modules/audio_device",
|
"../modules/audio_device",
|
||||||
"../modules/audio_processing",
|
"../modules/audio_processing",
|
||||||
"../modules/audio_processing:api",
|
"../modules/audio_processing:api",
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
|
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
|
||||||
#include "logging/rtc_event_log/rtc_stream_config.h"
|
#include "logging/rtc_event_log/rtc_stream_config.h"
|
||||||
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
||||||
|
#include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
|
||||||
#include "modules/audio_processing/include/audio_processing.h"
|
#include "modules/audio_processing/include/audio_processing.h"
|
||||||
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
|
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
@ -659,6 +660,14 @@ bool AudioSendStream::SetupSendCodec(const Config& new_config) {
|
|||||||
new_config.send_codec_spec->format.clockrate_hz);
|
new_config.send_codec_spec->format.clockrate_hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap the encoder in a RED encoder, if RED is enabled.
|
||||||
|
if (spec.red_payload_type) {
|
||||||
|
AudioEncoderCopyRed::Config red_config;
|
||||||
|
red_config.payload_type = *spec.red_payload_type;
|
||||||
|
red_config.speech_encoder = std::move(encoder);
|
||||||
|
encoder = std::make_unique<AudioEncoderCopyRed>(std::move(red_config));
|
||||||
|
}
|
||||||
|
|
||||||
// Set currently known overhead (used in ANA, opus only).
|
// Set currently known overhead (used in ANA, opus only).
|
||||||
// If overhead changes later, it will be updated in UpdateOverheadForEncoder.
|
// If overhead changes later, it will be updated in UpdateOverheadForEncoder.
|
||||||
{
|
{
|
||||||
|
|||||||
@ -371,6 +371,7 @@ TEST(AudioSendStreamTest, ConfigToString) {
|
|||||||
config.send_codec_spec->nack_enabled = true;
|
config.send_codec_spec->nack_enabled = true;
|
||||||
config.send_codec_spec->transport_cc_enabled = false;
|
config.send_codec_spec->transport_cc_enabled = false;
|
||||||
config.send_codec_spec->cng_payload_type = 42;
|
config.send_codec_spec->cng_payload_type = 42;
|
||||||
|
config.send_codec_spec->red_payload_type = 43;
|
||||||
config.encoder_factory = MockAudioEncoderFactory::CreateUnusedFactory();
|
config.encoder_factory = MockAudioEncoderFactory::CreateUnusedFactory();
|
||||||
config.rtp.extmap_allow_mixed = true;
|
config.rtp.extmap_allow_mixed = true;
|
||||||
config.rtp.extensions.push_back(
|
config.rtp.extensions.push_back(
|
||||||
@ -383,7 +384,7 @@ TEST(AudioSendStreamTest, ConfigToString) {
|
|||||||
"send_transport: null, "
|
"send_transport: null, "
|
||||||
"min_bitrate_bps: 12000, max_bitrate_bps: 34000, "
|
"min_bitrate_bps: 12000, max_bitrate_bps: 34000, "
|
||||||
"send_codec_spec: {nack_enabled: true, transport_cc_enabled: false, "
|
"send_codec_spec: {nack_enabled: true, transport_cc_enabled: false, "
|
||||||
"cng_payload_type: 42, payload_type: 103, "
|
"cng_payload_type: 42, red_payload_type: 43, payload_type: 103, "
|
||||||
"format: {name: isac, clockrate_hz: 16000, num_channels: 1, "
|
"format: {name: isac, clockrate_hz: 16000, num_channels: 1, "
|
||||||
"parameters: {}}}}",
|
"parameters: {}}}}",
|
||||||
config.ToString());
|
config.ToString());
|
||||||
|
|||||||
@ -75,6 +75,8 @@ std::string AudioSendStream::Config::SendCodecSpec::ToString() const {
|
|||||||
ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false");
|
ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false");
|
||||||
ss << ", cng_payload_type: "
|
ss << ", cng_payload_type: "
|
||||||
<< (cng_payload_type ? rtc::ToString(*cng_payload_type) : "<unset>");
|
<< (cng_payload_type ? rtc::ToString(*cng_payload_type) : "<unset>");
|
||||||
|
ss << ", red_payload_type: "
|
||||||
|
<< (red_payload_type ? rtc::ToString(*red_payload_type) : "<unset>");
|
||||||
ss << ", payload_type: " << payload_type;
|
ss << ", payload_type: " << payload_type;
|
||||||
ss << ", format: " << rtc::ToString(format);
|
ss << ", format: " << rtc::ToString(format);
|
||||||
ss << '}';
|
ss << '}';
|
||||||
|
|||||||
@ -140,6 +140,7 @@ class AudioSendStream : public AudioSender {
|
|||||||
bool nack_enabled = false;
|
bool nack_enabled = false;
|
||||||
bool transport_cc_enabled = false;
|
bool transport_cc_enabled = false;
|
||||||
absl::optional<int> cng_payload_type;
|
absl::optional<int> cng_payload_type;
|
||||||
|
absl::optional<int> red_payload_type;
|
||||||
// If unset, use the encoder's default target bitrate.
|
// If unset, use the encoder's default target bitrate.
|
||||||
absl::optional<int> target_bitrate_bps;
|
absl::optional<int> target_bitrate_bps;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -99,6 +99,12 @@ std::string ToString(const AudioCodec& codec) {
|
|||||||
return ss.Release();
|
return ss.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this field trial is enabled, we will negotiate and use RFC 2198
|
||||||
|
// redundancy for opus audio.
|
||||||
|
bool IsAudioRedForOpusFieldTrialEnabled() {
|
||||||
|
return webrtc::field_trial::IsEnabled("WebRTC-Audio-Red-For-Opus");
|
||||||
|
}
|
||||||
|
|
||||||
bool IsCodec(const AudioCodec& codec, const char* ref_name) {
|
bool IsCodec(const AudioCodec& codec, const char* ref_name) {
|
||||||
return absl::EqualsIgnoreCase(codec.name, ref_name);
|
return absl::EqualsIgnoreCase(codec.name, ref_name);
|
||||||
}
|
}
|
||||||
@ -682,6 +688,11 @@ std::vector<AudioCodec> WebRtcVoiceEngine::CollectCodecs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add red codec.
|
||||||
|
if (IsAudioRedForOpusFieldTrialEnabled()) {
|
||||||
|
map_format({kRedCodecName, 48000, 2}, &out);
|
||||||
|
}
|
||||||
|
|
||||||
// Add telephone-event codecs last.
|
// Add telephone-event codecs last.
|
||||||
for (const auto& dtmf : generate_dtmf) {
|
for (const auto& dtmf : generate_dtmf) {
|
||||||
if (dtmf.second) {
|
if (dtmf.second) {
|
||||||
@ -1542,6 +1553,8 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
|
|||||||
}
|
}
|
||||||
auto format = AudioCodecToSdpAudioFormat(codec);
|
auto format = AudioCodecToSdpAudioFormat(codec);
|
||||||
if (!IsCodec(codec, kCnCodecName) && !IsCodec(codec, kDtmfCodecName) &&
|
if (!IsCodec(codec, kCnCodecName) && !IsCodec(codec, kDtmfCodecName) &&
|
||||||
|
(!IsAudioRedForOpusFieldTrialEnabled() ||
|
||||||
|
!IsCodec(codec, kRedCodecName)) &&
|
||||||
!engine()->decoder_factory_->IsSupportedDecoder(format)) {
|
!engine()->decoder_factory_->IsSupportedDecoder(format)) {
|
||||||
RTC_LOG(LS_ERROR) << "Unsupported codec: " << rtc::ToString(format);
|
RTC_LOG(LS_ERROR) << "Unsupported codec: " << rtc::ToString(format);
|
||||||
return false;
|
return false;
|
||||||
@ -1692,6 +1705,19 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsAudioRedForOpusFieldTrialEnabled()) {
|
||||||
|
// Loop through the codecs to find the RED codec that matches opus
|
||||||
|
// with respect to clockrate and number of channels.
|
||||||
|
for (const AudioCodec& red_codec : codecs) {
|
||||||
|
if (IsCodec(red_codec, kRedCodecName) &&
|
||||||
|
red_codec.clockrate == send_codec_spec->format.clockrate_hz &&
|
||||||
|
red_codec.channels == send_codec_spec->format.num_channels) {
|
||||||
|
send_codec_spec->red_payload_type = red_codec.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (send_codec_spec_ != send_codec_spec) {
|
if (send_codec_spec_ != send_codec_spec) {
|
||||||
send_codec_spec_ = std::move(send_codec_spec);
|
send_codec_spec_ = std::move(send_codec_spec);
|
||||||
// Apply new settings to all streams.
|
// Apply new settings to all streams.
|
||||||
|
|||||||
@ -59,6 +59,7 @@ const cricket::AudioCodec kG722CodecVoE(9, "G722", 16000, 64000, 1);
|
|||||||
const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1);
|
const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1);
|
||||||
const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1);
|
const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1);
|
||||||
const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1);
|
const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1);
|
||||||
|
const cricket::AudioCodec kRed48000Codec(112, "RED", 48000, 32000, 2);
|
||||||
const cricket::AudioCodec kTelephoneEventCodec1(106,
|
const cricket::AudioCodec kTelephoneEventCodec1(106,
|
||||||
"telephone-event",
|
"telephone-event",
|
||||||
8000,
|
8000,
|
||||||
@ -1031,6 +1032,30 @@ TEST_P(WebRtcVoiceEngineTestFake, ChangeRecvCodecPayloadType) {
|
|||||||
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
|
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that we set Opus/Red under the field trial.
|
||||||
|
TEST_P(WebRtcVoiceEngineTestFake, RecvRed) {
|
||||||
|
webrtc::test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-Red-For-Opus/Enabled/");
|
||||||
|
|
||||||
|
EXPECT_TRUE(SetupRecvStream());
|
||||||
|
cricket::AudioRecvParameters parameters;
|
||||||
|
parameters.codecs.push_back(kOpusCodec);
|
||||||
|
parameters.codecs.push_back(kRed48000Codec);
|
||||||
|
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
|
||||||
|
EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map,
|
||||||
|
(ContainerEq<std::map<int, webrtc::SdpAudioFormat>>(
|
||||||
|
{{111, {"opus", 48000, 2}}, {112, {"red", 48000, 2}}})));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we do not allow setting Opus/Red by default.
|
||||||
|
TEST_P(WebRtcVoiceEngineTestFake, RecvRedDefault) {
|
||||||
|
EXPECT_TRUE(SetupRecvStream());
|
||||||
|
cricket::AudioRecvParameters parameters;
|
||||||
|
parameters.codecs.push_back(kOpusCodec);
|
||||||
|
parameters.codecs.push_back(kRed48000Codec);
|
||||||
|
EXPECT_FALSE(channel_->SetRecvParameters(parameters));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(WebRtcVoiceEngineTestFake, SetSendBandwidthAuto) {
|
TEST_P(WebRtcVoiceEngineTestFake, SetSendBandwidthAuto) {
|
||||||
EXPECT_TRUE(SetupSendStream());
|
EXPECT_TRUE(SetupSendStream());
|
||||||
|
|
||||||
@ -1442,6 +1467,37 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecs) {
|
|||||||
EXPECT_FALSE(channel_->CanInsertDtmf());
|
EXPECT_FALSE(channel_->CanInsertDtmf());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that we set Opus/Red under the field trial.
|
||||||
|
TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsRed) {
|
||||||
|
webrtc::test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-Red-For-Opus/Enabled/");
|
||||||
|
|
||||||
|
EXPECT_TRUE(SetupSendStream());
|
||||||
|
cricket::AudioSendParameters parameters;
|
||||||
|
parameters.codecs.push_back(kOpusCodec);
|
||||||
|
parameters.codecs.push_back(kRed48000Codec);
|
||||||
|
parameters.codecs[0].id = 96;
|
||||||
|
SetSendParameters(parameters);
|
||||||
|
const auto& send_codec_spec = *GetSendStreamConfig(kSsrcX).send_codec_spec;
|
||||||
|
EXPECT_EQ(96, send_codec_spec.payload_type);
|
||||||
|
EXPECT_STRCASEEQ("opus", send_codec_spec.format.name.c_str());
|
||||||
|
EXPECT_EQ(112, send_codec_spec.red_payload_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we set do not interpret Opus/Red by default.
|
||||||
|
TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsRedDefault) {
|
||||||
|
EXPECT_TRUE(SetupSendStream());
|
||||||
|
cricket::AudioSendParameters parameters;
|
||||||
|
parameters.codecs.push_back(kOpusCodec);
|
||||||
|
parameters.codecs.push_back(kRed48000Codec);
|
||||||
|
parameters.codecs[0].id = 96;
|
||||||
|
SetSendParameters(parameters);
|
||||||
|
const auto& send_codec_spec = *GetSendStreamConfig(kSsrcX).send_codec_spec;
|
||||||
|
EXPECT_EQ(96, send_codec_spec.payload_type);
|
||||||
|
EXPECT_STRCASEEQ("opus", send_codec_spec.format.name.c_str());
|
||||||
|
EXPECT_EQ(absl::nullopt, send_codec_spec.red_payload_type);
|
||||||
|
}
|
||||||
|
|
||||||
// Test that WebRtcVoiceEngine reconfigures, rather than recreates its
|
// Test that WebRtcVoiceEngine reconfigures, rather than recreates its
|
||||||
// AudioSendStream.
|
// AudioSendStream.
|
||||||
TEST_P(WebRtcVoiceEngineTestFake, DontRecreateSendStream) {
|
TEST_P(WebRtcVoiceEngineTestFake, DontRecreateSendStream) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user