From b3ad8cf6ca8d2d9fa1152bb8bff624c0be83373f Mon Sep 17 00:00:00 2001 From: "kwiberg@webrtc.org" Date: Thu, 11 Dec 2014 10:08:19 +0000 Subject: [PATCH] Make an AudioEncoder subclass for iSAC BUG=3926 Previously committed: https://code.google.com/p/webrtc/source/detail?r=7675 and reverted: https://code.google.com/p/webrtc/source/detail?r=7676 R=henrik.lundin@webrtc.org, kjellander@webrtc.org Review URL: https://webrtc-codereview.appspot.com/25359004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7871 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/audio_coding/BUILD.gn | 13 +- .../isac/main/interface/audio_encoder_isac.h | 111 ++++++++++ .../isac/main/source/audio_encoder_isac.cc | 201 ++++++++++++++++++ .../codecs/isac/main/source/isac.gypi | 3 + .../audio_coding/neteq/audio_decoder_impl.cc | 77 +------ .../audio_coding/neteq/audio_decoder_impl.h | 25 --- .../neteq/audio_decoder_unittest.cc | 76 ++----- 7 files changed, 357 insertions(+), 149 deletions(-) create mode 100644 webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h create mode 100644 webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index d680d6f025..ec28431da4 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -369,11 +369,13 @@ config("isac_config") { source_set("isac") { sources = [ + "codecs/isac/main/interface/audio_encoder_isac.h", "codecs/isac/main/interface/isac.h", "codecs/isac/main/source/arith_routines.c", "codecs/isac/main/source/arith_routines.h", "codecs/isac/main/source/arith_routines_hist.c", "codecs/isac/main/source/arith_routines_logist.c", + "codecs/isac/main/source/audio_encoder_isac.cc", "codecs/isac/main/source/bandwidth_estimator.c", "codecs/isac/main/source/bandwidth_estimator.h", "codecs/isac/main/source/codec.h", @@ -420,6 +422,12 @@ source_set("isac") { "codecs/isac/main/source/transform.c", ] + if (is_clang) { + # Suppress warnings from Chrome's Clang plugins. + # See http://code.google.com/p/webrtc/issues/detail?id=163 for details. + configs -= [ "//build/config/clang:find_bad_constructs" ] + } + if (is_linux) { libs = [ "m" ] } @@ -431,7 +439,10 @@ source_set("isac") { ":isac_config", ] - deps = [ "../../common_audio" ] + deps = [ + ":audio_decoder_interface", + "../../common_audio", + ] } config("isac_fix_config") { diff --git a/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h new file mode 100644 index 0000000000..bf53b28fc2 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_ + +#include + +#include "webrtc/base/thread_annotations.h" +#include "webrtc/modules/audio_coding/codecs/audio_decoder.h" +#include "webrtc/modules/audio_coding/codecs/audio_encoder.h" +#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class CriticalSectionWrapper; + +class AudioEncoderDecoderIsac : public AudioEncoder, public AudioDecoder { + public: + // For constructing an encoder in instantaneous 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 + 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. + }; + + // For constructing an encoder in channel-adaptive mode. The sample rate must + // be 16000 Hz; the initial frame size can be 30 or 60 ms; and the initial bit + // rate can be 10000-56000 bps. + struct ConfigAdaptive { + ConfigAdaptive(); + bool IsOk() const; + int payload_type; + int sample_rate_hz; + int initial_frame_size_ms; + int initial_bit_rate; + bool enforce_frame_size; // Prevent adaptive changes to the frame size? + }; + + explicit AudioEncoderDecoderIsac(const Config& config); + explicit AudioEncoderDecoderIsac(const ConfigAdaptive& config); + virtual ~AudioEncoderDecoderIsac() OVERRIDE; + + // AudioEncoder public methods. + virtual int sample_rate_hz() const OVERRIDE; + virtual int num_channels() const OVERRIDE; + virtual int Num10MsFramesInNextPacket() const OVERRIDE; + virtual int Max10MsFramesInAPacket() const OVERRIDE; + + // AudioDecoder methods. + virtual int Decode(const uint8_t* encoded, + size_t encoded_len, + int16_t* decoded, + SpeechType* speech_type) OVERRIDE; + virtual int DecodeRedundant(const uint8_t* encoded, + size_t encoded_len, + int16_t* decoded, + SpeechType* speech_type) OVERRIDE; + virtual bool HasDecodePlc() const OVERRIDE; + virtual int DecodePlc(int num_frames, int16_t* decoded) OVERRIDE; + virtual int Init() OVERRIDE; + virtual int IncomingPacket(const uint8_t* payload, + size_t payload_len, + uint16_t rtp_sequence_number, + uint32_t rtp_timestamp, + uint32_t arrival_timestamp) OVERRIDE; + virtual int ErrorCode() OVERRIDE; + + protected: + // AudioEncoder protected method. + virtual bool EncodeInternal(uint32_t timestamp, + const int16_t* audio, + size_t max_encoded_bytes, + uint8_t* encoded, + size_t* encoded_bytes, + EncodedInfo* info) OVERRIDE; + + private: + const int payload_type_; + + // iSAC encoder/decoder state, guarded by a mutex to ensure that encode calls + // from one thread won't clash with decode calls from another thread. + const scoped_ptr lock_; + ISACStruct* isac_state_ GUARDED_BY(lock_); + + // Have we accepted input but not yet emitted it in a packet? + bool packet_in_progress_; + + // Timestamp of the first input of the currently in-progress packet. + uint32_t packet_timestamp_; + + DISALLOW_COPY_AND_ASSIGN(AudioEncoderDecoderIsac); +}; + +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_ diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc new file mode 100644 index 0000000000..79e75e27be --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2014 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 "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" + +#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +namespace webrtc { + +namespace { + +const int kIsacPayloadType = 103; + +int DivExact(int a, int b) { + CHECK_EQ(a % b, 0); + return a / b; +} + +} // namespace + +AudioEncoderDecoderIsac::Config::Config() + : payload_type(kIsacPayloadType), + sample_rate_hz(16000), + frame_size_ms(30), + bit_rate(32000) {} + +bool AudioEncoderDecoderIsac::Config::IsOk() const { + switch (sample_rate_hz) { + case 16000: + return (frame_size_ms == 30 || frame_size_ms == 60) && + bit_rate >= 10000 && bit_rate <= 32000; + case 32000: + return frame_size_ms == 30 && bit_rate >= 10000 && bit_rate <= 56000; + default: + return false; + } +} + +AudioEncoderDecoderIsac::ConfigAdaptive::ConfigAdaptive() + : payload_type(kIsacPayloadType), + sample_rate_hz(16000), + initial_frame_size_ms(30), + initial_bit_rate(32000), + enforce_frame_size(false) {} + +bool AudioEncoderDecoderIsac::ConfigAdaptive::IsOk() const { + return sample_rate_hz == 16000 && + (initial_frame_size_ms == 30 || initial_frame_size_ms == 60) && + initial_bit_rate >= 10000 && initial_bit_rate <= 56000; +} + +AudioEncoderDecoderIsac::AudioEncoderDecoderIsac(const Config& config) + : payload_type_(config.payload_type), + lock_(CriticalSectionWrapper::CreateCriticalSection()), + packet_in_progress_(false) { + CHECK(config.IsOk()); + CHECK_EQ(0, WebRtcIsac_Create(&isac_state_)); + CHECK_EQ(0, WebRtcIsac_EncoderInit(isac_state_, 1)); + CHECK_EQ(0, WebRtcIsac_SetEncSampRate(isac_state_, config.sample_rate_hz)); + CHECK_EQ(0, WebRtcIsac_Control(isac_state_, config.bit_rate, + config.frame_size_ms)); + CHECK_EQ(0, WebRtcIsac_SetDecSampRate(isac_state_, config.sample_rate_hz)); +} + +AudioEncoderDecoderIsac::AudioEncoderDecoderIsac(const ConfigAdaptive& config) + : payload_type_(config.payload_type), + lock_(CriticalSectionWrapper::CreateCriticalSection()), + packet_in_progress_(false) { + CHECK(config.IsOk()); + CHECK_EQ(0, WebRtcIsac_Create(&isac_state_)); + CHECK_EQ(0, WebRtcIsac_EncoderInit(isac_state_, 0)); + CHECK_EQ(0, WebRtcIsac_SetEncSampRate(isac_state_, config.sample_rate_hz)); + CHECK_EQ(0, WebRtcIsac_ControlBwe(isac_state_, config.initial_bit_rate, + config.initial_frame_size_ms, + config.enforce_frame_size)); + CHECK_EQ(0, WebRtcIsac_SetDecSampRate(isac_state_, config.sample_rate_hz)); +} + +AudioEncoderDecoderIsac::~AudioEncoderDecoderIsac() { + CHECK_EQ(0, WebRtcIsac_Free(isac_state_)); +} + +int AudioEncoderDecoderIsac::sample_rate_hz() const { + CriticalSectionScoped cs(lock_.get()); + return WebRtcIsac_EncSampRate(isac_state_); +} + +int AudioEncoderDecoderIsac::num_channels() const { + return 1; +} + +int AudioEncoderDecoderIsac::Num10MsFramesInNextPacket() const { + CriticalSectionScoped cs(lock_.get()); + const int samples_in_next_packet = WebRtcIsac_GetNewFrameLen(isac_state_); + return DivExact(samples_in_next_packet, DivExact(sample_rate_hz(), 100)); +} + +int AudioEncoderDecoderIsac::Max10MsFramesInAPacket() const { + return 6; // iSAC puts at most 60 ms in a packet. +} + +bool AudioEncoderDecoderIsac::EncodeInternal(uint32_t timestamp, + const int16_t* audio, + size_t max_encoded_bytes, + uint8_t* encoded, + size_t* encoded_bytes, + EncodedInfo* info) { + if (!packet_in_progress_) { + // Starting a new packet; remember the timestamp for later. + packet_in_progress_ = true; + packet_timestamp_ = timestamp; + } + int r; + { + CriticalSectionScoped cs(lock_.get()); + r = WebRtcIsac_Encode(isac_state_, audio, encoded); + } + if (r < 0) { + // An error occurred; propagate it to the caller. + packet_in_progress_ = false; + return false; + } + + // WebRtcIsac_Encode doesn't allow us to tell it the size of the output + // buffer. All we can do is check for an overrun after the fact. + CHECK(static_cast(r) <= max_encoded_bytes); + + *encoded_bytes = r; + if (r > 0) { + // Got enough input to produce a packet. Return the saved timestamp from + // the first chunk of input that went into the packet. + packet_in_progress_ = false; + info->encoded_timestamp = packet_timestamp_; + info->payload_type = payload_type_; + } + return true; +} + +int AudioEncoderDecoderIsac::Decode(const uint8_t* encoded, + size_t encoded_len, + int16_t* decoded, + SpeechType* speech_type) { + CriticalSectionScoped cs(lock_.get()); + int16_t temp_type = 1; // Default is speech. + int16_t ret = + WebRtcIsac_Decode(isac_state_, encoded, static_cast(encoded_len), + decoded, &temp_type); + *speech_type = ConvertSpeechType(temp_type); + return ret; +} + +int AudioEncoderDecoderIsac::DecodeRedundant(const uint8_t* encoded, + size_t encoded_len, + int16_t* decoded, + SpeechType* speech_type) { + CriticalSectionScoped cs(lock_.get()); + int16_t temp_type = 1; // Default is speech. + int16_t ret = WebRtcIsac_DecodeRcu(isac_state_, encoded, + static_cast(encoded_len), decoded, + &temp_type); + *speech_type = ConvertSpeechType(temp_type); + return ret; +} + +bool AudioEncoderDecoderIsac::HasDecodePlc() const { return true; } + +int AudioEncoderDecoderIsac::DecodePlc(int num_frames, int16_t* decoded) { + CriticalSectionScoped cs(lock_.get()); + return WebRtcIsac_DecodePlc(isac_state_, decoded, num_frames); +} + +int AudioEncoderDecoderIsac::Init() { + CriticalSectionScoped cs(lock_.get()); + return WebRtcIsac_DecoderInit(isac_state_); +} + +int AudioEncoderDecoderIsac::IncomingPacket(const uint8_t* payload, + size_t payload_len, + uint16_t rtp_sequence_number, + uint32_t rtp_timestamp, + uint32_t arrival_timestamp) { + CriticalSectionScoped cs(lock_.get()); + return WebRtcIsac_UpdateBwEstimate( + isac_state_, payload, static_cast(payload_len), + rtp_sequence_number, rtp_timestamp, arrival_timestamp); +} + +int AudioEncoderDecoderIsac::ErrorCode() { + CriticalSectionScoped cs(lock_.get()); + return WebRtcIsac_GetErrorCode(isac_state_); +} + +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi index 5ed6d448bb..8f8cd35a53 100644 --- a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi +++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi @@ -13,6 +13,7 @@ 'type': 'static_library', 'dependencies': [ '<(webrtc_root)/common_audio/common_audio.gyp:common_audio', + 'audio_decoder_interface', ], 'include_dirs': [ '../interface', @@ -25,10 +26,12 @@ ], }, 'sources': [ + '../interface/audio_encoder_isac.h', '../interface/isac.h', 'arith_routines.c', 'arith_routines_hist.c', 'arith_routines_logist.c', + 'audio_encoder_isac.cc', 'bandwidth_estimator.c', 'crc.c', 'decode.c', diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc index 4c0bd31804..f565faf1ce 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc @@ -26,7 +26,7 @@ #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" #endif #ifdef WEBRTC_CODEC_ISAC -#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" +#include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" #endif #ifdef WEBRTC_CODEC_OPUS #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" @@ -127,67 +127,6 @@ int AudioDecoderIlbc::Init() { } #endif -// iSAC float -#ifdef WEBRTC_CODEC_ISAC -AudioDecoderIsac::AudioDecoderIsac(int decode_sample_rate_hz) { - DCHECK(decode_sample_rate_hz == 16000 || decode_sample_rate_hz == 32000); - WebRtcIsac_Create(&isac_state_); - WebRtcIsac_SetDecSampRate(isac_state_, decode_sample_rate_hz); -} - -AudioDecoderIsac::~AudioDecoderIsac() { - WebRtcIsac_Free(isac_state_); -} - -int AudioDecoderIsac::Decode(const uint8_t* encoded, size_t encoded_len, - int16_t* decoded, SpeechType* speech_type) { - int16_t temp_type = 1; // Default is speech. - int16_t ret = WebRtcIsac_Decode(isac_state_, - encoded, - static_cast(encoded_len), decoded, - &temp_type); - *speech_type = ConvertSpeechType(temp_type); - return ret; -} - -int AudioDecoderIsac::DecodeRedundant(const uint8_t* encoded, - size_t encoded_len, int16_t* decoded, - SpeechType* speech_type) { - int16_t temp_type = 1; // Default is speech. - int16_t ret = WebRtcIsac_DecodeRcu(isac_state_, - encoded, - static_cast(encoded_len), decoded, - &temp_type); - *speech_type = ConvertSpeechType(temp_type); - return ret; -} - -int AudioDecoderIsac::DecodePlc(int num_frames, int16_t* decoded) { - return WebRtcIsac_DecodePlc(isac_state_, decoded, num_frames); -} - -int AudioDecoderIsac::Init() { - return WebRtcIsac_DecoderInit(isac_state_); -} - -int AudioDecoderIsac::IncomingPacket(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp) { - return WebRtcIsac_UpdateBwEstimate(isac_state_, - payload, - static_cast(payload_len), - rtp_sequence_number, - rtp_timestamp, - arrival_timestamp); -} - -int AudioDecoderIsac::ErrorCode() { - return WebRtcIsac_GetErrorCode(isac_state_); -} -#endif - // iSAC fix #ifdef WEBRTC_CODEC_ISACFX AudioDecoderIsacFix::AudioDecoderIsacFix() { @@ -549,11 +488,17 @@ AudioDecoder* CreateAudioDecoder(NetEqDecoder codec_type) { case kDecoderISAC: return new AudioDecoderIsacFix; #elif defined(WEBRTC_CODEC_ISAC) - case kDecoderISAC: - return new AudioDecoderIsac(16000); + case kDecoderISAC: { + AudioEncoderDecoderIsac::Config config; + config.sample_rate_hz = 16000; + return new AudioEncoderDecoderIsac(config); + } case kDecoderISACswb: - case kDecoderISACfb: - return new AudioDecoderIsac(32000); + case kDecoderISACfb: { + AudioEncoderDecoderIsac::Config config; + config.sample_rate_hz = 32000; + return new AudioEncoderDecoderIsac(config); + } #endif #ifdef WEBRTC_CODEC_PCM16 case kDecoderPCM16B: diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h index 68d3627e3f..7d1172c07d 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h @@ -130,31 +130,6 @@ class AudioDecoderIlbc : public AudioDecoder { }; #endif -#ifdef WEBRTC_CODEC_ISAC -class AudioDecoderIsac : public AudioDecoder { - public: - explicit AudioDecoderIsac(int decode_sample_rate_hz); - virtual ~AudioDecoderIsac(); - virtual int Decode(const uint8_t* encoded, size_t encoded_len, - int16_t* decoded, SpeechType* speech_type); - virtual int DecodeRedundant(const uint8_t* encoded, size_t encoded_len, - int16_t* decoded, SpeechType* speech_type); - virtual bool HasDecodePlc() const { return true; } - virtual int DecodePlc(int num_frames, int16_t* decoded); - virtual int Init(); - virtual int IncomingPacket(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp); - virtual int ErrorCode(); - - private: - ISACStruct* isac_state_; - DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsac); -}; -#endif - #ifdef WEBRTC_CODEC_ISACFX class AudioDecoderIsacFix : public AudioDecoder { public: diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 417e458697..056bc5a24a 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -22,7 +22,7 @@ #include "webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h" #include "webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h" #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" -#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" +#include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" #include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h" @@ -354,76 +354,38 @@ class AudioDecoderIsacFloatTest : public AudioDecoderTest { protected: AudioDecoderIsacFloatTest() : AudioDecoderTest() { codec_input_rate_hz_ = 16000; - input_size_ = 160; frame_size_ = 480; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderIsac(16000); - assert(decoder_); - WebRtcIsac_Create(&encoder_); - WebRtcIsac_SetEncSampRate(encoder_, 16000); - } + AudioEncoderDecoderIsac::Config config; + config.payload_type = payload_type_; + config.sample_rate_hz = codec_input_rate_hz_; + config.frame_size_ms = + 1000 * static_cast(frame_size_) / codec_input_rate_hz_; - ~AudioDecoderIsacFloatTest() { - WebRtcIsac_Free(encoder_); + // We need to create separate AudioEncoderDecoderIsac objects for encoding + // and decoding, because the test class destructor destroys them both. + audio_encoder_.reset(new AudioEncoderDecoderIsac(config)); + decoder_ = new AudioEncoderDecoderIsac(config); } - - virtual void InitEncoder() { - ASSERT_EQ(0, WebRtcIsac_EncoderInit(encoder_, 1)); // Fixed mode. - ASSERT_EQ(0, WebRtcIsac_Control(encoder_, 32000, 30)); // 32 kbps, 30 ms. - } - - virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, - uint8_t* output) { - // Insert 3 * 10 ms. Expect non-zero output on third call. - EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, output)); - input += input_size_; - EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, output)); - input += input_size_; - int enc_len_bytes = WebRtcIsac_Encode(encoder_, input, output); - EXPECT_GT(enc_len_bytes, 0); - return enc_len_bytes; - } - - ISACStruct* encoder_; - int input_size_; }; class AudioDecoderIsacSwbTest : public AudioDecoderTest { protected: AudioDecoderIsacSwbTest() : AudioDecoderTest() { codec_input_rate_hz_ = 32000; - input_size_ = 320; frame_size_ = 960; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderIsac(32000); - assert(decoder_); - WebRtcIsac_Create(&encoder_); - WebRtcIsac_SetEncSampRate(encoder_, 32000); - } + AudioEncoderDecoderIsac::Config config; + config.payload_type = payload_type_; + config.sample_rate_hz = codec_input_rate_hz_; + config.frame_size_ms = + 1000 * static_cast(frame_size_) / codec_input_rate_hz_; - ~AudioDecoderIsacSwbTest() { - WebRtcIsac_Free(encoder_); + // We need to create separate AudioEncoderDecoderIsac objects for encoding + // and decoding, because the test class destructor destroys them both. + audio_encoder_.reset(new AudioEncoderDecoderIsac(config)); + decoder_ = new AudioEncoderDecoderIsac(config); } - - virtual void InitEncoder() { - ASSERT_EQ(0, WebRtcIsac_EncoderInit(encoder_, 1)); // Fixed mode. - ASSERT_EQ(0, WebRtcIsac_Control(encoder_, 32000, 30)); // 32 kbps, 30 ms. - } - - virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, - uint8_t* output) { - // Insert 3 * 10 ms. Expect non-zero output on third call. - EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, output)); - input += input_size_; - EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, output)); - input += input_size_; - int enc_len_bytes = WebRtcIsac_Encode(encoder_, input, output); - EXPECT_GT(enc_len_bytes, 0); - return enc_len_bytes; - } - - ISACStruct* encoder_; - int input_size_; }; class AudioDecoderIsacFixTest : public AudioDecoderTest {