diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index 2a9087c32..97b432d32 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -369,6 +369,8 @@ config("isac_config") { source_set("isac") { sources = [ + "codecs/isac/audio_encoder_isac_t.h", + "codecs/isac/audio_encoder_isac_t_impl.h", "codecs/isac/main/interface/audio_encoder_isac.h", "codecs/isac/main/interface/isac.h", "codecs/isac/main/source/arith_routines.c", @@ -454,11 +456,15 @@ config("isac_fix_config") { source_set("isacfix") { sources = [ + "codecs/isac/audio_encoder_isac_t.h", + "codecs/isac/audio_encoder_isac_t_impl.h", + "codecs/isac/fix/interface/audio_encoder_isacfix.h", "codecs/isac/fix/interface/isacfix.h", "codecs/isac/fix/source/arith_routines.c", "codecs/isac/fix/source/arith_routines_hist.c", "codecs/isac/fix/source/arith_routines_logist.c", "codecs/isac/fix/source/arith_routins.h", + "codecs/isac/fix/source/audio_encoder_isacfix.cc", "codecs/isac/fix/source/bandwidth_estimator.c", "codecs/isac/fix/source/bandwidth_estimator.h", "codecs/isac/fix/source/codec.h", @@ -496,6 +502,12 @@ source_set("isacfix") { "codecs/isac/fix/source/transform_tables.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_win) { defines = [ "WEBRTC_LINUX" ] } 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 new file mode 100644 index 000000000..a20da9da9 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.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_AUDIO_ENCODER_ISAC_T_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_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/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class CriticalSectionWrapper; + +template +class AudioEncoderDecoderIsacT : 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 (if T has 32 kHz support) + 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 if T has 32 kHz support, 10000-32000 bps + // otherwise. + 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 AudioEncoderDecoderIsacT(const Config& config); + explicit AudioEncoderDecoderIsacT(const ConfigAdaptive& config); + virtual ~AudioEncoderDecoderIsacT() 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, + 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_; + typename T::instance_type* 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(AudioEncoderDecoderIsacT); +}; + +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_ 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 new file mode 100644 index 000000000..7c13e8728 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h @@ -0,0 +1,226 @@ +/* + * 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_AUDIO_ENCODER_ISAC_T_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ + +#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 { + +const int kIsacPayloadType = 103; + +inline int DivExact(int a, int b) { + CHECK_EQ(a % b, 0); + return a / b; +} + +template +AudioEncoderDecoderIsacT::Config::Config() + : payload_type(kIsacPayloadType), + sample_rate_hz(16000), + frame_size_ms(30), + bit_rate(32000) { +} + +template +bool AudioEncoderDecoderIsacT::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 T::has_32kHz && + (frame_size_ms == 30 && bit_rate >= 10000 && bit_rate <= 56000); + default: + return false; + } +} + +template +AudioEncoderDecoderIsacT::ConfigAdaptive::ConfigAdaptive() + : payload_type(kIsacPayloadType), + sample_rate_hz(16000), + initial_frame_size_ms(30), + initial_bit_rate(32000), + enforce_frame_size(false) { +} + +template +bool AudioEncoderDecoderIsacT::ConfigAdaptive::IsOk() const { + static const int max_rate = T::has_32kHz ? 56000 : 32000; + return sample_rate_hz == 16000 && + (initial_frame_size_ms == 30 || initial_frame_size_ms == 60) && + initial_bit_rate >= 10000 && initial_bit_rate <= max_rate; +} + +template +AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT(const Config& config) + : payload_type_(config.payload_type), + lock_(CriticalSectionWrapper::CreateCriticalSection()), + 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::SetEncSampRate(isac_state_, config.sample_rate_hz)); + CHECK_EQ(0, T::Control(isac_state_, config.bit_rate, config.frame_size_ms)); + CHECK_EQ(0, T::SetDecSampRate(isac_state_, config.sample_rate_hz)); +} + +template +AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT( + const ConfigAdaptive& config) + : payload_type_(config.payload_type), + 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)); +} + +template +AudioEncoderDecoderIsacT::~AudioEncoderDecoderIsacT() { + CHECK_EQ(0, T::Free(isac_state_)); +} + +template +int AudioEncoderDecoderIsacT::sample_rate_hz() const { + CriticalSectionScoped cs(lock_.get()); + return T::EncSampRate(isac_state_); +} + +template +int AudioEncoderDecoderIsacT::num_channels() const { + return 1; +} + +template +int AudioEncoderDecoderIsacT::Num10MsFramesInNextPacket() const { + CriticalSectionScoped cs(lock_.get()); + const int samples_in_next_packet = T::GetNewFrameLen(isac_state_); + return DivExact(samples_in_next_packet, DivExact(sample_rate_hz(), 100)); +} + +template +int AudioEncoderDecoderIsacT::Max10MsFramesInAPacket() const { + return 6; // iSAC puts at most 60 ms in a packet. +} + +template +bool AudioEncoderDecoderIsacT::EncodeInternal(uint32_t timestamp, + const int16_t* audio, + size_t max_encoded_bytes, + uint8_t* encoded, + 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 = T::Encode(isac_state_, audio, encoded); + } + if (r < 0) { + // An error occurred; propagate it to the caller. + packet_in_progress_ = false; + return false; + } + + // T::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); + + info->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; +} + +template +int AudioEncoderDecoderIsacT::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 = + T::Decode(isac_state_, encoded, static_cast(encoded_len), + decoded, &temp_type); + *speech_type = ConvertSpeechType(temp_type); + return ret; +} + +template +int AudioEncoderDecoderIsacT::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 = + T::DecodeRcu(isac_state_, encoded, static_cast(encoded_len), + decoded, &temp_type); + *speech_type = ConvertSpeechType(temp_type); + return ret; +} + +template +bool AudioEncoderDecoderIsacT::HasDecodePlc() const { + return true; +} + +template +int AudioEncoderDecoderIsacT::DecodePlc(int num_frames, int16_t* decoded) { + CriticalSectionScoped cs(lock_.get()); + return T::DecodePlc(isac_state_, decoded, num_frames); +} + +template +int AudioEncoderDecoderIsacT::Init() { + CriticalSectionScoped cs(lock_.get()); + return T::DecoderInit(isac_state_); +} + +template +int AudioEncoderDecoderIsacT::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 T::UpdateBwEstimate( + isac_state_, payload, static_cast(payload_len), + rtp_sequence_number, rtp_timestamp, arrival_timestamp); +} + +template +int AudioEncoderDecoderIsacT::ErrorCode() { + CriticalSectionScoped cs(lock_.get()); + return T::GetErrorCode(isac_state_); +} + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h b/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h new file mode 100644 index 000000000..06722b105 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h @@ -0,0 +1,108 @@ +/* + * 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_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_ + +#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h" +#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" + +namespace webrtc { + +struct IsacFix { + typedef ISACFIX_MainStruct instance_type; + static const bool has_32kHz = false; + static const uint16_t kFixSampleRate = 16000; + static inline int16_t Control(instance_type* inst, + int32_t rate, + int16_t framesize) { + return WebRtcIsacfix_Control(inst, rate, framesize); + } + static inline int16_t ControlBwe(instance_type* inst, + int32_t rate_bps, + int16_t frame_size_ms, + int16_t enforce_frame_size) { + return WebRtcIsacfix_ControlBwe(inst, rate_bps, frame_size_ms, + enforce_frame_size); + } + static inline int16_t Create(instance_type** inst) { + return WebRtcIsacfix_Create(inst); + } + static inline int16_t Decode(instance_type* inst, + const uint8_t* encoded, + int16_t len, + int16_t* decoded, + int16_t* speech_type) { + return WebRtcIsacfix_Decode(inst, encoded, len, decoded, speech_type); + } + static inline int16_t DecodePlc(instance_type* inst, + int16_t* decoded, + int16_t num_lost_frames) { + return WebRtcIsacfix_DecodePlc(inst, decoded, num_lost_frames); + } + static inline int16_t DecodeRcu(instance_type* inst, + const uint8_t* encoded, + int16_t len, + int16_t* decoded, + int16_t* speech_type) { + // iSACfix has no DecodeRcu; just call the normal Decode. + return WebRtcIsacfix_Decode(inst, encoded, len, decoded, speech_type); + } + static inline int16_t DecoderInit(instance_type* inst) { + return WebRtcIsacfix_DecoderInit(inst); + } + static inline int16_t Encode(instance_type* inst, + const int16_t* speech_in, + uint8_t* encoded) { + return WebRtcIsacfix_Encode(inst, speech_in, encoded); + } + static inline int16_t EncoderInit(instance_type* inst, int16_t coding_mode) { + return WebRtcIsacfix_EncoderInit(inst, coding_mode); + } + static inline uint16_t EncSampRate(instance_type* inst) { + return kFixSampleRate; + } + + static inline int16_t Free(instance_type* inst) { + return WebRtcIsacfix_Free(inst); + } + static inline int16_t GetErrorCode(instance_type* inst) { + return WebRtcIsacfix_GetErrorCode(inst); + } + + static inline int16_t GetNewFrameLen(instance_type* inst) { + return WebRtcIsacfix_GetNewFrameLen(inst); + } + + static inline int16_t SetDecSampRate(instance_type* inst, + uint16_t sample_rate_hz) { + DCHECK_EQ(sample_rate_hz, kFixSampleRate); + return 0; + } + static inline int16_t SetEncSampRate(instance_type* inst, + uint16_t sample_rate_hz) { + DCHECK_EQ(sample_rate_hz, kFixSampleRate); + return 0; + } + static inline int16_t UpdateBwEstimate(instance_type* inst, + const uint8_t* encoded, + int32_t packet_size, + uint16_t rtp_seq_number, + uint32_t send_ts, + uint32_t arr_ts) { + return WebRtcIsacfix_UpdateBwEstimate(inst, encoded, packet_size, + rtp_seq_number, send_ts, arr_ts); + } +}; + +typedef AudioEncoderDecoderIsacT AudioEncoderDecoderIsacFix; + +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_ diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc b/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc new file mode 100644 index 000000000..d0aea26e4 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc @@ -0,0 +1,23 @@ +/* + * 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/fix/interface/audio_encoder_isacfix.h" + +#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h" + +namespace webrtc { + +const uint16_t IsacFix::kFixSampleRate; + +// Explicit instantiation of AudioEncoderDecoderIsacT, a.k.a. +// AudioEncoderDecoderIsacFix. +template class AudioEncoderDecoderIsacT; + +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi b/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi index 54ff9df16..d3ab883eb 100644 --- a/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi +++ b/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi @@ -26,10 +26,14 @@ ], }, 'sources': [ + '../../audio_encoder_isac_t.h', + '../../audio_encoder_isac_t_impl.h', + '../interface/audio_encoder_isacfix.h', '../interface/isacfix.h', 'arith_routines.c', 'arith_routines_hist.c', 'arith_routines_logist.c', + 'audio_encoder_isacfix.cc', 'bandwidth_estimator.c', 'decode.c', 'decode_bwe.c', 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 index e111a57d9..091b77574 100644 --- 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 @@ -11,100 +11,95 @@ #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/audio_encoder_isac_t.h" #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" -#include "webrtc/system_wrappers/interface/scoped_ptr.h" namespace webrtc { -class CriticalSectionWrapper; +struct IsacFloat { + typedef ISACStruct instance_type; + static const bool has_32kHz = true; + static inline int16_t Control(instance_type* inst, + int32_t rate, + int16_t framesize) { + return WebRtcIsac_Control(inst, rate, framesize); + } + static inline int16_t ControlBwe(instance_type* inst, + int32_t rate_bps, + int16_t frame_size_ms, + int16_t enforce_frame_size) { + return WebRtcIsac_ControlBwe(inst, rate_bps, frame_size_ms, + enforce_frame_size); + } + static inline int16_t Create(instance_type** inst) { + return WebRtcIsac_Create(inst); + } + static inline int16_t Decode(instance_type* inst, + const uint8_t* encoded, + int16_t len, + int16_t* decoded, + int16_t* speech_type) { + return WebRtcIsac_Decode(inst, encoded, len, decoded, speech_type); + } + static inline int16_t DecodePlc(instance_type* inst, + int16_t* decoded, + int16_t num_lost_frames) { + return WebRtcIsac_DecodePlc(inst, decoded, num_lost_frames); + } -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. - }; + static inline int16_t DecodeRcu(instance_type* inst, + const uint8_t* encoded, + int16_t len, + int16_t* decoded, + int16_t* speech_type) { + return WebRtcIsac_DecodeRcu(inst, encoded, len, decoded, speech_type); + } + static inline int16_t DecoderInit(instance_type* inst) { + return WebRtcIsac_DecoderInit(inst); + } + static inline int16_t Encode(instance_type* inst, + const int16_t* speech_in, + uint8_t* encoded) { + return WebRtcIsac_Encode(inst, speech_in, encoded); + } + static inline int16_t EncoderInit(instance_type* inst, int16_t coding_mode) { + return WebRtcIsac_EncoderInit(inst, coding_mode); + } + static inline uint16_t EncSampRate(instance_type* inst) { + return WebRtcIsac_EncSampRate(inst); + } - // 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? - }; + static inline int16_t Free(instance_type* inst) { + return WebRtcIsac_Free(inst); + } + static inline int16_t GetErrorCode(instance_type* inst) { + return WebRtcIsac_GetErrorCode(inst); + } - explicit AudioEncoderDecoderIsac(const Config& config); - explicit AudioEncoderDecoderIsac(const ConfigAdaptive& config); - virtual ~AudioEncoderDecoderIsac() OVERRIDE; + static inline int16_t GetNewFrameLen(instance_type* inst) { + return WebRtcIsac_GetNewFrameLen(inst); + } - // 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, - 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); + static inline int16_t SetDecSampRate(instance_type* inst, + uint16_t sample_rate_hz) { + return WebRtcIsac_SetDecSampRate(inst, sample_rate_hz); + } + static inline int16_t SetEncSampRate(instance_type* inst, + uint16_t sample_rate_hz) { + return WebRtcIsac_SetEncSampRate(inst, sample_rate_hz); + } + static inline int16_t UpdateBwEstimate(instance_type* inst, + const uint8_t* encoded, + int32_t packet_size, + uint16_t rtp_seq_number, + uint32_t send_ts, + uint32_t arr_ts) { + return WebRtcIsac_UpdateBwEstimate(inst, encoded, packet_size, + rtp_seq_number, send_ts, arr_ts); + } }; +typedef AudioEncoderDecoderIsacT 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 index c80104aff..ba0860363 100644 --- 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 @@ -10,191 +10,12 @@ #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" +#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.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, - 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); - - info->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_); -} +// Explicit instantiation of AudioEncoderDecoderIsacT, a.k.a. +// AudioEncoderDecoderIsac. +template class AudioEncoderDecoderIsacT; } // 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 8f8cd35a5..0b0c07063 100644 --- a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi +++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.gypi @@ -26,6 +26,8 @@ ], }, 'sources': [ + '../../audio_encoder_isac_t.h', + '../../audio_encoder_isac_t_impl.h', '../interface/audio_encoder_isac.h', '../interface/isac.h', 'arith_routines.c', diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc index f565faf1c..b8c5976d1 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc @@ -23,7 +23,7 @@ #include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h" #endif #ifdef WEBRTC_CODEC_ISACFX -#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" +#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h" #endif #ifdef WEBRTC_CODEC_ISAC #include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" @@ -127,48 +127,6 @@ int AudioDecoderIlbc::Init() { } #endif -// iSAC fix -#ifdef WEBRTC_CODEC_ISACFX -AudioDecoderIsacFix::AudioDecoderIsacFix() { - WebRtcIsacfix_Create(&isac_state_); -} - -AudioDecoderIsacFix::~AudioDecoderIsacFix() { - WebRtcIsacfix_Free(isac_state_); -} - -int AudioDecoderIsacFix::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 = WebRtcIsacfix_Decode(isac_state_, - encoded, - static_cast(encoded_len), decoded, - &temp_type); - *speech_type = ConvertSpeechType(temp_type); - return ret; -} - -int AudioDecoderIsacFix::Init() { - return WebRtcIsacfix_DecoderInit(isac_state_); -} - -int AudioDecoderIsacFix::IncomingPacket(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp) { - return WebRtcIsacfix_UpdateBwEstimate( - isac_state_, - payload, - static_cast(payload_len), - rtp_sequence_number, rtp_timestamp, arrival_timestamp); -} - -int AudioDecoderIsacFix::ErrorCode() { - return WebRtcIsacfix_GetErrorCode(isac_state_); -} -#endif - // G.722 #ifdef WEBRTC_CODEC_G722 AudioDecoderG722::AudioDecoderG722() { @@ -485,8 +443,10 @@ AudioDecoder* CreateAudioDecoder(NetEqDecoder codec_type) { return new AudioDecoderIlbc; #endif #if defined(WEBRTC_CODEC_ISACFX) - case kDecoderISAC: - return new AudioDecoderIsacFix; + case kDecoderISAC: { + AudioEncoderDecoderIsacFix::Config config; + return new AudioEncoderDecoderIsacFix(config); + } #elif defined(WEBRTC_CODEC_ISAC) case kDecoderISAC: { AudioEncoderDecoderIsac::Config config; diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h index 7d1172c07..365972624 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h @@ -27,12 +27,6 @@ #ifdef WEBRTC_CODEC_ILBC #include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h" #endif -#ifdef WEBRTC_CODEC_ISACFX -#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" -#endif #ifdef WEBRTC_CODEC_OPUS #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" #endif @@ -130,27 +124,6 @@ class AudioDecoderIlbc : public AudioDecoder { }; #endif -#ifdef WEBRTC_CODEC_ISACFX -class AudioDecoderIsacFix : public AudioDecoder { - public: - AudioDecoderIsacFix(); - virtual ~AudioDecoderIsacFix(); - virtual int Decode(const uint8_t* encoded, size_t encoded_len, - int16_t* decoded, SpeechType* speech_type); - 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: - ISACFIX_MainStruct* isac_state_; - DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacFix); -}; -#endif - #ifdef WEBRTC_CODEC_G722 class AudioDecoderG722 : 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 5a2c4ba5f..927c30b51 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -20,7 +20,7 @@ #include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h" #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/fix/interface/audio_encoder_isacfix.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/audio_encoder_pcm16b.h" @@ -388,38 +388,20 @@ class AudioDecoderIsacFixTest : public AudioDecoderTest { protected: AudioDecoderIsacFixTest() : AudioDecoderTest() { codec_input_rate_hz_ = 16000; - input_size_ = 160; frame_size_ = 480; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderIsacFix; - assert(decoder_); - WebRtcIsacfix_Create(&encoder_); - } + AudioEncoderDecoderIsacFix::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_; - ~AudioDecoderIsacFixTest() { - WebRtcIsacfix_Free(encoder_); + // We need to create separate AudioEncoderDecoderIsacFix objects for + // encoding and decoding, because the test class destructor destroys them + // both. + audio_encoder_.reset(new AudioEncoderDecoderIsacFix(config)); + decoder_ = new AudioEncoderDecoderIsacFix(config); } - - virtual void InitEncoder() { - ASSERT_EQ(0, WebRtcIsacfix_EncoderInit(encoder_, 1)); // Fixed mode. - ASSERT_EQ(0, - WebRtcIsacfix_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, WebRtcIsacfix_Encode(encoder_, input, output)); - input += input_size_; - EXPECT_EQ(0, WebRtcIsacfix_Encode(encoder_, input, output)); - input += input_size_; - int enc_len_bytes = WebRtcIsacfix_Encode(encoder_, input, output); - EXPECT_GT(enc_len_bytes, 0); - return enc_len_bytes; - } - - ISACFIX_MainStruct* encoder_; - int input_size_; }; class AudioDecoderG722Test : public AudioDecoderTest {