diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h index cda554876b..ad531667f5 100644 --- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h +++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h @@ -25,8 +25,7 @@ class CriticalSectionWrapper; template class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder { public: - // For constructing an encoder in instantaneous mode. Allowed combinations - // are + // Allowed combinations of sample rate, frame size, and bit rate are // - 16000 Hz, 30 ms, 10000-32000 bps // - 16000 Hz, 60 ms, 10000-32000 bps // - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support) @@ -34,34 +33,24 @@ class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder { struct Config { Config(); bool IsOk() const; + int payload_type; int sample_rate_hz; int frame_size_ms; - int bit_rate; // Limit on the short-term average bit rate, in bits/second. - int max_bit_rate; + int bit_rate; // Limit on the short-term average bit rate, in bits/s. int max_payload_size_bytes; - }; + int max_bit_rate; - // For constructing an encoder in channel-adaptive mode. Allowed combinations - // are - // - 16000 Hz, 30 ms, 10000-32000 bps - // - 16000 Hz, 60 ms, 10000-32000 bps - // - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support) - // - 48000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support) - struct ConfigAdaptive { - ConfigAdaptive(); - bool IsOk() const; - int payload_type; - int sample_rate_hz; - int initial_frame_size_ms; - int initial_bit_rate; - int max_bit_rate; - bool enforce_frame_size; // Prevent adaptive changes to the frame size? - int max_payload_size_bytes; + // If true, the encoder will dynamically adjust frame size and bit rate; + // the configured values are then merely the starting point. + bool adaptive_mode; + + // In adaptive mode, prevent adaptive changes to the frame size. (Not used + // in nonadaptive mode.) + bool enforce_frame_size; }; explicit AudioEncoderDecoderIsacT(const Config& config); - explicit AudioEncoderDecoderIsacT(const ConfigAdaptive& config); ~AudioEncoderDecoderIsacT() override; // AudioEncoder public methods. diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h index e81686a96c..c5982f5be6 100644 --- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h +++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h @@ -30,8 +30,10 @@ AudioEncoderDecoderIsacT::Config::Config() sample_rate_hz(16000), frame_size_ms(30), bit_rate(kDefaultBitRate), + max_payload_size_bytes(-1), max_bit_rate(-1), - max_payload_size_bytes(-1) { + adaptive_mode(false), + enforce_frame_size(false) { } template @@ -47,7 +49,7 @@ bool AudioEncoderDecoderIsacT::Config::IsOk() const { if (max_payload_size_bytes > 400) return false; return (frame_size_ms == 30 || frame_size_ms == 60) && - ((bit_rate >= 10000 && bit_rate <= 32000) || bit_rate == 0); + (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 32000)); case 32000: case 48000: if (max_bit_rate > 160000) @@ -56,46 +58,7 @@ bool AudioEncoderDecoderIsacT::Config::IsOk() const { return false; return T::has_swb && (frame_size_ms == 30 && - ((bit_rate >= 10000 && bit_rate <= 56000) || bit_rate == 0)); - default: - return false; - } -} - -template -AudioEncoderDecoderIsacT::ConfigAdaptive::ConfigAdaptive() - : payload_type(kIsacPayloadType), - sample_rate_hz(16000), - initial_frame_size_ms(30), - initial_bit_rate(kDefaultBitRate), - max_bit_rate(-1), - enforce_frame_size(false), - max_payload_size_bytes(-1) { -} - -template -bool AudioEncoderDecoderIsacT::ConfigAdaptive::IsOk() const { - if (max_bit_rate < 32000 && max_bit_rate != -1) - return false; - if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1) - return false; - switch (sample_rate_hz) { - case 16000: - if (max_bit_rate > 53400) - return false; - if (max_payload_size_bytes > 400) - return false; - return (initial_frame_size_ms == 30 || initial_frame_size_ms == 60) && - initial_bit_rate >= 10000 && initial_bit_rate <= 32000; - case 32000: - case 48000: - if (max_bit_rate > 160000) - return false; - if (max_payload_size_bytes > 600) - return false; - return T::has_swb && - (initial_frame_size_ms == 30 && initial_bit_rate >= 10000 && - initial_bit_rate <= 56000); + (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 56000))); default: return false; } @@ -110,11 +73,16 @@ AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT(const Config& config) packet_in_progress_(false) { CHECK(config.IsOk()); CHECK_EQ(0, T::Create(&isac_state_)); - CHECK_EQ(0, T::EncoderInit(isac_state_, 1)); + CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1)); CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); - CHECK_EQ(0, T::Control(isac_state_, config.bit_rate == 0 ? kDefaultBitRate - : config.bit_rate, - config.frame_size_ms)); + const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate; + if (config.adaptive_mode) { + CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, + config.frame_size_ms, config.enforce_frame_size)); + + } else { + CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms)); + } // When config.sample_rate_hz is set to 48000 Hz (iSAC-fb), the decoder is // still set to 32000 Hz, since there is no full-band mode in the decoder. CHECK_EQ(0, T::SetDecSampRate(isac_state_, @@ -124,29 +92,7 @@ AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT(const Config& config) T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes)); if (config.max_bit_rate != -1) CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate)); -} - -template -AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT( - const ConfigAdaptive& config) - : payload_type_(config.payload_type), - state_lock_(CriticalSectionWrapper::CreateCriticalSection()), - decoder_sample_rate_hz_(0), - lock_(CriticalSectionWrapper::CreateCriticalSection()), - packet_in_progress_(false) { - CHECK(config.IsOk()); - CHECK_EQ(0, T::Create(&isac_state_)); - CHECK_EQ(0, T::EncoderInit(isac_state_, 0)); - CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); - CHECK_EQ(0, T::ControlBwe(isac_state_, config.initial_bit_rate, - config.initial_frame_size_ms, - config.enforce_frame_size)); - CHECK_EQ(0, T::SetDecSampRate(isac_state_, config.sample_rate_hz)); - if (config.max_payload_size_bytes != -1) - CHECK_EQ(0, - T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes)); - if (config.max_bit_rate != -1) - CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate)); + CHECK_EQ(0, T::DecoderInit(isac_state_)); } template diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc new file mode 100644 index 0000000000..ee5c03121b --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" + +namespace webrtc { + +namespace { + +void TestBadConfig(const AudioEncoderDecoderIsac::Config& config) { + EXPECT_FALSE(config.IsOk()); +} + +void TestGoodConfig(const AudioEncoderDecoderIsac::Config& config) { + EXPECT_TRUE(config.IsOk()); + AudioEncoderDecoderIsac ed(config); +} + +// Wrap subroutine calls that test things in this, so that the error messages +// will be accompanied by stack traces that make it possible to tell which +// subroutine invocation caused the failure. +#define S(x) do { SCOPED_TRACE(#x); x; } while (0) + +} // namespace + +TEST(AudioEncoderIsacTest, TestConfigBitrate) { + AudioEncoderDecoderIsac::Config config; + + // The default value is some real, positive value. + EXPECT_GT(config.bit_rate, 1); + S(TestGoodConfig(config)); + + // 0 is another way to ask for the default value. + config.bit_rate = 0; + S(TestGoodConfig(config)); + + // Try some unreasonable values and watch them fail. + config.bit_rate = -1; + S(TestBadConfig(config)); + config.bit_rate = 1; + S(TestBadConfig(config)); + config.bit_rate = std::numeric_limits::max(); + S(TestBadConfig(config)); +} + +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc index 6b04081d3e..c852d8b3e6 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc @@ -293,51 +293,34 @@ void ACMGenericCodec::ResetAudioEncoder() { #endif #ifdef WEBRTC_CODEC_ISACFX } else if (!STR_CASE_CMP(codec_inst.plname, "ISAC")) { - DCHECK_EQ(codec_inst.plfreq, 16000); is_isac_ = true; - AudioEncoderDecoderIsacFix* enc_dec; - if (codec_inst.rate == -1) { - // Adaptive mode. - AudioEncoderDecoderIsacFix::ConfigAdaptive config; - config.payload_type = codec_inst.pltype; - enc_dec = new AudioEncoderDecoderIsacFix(config); - } else { - // Channel independent mode. - AudioEncoderDecoderIsacFix::Config config; + AudioEncoderDecoderIsacFix::Config config; + config.payload_type = codec_inst.pltype; + config.sample_rate_hz = codec_inst.plfreq; + config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 16); + if (codec_inst.rate != -1) config.bit_rate = codec_inst.rate; - config.frame_size_ms = codec_inst.pacsize / 16; - config.payload_type = codec_inst.pltype; - enc_dec = new AudioEncoderDecoderIsacFix(config); - } + config.max_payload_size_bytes = max_payload_size_bytes_; + config.max_bit_rate = max_rate_bps_; + config.adaptive_mode = (codec_inst.rate == -1); + auto* enc_dec = new AudioEncoderDecoderIsacFix(config); decoder_proxy_.SetDecoder(enc_dec); audio_encoder_.reset(enc_dec); #endif #ifdef WEBRTC_CODEC_ISAC } else if (!STR_CASE_CMP(codec_inst.plname, "ISAC")) { is_isac_ = true; - AudioEncoderDecoderIsac* enc_dec; - if (codec_inst.rate == -1) { - // Adaptive mode. - AudioEncoderDecoderIsac::ConfigAdaptive config; - config.sample_rate_hz = codec_inst.plfreq; - config.initial_frame_size_ms = rtc::CheckedDivExact( - 1000 * codec_inst.pacsize, config.sample_rate_hz); - config.max_payload_size_bytes = max_payload_size_bytes_; - config.max_bit_rate = max_rate_bps_; - config.payload_type = codec_inst.pltype; - enc_dec = new AudioEncoderDecoderIsac(config); - } else { - // Channel independent mode. - AudioEncoderDecoderIsac::Config config; - config.sample_rate_hz = codec_inst.plfreq; + AudioEncoderDecoderIsac::Config config; + config.payload_type = codec_inst.pltype; + config.sample_rate_hz = codec_inst.plfreq; + config.frame_size_ms = + rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz); + if (codec_inst.rate != -1) config.bit_rate = codec_inst.rate; - config.frame_size_ms = rtc::CheckedDivExact(1000 * codec_inst.pacsize, - config.sample_rate_hz); - config.max_payload_size_bytes = max_payload_size_bytes_; - config.max_bit_rate = max_rate_bps_; - config.payload_type = codec_inst.pltype; - enc_dec = new AudioEncoderDecoderIsac(config); - } + config.max_payload_size_bytes = max_payload_size_bytes_; + config.max_bit_rate = max_rate_bps_; + config.adaptive_mode = (codec_inst.rate == -1); + auto* enc_dec = new AudioEncoderDecoderIsac(config); decoder_proxy_.SetDecoder(enc_dec); audio_encoder_.reset(enc_dec); #endif diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 728caefcfe..334a2fc4ba 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -361,6 +361,7 @@ class AudioDecoderIsacFloatTest : public AudioDecoderTest { AudioEncoderDecoderIsac::Config config; config.payload_type = payload_type_; config.sample_rate_hz = codec_input_rate_hz_; + config.adaptive_mode = false; config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; @@ -380,6 +381,7 @@ class AudioDecoderIsacSwbTest : public AudioDecoderTest { AudioEncoderDecoderIsac::Config config; config.payload_type = payload_type_; config.sample_rate_hz = codec_input_rate_hz_; + config.adaptive_mode = false; config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; @@ -399,6 +401,7 @@ class AudioDecoderIsacFixTest : public AudioDecoderTest { AudioEncoderDecoderIsacFix::Config config; config.payload_type = payload_type_; config.sample_rate_hz = codec_input_rate_hz_; + config.adaptive_mode = false; config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index dbf01878a5..771e67257a 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -108,6 +108,7 @@ 'audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc', 'audio_coding/codecs/isac/fix/source/lpc_masking_model_unittest.cc', 'audio_coding/codecs/isac/fix/source/transform_unittest.cc', + 'audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc', 'audio_coding/codecs/isac/main/source/isac_unittest.cc', 'audio_coding/codecs/opus/audio_encoder_opus_unittest.cc', 'audio_coding/codecs/opus/opus_unittest.cc',