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_encoder_cng",
|
||||
"../modules/audio_coding:audio_network_adaptor_config",
|
||||
"../modules/audio_coding:red",
|
||||
"../modules/audio_device",
|
||||
"../modules/audio_processing",
|
||||
"../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/rtc_stream_config.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/rtp_rtcp/source/rtp_header_extensions.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);
|
||||
}
|
||||
|
||||
// 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).
|
||||
// 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->transport_cc_enabled = false;
|
||||
config.send_codec_spec->cng_payload_type = 42;
|
||||
config.send_codec_spec->red_payload_type = 43;
|
||||
config.encoder_factory = MockAudioEncoderFactory::CreateUnusedFactory();
|
||||
config.rtp.extmap_allow_mixed = true;
|
||||
config.rtp.extensions.push_back(
|
||||
@ -383,7 +384,7 @@ TEST(AudioSendStreamTest, ConfigToString) {
|
||||
"send_transport: null, "
|
||||
"min_bitrate_bps: 12000, max_bitrate_bps: 34000, "
|
||||
"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, "
|
||||
"parameters: {}}}}",
|
||||
config.ToString());
|
||||
|
||||
@ -75,6 +75,8 @@ std::string AudioSendStream::Config::SendCodecSpec::ToString() const {
|
||||
ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false");
|
||||
ss << ", cng_payload_type: "
|
||||
<< (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 << ", format: " << rtc::ToString(format);
|
||||
ss << '}';
|
||||
|
||||
@ -140,6 +140,7 @@ class AudioSendStream : public AudioSender {
|
||||
bool nack_enabled = false;
|
||||
bool transport_cc_enabled = false;
|
||||
absl::optional<int> cng_payload_type;
|
||||
absl::optional<int> red_payload_type;
|
||||
// If unset, use the encoder's default target bitrate.
|
||||
absl::optional<int> target_bitrate_bps;
|
||||
};
|
||||
|
||||
@ -99,6 +99,12 @@ std::string ToString(const AudioCodec& codec) {
|
||||
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) {
|
||||
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.
|
||||
for (const auto& dtmf : generate_dtmf) {
|
||||
if (dtmf.second) {
|
||||
@ -1542,6 +1553,8 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
|
||||
}
|
||||
auto format = AudioCodecToSdpAudioFormat(codec);
|
||||
if (!IsCodec(codec, kCnCodecName) && !IsCodec(codec, kDtmfCodecName) &&
|
||||
(!IsAudioRedForOpusFieldTrialEnabled() ||
|
||||
!IsCodec(codec, kRedCodecName)) &&
|
||||
!engine()->decoder_factory_->IsSupportedDecoder(format)) {
|
||||
RTC_LOG(LS_ERROR) << "Unsupported codec: " << rtc::ToString(format);
|
||||
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) {
|
||||
send_codec_spec_ = std::move(send_codec_spec);
|
||||
// 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 kCn8000Codec(13, "CN", 8000, 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,
|
||||
"telephone-event",
|
||||
8000,
|
||||
@ -1031,6 +1032,30 @@ TEST_P(WebRtcVoiceEngineTestFake, ChangeRecvCodecPayloadType) {
|
||||
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) {
|
||||
EXPECT_TRUE(SetupSendStream());
|
||||
|
||||
@ -1442,6 +1467,37 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecs) {
|
||||
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
|
||||
// AudioSendStream.
|
||||
TEST_P(WebRtcVoiceEngineTestFake, DontRecreateSendStream) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user