From 3e89dbf45835896c8fd89f235f396d03bc2e6065 Mon Sep 17 00:00:00 2001 From: Henrik Lundin Date: Thu, 18 Jun 2015 14:58:34 +0200 Subject: [PATCH] Add AudioEncoder::GetTargetBitrate The GetTargetBitrate implementation will return the target bitrate of the codec. This may differ from the desired target bitrate, as set by SetTargetBitrate, depending on implementation. Tests are updated to exercise the new functionality. R=kwiberg@webrtc.org Review URL: https://codereview.webrtc.org/1184313002. Cr-Commit-Position: refs/heads/master@{#9461} --- .../audio_coding/codecs/audio_encoder.h | 5 ++ .../codecs/audio_encoder_mutable_impl.h | 4 ++ .../codecs/cng/audio_encoder_cng.cc | 4 ++ .../codecs/cng/include/audio_encoder_cng.h | 1 + .../codecs/g711/audio_encoder_pcm.cc | 14 +++- .../codecs/g711/include/audio_encoder_pcm.h | 11 ++- .../codecs/g722/audio_encoder_g722.cc | 5 ++ .../codecs/g722/include/audio_encoder_g722.h | 3 +- .../codecs/ilbc/audio_encoder_ilbc.cc | 13 ++++ .../ilbc/interface/audio_encoder_ilbc.h | 3 +- .../codecs/isac/audio_encoder_isac_t.h | 3 + .../codecs/isac/audio_encoder_isac_t_impl.h | 15 ++-- .../codecs/mock/mock_audio_encoder.h | 2 + .../opus/audio_encoder_mutable_opus_test.cc | 24 +++++++ .../codecs/opus/audio_encoder_opus.cc | 4 ++ .../opus/interface/audio_encoder_opus.h | 2 + .../codecs/pcm16b/audio_encoder_pcm16b.cc | 4 ++ .../pcm16b/include/audio_encoder_pcm16b.h | 4 +- .../codecs/red/audio_encoder_copy_red.cc | 4 ++ .../codecs/red/audio_encoder_copy_red.h | 1 + .../neteq/audio_decoder_unittest.cc | 69 +++++++++++++++++++ 21 files changed, 185 insertions(+), 10 deletions(-) diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h index 9025834dfa..fe6fd87dfd 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h @@ -96,6 +96,11 @@ class AudioEncoder { // Num10MsFramesInNextPacket(). virtual int Max10MsFramesInAPacket() const = 0; + // Returns the current target bitrate in bits/s. The value -1 means that the + // codec adapts the target automatically, and a current target cannot be + // 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) {} diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h b/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h index 0bf818a037..553d8ad4b8 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h +++ b/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h @@ -82,6 +82,10 @@ class AudioEncoderMutableImpl : public P { 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); 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 c662b5ba5a..d2acaa1a1a 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc @@ -97,6 +97,10 @@ int AudioEncoderCng::Max10MsFramesInAPacket() const { return speech_encoder_->Max10MsFramesInAPacket(); } +int AudioEncoderCng::GetTargetBitrate() const { + return speech_encoder_->GetTargetBitrate(); +} + void AudioEncoderCng::SetTargetBitrate(int bits_per_second) { speech_encoder_->SetTargetBitrate(bits_per_second); } 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 094b73074b..51d2febad6 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 @@ -52,6 +52,7 @@ class AudioEncoderCng final : public AudioEncoder { int RtpTimestampRateHz() const override; int Num10MsFramesInNextPacket() const override; int 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, 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 ed49618646..905a7152dd 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc +++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc @@ -60,7 +60,7 @@ int AudioEncoderPcm::NumChannels() const { } size_t AudioEncoderPcm::MaxEncodedBytes() const { - return full_frame_samples_; + return full_frame_samples_ * BytesPerSample(); } int AudioEncoderPcm::Num10MsFramesInNextPacket() const { @@ -71,6 +71,10 @@ int AudioEncoderPcm::Max10MsFramesInAPacket() const { return num_10ms_frames_per_packet_; } +int AudioEncoderPcm::GetTargetBitrate() const { + return 8 * BytesPerSample() * SampleRateHz() * NumChannels(); +} + AudioEncoder::EncodedInfo AudioEncoderPcm::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, @@ -104,12 +108,20 @@ int16_t AudioEncoderPcmA::EncodeCall(const int16_t* audio, return WebRtcG711_EncodeA(audio, static_cast(input_len), encoded); } +int AudioEncoderPcmA::BytesPerSample() const { + return 1; +} + int16_t AudioEncoderPcmU::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) { return WebRtcG711_EncodeU(audio, static_cast(input_len), encoded); } +int AudioEncoderPcmU::BytesPerSample() const { + return 1; +} + namespace { template typename T::Config CreateConfig(const CodecInst& codec_inst) { 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 870b4ddfb6..c8690379c6 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 @@ -41,6 +41,7 @@ class AudioEncoderPcm : public AudioEncoder { size_t MaxEncodedBytes() const override; int Num10MsFramesInNextPacket() const override; int Max10MsFramesInAPacket() const override; + int GetTargetBitrate() const override; EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, @@ -53,6 +54,8 @@ class AudioEncoderPcm : public AudioEncoder { size_t input_len, uint8_t* encoded) = 0; + virtual int BytesPerSample() const = 0; + private: const int sample_rate_hz_; const int num_channels_; @@ -63,7 +66,7 @@ class AudioEncoderPcm : public AudioEncoder { uint32_t first_timestamp_in_buffer_; }; -class AudioEncoderPcmA : public AudioEncoderPcm { +class AudioEncoderPcmA final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { Config() : AudioEncoderPcm::Config(8) {} @@ -77,11 +80,13 @@ class AudioEncoderPcmA : public AudioEncoderPcm { size_t input_len, uint8_t* encoded) override; + int BytesPerSample() const override; + private: static const int kSampleRateHz = 8000; }; -class AudioEncoderPcmU : public AudioEncoderPcm { +class AudioEncoderPcmU final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { Config() : AudioEncoderPcm::Config(0) {} @@ -95,6 +100,8 @@ class AudioEncoderPcmU : public AudioEncoderPcm { size_t input_len, uint8_t* encoded) override; + int BytesPerSample() const override; + private: static const int kSampleRateHz = 8000; }; 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 8e10dffe8e..a0d1720e46 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc @@ -82,6 +82,11 @@ int AudioEncoderG722::Max10MsFramesInAPacket() const { return num_10ms_frames_per_packet_; } +int AudioEncoderG722::GetTargetBitrate() const { + // 4 bits/sample, 16000 samples/s/channel. + return 64000 * NumChannels(); +} + AudioEncoder::EncodedInfo AudioEncoderG722::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, 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 f5e0a9899f..9b57fbe625 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 @@ -19,7 +19,7 @@ namespace webrtc { -class AudioEncoderG722 : public AudioEncoder { +class AudioEncoderG722 final : public AudioEncoder { public: struct Config { Config() : payload_type(9), frame_size_ms(20), num_channels(1) {} @@ -39,6 +39,7 @@ class AudioEncoderG722 : public AudioEncoder { int RtpTimestampRateHz() const override; int Num10MsFramesInNextPacket() const override; int Max10MsFramesInAPacket() const override; + int GetTargetBitrate() const override; EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, 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 66d24650a6..8dc9bdf4bd 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc @@ -66,6 +66,19 @@ int AudioEncoderIlbc::Max10MsFramesInAPacket() const { return num_10ms_frames_per_packet_; } +int AudioEncoderIlbc::GetTargetBitrate() const { + switch (num_10ms_frames_per_packet_) { + case 2: case 4: + // 38 bytes per frame of 20 ms => 15200 bits/s. + return 15200; + case 3: case 6: + // 50 bytes per frame of 30 ms => (approx) 13333 bits/s. + return 13333; + default: + FATAL(); + } +} + AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, 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 c172db1b8f..b627c3a087 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 @@ -18,7 +18,7 @@ namespace webrtc { -class AudioEncoderIlbc : public AudioEncoder { +class AudioEncoderIlbc final : public AudioEncoder { public: struct Config { Config() : payload_type(102), frame_size_ms(30) {} @@ -38,6 +38,7 @@ class AudioEncoderIlbc : public AudioEncoder { size_t MaxEncodedBytes() const override; int Num10MsFramesInNextPacket() const override; int Max10MsFramesInAPacket() const override; + int GetTargetBitrate() const override; EncodedInfo EncodeInternal(uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, 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 b67a9b09fc..49df3c68be 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 @@ -59,6 +59,7 @@ class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder { size_t MaxEncodedBytes() const override; int Num10MsFramesInNextPacket() const override; int Max10MsFramesInAPacket() const override; + int GetTargetBitrate() const override; // AudioDecoder methods. bool HasDecodePlc() const override; @@ -113,6 +114,8 @@ class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder { // Timestamp of the previously encoded packet. uint32_t last_encoded_timestamp_ GUARDED_BY(lock_); + const int target_bitrate_bps_; + DISALLOW_COPY_AND_ASSIGN(AudioEncoderDecoderIsacT); }; 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 befb3558be..d2b20e3b94 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 @@ -70,16 +70,18 @@ AudioEncoderDecoderIsacT::AudioEncoderDecoderIsacT(const Config& config) state_lock_(CriticalSectionWrapper::CreateCriticalSection()), decoder_sample_rate_hz_(0), lock_(CriticalSectionWrapper::CreateCriticalSection()), - packet_in_progress_(false) { + 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)); - + 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)); } @@ -129,6 +131,11 @@ int AudioEncoderDecoderIsacT::Max10MsFramesInAPacket() const { return 6; // iSAC puts at most 60 ms in a packet. } +template +int AudioEncoderDecoderIsacT::GetTargetBitrate() const { + return target_bitrate_bps_; +} + template AudioEncoder::EncodedInfo AudioEncoderDecoderIsacT::EncodeInternal( uint32_t rtp_timestamp, 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 786c83cd6a..18d4068873 100644 --- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h @@ -26,6 +26,7 @@ class MockAudioEncoder : public AudioEncoder { MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, int()); MOCK_CONST_METHOD0(Max10MsFramesInAPacket, int()); + 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. @@ -43,6 +44,7 @@ class MockAudioEncoderMutable : public AudioEncoderMutable { MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, int()); MOCK_CONST_METHOD0(Max10MsFramesInAPacket, int()); + 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. 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 ed3f52fff7..3a083985df 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 @@ -79,6 +79,30 @@ TEST_F(AudioEncoderMutableOpusTest, ToggleDtx) { // Turn off DTX. EXPECT_TRUE(encoder_->SetDtx(false)); } + +TEST_F(AudioEncoderMutableOpusTest, SetBitrate) { + CreateCodec(1); + // Constants are replicated from audio_encoder_opus.cc. + const int kMinBitrateBps = 500; + const int kMaxBitrateBps = 512000; + // Set a too low bitrate. + encoder_->SetTargetBitrate(kMinBitrateBps - 1); + EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate()); + // Set a too high bitrate. + encoder_->SetTargetBitrate(kMaxBitrateBps + 1); + EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate()); + // Set the minimum rate. + encoder_->SetTargetBitrate(kMinBitrateBps); + EXPECT_EQ(kMinBitrateBps, encoder_->GetTargetBitrate()); + // Set the maximum rate. + encoder_->SetTargetBitrate(kMaxBitrateBps); + EXPECT_EQ(kMaxBitrateBps, encoder_->GetTargetBitrate()); + // Set rates from 1000 up to 32000 bps. + for (int rate = 1000; rate <= 32000; rate += 1000) { + encoder_->SetTargetBitrate(rate); + EXPECT_EQ(rate, encoder_->GetTargetBitrate()); + } +} #endif // WEBRTC_CODEC_OPUS } // namespace acm2 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 328698380a..88e084fe1d 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc @@ -129,6 +129,10 @@ int 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); 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 4de4e26273..3393bd516d 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 @@ -52,12 +52,14 @@ class AudioEncoderOpus final : public AudioEncoder { size_t MaxEncodedBytes() const override; int Num10MsFramesInNextPacket() const override; int 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, 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 491fdfdb14..0c246c34bd 100644 --- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc +++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc @@ -29,6 +29,10 @@ int16_t AudioEncoderPcm16B::EncodeCall(const int16_t* audio, return WebRtcPcm16b_Encode(audio, static_cast(input_len), encoded); } +int AudioEncoderPcm16B::BytesPerSample() const { + return 2; +} + namespace { AudioEncoderPcm16B::Config CreateConfig(const CodecInst& codec_inst) { AudioEncoderPcm16B::Config config; 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 f1e1c51da8..f02cf92dd9 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 @@ -17,7 +17,7 @@ namespace webrtc { -class AudioEncoderPcm16B : public AudioEncoderPcm { +class AudioEncoderPcm16B final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { public: @@ -34,6 +34,8 @@ class AudioEncoderPcm16B : public AudioEncoderPcm { int16_t EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) override; + + int BytesPerSample() const override; }; struct CodecInst; 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 cc657a6838..16ba290fc3 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 @@ -49,6 +49,10 @@ int AudioEncoderCopyRed::Max10MsFramesInAPacket() const { return speech_encoder_->Max10MsFramesInAPacket(); } +int AudioEncoderCopyRed::GetTargetBitrate() const { + return speech_encoder_->GetTargetBitrate(); +} + void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) { speech_encoder_->SetTargetBitrate(bits_per_second); } 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 49ab948fab..78e1e9aff3 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 @@ -42,6 +42,7 @@ class AudioEncoderCopyRed : public AudioEncoder { int RtpTimestampRateHz() const override; int Num10MsFramesInNextPacket() const override; int 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, diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 1850807783..d54fbe9099 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -485,6 +485,24 @@ TEST_F(AudioDecoderPcmUTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +namespace { +int SetAndGetTargetBitrate(AudioEncoder* audio_encoder, int rate) { + audio_encoder->SetTargetBitrate(rate); + return audio_encoder->GetTargetBitrate(); +} +void TestSetAndGetTargetBitratesWithFixedCodec(AudioEncoder* audio_encoder, + int fixed_rate) { + EXPECT_EQ(fixed_rate, SetAndGetTargetBitrate(audio_encoder, 32000)); + EXPECT_EQ(fixed_rate, SetAndGetTargetBitrate(audio_encoder, fixed_rate - 1)); + EXPECT_EQ(fixed_rate, SetAndGetTargetBitrate(audio_encoder, fixed_rate)); + EXPECT_EQ(fixed_rate, SetAndGetTargetBitrate(audio_encoder, fixed_rate + 1)); +} +} // namespace + +TEST_F(AudioDecoderPcmUTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 64000); +} + TEST_F(AudioDecoderPcmATest, EncodeDecode) { int tolerance = 308; double mse = 1931.0; @@ -494,6 +512,10 @@ TEST_F(AudioDecoderPcmATest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderPcmATest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 64000); +} + TEST_F(AudioDecoderPcm16BTest, EncodeDecode) { int tolerance = 0; double mse = 0.0; @@ -506,6 +528,11 @@ TEST_F(AudioDecoderPcm16BTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderPcm16BTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), + codec_input_rate_hz_ * 16); +} + TEST_F(AudioDecoderIlbcTest, EncodeDecode) { int tolerance = 6808; double mse = 2.13e6; @@ -517,6 +544,10 @@ TEST_F(AudioDecoderIlbcTest, EncodeDecode) { DecodePlcTest(); } +TEST_F(AudioDecoderIlbcTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 13333); +} + TEST_F(AudioDecoderIsacFloatTest, EncodeDecode) { int tolerance = 3399; double mse = 434951.0; @@ -527,6 +558,10 @@ TEST_F(AudioDecoderIsacFloatTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderIsacFloatTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); +} + TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) { int tolerance = 19757; double mse = 8.18e6; @@ -537,6 +572,10 @@ TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderIsacSwbTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); +} + // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4198 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) #define MAYBE_EncodeDecode DISABLED_EncodeDecode @@ -558,6 +597,10 @@ TEST_F(AudioDecoderIsacFixTest, MAYBE_EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderIsacFixTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); +} + TEST_F(AudioDecoderG722Test, EncodeDecode) { int tolerance = 6176; double mse = 238630.0; @@ -568,6 +611,10 @@ TEST_F(AudioDecoderG722Test, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderG722Test, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 64000); +} + TEST_F(AudioDecoderG722StereoTest, CreateAndDestroy) { EXPECT_TRUE(CodecSupported(kDecoderG722_2ch)); } @@ -583,6 +630,10 @@ TEST_F(AudioDecoderG722StereoTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderG722StereoTest, SetTargetBitrate) { + TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 128000); +} + TEST_F(AudioDecoderOpusTest, EncodeDecode) { int tolerance = 6176; double mse = 238630.0; @@ -593,6 +644,20 @@ TEST_F(AudioDecoderOpusTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +namespace { +void TestOpusSetTargetBitrates(AudioEncoder* audio_encoder) { + EXPECT_EQ(500, SetAndGetTargetBitrate(audio_encoder, 499)); + EXPECT_EQ(500, SetAndGetTargetBitrate(audio_encoder, 500)); + EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder, 32000)); + EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 512000)); + EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 513000)); +} +} // namespace + +TEST_F(AudioDecoderOpusTest, SetTargetBitrate) { + TestOpusSetTargetBitrates(audio_encoder_.get()); +} + TEST_F(AudioDecoderOpusStereoTest, EncodeDecode) { int tolerance = 6176; int channel_diff_tolerance = 0; @@ -604,6 +669,10 @@ TEST_F(AudioDecoderOpusStereoTest, EncodeDecode) { EXPECT_FALSE(decoder_->HasDecodePlc()); } +TEST_F(AudioDecoderOpusStereoTest, SetTargetBitrate) { + TestOpusSetTargetBitrates(audio_encoder_.get()); +} + TEST(AudioDecoder, CodecSampleRateHz) { EXPECT_EQ(8000, CodecSampleRateHz(kDecoderPCMu)); EXPECT_EQ(8000, CodecSampleRateHz(kDecoderPCMa));