diff --git a/webrtc/common_audio/vad/include/vad.h b/webrtc/common_audio/vad/include/vad.h index 1944f9dc5a..72c09492b3 100644 --- a/webrtc/common_audio/vad/include/vad.h +++ b/webrtc/common_audio/vad/include/vad.h @@ -37,8 +37,12 @@ class Vad { size_t num_samples, int sample_rate_hz); + // Reset VAD state. + virtual void Reset(); + private: VadInst* handle_; + Aggressiveness aggressiveness_; }; } // namespace webrtc diff --git a/webrtc/common_audio/vad/mock/mock_vad.h b/webrtc/common_audio/vad/mock/mock_vad.h index 7a7de0fa7d..916480a928 100644 --- a/webrtc/common_audio/vad/mock/mock_vad.h +++ b/webrtc/common_audio/vad/mock/mock_vad.h @@ -27,6 +27,7 @@ class MockVad : public Vad { enum Activity(const int16_t* audio, size_t num_samples, int sample_rate_hz)); + MOCK_METHOD0(Reset, void()); }; } // namespace webrtc diff --git a/webrtc/common_audio/vad/vad.cc b/webrtc/common_audio/vad/vad.cc index 764d024cbd..dc4eb6db32 100644 --- a/webrtc/common_audio/vad/vad.cc +++ b/webrtc/common_audio/vad/vad.cc @@ -14,11 +14,8 @@ namespace webrtc { -Vad::Vad(enum Aggressiveness mode) { - handle_ = WebRtcVad_Create(); - CHECK(handle_); - CHECK_EQ(WebRtcVad_Init(handle_), 0); - CHECK_EQ(WebRtcVad_set_mode(handle_, mode), 0); +Vad::Vad(enum Aggressiveness mode) : handle_(nullptr), aggressiveness_(mode) { + Reset(); } Vad::~Vad() { @@ -40,4 +37,13 @@ enum Vad::Activity Vad::VoiceActivity(const int16_t* audio, } } +void Vad::Reset() { + if (handle_) + WebRtcVad_Free(handle_); + handle_ = WebRtcVad_Create(); + CHECK(handle_); + CHECK_EQ(WebRtcVad_Init(handle_), 0); + CHECK_EQ(WebRtcVad_set_mode(handle_, aggressiveness_), 0); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc index 72e4265e98..eb553a7e7d 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder.cc +++ b/webrtc/modules/audio_coding/codecs/audio_encoder.cc @@ -13,10 +13,12 @@ namespace webrtc { -AudioEncoder::EncodedInfo::EncodedInfo() : EncodedInfoLeaf() { -} +AudioEncoder::EncodedInfo::EncodedInfo() = default; -AudioEncoder::EncodedInfo::~EncodedInfo() { +AudioEncoder::EncodedInfo::~EncodedInfo() = default; + +int AudioEncoder::RtpTimestampRateHz() const { + return SampleRateHz(); } AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp, @@ -32,8 +34,28 @@ AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp, return info; } -int AudioEncoder::RtpTimestampRateHz() const { - return SampleRateHz(); +bool AudioEncoder::SetFec(bool enable) { + return !enable; } +bool AudioEncoder::SetDtx(bool enable) { + return !enable; +} + +bool AudioEncoder::SetApplication(Application application) { + return false; +} + +bool AudioEncoder::SetMaxPlaybackRate(int frequency_hz) { + return true; +} + +void AudioEncoder::SetProjectedPacketLossRate(double fraction) {} + +void AudioEncoder::SetTargetBitrate(int target_bps) {} + +void AudioEncoder::SetMaxBitrate(int max_bps) {} + +void AudioEncoder::SetMaxPayloadSize(int max_payload_size_bytes) {} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h index 0a40316b71..73b4468d46 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h @@ -23,18 +23,11 @@ namespace webrtc { class AudioEncoder { public: struct EncodedInfoLeaf { - EncodedInfoLeaf() - : encoded_bytes(0), - encoded_timestamp(0), - payload_type(0), - send_even_if_empty(false), - speech(true) {} - - size_t encoded_bytes; - uint32_t encoded_timestamp; - int payload_type; - bool send_even_if_empty; - bool speech; + size_t encoded_bytes = 0; + uint32_t encoded_timestamp = 0; + int payload_type = 0; + bool send_even_if_empty = false; + bool speech = true; }; // This is the main struct for auxiliary encoding information. Each encoded @@ -54,26 +47,9 @@ class AudioEncoder { std::vector redundant; }; - virtual ~AudioEncoder() {} + virtual ~AudioEncoder() = default; - // Accepts one 10 ms block of input audio (i.e., sample_rate_hz() / 100 * - // num_channels() samples). Multi-channel audio must be sample-interleaved. - // The encoder produces zero or more bytes of output in |encoded| and - // returns additional encoding information. - // The caller is responsible for making sure that |max_encoded_bytes| is - // not smaller than the number of bytes actually produced by the encoder. - EncodedInfo Encode(uint32_t rtp_timestamp, - const int16_t* audio, - size_t num_samples_per_channel, - size_t max_encoded_bytes, - uint8_t* encoded); - - // Return the input sample rate in Hz and the number of input channels. - // These are constants set at instantiation time. - virtual int SampleRateHz() const = 0; - virtual int NumChannels() const = 0; - - // Return the maximum number of bytes that can be produced by the encoder + // Returns the maximum number of bytes that can be produced by the encoder // at each Encode() call. The caller can use the return value to determine // the size of the buffer that needs to be allocated. This value is allowed // to depend on encoder parameters like bitrate, frame size etc., so if @@ -81,8 +57,13 @@ class AudioEncoder { // that the buffer is large enough by calling MaxEncodedBytes() again. virtual size_t MaxEncodedBytes() const = 0; - // Returns the rate with which the RTP timestamps are updated. By default, - // this is the same as sample_rate_hz(). + // Returns the input sample rate in Hz and the number of input channels. + // These are constants set at instantiation time. + virtual int SampleRateHz() const = 0; + virtual int NumChannels() const = 0; + + // Returns the rate at which the RTP timestamps are updated. The default + // implementation returns SampleRateHz(). virtual int RtpTimestampRateHz() const; // Returns the number of 10 ms frames the encoder will put in the next @@ -101,52 +82,74 @@ class AudioEncoder { // provided. virtual int GetTargetBitrate() const = 0; - // Changes the target bitrate. The implementation is free to alter this value, - // e.g., if the desired value is outside the valid range. - virtual void SetTargetBitrate(int bits_per_second) {} + // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 * + // NumChannels() samples). Multi-channel audio must be sample-interleaved. + // The encoder produces zero or more bytes of output in |encoded| and + // returns additional encoding information. + // The caller is responsible for making sure that |max_encoded_bytes| is + // not smaller than the number of bytes actually produced by the encoder. + // Encode() checks some preconditions, calls EncodeInternal() which does the + // actual work, and then checks some postconditions. + EncodedInfo Encode(uint32_t rtp_timestamp, + const int16_t* audio, + size_t num_samples_per_channel, + size_t max_encoded_bytes, + uint8_t* encoded); - // Tells the implementation what the projected packet loss rate is. The rate - // is in the range [0.0, 1.0]. This rate is typically used to adjust channel - // coding efforts, such as FEC. - virtual void SetProjectedPacketLossRate(double fraction) {} - - // This is the encode function that the inherited classes must implement. It - // is called from Encode in the base class. virtual EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) = 0; -}; -class AudioEncoderMutable : public AudioEncoder { - public: - enum Application { kApplicationSpeech, kApplicationAudio }; - - // Discards unprocessed audio data. + // Resets the encoder to its starting state, discarding any input that has + // been fed to the encoder but not yet emitted in a packet. virtual void Reset() = 0; - // Enables codec-internal FEC, if the implementation supports it. - virtual bool SetFec(bool enable) = 0; + // Enables or disables codec-internal FEC (forward error correction). Returns + // true if the codec was able to comply. The default implementation returns + // true when asked to disable FEC and false when asked to enable it (meaning + // that FEC isn't supported). + virtual bool SetFec(bool enable); - // Enables or disables codec-internal VAD/DTX, if the implementation supports - // it. - virtual bool SetDtx(bool enable) = 0; + // Enables or disables codec-internal VAD/DTX. Returns true if the codec was + // able to comply. The default implementation returns true when asked to + // disable DTX and false when asked to enable it (meaning that DTX isn't + // supported). + virtual bool SetDtx(bool enable); - // Sets the application mode. The implementation is free to disregard this - // setting. - virtual bool SetApplication(Application application) = 0; + // Sets the application mode. Returns true if the codec was able to comply. + // The default implementation just returns false. + enum class Application { kSpeech, kAudio }; + virtual bool SetApplication(Application application); - // Sets an upper limit on the payload size produced by the encoder. The - // implementation is free to disregard this setting. - virtual void SetMaxPayloadSize(int max_payload_size_bytes) = 0; + // Tells the encoder about the highest sample rate the decoder is expected to + // use when decoding the bitstream. The encoder would typically use this + // information to adjust the quality of the encoding. The default + // implementation just returns true. + // TODO(kwiberg): Change return value to void, since it doesn't matter + // whether the encoder approved of the max playback rate or not. + virtual bool SetMaxPlaybackRate(int frequency_hz); - // Sets the maximum rate which the codec may not exceed for any packet. - virtual void SetMaxRate(int max_rate_bps) = 0; + // Tells the encoder what the projected packet loss rate is. The rate is in + // the range [0.0, 1.0]. The encoder would typically use this information to + // adjust channel coding efforts, such as FEC. The default implementation + // does nothing. + virtual void SetProjectedPacketLossRate(double fraction); - // Informs the encoder about the maximum sample rate which the decoder will - // use when decoding the bitstream. The implementation is free to disregard - // this hint. - virtual bool SetMaxPlaybackRate(int frequency_hz) = 0; + // Tells the encoder what average bitrate we'd like it to produce. The + // encoder is free to adjust or disregard the given bitrate (the default + // implementation does the latter). + virtual void SetTargetBitrate(int target_bps); + + // Sets the maximum bitrate which must not be exceeded for any packet. The + // encoder is free to adjust or disregard this value (the default + // implementation does the latter). + virtual void SetMaxBitrate(int max_bps); + + // Sets an upper limit on the size of packet payloads produced by the + // encoder. The encoder is free to adjust or disregard this value (the + // default implementation does the latter). + virtual void SetMaxPayloadSize(int max_payload_size_bytes); }; } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_ diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h b/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h deleted file mode 100644 index c1184e16a8..0000000000 --- a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_MUTABLE_IMPL_H_ -#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_MUTABLE_IMPL_H_ - -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/thread_annotations.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder.h" -#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" -#include "webrtc/system_wrappers/interface/thread_wrapper.h" - -namespace webrtc { - -// This is a convenient base class for implementations of AudioEncoderMutable. -// T is the type of the encoder state; it has to look like an AudioEncoder -// subclass whose constructor takes a single T::Config parameter. If P is -// given, this class will inherit from it instead of directly from -// AudioEncoderMutable. -template -class AudioEncoderMutableImpl : public P { - public: - void Reset() override { - typename T::Config config; - { - CriticalSectionScoped cs(encoder_lock_.get()); - config = config_; - } - Reconstruct(config); - } - - bool SetFec(bool enable) override { return false; } - - bool SetDtx(bool enable) override { return false; } - - bool SetApplication(AudioEncoderMutable::Application application) override { - return false; - } - - void SetMaxPayloadSize(int max_payload_size_bytes) override {} - - void SetMaxRate(int max_rate_bps) override {} - - bool SetMaxPlaybackRate(int frequency_hz) override { return false; } - - AudioEncoderMutable::EncodedInfo EncodeInternal(uint32_t rtp_timestamp, - const int16_t* audio, - size_t max_encoded_bytes, - uint8_t* encoded) override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, - encoded); - } - int SampleRateHz() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->SampleRateHz(); - } - int NumChannels() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->NumChannels(); - } - size_t MaxEncodedBytes() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->MaxEncodedBytes(); - } - int RtpTimestampRateHz() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->RtpTimestampRateHz(); - } - size_t Num10MsFramesInNextPacket() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->Num10MsFramesInNextPacket(); - } - size_t Max10MsFramesInAPacket() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->Max10MsFramesInAPacket(); - } - int GetTargetBitrate() const override { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder_->GetTargetBitrate(); - } - void SetTargetBitrate(int bits_per_second) override { - CriticalSectionScoped cs(encoder_lock_.get()); - encoder_->SetTargetBitrate(bits_per_second); - } - void SetProjectedPacketLossRate(double fraction) override { - CriticalSectionScoped cs(encoder_lock_.get()); - encoder_->SetProjectedPacketLossRate(fraction); - } - - protected: - explicit AudioEncoderMutableImpl(const typename T::Config& config) - : encoder_lock_(CriticalSectionWrapper::CreateCriticalSection()) { - Reconstruct(config); - } - - bool Reconstruct(const typename T::Config& config) { - if (!config.IsOk()) - return false; - CriticalSectionScoped cs(encoder_lock_.get()); - config_ = config; - encoder_.reset(new T(config_)); - return true; - } - - typename T::Config config() const { - CriticalSectionScoped cs(encoder_lock_.get()); - return config_; - } - T* encoder() EXCLUSIVE_LOCKS_REQUIRED(encoder_lock_) { - return encoder_.get(); - } - const T* encoder() const EXCLUSIVE_LOCKS_REQUIRED(encoder_lock_) { - return encoder_.get(); - } - - const rtc::scoped_ptr encoder_lock_; - - private: - rtc::scoped_ptr encoder_ GUARDED_BY(encoder_lock_); - typename T::Config config_ GUARDED_BY(encoder_lock_); -}; - -} // namespace webrtc - -#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_MUTABLE_IMPL_H_ diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc index 279616e080..171198b9a3 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc @@ -19,18 +19,19 @@ namespace { const int kMaxFrameSizeMs = 60; -} // namespace - -AudioEncoderCng::Config::Config() - : num_channels(1), - payload_type(13), - speech_encoder(NULL), - vad_mode(Vad::kVadNormal), - sid_frame_interval_ms(100), - num_cng_coefficients(8), - vad(NULL) { +rtc::scoped_ptr CreateCngInst( + int sample_rate_hz, + int sid_frame_interval_ms, + int num_cng_coefficients) { + rtc::scoped_ptr cng_inst; + CHECK_EQ(0, WebRtcCng_CreateEnc(cng_inst.accept())); + CHECK_EQ(0, WebRtcCng_InitEnc(cng_inst.get(), sample_rate_hz, + sid_frame_interval_ms, num_cng_coefficients)); + return cng_inst; } +} // namespace + bool AudioEncoderCng::Config::IsOk() const { if (num_channels != 1) return false; @@ -51,37 +52,15 @@ AudioEncoderCng::AudioEncoderCng(const Config& config) : speech_encoder_(config.speech_encoder), cng_payload_type_(config.payload_type), num_cng_coefficients_(config.num_cng_coefficients), + sid_frame_interval_ms_(config.sid_frame_interval_ms), last_frame_active_(true), - vad_(new Vad(config.vad_mode)) { - if (config.vad) { - // Replace default Vad object with user-provided one. - vad_.reset(config.vad); - } + vad_(config.vad ? config.vad : new Vad(config.vad_mode)) { CHECK(config.IsOk()) << "Invalid configuration."; - CNG_enc_inst* cng_inst; - CHECK_EQ(WebRtcCng_CreateEnc(&cng_inst), 0) << "WebRtcCng_CreateEnc failed."; - cng_inst_.reset(cng_inst); // Transfer ownership to scoped_ptr. - CHECK_EQ(WebRtcCng_InitEnc(cng_inst_.get(), SampleRateHz(), - config.sid_frame_interval_ms, - config.num_cng_coefficients), - 0) - << "WebRtcCng_InitEnc failed"; + cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, + num_cng_coefficients_); } -AudioEncoderCng::~AudioEncoderCng() { -} - -int AudioEncoderCng::SampleRateHz() const { - return speech_encoder_->SampleRateHz(); -} - -int AudioEncoderCng::RtpTimestampRateHz() const { - return speech_encoder_->RtpTimestampRateHz(); -} - -int AudioEncoderCng::NumChannels() const { - return 1; -} +AudioEncoderCng::~AudioEncoderCng() = default; size_t AudioEncoderCng::MaxEncodedBytes() const { const size_t max_encoded_bytes_active = speech_encoder_->MaxEncodedBytes(); @@ -90,6 +69,18 @@ size_t AudioEncoderCng::MaxEncodedBytes() const { return std::max(max_encoded_bytes_active, max_encoded_bytes_passive); } +int AudioEncoderCng::SampleRateHz() const { + return speech_encoder_->SampleRateHz(); +} + +int AudioEncoderCng::NumChannels() const { + return 1; +} + +int AudioEncoderCng::RtpTimestampRateHz() const { + return speech_encoder_->RtpTimestampRateHz(); +} + size_t AudioEncoderCng::Num10MsFramesInNextPacket() const { return speech_encoder_->Num10MsFramesInNextPacket(); } @@ -102,16 +93,6 @@ int AudioEncoderCng::GetTargetBitrate() const { return speech_encoder_->GetTargetBitrate(); } -void AudioEncoderCng::SetTargetBitrate(int bits_per_second) { - speech_encoder_->SetTargetBitrate(bits_per_second); -} - -void AudioEncoderCng::SetProjectedPacketLossRate(double fraction) { - DCHECK_GE(fraction, 0.0); - DCHECK_LE(fraction, 1.0); - speech_encoder_->SetProjectedPacketLossRate(fraction); -} - AudioEncoder::EncodedInfo AudioEncoderCng::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, @@ -183,6 +164,48 @@ AudioEncoder::EncodedInfo AudioEncoderCng::EncodeInternal( return info; } +void AudioEncoderCng::Reset() { + speech_encoder_->Reset(); + speech_buffer_.clear(); + rtp_timestamps_.clear(); + last_frame_active_ = true; + vad_->Reset(); + cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, + num_cng_coefficients_); +} + +bool AudioEncoderCng::SetFec(bool enable) { + return speech_encoder_->SetFec(enable); +} + +bool AudioEncoderCng::SetDtx(bool enable) { + return speech_encoder_->SetDtx(enable); +} + +bool AudioEncoderCng::SetApplication(Application application) { + return speech_encoder_->SetApplication(application); +} + +bool AudioEncoderCng::SetMaxPlaybackRate(int frequency_hz) { + return speech_encoder_->SetMaxPlaybackRate(frequency_hz); +} + +void AudioEncoderCng::SetProjectedPacketLossRate(double fraction) { + speech_encoder_->SetProjectedPacketLossRate(fraction); +} + +void AudioEncoderCng::SetTargetBitrate(int bits_per_second) { + speech_encoder_->SetTargetBitrate(bits_per_second); +} + +void AudioEncoderCng::SetMaxBitrate(int max_bps) { + speech_encoder_->SetMaxBitrate(max_bps); +} + +void AudioEncoderCng::SetMaxPayloadSize(int max_payload_size_bytes) { + speech_encoder_->SetMaxPayloadSize(max_payload_size_bytes); +} + AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive( size_t frames_to_encode, size_t max_encoded_bytes, diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc index a2ab6e8ecb..d7bc474d36 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc @@ -386,6 +386,14 @@ TEST_F(AudioEncoderCngTest, VerifySidFrameAfterSpeech) { encoded_info_.encoded_bytes); } +// Resetting the CNG should reset both the VAD and the encoder. +TEST_F(AudioEncoderCngTest, Reset) { + CreateCng(); + EXPECT_CALL(mock_encoder_, Reset()).Times(1); + EXPECT_CALL(*mock_vad_, Reset()).Times(1); + cng_->Reset(); +} + #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) // This test fixture tests various error conditions that makes the diff --git a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h index 6a1136602e..2ac1f95e57 100644 --- a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h +++ b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h @@ -20,53 +20,57 @@ namespace webrtc { +// Deleter for use with scoped_ptr. +struct CngInstDeleter { + void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); } +}; + class Vad; class AudioEncoderCng final : public AudioEncoder { public: struct Config { - Config(); bool IsOk() const; - int num_channels; - int payload_type; + int num_channels = 1; + int payload_type = 13; // Caller keeps ownership of the AudioEncoder object. - AudioEncoder* speech_encoder; - Vad::Aggressiveness vad_mode; - int sid_frame_interval_ms; - int num_cng_coefficients; + AudioEncoder* speech_encoder = nullptr; + Vad::Aggressiveness vad_mode = Vad::kVadNormal; + int sid_frame_interval_ms = 100; + int num_cng_coefficients = 8; // The Vad pointer is mainly for testing. If a NULL pointer is passed, the // AudioEncoderCng creates (and destroys) a Vad object internally. If an // object is passed, the AudioEncoderCng assumes ownership of the Vad // object. - Vad* vad; + Vad* vad = nullptr; }; explicit AudioEncoderCng(const Config& config); - ~AudioEncoderCng() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; int RtpTimestampRateHz() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; - void SetTargetBitrate(int bits_per_second) override; - void SetProjectedPacketLossRate(double fraction) override; EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; + bool SetFec(bool enable) override; + bool SetDtx(bool enable) override; + bool SetApplication(Application application) override; + bool SetMaxPlaybackRate(int frequency_hz) override; + void SetProjectedPacketLossRate(double fraction) override; + void SetTargetBitrate(int target_bps) override; + void SetMaxBitrate(int max_bps) override; + void SetMaxPayloadSize(int max_payload_size_bytes) override; private: - // Deleter for use with scoped_ptr. E.g., use as - // rtc::scoped_ptr cng_inst_; - struct CngInstDeleter { - inline void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); } - }; - EncodedInfo EncodePassive(size_t frames_to_encode, size_t max_encoded_bytes, uint8_t* encoded); @@ -78,6 +82,7 @@ class AudioEncoderCng final : public AudioEncoder { AudioEncoder* speech_encoder_; const int cng_payload_type_; const int num_cng_coefficients_; + const int sid_frame_interval_ms_; std::vector speech_buffer_; std::vector rtp_timestamps_; bool last_frame_active_; diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc index ba5959dbcd..f7812b34f7 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc +++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc @@ -19,6 +19,7 @@ namespace webrtc { namespace { + int16_t NumSamplesPerFrame(int num_channels, int frame_size_ms, int sample_rate_hz) { @@ -27,6 +28,16 @@ int16_t NumSamplesPerFrame(int num_channels, << "Frame size too large."; return static_cast(samples_per_frame); } + +template +typename T::Config CreateConfig(const CodecInst& codec_inst) { + typename T::Config config; + config.frame_size_ms = codec_inst.pacsize / 8; + config.num_channels = codec_inst.channels; + config.payload_type = codec_inst.pltype; + return config; +} + } // namespace bool AudioEncoderPcm::Config::IsOk() const { @@ -49,7 +60,10 @@ AudioEncoderPcm::AudioEncoderPcm(const Config& config, int sample_rate_hz) speech_buffer_.reserve(full_frame_samples_); } -AudioEncoderPcm::~AudioEncoderPcm() { +AudioEncoderPcm::~AudioEncoderPcm() = default; + +size_t AudioEncoderPcm::MaxEncodedBytes() const { + return full_frame_samples_ * BytesPerSample(); } int AudioEncoderPcm::SampleRateHz() const { @@ -60,10 +74,6 @@ int AudioEncoderPcm::NumChannels() const { return num_channels_; } -size_t AudioEncoderPcm::MaxEncodedBytes() const { - return full_frame_samples_ * BytesPerSample(); -} - size_t AudioEncoderPcm::Num10MsFramesInNextPacket() const { return num_10ms_frames_per_packet_; } @@ -102,6 +112,13 @@ AudioEncoder::EncodedInfo AudioEncoderPcm::EncodeInternal( return info; } +void AudioEncoderPcm::Reset() { + speech_buffer_.clear(); +} + +AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst) + : AudioEncoderPcmA(CreateConfig(codec_inst)) {} + size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) { @@ -112,6 +129,9 @@ int AudioEncoderPcmA::BytesPerSample() const { return 1; } +AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst) + : AudioEncoderPcmU(CreateConfig(codec_inst)) {} + size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) { @@ -122,25 +142,4 @@ int AudioEncoderPcmU::BytesPerSample() const { return 1; } -namespace { -template -typename T::Config CreateConfig(const CodecInst& codec_inst) { - typename T::Config config; - config.frame_size_ms = codec_inst.pacsize / 8; - config.num_channels = codec_inst.channels; - config.payload_type = codec_inst.pltype; - return config; -} -} // namespace - -AudioEncoderMutablePcmU::AudioEncoderMutablePcmU(const CodecInst& codec_inst) - : AudioEncoderMutableImpl( - CreateConfig(codec_inst)) { -} - -AudioEncoderMutablePcmA::AudioEncoderMutablePcmA(const CodecInst& codec_inst) - : AudioEncoderMutableImpl( - CreateConfig(codec_inst)) { -} - } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h index 7d45f3f71d..c2788f14d6 100644 --- a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h +++ b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h @@ -15,7 +15,6 @@ #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" namespace webrtc { @@ -36,9 +35,9 @@ class AudioEncoderPcm : public AudioEncoder { ~AudioEncoderPcm() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; @@ -46,6 +45,7 @@ class AudioEncoderPcm : public AudioEncoder { const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; protected: AudioEncoderPcm(const Config& config, int sample_rate_hz); @@ -66,6 +66,8 @@ class AudioEncoderPcm : public AudioEncoder { uint32_t first_timestamp_in_buffer_; }; +struct CodecInst; + class AudioEncoderPcmA final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { @@ -74,6 +76,7 @@ class AudioEncoderPcmA final : public AudioEncoderPcm { explicit AudioEncoderPcmA(const Config& config) : AudioEncoderPcm(config, kSampleRateHz) {} + explicit AudioEncoderPcmA(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio, @@ -94,6 +97,7 @@ class AudioEncoderPcmU final : public AudioEncoderPcm { explicit AudioEncoderPcmU(const Config& config) : AudioEncoderPcm(config, kSampleRateHz) {} + explicit AudioEncoderPcmU(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio, @@ -106,19 +110,5 @@ class AudioEncoderPcmU final : public AudioEncoderPcm { static const int kSampleRateHz = 8000; }; -struct CodecInst; - -class AudioEncoderMutablePcmU - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutablePcmU(const CodecInst& codec_inst); -}; - -class AudioEncoderMutablePcmA - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutablePcmA(const CodecInst& codec_inst); -}; - } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_G711_INCLUDE_AUDIO_ENCODER_PCM_H_ diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc index 9eb7a11524..6df5430cba 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc @@ -21,6 +21,14 @@ namespace { const size_t kSampleRateHz = 16000; +AudioEncoderG722::Config CreateConfig(const CodecInst& codec_inst) { + AudioEncoderG722::Config config; + config.num_channels = codec_inst.channels; + config.frame_size_ms = codec_inst.pacsize / 16; + config.payload_type = codec_inst.pltype; + return config; +} + } // namespace bool AudioEncoderG722::Config::IsOk() const { @@ -28,15 +36,6 @@ bool AudioEncoderG722::Config::IsOk() const { (num_channels >= 1); } -AudioEncoderG722::EncoderState::EncoderState() { - CHECK_EQ(0, WebRtcG722_CreateEncoder(&encoder)); - CHECK_EQ(0, WebRtcG722_EncoderInit(encoder)); -} - -AudioEncoderG722::EncoderState::~EncoderState() { - CHECK_EQ(0, WebRtcG722_FreeEncoder(encoder)); -} - AudioEncoderG722::AudioEncoderG722(const Config& config) : num_channels_(config.num_channels), payload_type_(config.payload_type), @@ -53,26 +52,30 @@ AudioEncoderG722::AudioEncoderG722(const Config& config) encoders_[i].speech_buffer.reset(new int16_t[samples_per_channel]); encoders_[i].encoded_buffer.SetSize(samples_per_channel / 2); } + Reset(); } -AudioEncoderG722::~AudioEncoderG722() {} +AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst) + : AudioEncoderG722(CreateConfig(codec_inst)) {} + +AudioEncoderG722::~AudioEncoderG722() = default; + +size_t AudioEncoderG722::MaxEncodedBytes() const { + return SamplesPerChannel() / 2 * num_channels_; +} int AudioEncoderG722::SampleRateHz() const { return kSampleRateHz; } -int AudioEncoderG722::RtpTimestampRateHz() const { - // The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz - // codec. - return kSampleRateHz / 2; -} - int AudioEncoderG722::NumChannels() const { return num_channels_; } -size_t AudioEncoderG722::MaxEncodedBytes() const { - return SamplesPerChannel() / 2 * num_channels_; +int AudioEncoderG722::RtpTimestampRateHz() const { + // The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz + // codec. + return kSampleRateHz / 2; } size_t AudioEncoderG722::Num10MsFramesInNextPacket() const { @@ -116,7 +119,7 @@ AudioEncoder::EncodedInfo AudioEncoderG722::EncodeInternal( for (int i = 0; i < num_channels_; ++i) { const size_t encoded = WebRtcG722_Encode( encoders_[i].encoder, encoders_[i].speech_buffer.get(), - samples_per_channel, encoders_[i].encoded_buffer.data()); + samples_per_channel, encoders_[i].encoded_buffer.data()); CHECK_EQ(encoded, samples_per_channel / 2); } @@ -140,22 +143,22 @@ AudioEncoder::EncodedInfo AudioEncoderG722::EncodeInternal( return info; } +void AudioEncoderG722::Reset() { + num_10ms_frames_buffered_ = 0; + for (int i = 0; i < num_channels_; ++i) + CHECK_EQ(0, WebRtcG722_EncoderInit(encoders_[i].encoder)); +} + +AudioEncoderG722::EncoderState::EncoderState() { + CHECK_EQ(0, WebRtcG722_CreateEncoder(&encoder)); +} + +AudioEncoderG722::EncoderState::~EncoderState() { + CHECK_EQ(0, WebRtcG722_FreeEncoder(encoder)); +} + size_t AudioEncoderG722::SamplesPerChannel() const { return kSampleRateHz / 100 * num_10ms_frames_per_packet_; } -namespace { -AudioEncoderG722::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderG722::Config config; - config.num_channels = codec_inst.channels; - config.frame_size_ms = codec_inst.pacsize / 16; - config.payload_type = codec_inst.pltype; - return config; -} -} // namespace - -AudioEncoderMutableG722::AudioEncoderMutableG722(const CodecInst& codec_inst) - : AudioEncoderMutableImpl(CreateConfig(codec_inst)) { -} - } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h index 1f36facd66..36f809a9dd 100644 --- a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h +++ b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h @@ -14,28 +14,29 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/g722/include/g722_interface.h" namespace webrtc { +struct CodecInst; + class AudioEncoderG722 final : public AudioEncoder { public: struct Config { - Config() : payload_type(9), frame_size_ms(20), num_channels(1) {} bool IsOk() const; - int payload_type; - int frame_size_ms; - int num_channels; + int payload_type = 9; + int frame_size_ms = 20; + int num_channels = 1; }; explicit AudioEncoderG722(const Config& config); + explicit AudioEncoderG722(const CodecInst& codec_inst); ~AudioEncoderG722() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; int RtpTimestampRateHz() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; @@ -44,6 +45,7 @@ class AudioEncoderG722 final : public AudioEncoder { const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; private: // The encoder state for one channel. @@ -66,13 +68,5 @@ class AudioEncoderG722 final : public AudioEncoder { rtc::Buffer interleave_buffer_; }; -struct CodecInst; - -class AudioEncoderMutableG722 - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutableG722(const CodecInst& codec_inst); -}; - } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_G722_INCLUDE_AUDIO_ENCODER_G722_H_ diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc index 33aba38334..8f16d660bc 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc @@ -22,6 +22,13 @@ namespace { const int kSampleRateHz = 8000; +AudioEncoderIlbc::Config CreateConfig(const CodecInst& codec_inst) { + AudioEncoderIlbc::Config config; + config.frame_size_ms = codec_inst.pacsize / 8; + config.payload_type = codec_inst.pltype; + return config; +} + } // namespace // static @@ -35,22 +42,24 @@ bool AudioEncoderIlbc::Config::IsOk() const { } AudioEncoderIlbc::AudioEncoderIlbc(const Config& config) - : payload_type_(config.payload_type), + : config_(config), num_10ms_frames_per_packet_( static_cast(config.frame_size_ms / 10)), - num_10ms_frames_buffered_(0) { - CHECK(config.IsOk()); - CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_)); - const int encoder_frame_size_ms = config.frame_size_ms > 30 - ? config.frame_size_ms / 2 - : config.frame_size_ms; - CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms)); + encoder_(nullptr) { + Reset(); } +AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst) + : AudioEncoderIlbc(CreateConfig(codec_inst)) {} + AudioEncoderIlbc::~AudioEncoderIlbc() { CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); } +size_t AudioEncoderIlbc::MaxEncodedBytes() const { + return RequiredOutputSizeBytes(); +} + int AudioEncoderIlbc::SampleRateHz() const { return kSampleRateHz; } @@ -59,10 +68,6 @@ int AudioEncoderIlbc::NumChannels() const { return 1; } -size_t AudioEncoderIlbc::MaxEncodedBytes() const { - return RequiredOutputSizeBytes(); -} - size_t AudioEncoderIlbc::Num10MsFramesInNextPacket() const { return num_10ms_frames_per_packet_; } @@ -119,10 +124,22 @@ AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeInternal( info.encoded_bytes = static_cast(output_len); DCHECK_EQ(info.encoded_bytes, RequiredOutputSizeBytes()); info.encoded_timestamp = first_timestamp_in_buffer_; - info.payload_type = payload_type_; + info.payload_type = config_.payload_type; return info; } +void AudioEncoderIlbc::Reset() { + if (encoder_) + CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); + CHECK(config_.IsOk()); + CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_)); + const int encoder_frame_size_ms = config_.frame_size_ms > 30 + ? config_.frame_size_ms / 2 + : config_.frame_size_ms; + CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms)); + num_10ms_frames_buffered_ = 0; +} + size_t AudioEncoderIlbc::RequiredOutputSizeBytes() const { switch (num_10ms_frames_per_packet_) { case 2: return 38; @@ -133,17 +150,4 @@ size_t AudioEncoderIlbc::RequiredOutputSizeBytes() const { } } -namespace { -AudioEncoderIlbc::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderIlbc::Config config; - config.frame_size_ms = codec_inst.pacsize / 8; - config.payload_type = codec_inst.pltype; - return config; -} -} // namespace - -AudioEncoderMutableIlbc::AudioEncoderMutableIlbc(const CodecInst& codec_inst) - : AudioEncoderMutableImpl(CreateConfig(codec_inst)) { -} - } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h index c3cf4d8a1e..7e7e898ddf 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h +++ b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h @@ -13,29 +13,30 @@ #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h" namespace webrtc { +struct CodecInst; + class AudioEncoderIlbc final : public AudioEncoder { public: struct Config { - Config() : payload_type(102), frame_size_ms(30) {} bool IsOk() const; - int payload_type; - int frame_size_ms; // Valid values are 20, 30, 40, and 60 ms. + int payload_type = 102; + int frame_size_ms = 30; // Valid values are 20, 30, 40, and 60 ms. // Note that frame size 40 ms produces encodings with two 20 ms frames in // them, and frame size 60 ms consists of two 30 ms frames. }; explicit AudioEncoderIlbc(const Config& config); + explicit AudioEncoderIlbc(const CodecInst& codec_inst); ~AudioEncoderIlbc() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; @@ -43,12 +44,13 @@ class AudioEncoderIlbc final : public AudioEncoder { const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; private: size_t RequiredOutputSizeBytes() const; static const size_t kMaxSamplesPerPacket = 480; - const int payload_type_; + const Config config_; const size_t num_10ms_frames_per_packet_; size_t num_10ms_frames_buffered_; uint32_t first_timestamp_in_buffer_; @@ -56,13 +58,5 @@ class AudioEncoderIlbc final : public AudioEncoder { IlbcEncoderInstance* encoder_; }; -struct CodecInst; - -class AudioEncoderMutableIlbc - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutableIlbc(const CodecInst& codec_inst); -}; - } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_INTERFACE_AUDIO_ENCODER_ILBC_H_ 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 a8498fa224..5484395ad8 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 @@ -19,6 +19,8 @@ namespace webrtc { +struct CodecInst; + template class AudioEncoderIsacT final : public AudioEncoder { public: @@ -28,33 +30,35 @@ class AudioEncoderIsacT final : public AudioEncoder { // - 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 Config { - Config(); bool IsOk() const; - LockedIsacBandwidthInfo* bwinfo; + LockedIsacBandwidthInfo* bwinfo = nullptr; - int payload_type; - int sample_rate_hz; - int frame_size_ms; - int bit_rate; // Limit on the short-term average bit rate, in bits/s. - int max_payload_size_bytes; - int max_bit_rate; + int payload_type = 103; + int sample_rate_hz = 16000; + int frame_size_ms = 30; + int bit_rate = kDefaultBitRate; // Limit on the short-term average bit + // rate, in bits/s. + int max_payload_size_bytes = -1; + int max_bit_rate = -1; // If true, the encoder will dynamically adjust frame size and bit rate; // the configured values are then merely the starting point. - bool adaptive_mode; + bool adaptive_mode = false; // In adaptive mode, prevent adaptive changes to the frame size. (Not used // in nonadaptive mode.) - bool enforce_frame_size; + bool enforce_frame_size = false; }; explicit AudioEncoderIsacT(const Config& config); + explicit AudioEncoderIsacT(const CodecInst& codec_inst, + LockedIsacBandwidthInfo* bwinfo); ~AudioEncoderIsacT() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; @@ -62,18 +66,26 @@ class AudioEncoderIsacT final : public AudioEncoder { const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; + void SetMaxPayloadSize(int max_payload_size_bytes) override; + void SetMaxBitrate(int max_rate_bps) override; private: // This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and // STREAM_MAXW16_60MS for iSAC fix (60 ms). static const size_t kSufficientEncodeBufferSizeBytes = 400; - const int payload_type_; - typename T::instance_type* isac_state_; - LockedIsacBandwidthInfo* bwinfo_; + static const int kDefaultBitRate = 32000; + + // Recreate the iSAC encoder instance with the given settings, and save them. + void RecreateEncoderInstance(const Config& config); + + Config config_; + typename T::instance_type* isac_state_ = nullptr; + LockedIsacBandwidthInfo* bwinfo_ = nullptr; // Have we accepted input but not yet emitted it in a packet? - bool packet_in_progress_; + bool packet_in_progress_ = false; // Timestamp of the first input of the currently in-progress packet. uint32_t packet_timestamp_; @@ -81,8 +93,6 @@ class AudioEncoderIsacT final : public AudioEncoder { // Timestamp of the previously encoded packet. uint32_t last_encoded_timestamp_; - const int target_bitrate_bps_; - DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT); }; 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 28e9b8e83f..ad09c3f90d 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 @@ -20,20 +20,20 @@ namespace webrtc { -const int kIsacPayloadType = 103; -const int kDefaultBitRate = 32000; - template -AudioEncoderIsacT::Config::Config() - : bwinfo(nullptr), - payload_type(kIsacPayloadType), - sample_rate_hz(16000), - frame_size_ms(30), - bit_rate(kDefaultBitRate), - max_payload_size_bytes(-1), - max_bit_rate(-1), - adaptive_mode(false), - enforce_frame_size(false) { +typename AudioEncoderIsacT::Config CreateIsacConfig( + const CodecInst& codec_inst, + LockedIsacBandwidthInfo* bwinfo) { + typename AudioEncoderIsacT::Config config; + config.bwinfo = bwinfo; + 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); + config.adaptive_mode = (codec_inst.rate == -1); + if (codec_inst.rate != -1) + config.bit_rate = codec_inst.rate; + return config; } template @@ -67,46 +67,25 @@ bool AudioEncoderIsacT::Config::IsOk() const { } template -AudioEncoderIsacT::AudioEncoderIsacT(const Config& config) - : payload_type_(config.payload_type), - bwinfo_(config.bwinfo), - packet_in_progress_(false), - target_bitrate_bps_(config.adaptive_mode ? -1 : (config.bit_rate == 0 - ? kDefaultBitRate - : config.bit_rate)) { - CHECK(config.IsOk()); - CHECK_EQ(0, T::Create(&isac_state_)); - CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1)); - CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); - 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)); - } - 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)); - - // 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. - const int decoder_sample_rate_hz = std::min(config.sample_rate_hz, 32000); - - // Set the decoder sample rate even though we just use the encoder. This - // doesn't appear to be necessary to produce a valid encoding, but without it - // we get an encoding that isn't bit-for-bit identical with what a combined - // encoder+decoder object produces. - CHECK_EQ(0, T::SetDecSampRate(isac_state_, decoder_sample_rate_hz)); +AudioEncoderIsacT::AudioEncoderIsacT(const Config& config) { + RecreateEncoderInstance(config); } +template +AudioEncoderIsacT::AudioEncoderIsacT(const CodecInst& codec_inst, + LockedIsacBandwidthInfo* bwinfo) + : AudioEncoderIsacT(CreateIsacConfig(codec_inst, bwinfo)) {} + template AudioEncoderIsacT::~AudioEncoderIsacT() { CHECK_EQ(0, T::Free(isac_state_)); } +template +size_t AudioEncoderIsacT::MaxEncodedBytes() const { + return kSufficientEncodeBufferSizeBytes; +} + template int AudioEncoderIsacT::SampleRateHz() const { return T::EncSampRate(isac_state_); @@ -117,11 +96,6 @@ int AudioEncoderIsacT::NumChannels() const { return 1; } -template -size_t AudioEncoderIsacT::MaxEncodedBytes() const { - return kSufficientEncodeBufferSizeBytes; -} - template size_t AudioEncoderIsacT::Num10MsFramesInNextPacket() const { const int samples_in_next_packet = T::GetNewFrameLen(isac_state_); @@ -137,7 +111,9 @@ size_t AudioEncoderIsacT::Max10MsFramesInAPacket() const { template int AudioEncoderIsacT::GetTargetBitrate() const { - return target_bitrate_bps_; + if (config_.adaptive_mode) + return -1; + return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate; } template @@ -172,15 +148,69 @@ AudioEncoder::EncodedInfo AudioEncoderIsacT::EncodeInternal( EncodedInfo info; info.encoded_bytes = r; info.encoded_timestamp = packet_timestamp_; - info.payload_type = payload_type_; + info.payload_type = config_.payload_type; return info; } template -AudioDecoderIsacT::AudioDecoderIsacT() - : AudioDecoderIsacT(nullptr) { +void AudioEncoderIsacT::Reset() { + RecreateEncoderInstance(config_); } +template +void AudioEncoderIsacT::SetMaxPayloadSize(int max_payload_size_bytes) { + auto conf = config_; + conf.max_payload_size_bytes = max_payload_size_bytes; + RecreateEncoderInstance(conf); +} + +template +void AudioEncoderIsacT::SetMaxBitrate(int max_rate_bps) { + auto conf = config_; + conf.max_bit_rate = max_rate_bps; + RecreateEncoderInstance(conf); +} + +template +void AudioEncoderIsacT::RecreateEncoderInstance(const Config& config) { + CHECK(config.IsOk()); + packet_in_progress_ = false; + bwinfo_ = config.bwinfo; + if (isac_state_) + CHECK_EQ(0, T::Free(isac_state_)); + CHECK_EQ(0, T::Create(&isac_state_)); + CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1)); + CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); + 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)); + } + 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)); + + // 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. + const int decoder_sample_rate_hz = std::min(config.sample_rate_hz, 32000); + + // Set the decoder sample rate even though we just use the encoder. This + // doesn't appear to be necessary to produce a valid encoding, but without it + // we get an encoding that isn't bit-for-bit identical with what a combined + // encoder+decoder object produces. + CHECK_EQ(0, T::SetDecSampRate(isac_state_, decoder_sample_rate_hz)); + + config_ = config; +} + +template +AudioDecoderIsacT::AudioDecoderIsacT() + : AudioDecoderIsacT(nullptr) {} + template AudioDecoderIsacT::AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo) : bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) { 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 index 0fd05da682..e710f24769 100644 --- 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 @@ -13,7 +13,6 @@ #include "webrtc/base/checks.h" #include "webrtc/base/scoped_ptr.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h" #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" @@ -123,16 +122,5 @@ struct IsacFix { using AudioEncoderIsacFix = AudioEncoderIsacT; using AudioDecoderIsacFix = AudioDecoderIsacT; -struct CodecInst; - -class AudioEncoderMutableIsacFix - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutableIsacFix(const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo); - void SetMaxPayloadSize(int max_payload_size_bytes) override; - void SetMaxRate(int max_rate_bps) override; -}; - } // 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 index 2f8d4b6e5d..9b2f3174b8 100644 --- 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 @@ -10,7 +10,6 @@ #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h" -#include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h" namespace webrtc { @@ -21,38 +20,4 @@ const uint16_t IsacFix::kFixSampleRate; template class AudioEncoderIsacT; template class AudioDecoderIsacT; -namespace { -AudioEncoderIsacFix::Config CreateConfig(const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo) { - AudioEncoderIsacFix::Config config; - config.bwinfo = bwinfo; - 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.adaptive_mode = (codec_inst.rate == -1); - return config; -} -} // namespace - -AudioEncoderMutableIsacFix::AudioEncoderMutableIsacFix( - const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo) - : AudioEncoderMutableImpl( - CreateConfig(codec_inst, bwinfo)) {} - -void AudioEncoderMutableIsacFix::SetMaxPayloadSize(int max_payload_size_bytes) { - auto conf = config(); - conf.max_payload_size_bytes = max_payload_size_bytes; - Reconstruct(conf); -} - -void AudioEncoderMutableIsacFix::SetMaxRate(int max_rate_bps) { - auto conf = config(); - conf.max_bit_rate = max_rate_bps; - Reconstruct(conf); -} - } // namespace webrtc 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 58abbdf3c3..da363d8c91 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 @@ -13,7 +13,6 @@ #include "webrtc/base/checks.h" #include "webrtc/base/scoped_ptr.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h" #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h" @@ -121,16 +120,5 @@ struct IsacFloat { using AudioEncoderIsac = AudioEncoderIsacT; using AudioDecoderIsac = AudioDecoderIsacT; -struct CodecInst; - -class AudioEncoderMutableIsacFloat - : public AudioEncoderMutableImpl { - public: - AudioEncoderMutableIsacFloat(const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo); - void SetMaxPayloadSize(int max_payload_size_bytes) override; - void SetMaxRate(int max_rate_bps) override; -}; - } // 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 195265dba6..eac7cc79e7 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,7 +10,6 @@ #include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" -#include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h" namespace webrtc { @@ -19,40 +18,4 @@ namespace webrtc { template class AudioEncoderIsacT; template class AudioDecoderIsacT; -namespace { -AudioEncoderIsac::Config CreateConfig(const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo) { - AudioEncoderIsac::Config config; - config.bwinfo = bwinfo; - 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.adaptive_mode = (codec_inst.rate == -1); - return config; -} -} // namespace - -AudioEncoderMutableIsacFloat::AudioEncoderMutableIsacFloat( - const CodecInst& codec_inst, - LockedIsacBandwidthInfo* bwinfo) - : AudioEncoderMutableImpl( - CreateConfig(codec_inst, bwinfo)) { -} - -void AudioEncoderMutableIsacFloat::SetMaxPayloadSize( - int max_payload_size_bytes) { - auto conf = config(); - conf.max_payload_size_bytes = max_payload_size_bytes; - Reconstruct(conf); -} - -void AudioEncoderMutableIsacFloat::SetMaxRate(int max_rate_bps) { - auto conf = config(); - conf.max_bit_rate = max_rate_bps; - Reconstruct(conf); -} - } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h index 545fc1941a..41c7e58461 100644 --- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h @@ -17,50 +17,32 @@ namespace webrtc { -class MockAudioEncoder : public AudioEncoder { +class MockAudioEncoder final : public AudioEncoder { public: - virtual ~MockAudioEncoder() { Die(); } + ~MockAudioEncoder() override { Die(); } MOCK_METHOD0(Die, void()); + MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); MOCK_CONST_METHOD0(SampleRateHz, int()); MOCK_CONST_METHOD0(NumChannels, int()); - MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); + MOCK_CONST_METHOD0(RtpTimestampRateHz, int()); MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t()); MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t()); MOCK_CONST_METHOD0(GetTargetBitrate, int()); - MOCK_METHOD1(SetTargetBitrate, void(int)); - MOCK_METHOD1(SetProjectedPacketLossRate, void(double)); // Note, we explicitly chose not to create a mock for the Encode method. MOCK_METHOD4(EncodeInternal, EncodedInfo(uint32_t timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded)); -}; - -class MockAudioEncoderMutable : public AudioEncoderMutable { - public: - MOCK_CONST_METHOD0(SampleRateHz, int()); - MOCK_CONST_METHOD0(NumChannels, int()); - MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); - MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t()); - MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t()); - MOCK_CONST_METHOD0(GetTargetBitrate, int()); - MOCK_METHOD1(SetTargetBitrate, void(int)); - MOCK_METHOD1(SetProjectedPacketLossRate, void(double)); - // Note, we explicitly chose not to create a mock for the Encode method. - MOCK_METHOD4(EncodeInternal, - EncodedInfo(uint32_t timestamp, - const int16_t* audio, - size_t max_encoded_bytes, - uint8_t* encoded)); - MOCK_METHOD0(Reset, void()); MOCK_METHOD1(SetFec, bool(bool enable)); MOCK_METHOD1(SetDtx, bool(bool enable)); MOCK_METHOD1(SetApplication, bool(Application application)); - MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); - MOCK_METHOD1(SetMaxRate, void(int max_rate_bps)); MOCK_METHOD1(SetMaxPlaybackRate, bool(int frequency_hz)); + MOCK_METHOD1(SetProjectedPacketLossRate, void(double fraction)); + MOCK_METHOD1(SetTargetBitrate, void(int target_bps)); + MOCK_METHOD1(SetMaxBitrate, void(int max_bps)); + MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc index 3a083985df..29c8678aff 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc @@ -8,6 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ +// TODO(kwiberg): Merge these tests into audio_encoder_opus_unittest.cc + #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h" @@ -26,14 +28,14 @@ class AudioEncoderMutableOpusTest : public ::testing::Test { void CreateCodec(int num_channels) { codec_inst_.channels = num_channels; - encoder_.reset(new AudioEncoderMutableOpus(codec_inst_)); + encoder_.reset(new AudioEncoderOpus(codec_inst_)); auto expected_app = num_channels == 1 ? AudioEncoderOpus::kVoip : AudioEncoderOpus::kAudio; EXPECT_EQ(expected_app, encoder_->application()); } CodecInst codec_inst_; - rtc::scoped_ptr encoder_; + rtc::scoped_ptr encoder_; }; TEST_F(AudioEncoderMutableOpusTest, DefaultApplicationModeMono) { @@ -46,8 +48,7 @@ TEST_F(AudioEncoderMutableOpusTest, DefaultApplicationModeStereo) { TEST_F(AudioEncoderMutableOpusTest, ChangeApplicationMode) { CreateCodec(2); - EXPECT_TRUE( - encoder_->SetApplication(AudioEncoderMutable::kApplicationSpeech)); + EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech)); EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application()); } @@ -60,8 +61,7 @@ TEST_F(AudioEncoderMutableOpusTest, ResetWontChangeApplicationMode) { EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application()); // Now change to kVoip. - EXPECT_TRUE( - encoder_->SetApplication(AudioEncoderMutable::kApplicationSpeech)); + EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech)); EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application()); // Trigger a reset again. diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc index 37ce8733fe..e750aa1323 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc @@ -11,6 +11,7 @@ #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h" #include "webrtc/base/checks.h" +#include "webrtc/base/safe_conversions.h" #include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" @@ -18,36 +19,63 @@ namespace webrtc { namespace { +const int kSampleRateHz = 48000; const int kMinBitrateBps = 500; const int kMaxBitrateBps = 512000; -// TODO(tlegrand): Remove this code when we have proper APIs to set the -// complexity at a higher level. -#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) -// If we are on Android, iOS and/or ARM, use a lower complexity setting as -// default, to save encoder complexity. -const int kDefaultComplexity = 5; -#else -const int kDefaultComplexity = 9; -#endif +AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { + AudioEncoderOpus::Config config; + config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); + config.num_channels = codec_inst.channels; + config.bitrate_bps = codec_inst.rate; + config.payload_type = codec_inst.pltype; + config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip + : AudioEncoderOpus::kAudio; + return config; +} -// We always encode at 48 kHz. -const int kSampleRateHz = 48000; +// Optimize the loss rate to configure Opus. Basically, optimized loss rate is +// the input loss rate rounded down to various levels, because a robustly good +// audio quality is achieved by lowering the packet loss down. +// Additionally, to prevent toggling, margins are used, i.e., when jumping to +// a loss rate from below, a higher threshold is used than jumping to the same +// level from above. +double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { + DCHECK_GE(new_loss_rate, 0.0); + DCHECK_LE(new_loss_rate, 1.0); + DCHECK_GE(old_loss_rate, 0.0); + DCHECK_LE(old_loss_rate, 1.0); + const double kPacketLossRate20 = 0.20; + const double kPacketLossRate10 = 0.10; + const double kPacketLossRate5 = 0.05; + const double kPacketLossRate1 = 0.01; + const double kLossRate20Margin = 0.02; + const double kLossRate10Margin = 0.01; + const double kLossRate5Margin = 0.01; + if (new_loss_rate >= + kPacketLossRate20 + + kLossRate20Margin * + (kPacketLossRate20 - old_loss_rate > 0 ? 1 : -1)) { + return kPacketLossRate20; + } else if (new_loss_rate >= + kPacketLossRate10 + + kLossRate10Margin * + (kPacketLossRate10 - old_loss_rate > 0 ? 1 : -1)) { + return kPacketLossRate10; + } else if (new_loss_rate >= + kPacketLossRate5 + + kLossRate5Margin * + (kPacketLossRate5 - old_loss_rate > 0 ? 1 : -1)) { + return kPacketLossRate5; + } else if (new_loss_rate >= kPacketLossRate1) { + return kPacketLossRate1; + } else { + return 0.0; + } +} } // namespace -AudioEncoderOpus::Config::Config() - : frame_size_ms(20), - num_channels(1), - payload_type(120), - application(kVoip), - bitrate_bps(64000), - fec_enabled(false), - max_playback_rate_hz(48000), - complexity(kDefaultComplexity), - dtx_enabled(false) { -} - bool AudioEncoderOpus::Config::IsOk() const { if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) return false; @@ -61,19 +89,150 @@ bool AudioEncoderOpus::Config::IsOk() const { } AudioEncoderOpus::AudioEncoderOpus(const Config& config) - : num_10ms_frames_per_packet_( - static_cast(rtc::CheckedDivExact(config.frame_size_ms, 10))), - num_channels_(config.num_channels), - payload_type_(config.payload_type), - application_(config.application), - dtx_enabled_(config.dtx_enabled), - samples_per_10ms_frame_(static_cast( - rtc::CheckedDivExact(kSampleRateHz, 100) * num_channels_)), - packet_loss_rate_(0.0) { - CHECK(config.IsOk()); - input_buffer_.reserve(num_10ms_frames_per_packet_ * samples_per_10ms_frame_); - CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, num_channels_, application_)); - SetTargetBitrate(config.bitrate_bps); + : packet_loss_rate_(0.0), inst_(nullptr) { + CHECK(RecreateEncoderInstance(config)); +} + +AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) + : AudioEncoderOpus(CreateConfig(codec_inst)) {} + +AudioEncoderOpus::~AudioEncoderOpus() { + CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); +} + +size_t AudioEncoderOpus::MaxEncodedBytes() const { + // Calculate the number of bytes we expect the encoder to produce, + // then multiply by two to give a wide margin for error. + const size_t bytes_per_millisecond = + static_cast(config_.bitrate_bps / (1000 * 8) + 1); + const size_t approx_encoded_bytes = + Num10msFramesPerPacket() * 10 * bytes_per_millisecond; + return 2 * approx_encoded_bytes; +} + +int AudioEncoderOpus::SampleRateHz() const { + return kSampleRateHz; +} + +int AudioEncoderOpus::NumChannels() const { + return config_.num_channels; +} + +size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const { + return Num10msFramesPerPacket(); +} + +size_t AudioEncoderOpus::Max10MsFramesInAPacket() const { + return Num10msFramesPerPacket(); +} + +int AudioEncoderOpus::GetTargetBitrate() const { + return config_.bitrate_bps; +} + +AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal( + uint32_t rtp_timestamp, + const int16_t* audio, + size_t max_encoded_bytes, + uint8_t* encoded) { + if (input_buffer_.empty()) + first_timestamp_in_buffer_ = rtp_timestamp; + input_buffer_.insert(input_buffer_.end(), audio, + audio + SamplesPer10msFrame()); + if (input_buffer_.size() < + (static_cast(Num10msFramesPerPacket()) * SamplesPer10msFrame())) { + return EncodedInfo(); + } + CHECK_EQ(input_buffer_.size(), static_cast(Num10msFramesPerPacket()) * + SamplesPer10msFrame()); + int status = WebRtcOpus_Encode( + inst_, &input_buffer_[0], + rtc::CheckedDivExact(input_buffer_.size(), + static_cast(config_.num_channels)), + rtc::saturated_cast(max_encoded_bytes), encoded); + CHECK_GE(status, 0); // Fails only if fed invalid data. + input_buffer_.clear(); + EncodedInfo info; + info.encoded_bytes = static_cast(status); + info.encoded_timestamp = first_timestamp_in_buffer_; + info.payload_type = config_.payload_type; + info.send_even_if_empty = true; // Allows Opus to send empty packets. + info.speech = (status > 0); + return info; +} + +void AudioEncoderOpus::Reset() { + CHECK(RecreateEncoderInstance(config_)); +} + +bool AudioEncoderOpus::SetFec(bool enable) { + auto conf = config_; + conf.fec_enabled = enable; + return RecreateEncoderInstance(conf); +} + +bool AudioEncoderOpus::SetDtx(bool enable) { + auto conf = config_; + conf.dtx_enabled = enable; + return RecreateEncoderInstance(conf); +} + +bool AudioEncoderOpus::SetApplication(Application application) { + auto conf = config_; + switch (application) { + case Application::kSpeech: + conf.application = AudioEncoderOpus::kVoip; + break; + case Application::kAudio: + conf.application = AudioEncoderOpus::kAudio; + break; + } + return RecreateEncoderInstance(conf); +} + +bool AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) { + auto conf = config_; + conf.max_playback_rate_hz = frequency_hz; + return RecreateEncoderInstance(conf); +} + +void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { + double opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_); + if (packet_loss_rate_ != opt_loss_rate) { + packet_loss_rate_ = opt_loss_rate; + CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( + inst_, static_cast(packet_loss_rate_ * 100 + .5))); + } +} + +void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { + config_.bitrate_bps = + std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps); + DCHECK(config_.IsOk()); + CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps)); +} + +int AudioEncoderOpus::Num10msFramesPerPacket() const { + return rtc::CheckedDivExact(config_.frame_size_ms, 10); +} + +int AudioEncoderOpus::SamplesPer10msFrame() const { + return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; +} + +// If the given config is OK, recreate the Opus encoder instance with those +// settings, save the config, and return true. Otherwise, do nothing and return +// false. +bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { + if (!config.IsOk()) + return false; + if (inst_) + CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); + input_buffer_.clear(); + input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); + CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, + config.application)); + CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.bitrate_bps)); if (config.fec_enabled) { CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); } else { @@ -87,172 +246,10 @@ AudioEncoderOpus::AudioEncoderOpus(const Config& config) } else { CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); } -} - -AudioEncoderOpus::~AudioEncoderOpus() { - CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); -} - -int AudioEncoderOpus::SampleRateHz() const { - return kSampleRateHz; -} - -int AudioEncoderOpus::NumChannels() const { - return num_channels_; -} - -size_t AudioEncoderOpus::MaxEncodedBytes() const { - // Calculate the number of bytes we expect the encoder to produce, - // then multiply by two to give a wide margin for error. - size_t bytes_per_millisecond = - static_cast(bitrate_bps_ / (1000 * 8) + 1); - size_t approx_encoded_bytes = - num_10ms_frames_per_packet_ * 10 * bytes_per_millisecond; - return 2 * approx_encoded_bytes; -} - -size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const { - return num_10ms_frames_per_packet_; -} - -size_t AudioEncoderOpus::Max10MsFramesInAPacket() const { - return num_10ms_frames_per_packet_; -} - -int AudioEncoderOpus::GetTargetBitrate() const { - return bitrate_bps_; -} - -void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { - bitrate_bps_ = std::max(std::min(bits_per_second, kMaxBitrateBps), - kMinBitrateBps); - CHECK_EQ(WebRtcOpus_SetBitRate(inst_, bitrate_bps_), 0); -} - -void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { - DCHECK_GE(fraction, 0.0); - DCHECK_LE(fraction, 1.0); - // Optimize the loss rate to configure Opus. Basically, optimized loss rate is - // the input loss rate rounded down to various levels, because a robustly good - // audio quality is achieved by lowering the packet loss down. - // Additionally, to prevent toggling, margins are used, i.e., when jumping to - // a loss rate from below, a higher threshold is used than jumping to the same - // level from above. - const double kPacketLossRate20 = 0.20; - const double kPacketLossRate10 = 0.10; - const double kPacketLossRate5 = 0.05; - const double kPacketLossRate1 = 0.01; - const double kLossRate20Margin = 0.02; - const double kLossRate10Margin = 0.01; - const double kLossRate5Margin = 0.01; - double opt_loss_rate; - if (fraction >= - kPacketLossRate20 + - kLossRate20Margin * - (kPacketLossRate20 - packet_loss_rate_ > 0 ? 1 : -1)) { - opt_loss_rate = kPacketLossRate20; - } else if (fraction >= - kPacketLossRate10 + - kLossRate10Margin * - (kPacketLossRate10 - packet_loss_rate_ > 0 ? 1 : -1)) { - opt_loss_rate = kPacketLossRate10; - } else if (fraction >= - kPacketLossRate5 + - kLossRate5Margin * - (kPacketLossRate5 - packet_loss_rate_ > 0 ? 1 : -1)) { - opt_loss_rate = kPacketLossRate5; - } else if (fraction >= kPacketLossRate1) { - opt_loss_rate = kPacketLossRate1; - } else { - opt_loss_rate = 0; - } - - if (packet_loss_rate_ != opt_loss_rate) { - // Ask the encoder to change the target packet loss rate. - CHECK_EQ(WebRtcOpus_SetPacketLossRate( - inst_, static_cast(opt_loss_rate * 100 + .5)), - 0); - packet_loss_rate_ = opt_loss_rate; - } -} - -AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal( - uint32_t rtp_timestamp, - const int16_t* audio, - size_t max_encoded_bytes, - uint8_t* encoded) { - if (input_buffer_.empty()) - first_timestamp_in_buffer_ = rtp_timestamp; - input_buffer_.insert(input_buffer_.end(), audio, - audio + samples_per_10ms_frame_); - if (input_buffer_.size() < - (num_10ms_frames_per_packet_ * samples_per_10ms_frame_)) { - return EncodedInfo(); - } - CHECK_EQ(input_buffer_.size(), - num_10ms_frames_per_packet_ * samples_per_10ms_frame_); - int status = WebRtcOpus_Encode( - inst_, &input_buffer_[0], - rtc::CheckedDivExact(input_buffer_.size(), - static_cast(num_channels_)), - max_encoded_bytes, encoded); - CHECK_GE(status, 0); // Fails only if fed invalid data. - input_buffer_.clear(); - EncodedInfo info; - info.encoded_bytes = static_cast(status); - info.encoded_timestamp = first_timestamp_in_buffer_; - info.payload_type = payload_type_; - info.send_even_if_empty = true; // Allows Opus to send empty packets. - info.speech = (status > 0); - return info; -} - -namespace { -AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderOpus::Config config; - config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); - config.num_channels = codec_inst.channels; - config.bitrate_bps = codec_inst.rate; - config.payload_type = codec_inst.pltype; - config.application = (config.num_channels == 1 ? AudioEncoderOpus::kVoip - : AudioEncoderOpus::kAudio); - return config; -} -} // namespace - -AudioEncoderMutableOpus::AudioEncoderMutableOpus(const CodecInst& codec_inst) - : AudioEncoderMutableImpl(CreateConfig(codec_inst)) { -} - -bool AudioEncoderMutableOpus::SetFec(bool enable) { - auto conf = config(); - conf.fec_enabled = enable; - return Reconstruct(conf); -} - -bool AudioEncoderMutableOpus::SetDtx(bool enable) { - auto conf = config(); - conf.dtx_enabled = enable; - return Reconstruct(conf); -} - -bool AudioEncoderMutableOpus::SetApplication(Application application) { - auto conf = config(); - switch (application) { - case kApplicationSpeech: - conf.application = AudioEncoderOpus::kVoip; - break; - case kApplicationAudio: - conf.application = AudioEncoderOpus::kAudio; - break; - } - return Reconstruct(conf); -} - -bool AudioEncoderMutableOpus::SetMaxPlaybackRate(int frequency_hz) { - auto conf = config(); - conf.max_playback_rate_hz = frequency_hz; - return Reconstruct(conf); + CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( + inst_, static_cast(packet_loss_rate_ * 100 + .5))); + config_ = config; + return true; } } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h index 5fab599fe1..d95d6c6710 100644 --- a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h @@ -13,15 +13,14 @@ #include +#include "webrtc/base/checks.h" #include "webrtc/base/scoped_ptr.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" namespace webrtc { -// NOTE: This class has neither ThreadChecker, nor locks. The owner of an -// AudioEncoderOpus object must ensure that it is not accessed concurrently. +struct CodecInst; class AudioEncoderOpus final : public AudioEncoder { public: @@ -31,60 +30,44 @@ class AudioEncoderOpus final : public AudioEncoder { }; struct Config { - Config(); bool IsOk() const; - int frame_size_ms; - int num_channels; - int payload_type; - ApplicationMode application; - int bitrate_bps; - bool fec_enabled; - int max_playback_rate_hz; - int complexity; - bool dtx_enabled; + int frame_size_ms = 20; + int num_channels = 1; + int payload_type = 120; + ApplicationMode application = kVoip; + int bitrate_bps = 64000; + bool fec_enabled = false; + int max_playback_rate_hz = 48000; + int complexity = kDefaultComplexity; + bool dtx_enabled = false; + + private: +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) + // If we are on Android, iOS and/or ARM, use a lower complexity setting as + // default, to save encoder complexity. + static const int kDefaultComplexity = 5; +#else + static const int kDefaultComplexity = 9; +#endif }; explicit AudioEncoderOpus(const Config& config); + explicit AudioEncoderOpus(const CodecInst& codec_inst); ~AudioEncoderOpus() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; - void SetTargetBitrate(int bits_per_second) override; - void SetProjectedPacketLossRate(double fraction) override; - - double packet_loss_rate() const { return packet_loss_rate_; } - ApplicationMode application() const { return application_; } - bool dtx_enabled() const { return dtx_enabled_; } EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; - private: - const size_t num_10ms_frames_per_packet_; - const int num_channels_; - const int payload_type_; - const ApplicationMode application_; - int bitrate_bps_; - const bool dtx_enabled_; - const size_t samples_per_10ms_frame_; - std::vector input_buffer_; - OpusEncInst* inst_; - uint32_t first_timestamp_in_buffer_; - double packet_loss_rate_; -}; - -struct CodecInst; - -class AudioEncoderMutableOpus - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutableOpus(const CodecInst& codec_inst); + void Reset() override; bool SetFec(bool enable) override; // Set Opus DTX. Once enabled, Opus stops transmission, when it detects voice @@ -94,18 +77,24 @@ class AudioEncoderMutableOpus bool SetApplication(Application application) override; bool SetMaxPlaybackRate(int frequency_hz) override; - AudioEncoderOpus::ApplicationMode application() const { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder()->application(); - } - double packet_loss_rate() const { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder()->packet_loss_rate(); - } - bool dtx_enabled() const { - CriticalSectionScoped cs(encoder_lock_.get()); - return encoder()->dtx_enabled(); - } + void SetProjectedPacketLossRate(double fraction) override; + void SetTargetBitrate(int target_bps) override; + + // Getters for testing. + double packet_loss_rate() const { return packet_loss_rate_; } + ApplicationMode application() const { return config_.application; } + bool dtx_enabled() const { return config_.dtx_enabled; } + + private: + int Num10msFramesPerPacket() const; + int SamplesPer10msFrame() const; + bool RecreateEncoderInstance(const Config& config); + + Config config_; + double packet_loss_rate_; + std::vector input_buffer_; + OpusEncInst* inst_; + uint32_t first_timestamp_in_buffer_; }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc index 4ca6fe94a8..6c30c7ff62 100644 --- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc +++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc @@ -16,13 +16,6 @@ namespace webrtc { -bool AudioEncoderPcm16B::Config::IsOk() const { - if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) && - (sample_rate_hz != 32000) && (sample_rate_hz != 48000)) - return false; - return AudioEncoderPcm::Config::IsOk(); -} - size_t AudioEncoderPcm16B::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) { @@ -45,9 +38,14 @@ AudioEncoderPcm16B::Config CreateConfig(const CodecInst& codec_inst) { } } // namespace -AudioEncoderMutablePcm16B::AudioEncoderMutablePcm16B( - const CodecInst& codec_inst) - : AudioEncoderMutableImpl(CreateConfig(codec_inst)) { +bool AudioEncoderPcm16B::Config::IsOk() const { + if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) && + (sample_rate_hz != 32000) && (sample_rate_hz != 48000)) + return false; + return AudioEncoderPcm::Config::IsOk(); } +AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst) + : AudioEncoderPcm16B(CreateConfig(codec_inst)) {} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h b/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h index 6a0fb438bf..5d368bce7a 100644 --- a/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h +++ b/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h @@ -12,11 +12,12 @@ #define WEBRTC_MODULES_AUDIO_CODING_CODECS_PCM16B_INCLUDE_AUDIO_ENCODER_PCM16B_H_ #include "webrtc/base/scoped_ptr.h" -#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h" #include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h" namespace webrtc { +struct CodecInst; + class AudioEncoderPcm16B final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { @@ -29,6 +30,7 @@ class AudioEncoderPcm16B final : public AudioEncoderPcm { explicit AudioEncoderPcm16B(const Config& config) : AudioEncoderPcm(config, config.sample_rate_hz) {} + explicit AudioEncoderPcm16B(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio, @@ -38,13 +40,5 @@ class AudioEncoderPcm16B final : public AudioEncoderPcm { int BytesPerSample() const override; }; -struct CodecInst; - -class AudioEncoderMutablePcm16B - : public AudioEncoderMutableImpl { - public: - explicit AudioEncoderMutablePcm16B(const CodecInst& codec_inst); -}; - } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_PCM16B_INCLUDE_AUDIO_ENCODER_PCM16B_H_ diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc index 96ec3ccf42..a54e01845b 100644 --- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc +++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc @@ -22,23 +22,22 @@ AudioEncoderCopyRed::AudioEncoderCopyRed(const Config& config) CHECK(speech_encoder_) << "Speech encoder not provided."; } -AudioEncoderCopyRed::~AudioEncoderCopyRed() { +AudioEncoderCopyRed::~AudioEncoderCopyRed() = default; + +size_t AudioEncoderCopyRed::MaxEncodedBytes() const { + return 2 * speech_encoder_->MaxEncodedBytes(); } int AudioEncoderCopyRed::SampleRateHz() const { return speech_encoder_->SampleRateHz(); } -int AudioEncoderCopyRed::RtpTimestampRateHz() const { - return speech_encoder_->RtpTimestampRateHz(); -} - int AudioEncoderCopyRed::NumChannels() const { return speech_encoder_->NumChannels(); } -size_t AudioEncoderCopyRed::MaxEncodedBytes() const { - return 2 * speech_encoder_->MaxEncodedBytes(); +int AudioEncoderCopyRed::RtpTimestampRateHz() const { + return speech_encoder_->RtpTimestampRateHz(); } size_t AudioEncoderCopyRed::Num10MsFramesInNextPacket() const { @@ -53,16 +52,6 @@ int AudioEncoderCopyRed::GetTargetBitrate() const { return speech_encoder_->GetTargetBitrate(); } -void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) { - speech_encoder_->SetTargetBitrate(bits_per_second); -} - -void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) { - DCHECK_GE(fraction, 0.0); - DCHECK_LE(fraction, 1.0); - speech_encoder_->SetProjectedPacketLossRate(fraction); -} - AudioEncoder::EncodedInfo AudioEncoderCopyRed::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, @@ -102,4 +91,42 @@ AudioEncoder::EncodedInfo AudioEncoderCopyRed::EncodeInternal( return info; } +void AudioEncoderCopyRed::Reset() { + speech_encoder_->Reset(); + secondary_encoded_.Clear(); + secondary_info_.encoded_bytes = 0; +} + +bool AudioEncoderCopyRed::SetFec(bool enable) { + return speech_encoder_->SetFec(enable); +} + +bool AudioEncoderCopyRed::SetDtx(bool enable) { + return speech_encoder_->SetDtx(enable); +} + +bool AudioEncoderCopyRed::SetApplication(Application application) { + return speech_encoder_->SetApplication(application); +} + +bool AudioEncoderCopyRed::SetMaxPlaybackRate(int frequency_hz) { + return speech_encoder_->SetMaxPlaybackRate(frequency_hz); +} + +void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) { + speech_encoder_->SetProjectedPacketLossRate(fraction); +} + +void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) { + speech_encoder_->SetTargetBitrate(bits_per_second); +} + +void AudioEncoderCopyRed::SetMaxBitrate(int max_bps) { + speech_encoder_->SetMaxBitrate(max_bps); +} + +void AudioEncoderCopyRed::SetMaxPayloadSize(int max_payload_size_bytes) { + speech_encoder_->SetMaxPayloadSize(max_payload_size_bytes); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h index 644255b835..5e2c9b2826 100644 --- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h +++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h @@ -23,7 +23,7 @@ namespace webrtc { // underlying AudioEncoder object that performs the actual encodings. The // current class will gather the two latest encodings from the underlying codec // into one packet. -class AudioEncoderCopyRed : public AudioEncoder { +class AudioEncoderCopyRed final : public AudioEncoder { public: struct Config { public: @@ -36,19 +36,26 @@ class AudioEncoderCopyRed : public AudioEncoder { ~AudioEncoderCopyRed() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; int NumChannels() const override; - size_t MaxEncodedBytes() const override; int RtpTimestampRateHz() const override; size_t Num10MsFramesInNextPacket() const override; size_t Max10MsFramesInAPacket() const override; int GetTargetBitrate() const override; - void SetTargetBitrate(int bits_per_second) override; - void SetProjectedPacketLossRate(double fraction) override; EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) override; + void Reset() override; + bool SetFec(bool enable) override; + bool SetDtx(bool enable) override; + bool SetApplication(Application application) override; + bool SetMaxPlaybackRate(int frequency_hz) override; + void SetProjectedPacketLossRate(double fraction) override; + void SetTargetBitrate(int target_bps) override; + void SetMaxBitrate(int max_bps) override; + void SetMaxPayloadSize(int max_payload_size_bytes) override; private: AudioEncoder* speech_encoder_; diff --git a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc index 74e98d9cd5..b84be29581 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc @@ -65,7 +65,7 @@ bool AcmSendTestOldApi::RegisterCodec(const char* payload_name, } bool AcmSendTestOldApi::RegisterExternalCodec( - AudioEncoderMutable* external_speech_encoder) { + AudioEncoder* external_speech_encoder) { acm_->RegisterExternalSendCodec(external_speech_encoder); input_frame_.num_channels_ = external_speech_encoder->NumChannels(); assert(input_block_size_samples_ * input_frame_.num_channels_ <= diff --git a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h index 008e264987..523498bc3e 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h @@ -20,7 +20,7 @@ #include "webrtc/system_wrappers/interface/clock.h" namespace webrtc { -class AudioEncoderMutable; +class AudioEncoder; namespace test { class InputAudioFile; @@ -42,7 +42,7 @@ class AcmSendTestOldApi : public AudioPacketizationCallback, int frame_size_samples); // Registers an external send codec. Returns true on success, false otherwise. - bool RegisterExternalCodec(AudioEncoderMutable* external_speech_encoder); + bool RegisterExternalCodec(AudioEncoder* external_speech_encoder); // Returns the next encoded packet. Returns NULL if the test duration was // exceeded. Ownership of the packet is handed over to the caller. diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc index ac0bc0b270..eec00dec3e 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc @@ -231,7 +231,7 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) { } void AudioCodingModuleImpl::RegisterExternalSendCodec( - AudioEncoderMutable* external_speech_encoder) { + AudioEncoder* external_speech_encoder) { CriticalSectionScoped lock(acm_crit_sect_.get()); codec_manager_.RegisterEncoder(external_speech_encoder); } @@ -485,8 +485,8 @@ int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) { int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) { CriticalSectionScoped lock(acm_crit_sect_.get()); if (HaveValidEncoder("SetPacketLossRate")) { - codec_manager_.CurrentSpeechEncoder()->SetProjectedPacketLossRate( - loss_rate / 100.0); + codec_manager_.CurrentEncoder()->SetProjectedPacketLossRate(loss_rate / + 100.0); } return 0; } @@ -741,7 +741,7 @@ int AudioCodingModuleImpl::SetISACMaxRate(int max_bit_per_sec) { return -1; } - codec_manager_.CurrentSpeechEncoder()->SetMaxRate(max_bit_per_sec); + codec_manager_.CurrentEncoder()->SetMaxBitrate(max_bit_per_sec); return 0; } @@ -753,7 +753,7 @@ int AudioCodingModuleImpl::SetISACMaxPayloadSize(int max_size_bytes) { return -1; } - codec_manager_.CurrentSpeechEncoder()->SetMaxPayloadSize(max_size_bytes); + codec_manager_.CurrentEncoder()->SetMaxPayloadSize(max_size_bytes); return 0; } @@ -762,19 +762,21 @@ int AudioCodingModuleImpl::SetOpusApplication(OpusApplicationMode application) { if (!HaveValidEncoder("SetOpusApplication")) { return -1; } - AudioEncoderMutable::Application app; + if (!codec_manager_.CurrentEncoderIsOpus()) + return -1; + AudioEncoder::Application app; switch (application) { case kVoip: - app = AudioEncoderMutable::kApplicationSpeech; + app = AudioEncoder::Application::kSpeech; break; case kAudio: - app = AudioEncoderMutable::kApplicationAudio; + app = AudioEncoder::Application::kAudio; break; default: FATAL(); return 0; } - return codec_manager_.CurrentSpeechEncoder()->SetApplication(app) ? 0 : -1; + return codec_manager_.CurrentEncoder()->SetApplication(app) ? 0 : -1; } // Informs Opus encoder of the maximum playback rate the receiver will render. @@ -783,9 +785,10 @@ int AudioCodingModuleImpl::SetOpusMaxPlaybackRate(int frequency_hz) { if (!HaveValidEncoder("SetOpusMaxPlaybackRate")) { return -1; } - return codec_manager_.CurrentSpeechEncoder()->SetMaxPlaybackRate(frequency_hz) - ? 0 - : -1; + if (!codec_manager_.CurrentEncoderIsOpus()) + return -1; + return codec_manager_.CurrentEncoder()->SetMaxPlaybackRate(frequency_hz) ? 0 + : -1; } int AudioCodingModuleImpl::EnableOpusDtx() { @@ -793,7 +796,9 @@ int AudioCodingModuleImpl::EnableOpusDtx() { if (!HaveValidEncoder("EnableOpusDtx")) { return -1; } - return codec_manager_.CurrentSpeechEncoder()->SetDtx(true) ? 0 : -1; + if (!codec_manager_.CurrentEncoderIsOpus()) + return -1; + return codec_manager_.CurrentEncoder()->SetDtx(true) ? 0 : -1; } int AudioCodingModuleImpl::DisableOpusDtx() { @@ -801,7 +806,9 @@ int AudioCodingModuleImpl::DisableOpusDtx() { if (!HaveValidEncoder("DisableOpusDtx")) { return -1; } - return codec_manager_.CurrentSpeechEncoder()->SetDtx(false) ? 0 : -1; + if (!codec_manager_.CurrentEncoderIsOpus()) + return -1; + return codec_manager_.CurrentEncoder()->SetDtx(false) ? 0 : -1; } int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) { diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h index fd93901205..db3e927c08 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h @@ -47,7 +47,7 @@ class AudioCodingModuleImpl final : public AudioCodingModule { int RegisterSendCodec(const CodecInst& send_codec) override; void RegisterExternalSendCodec( - AudioEncoderMutable* external_speech_encoder) override; + AudioEncoder* external_speech_encoder) override; // Get current send codec. int SendCodec(CodecInst* current_codec) const override; diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc index b7289fc7cb..36e27349cd 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc @@ -1074,7 +1074,7 @@ class AcmSenderBitExactnessOldApi : public ::testing::Test, frame_size_samples); } - bool RegisterExternalSendCodec(AudioEncoderMutable* external_speech_encoder, + bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder, int payload_type) { payload_type_ = payload_type; frame_size_rtp_timestamps_ = @@ -1176,7 +1176,7 @@ class AcmSenderBitExactnessOldApi : public ::testing::Test, codec_frame_size_rtp_timestamps)); } - void SetUpTestExternalEncoder(AudioEncoderMutable* external_speech_encoder, + void SetUpTestExternalEncoder(AudioEncoder* external_speech_encoder, int payload_type) { ASSERT_TRUE(SetUpSender()); ASSERT_TRUE( @@ -1601,36 +1601,36 @@ TEST_F(AcmSenderBitExactnessOldApi, External_Pcmu_20ms) { codec_inst.channels = 1; codec_inst.pacsize = 160; codec_inst.pltype = 0; - AudioEncoderMutablePcmU encoder(codec_inst); - MockAudioEncoderMutable mock_encoder; + AudioEncoderPcmU encoder(codec_inst); + MockAudioEncoder mock_encoder; // Set expectations on the mock encoder and also delegate the calls to the // real encoder. + EXPECT_CALL(mock_encoder, MaxEncodedBytes()) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::MaxEncodedBytes)); + EXPECT_CALL(mock_encoder, SampleRateHz()) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::SampleRateHz)); + EXPECT_CALL(mock_encoder, NumChannels()) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::NumChannels)); + EXPECT_CALL(mock_encoder, RtpTimestampRateHz()) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::RtpTimestampRateHz)); EXPECT_CALL(mock_encoder, Num10MsFramesInNextPacket()) .Times(AtLeast(1)) - .WillRepeatedly(Invoke( - &encoder, &AudioEncoderMutablePcmU::Num10MsFramesInNextPacket)); + .WillRepeatedly( + Invoke(&encoder, &AudioEncoderPcmU::Num10MsFramesInNextPacket)); EXPECT_CALL(mock_encoder, Max10MsFramesInAPacket()) .Times(AtLeast(1)) .WillRepeatedly( - Invoke(&encoder, &AudioEncoderMutablePcmU::Max10MsFramesInAPacket)); - EXPECT_CALL(mock_encoder, SampleRateHz()) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(&encoder, &AudioEncoderMutablePcmU::SampleRateHz)); - EXPECT_CALL(mock_encoder, NumChannels()) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(&encoder, &AudioEncoderMutablePcmU::NumChannels)); - EXPECT_CALL(mock_encoder, MaxEncodedBytes()) - .Times(AtLeast(1)) - .WillRepeatedly( - Invoke(&encoder, &AudioEncoderMutablePcmU::MaxEncodedBytes)); - EXPECT_CALL(mock_encoder, EncodeInternal(_, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly( - Invoke(&encoder, &AudioEncoderMutablePcmU::EncodeInternal)); + Invoke(&encoder, &AudioEncoderPcmU::Max10MsFramesInAPacket)); EXPECT_CALL(mock_encoder, GetTargetBitrate()) .Times(AtLeast(1)) - .WillRepeatedly(Invoke( - &encoder, &AudioEncoderMutablePcmU::GetTargetBitrate)); + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::GetTargetBitrate)); + EXPECT_CALL(mock_encoder, EncodeInternal(_, _, _, _)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::EncodeInternal)); ASSERT_NO_FATAL_FAILURE( SetUpTestExternalEncoder(&mock_encoder, codec_inst.pltype)); Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9", diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc index 7b9c7ed5a9..863a86eae5 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc +++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc @@ -164,7 +164,8 @@ CodecManager::CodecManager() vad_mode_(VADNormal), send_codec_inst_(kEmptyCodecInst), red_enabled_(false), - codec_fec_enabled_(false) { + codec_fec_enabled_(false), + encoder_is_opus_(false) { // Register the default payload type for RED and for CNG at sampling rates of // 8, 16, 32 and 48 kHz. for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { @@ -275,6 +276,8 @@ int CodecManager::RegisterEncoder(const CodecInst& send_codec) { red_enabled_ = false; } + encoder_is_opus_ = IsOpus(send_codec); + if (new_codec) { // This is a new codec. Register it and return. DCHECK(CodecSupported(send_codec)); @@ -287,9 +290,8 @@ int CodecManager::RegisterEncoder(const CodecInst& send_codec) { vad_mode_, red_enabled_ ? RedPayloadType(send_codec.plfreq) : -1); DCHECK(codec_owner_.Encoder()); - codec_fec_enabled_ = - codec_fec_enabled_ && - codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); + codec_fec_enabled_ = codec_fec_enabled_ && + codec_owner_.Encoder()->SetFec(codec_fec_enabled_); send_codec_inst_ = send_codec; return 0; @@ -311,18 +313,17 @@ int CodecManager::RegisterEncoder(const CodecInst& send_codec) { // Check if a change in Rate is required. if (send_codec.rate != send_codec_inst_.rate) { - codec_owner_.SpeechEncoder()->SetTargetBitrate(send_codec.rate); + codec_owner_.Encoder()->SetTargetBitrate(send_codec.rate); send_codec_inst_.rate = send_codec.rate; } - codec_fec_enabled_ = codec_fec_enabled_ && - codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); + codec_fec_enabled_ = + codec_fec_enabled_ && codec_owner_.Encoder()->SetFec(codec_fec_enabled_); return 0; } -void CodecManager::RegisterEncoder( - AudioEncoderMutable* external_speech_encoder) { +void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) { // Make up a CodecInst. send_codec_inst_.channels = external_speech_encoder->NumChannels(); send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz(); @@ -337,8 +338,8 @@ void CodecManager::RegisterEncoder( if (stereo_send_) dtx_enabled_ = false; - codec_fec_enabled_ = codec_fec_enabled_ && - codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); + codec_fec_enabled_ = + codec_fec_enabled_ && codec_owner_.Encoder()->SetFec(codec_fec_enabled_); int cng_pt = dtx_enabled_ ? CngPayloadType(external_speech_encoder->SampleRateHz()) : -1; @@ -430,9 +431,9 @@ int CodecManager::SetCodecFEC(bool enable_codec_fec) { return -1; } - CHECK(codec_owner_.SpeechEncoder()); - codec_fec_enabled_ = codec_owner_.SpeechEncoder()->SetFec(enable_codec_fec) && - enable_codec_fec; + CHECK(codec_owner_.Encoder()); + codec_fec_enabled_ = + codec_owner_.Encoder()->SetFec(enable_codec_fec) && enable_codec_fec; return codec_fec_enabled_ == enable_codec_fec ? 0 : -1; } diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h index bb9545d889..3372b7f27b 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_manager.h +++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h @@ -22,7 +22,6 @@ namespace webrtc { class AudioDecoder; class AudioEncoder; -class AudioEncoderMutable; namespace acm2 { @@ -33,7 +32,7 @@ class CodecManager final { int RegisterEncoder(const CodecInst& send_codec); - void RegisterEncoder(AudioEncoderMutable* external_speech_encoder); + void RegisterEncoder(AudioEncoder* external_speech_encoder); int GetCodecInst(CodecInst* current_codec) const; @@ -58,12 +57,11 @@ class CodecManager final { bool codec_fec_enabled() const { return codec_fec_enabled_; } - AudioEncoderMutable* CurrentSpeechEncoder() { - return codec_owner_.SpeechEncoder(); - } AudioEncoder* CurrentEncoder() { return codec_owner_.Encoder(); } const AudioEncoder* CurrentEncoder() const { return codec_owner_.Encoder(); } + bool CurrentEncoderIsOpus() const { return encoder_is_opus_; } + private: int CngPayloadType(int sample_rate_hz) const; @@ -82,6 +80,7 @@ class CodecManager final { bool red_enabled_; bool codec_fec_enabled_; CodecOwner codec_owner_; + bool encoder_is_opus_; DISALLOW_COPY_AND_ASSIGN(CodecManager); }; diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc index 2f7228bf71..f0c38b84dc 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc +++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc @@ -94,41 +94,39 @@ rtc::scoped_ptr CreateIsacDecoder( #endif } -rtc::scoped_ptr CreateIsacEncoder( +rtc::scoped_ptr CreateIsacEncoder( const CodecInst& speech_inst, LockedIsacBandwidthInfo* bwinfo) { #if defined(WEBRTC_CODEC_ISACFX) - return rtc_make_scoped_ptr( - new AudioEncoderMutableIsacFix(speech_inst, bwinfo)); + return rtc_make_scoped_ptr(new AudioEncoderIsacFix(speech_inst, bwinfo)); #elif defined(WEBRTC_CODEC_ISAC) - return rtc_make_scoped_ptr( - new AudioEncoderMutableIsacFloat(speech_inst, bwinfo)); + return rtc_make_scoped_ptr(new AudioEncoderIsac(speech_inst, bwinfo)); #else FATAL() << "iSAC is not supported."; return rtc::scoped_ptr(); #endif } -rtc::scoped_ptr CreateSpeechEncoder( +rtc::scoped_ptr CreateSpeechEncoder( const CodecInst& speech_inst, LockedIsacBandwidthInfo* bwinfo) { if (IsIsac(speech_inst)) { return CreateIsacEncoder(speech_inst, bwinfo); } else if (IsOpus(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutableOpus(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderOpus(speech_inst)); } else if (IsPcmU(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutablePcmU(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderPcmU(speech_inst)); } else if (IsPcmA(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutablePcmA(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderPcmA(speech_inst)); } else if (IsPcm16B(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutablePcm16B(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderPcm16B(speech_inst)); } else if (IsIlbc(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutableIlbc(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderIlbc(speech_inst)); } else if (IsG722(speech_inst)) { - return rtc_make_scoped_ptr(new AudioEncoderMutableG722(speech_inst)); + return rtc_make_scoped_ptr(new AudioEncoderG722(speech_inst)); } else { FATAL() << "Could not create encoder of type " << speech_inst.plname; - return rtc::scoped_ptr(); + return rtc::scoped_ptr(); } } @@ -187,7 +185,7 @@ void CodecOwner::SetEncoders(const CodecInst& speech_inst, ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type); } -void CodecOwner::SetEncoders(AudioEncoderMutable* external_speech_encoder, +void CodecOwner::SetEncoders(AudioEncoder* external_speech_encoder, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { @@ -199,7 +197,7 @@ void CodecOwner::SetEncoders(AudioEncoderMutable* external_speech_encoder, void CodecOwner::ChangeCngAndRed(int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { - AudioEncoderMutable* speech_encoder = SpeechEncoder(); + AudioEncoder* speech_encoder = SpeechEncoder(); if (cng_payload_type != -1 || red_payload_type != -1) { // The RED and CNG encoders need to be in sync with the speech encoder, so // reset the latter to ensure its buffer is empty. @@ -230,12 +228,12 @@ const AudioEncoder* CodecOwner::Encoder() const { return SpeechEncoder(); } -AudioEncoderMutable* CodecOwner::SpeechEncoder() { - const auto& const_this = *this; - return const_cast(const_this.SpeechEncoder()); +AudioEncoder* CodecOwner::SpeechEncoder() { + const auto* const_this = this; + return const_cast(const_this->SpeechEncoder()); } -const AudioEncoderMutable* CodecOwner::SpeechEncoder() const { +const AudioEncoder* CodecOwner::SpeechEncoder() const { DCHECK(!speech_encoder_ || !external_speech_encoder_); return external_speech_encoder_ ? external_speech_encoder_ : speech_encoder_.get(); diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.h b/webrtc/modules/audio_coding/main/acm2/codec_owner.h index 2c5e942ef5..cb533b676b 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_owner.h +++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.h @@ -34,7 +34,7 @@ class CodecOwner { ACMVADMode vad_mode, int red_payload_type); - void SetEncoders(AudioEncoderMutable* external_speech_encoder, + void SetEncoders(AudioEncoder* external_speech_encoder, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type); @@ -49,13 +49,14 @@ class CodecOwner { AudioEncoder* Encoder(); const AudioEncoder* Encoder() const; - AudioEncoderMutable* SpeechEncoder(); - const AudioEncoderMutable* SpeechEncoder() const; private: + AudioEncoder* SpeechEncoder(); + const AudioEncoder* SpeechEncoder() const; + // At most one of these is non-null: - rtc::scoped_ptr speech_encoder_; - AudioEncoderMutable* external_speech_encoder_; + rtc::scoped_ptr speech_encoder_; + AudioEncoder* external_speech_encoder_; // If we've created an iSAC decoder because someone called GetIsacDecoder, // store it here. diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc index a1366a9b88..0c510c0770 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc +++ b/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc @@ -99,7 +99,7 @@ TEST_F(CodecOwnerTest, VerifyCngFrames) { } TEST_F(CodecOwnerTest, ExternalEncoder) { - MockAudioEncoderMutable external_encoder; + MockAudioEncoder external_encoder; codec_owner_.SetEncoders(&external_encoder, -1, VADNormal, -1); const int kSampleRateHz = 8000; const int kPacketSizeSamples = kSampleRateHz / 100; diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h index 387632e0f4..f2972e712c 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h @@ -28,7 +28,7 @@ struct CodecInst; struct WebRtcRTPHeader; class AudioFrame; class RTPFragmentationHeader; -class AudioEncoderMutable; +class AudioEncoder; class AudioDecoder; #define WEBRTC_10MS_PCM_AUDIO 960 // 16 bits super wideband 48 kHz @@ -225,7 +225,7 @@ class AudioCodingModule { // Registers |external_speech_encoder| as encoder. The new encoder will // replace any previously registered speech encoder (internal or external). virtual void RegisterExternalSendCodec( - AudioEncoderMutable* external_speech_encoder) = 0; + AudioEncoder* external_speech_encoder) = 0; /////////////////////////////////////////////////////////////////////////// // int32_t SendCodec()