diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc index f00b2432f2..254c2f420b 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc @@ -104,6 +104,7 @@ void ConvertEncodedInfoToFragmentationHeader( class RawAudioEncoderWrapper final : public AudioEncoder { public: RawAudioEncoderWrapper(AudioEncoder* enc) : enc_(enc) {} + size_t MaxEncodedBytes() const override { return enc_->MaxEncodedBytes(); } int SampleRateHz() const override { return enc_->SampleRateHz(); } size_t NumChannels() const override { return enc_->NumChannels(); } int RtpTimestampRateHz() const override { return enc_->RtpTimestampRateHz(); } @@ -119,6 +120,13 @@ class RawAudioEncoderWrapper final : public AudioEncoder { rtc::Buffer* encoded) override { return enc_->Encode(rtp_timestamp, audio, encoded); } + EncodedInfo EncodeInternal(uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded) override { + return enc_->EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, + encoded); + } void Reset() override { return enc_->Reset(); } bool SetFec(bool enable) override { return enc_->SetFec(enable); } bool SetDtx(bool enable) override { return enc_->SetDtx(enable); } diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc index fa262c4644..6f793e2531 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder.cc +++ b/webrtc/modules/audio_coding/codecs/audio_encoder.cc @@ -37,6 +37,55 @@ AudioEncoder::EncodedInfo AudioEncoder::Encode( return info; } +AudioEncoder::EncodedInfo AudioEncoder::Encode( + uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded) { + return DEPRECATED_Encode(rtp_timestamp, audio, max_encoded_bytes, encoded); +} + +AudioEncoder::EncodedInfo AudioEncoder::DEPRECATED_Encode( + uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded) { + TRACE_EVENT0("webrtc", "AudioEncoder::Encode"); + RTC_CHECK_EQ(audio.size(), + static_cast(NumChannels() * SampleRateHz() / 100)); + EncodedInfo info = + EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded); + RTC_CHECK_LE(info.encoded_bytes, max_encoded_bytes); + return info; +} + +AudioEncoder::EncodedInfo AudioEncoder::EncodeImpl( + uint32_t rtp_timestamp, + rtc::ArrayView audio, + rtc::Buffer* encoded) +{ + EncodedInfo info; + encoded->AppendData(MaxEncodedBytes(), [&] (rtc::ArrayView encoded) { + info = EncodeInternal(rtp_timestamp, audio, + encoded.size(), encoded.data()); + return info.encoded_bytes; + }); + return info; +} + +AudioEncoder::EncodedInfo AudioEncoder::EncodeInternal( + uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded) +{ + rtc::Buffer temp_buffer; + EncodedInfo info = EncodeImpl(rtp_timestamp, audio, &temp_buffer); + RTC_DCHECK_LE(temp_buffer.size(), max_encoded_bytes); + std::memcpy(encoded, temp_buffer.data(), info.encoded_bytes); + return info; +} + bool AudioEncoder::SetFec(bool enable) { return !enable; } @@ -55,9 +104,4 @@ void AudioEncoder::SetProjectedPacketLossRate(double fraction) {} void AudioEncoder::SetTargetBitrate(int target_bps) {} -size_t AudioEncoder::MaxEncodedBytes() const { - RTC_CHECK(false); - return 0; -} - } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h index 58d9fff451..3fdee259ce 100644 --- a/webrtc/modules/audio_coding/codecs/audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h @@ -52,6 +52,14 @@ class AudioEncoder { virtual ~AudioEncoder() = default; + // 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 + // any of these change, the caller of Encode() is responsible for checking + // that the buffer is large enough by calling MaxEncodedBytes() again. + virtual size_t MaxEncodedBytes() const = 0; + // 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; @@ -87,6 +95,33 @@ class AudioEncoder { rtc::ArrayView audio, rtc::Buffer* encoded); + // Deprecated interface to Encode (remove eventually, bug 5591). May incur a + // copy. 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. + RTC_DEPRECATED EncodedInfo Encode(uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded); + + EncodedInfo DEPRECATED_Encode(uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded); + + // Deprecated interface EncodeInternal (see bug 5591). May incur a copy. + // Subclasses implement this to perform the actual encoding. Called by + // Encode(). By default, this is implemented as a call to the newer + // EncodeImpl() that accepts an rtc::Buffer instead of a raw pointer. + // That version is protected, so see below. At least one of EncodeInternal + // or EncodeImpl _must_ be implemented by a subclass. + virtual EncodedInfo EncodeInternal( + uint32_t rtp_timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded); + // 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; @@ -127,19 +162,13 @@ class AudioEncoder { protected: // Subclasses implement this to perform the actual encoding. Called by - // Encode(). + // Encode(). For compatibility reasons, this is implemented by default as a + // call to the older interface EncodeInternal(). At least one of + // EncodeInternal or EncodeImpl _must_ be implemented by a + // subclass. Preferably this one. virtual EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, - rtc::Buffer* encoded) = 0; - - private: - // This function is deprecated. It was used to return the maximum number of - // bytes that can be produced by the encoder at each Encode() call. Since the - // Encode interface was changed to use rtc::Buffer, this is no longer - // applicable. It is only kept in to avoid breaking subclasses that still have - // it implemented (with the override attribute). It will be removed as soon - // as these subclasses have been given a chance to change. - virtual size_t MaxEncodedBytes() const; + rtc::Buffer* encoded); }; } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_ diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_unittest.cc b/webrtc/modules/audio_coding/codecs/audio_encoder_unittest.cc new file mode 100644 index 0000000000..71ffcde323 --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/audio_encoder_unittest.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; + +namespace webrtc { + +TEST(AudioEncoderTest, EncodeInternalRedirectsOk) { + const size_t kPayloadSize = 16; + const uint8_t payload[kPayloadSize] = + {0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, + 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0}; + + MockAudioEncoderDeprecated old_impl; + MockAudioEncoder new_impl; + MockAudioEncoderBase* impls[] = { &old_impl, &new_impl }; + for (auto* impl : impls) { + EXPECT_CALL(*impl, Die()); + EXPECT_CALL(*impl, MaxEncodedBytes()) + .WillRepeatedly(Return(kPayloadSize * 2)); + EXPECT_CALL(*impl, NumChannels()).WillRepeatedly(Return(1)); + EXPECT_CALL(*impl, SampleRateHz()).WillRepeatedly(Return(8000)); + } + + EXPECT_CALL(old_impl, EncodeInternal(_, _, _, _)).WillOnce( + Invoke(MockAudioEncoderDeprecated::CopyEncoding(payload))); + + EXPECT_CALL(new_impl, EncodeImpl(_, _, _)).WillOnce( + Invoke(MockAudioEncoder::CopyEncoding(payload))); + + int16_t audio[80]; + uint8_t output_array[kPayloadSize * 2]; + rtc::Buffer output_buffer; + + AudioEncoder* old_encoder = &old_impl; + AudioEncoder* new_encoder = &new_impl; + auto old_info = old_encoder->Encode(0, audio, &output_buffer); + auto new_info = new_encoder->DEPRECATED_Encode(0, audio, + kPayloadSize * 2, + output_array); + + EXPECT_EQ(old_info.encoded_bytes, kPayloadSize); + EXPECT_EQ(new_info.encoded_bytes, kPayloadSize); + EXPECT_EQ(output_buffer.size(), kPayloadSize); + + for (size_t i = 0; i != kPayloadSize; ++i) { + EXPECT_EQ(output_buffer.data()[i], payload[i]); + EXPECT_EQ(output_array[i], payload[i]); + } +} + +} // namespace webrtc 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 0fa9d9e789..3b48131a75 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc @@ -82,6 +82,13 @@ AudioEncoderCng::AudioEncoderCng(Config&& config) AudioEncoderCng::~AudioEncoderCng() = default; +size_t AudioEncoderCng::MaxEncodedBytes() const { + const size_t max_encoded_bytes_active = speech_encoder_->MaxEncodedBytes(); + const size_t max_encoded_bytes_passive = + rtc::CheckedDivExact(kMaxFrameSizeMs, 10) * SamplesPer10msFrame(); + return std::max(max_encoded_bytes_active, max_encoded_bytes_passive); +} + int AudioEncoderCng::SampleRateHz() const { return speech_encoder_->SampleRateHz(); } diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h index b52665d9c0..1384cd511e 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h @@ -52,6 +52,7 @@ class AudioEncoderCng final : public AudioEncoder { explicit AudioEncoderCng(Config&& config); ~AudioEncoderCng() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; int RtpTimestampRateHz() const override; 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 8b80d2181d..8f30d783ae 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 @@ -25,6 +25,7 @@ using ::testing::Invoke; namespace webrtc { namespace { +static const size_t kMockMaxEncodedBytes = 1000; static const size_t kMaxNumSamples = 48 * 10 * 2; // 10 ms @ 48 kHz stereo. static const size_t kMockReturnEncodedBytes = 17; static const int kCngPayloadType = 18; @@ -73,6 +74,8 @@ class AudioEncoderCngTest : public ::testing::Test { // as long as it is smaller than 10. EXPECT_CALL(*mock_encoder_, Max10MsFramesInAPacket()) .WillOnce(Return(1u)); + EXPECT_CALL(*mock_encoder_, MaxEncodedBytes()) + .WillRepeatedly(Return(kMockMaxEncodedBytes)); } cng_.reset(new AudioEncoderCng(std::move(config))); } @@ -87,8 +90,8 @@ class AudioEncoderCngTest : public ::testing::Test { } // Expect |num_calls| calls to the encoder, all successful. The last call - // claims to have encoded |kMockReturnEncodedBytes| bytes, and all the - // preceding ones 0 bytes. + // claims to have encoded |kMockMaxEncodedBytes| bytes, and all the preceding + // ones 0 bytes. void ExpectEncodeCalls(size_t num_calls) { InSequence s; AudioEncoder::EncodedInfo info; 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 e4da8d7440..a24b1526fd 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc +++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc @@ -52,6 +52,10 @@ AudioEncoderPcm::AudioEncoderPcm(const Config& config, int sample_rate_hz) AudioEncoderPcm::~AudioEncoderPcm() = default; +size_t AudioEncoderPcm::MaxEncodedBytes() const { + return full_frame_samples_ * BytesPerSample(); +} + int AudioEncoderPcm::SampleRateHz() const { return sample_rate_hz_; } @@ -89,7 +93,7 @@ AudioEncoder::EncodedInfo AudioEncoderPcm::EncodeImpl( info.encoded_timestamp = first_timestamp_in_buffer_; info.payload_type = payload_type_; info.encoded_bytes = - encoded->AppendData(full_frame_samples_ * BytesPerSample(), + encoded->AppendData(MaxEncodedBytes(), [&] (rtc::ArrayView encoded) { return EncodeCall(&speech_buffer_[0], full_frame_samples_, diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h index eb5ad02878..6b3cebfb33 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h +++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h @@ -35,6 +35,7 @@ class AudioEncoderPcm : public AudioEncoder { ~AudioEncoderPcm() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; size_t Num10MsFramesInNextPacket() const override; 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 256013266d..9256518445 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc @@ -60,6 +60,10 @@ AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst) AudioEncoderG722::~AudioEncoderG722() = default; +size_t AudioEncoderG722::MaxEncodedBytes() const { + return SamplesPerChannel() / 2 * num_channels_; +} + int AudioEncoderG722::SampleRateHz() const { return kSampleRateHz; } diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h index b3f6965fff..dec87b2b7a 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h @@ -35,6 +35,7 @@ class AudioEncoderG722 final : public AudioEncoder { explicit AudioEncoderG722(const CodecInst& codec_inst); ~AudioEncoderG722() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; int RtpTimestampRateHz() const override; @@ -43,7 +44,7 @@ class AudioEncoderG722 final : public AudioEncoder { int GetTargetBitrate() const override; void Reset() override; - protected: +protected: EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) override; 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 45401a1280..c7d7411c45 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc @@ -56,6 +56,10 @@ AudioEncoderIlbc::~AudioEncoderIlbc() { RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); } +size_t AudioEncoderIlbc::MaxEncodedBytes() const { + return RequiredOutputSizeBytes(); +} + int AudioEncoderIlbc::SampleRateHz() const { return kSampleRateHz; } diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h index 63639860f4..27329bbc4e 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h @@ -34,6 +34,7 @@ class AudioEncoderIlbc final : public AudioEncoder { explicit AudioEncoderIlbc(const CodecInst& codec_inst); ~AudioEncoderIlbc() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; size_t Num10MsFramesInNextPacket() const override; 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 afe38d7940..0da8ed71d6 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 @@ -56,6 +56,7 @@ class AudioEncoderIsacT final : public AudioEncoder { const rtc::scoped_refptr& bwinfo); ~AudioEncoderIsacT() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; size_t Num10MsFramesInNextPacket() const override; 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 1f95e5980e..1debbeb903 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 @@ -79,6 +79,11 @@ AudioEncoderIsacT::~AudioEncoderIsacT() { RTC_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_); diff --git a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.cc b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.cc index a674eba660..52849691ac 100644 --- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.cc +++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.cc @@ -49,4 +49,26 @@ AudioEncoder::EncodedInfo MockAudioEncoder::CopyEncoding::operator()( return info_; } +MockAudioEncoderDeprecated::CopyEncoding::CopyEncoding( + AudioEncoder::EncodedInfo info, + rtc::ArrayView payload) + : info_(info), payload_(payload) { } + +MockAudioEncoderDeprecated::CopyEncoding::CopyEncoding( + rtc::ArrayView payload) + : payload_(payload) { + info_.encoded_bytes = payload_.size(); +} + +AudioEncoder::EncodedInfo MockAudioEncoderDeprecated::CopyEncoding::operator()( + uint32_t timestamp, + rtc::ArrayView audio, + size_t max_bytes_encoded, + uint8_t* encoded) { + RTC_CHECK(encoded); + RTC_CHECK_LE(info_.encoded_bytes, payload_.size()); + std::memcpy(encoded, payload_.data(), info_.encoded_bytes); + return info_; +} + } // 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 f898877c19..58a1e756f9 100644 --- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h +++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h @@ -18,11 +18,12 @@ namespace webrtc { -class MockAudioEncoder : public AudioEncoder { +class MockAudioEncoderBase : public AudioEncoder { public: - ~MockAudioEncoder() override { Die(); } + ~MockAudioEncoderBase() override { Die(); } MOCK_METHOD0(Die, void()); MOCK_METHOD1(Mark, void(std::string desc)); + MOCK_CONST_METHOD0(MaxEncodedBytes, size_t()); MOCK_CONST_METHOD0(SampleRateHz, int()); MOCK_CONST_METHOD0(NumChannels, size_t()); MOCK_CONST_METHOD0(RtpTimestampRateHz, int()); @@ -38,7 +39,10 @@ class MockAudioEncoder : public AudioEncoder { MOCK_METHOD1(SetTargetBitrate, void(int target_bps)); MOCK_METHOD1(SetMaxBitrate, void(int max_bps)); MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); +}; +class MockAudioEncoder final : public MockAudioEncoderBase { + public: // Note, we explicitly chose not to create a mock for the Encode method. MOCK_METHOD3(EncodeImpl, EncodedInfo(uint32_t timestamp, @@ -85,6 +89,36 @@ class MockAudioEncoder : public AudioEncoder { AudioEncoder::EncodedInfo info_; rtc::ArrayView payload_; }; + +}; + +class MockAudioEncoderDeprecated final : public MockAudioEncoderBase { + public: + // Note, we explicitly chose not to create a mock for the Encode method. + MOCK_METHOD4(EncodeInternal, + EncodedInfo(uint32_t timestamp, + rtc::ArrayView audio, + size_t max_encoded_bytes, + uint8_t* encoded)); + + // A functor like MockAudioEncoder::CopyEncoding above, but which has the + // deprecated Encode signature. Currently only used in one test and should be + // removed once that backwards compatibility is. + class CopyEncoding { + public: + CopyEncoding(AudioEncoder::EncodedInfo info, + rtc::ArrayView payload); + + CopyEncoding(rtc::ArrayView payload); + + AudioEncoder::EncodedInfo operator()(uint32_t timestamp, + rtc::ArrayView audio, + size_t max_bytes_encoded, + uint8_t* encoded); + private: + AudioEncoder::EncodedInfo info_; + rtc::ArrayView payload_; + }; }; } // namespace webrtc 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 0e50fdc82b..a599e291d4 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc @@ -100,6 +100,16 @@ AudioEncoderOpus::~AudioEncoderOpus() { RTC_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; } @@ -188,7 +198,7 @@ AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( RTC_CHECK_EQ(input_buffer_.size(), Num10msFramesPerPacket() * SamplesPer10msFrame()); - const size_t max_encoded_bytes = ApproximateEncodedBytes(); + const size_t max_encoded_bytes = MaxEncodedBytes(); EncodedInfo info; info.encoded_bytes = encoded->AppendData( @@ -221,16 +231,6 @@ size_t AudioEncoderOpus::SamplesPer10msFrame() const { return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; } -size_t AudioEncoderOpus::ApproximateEncodedBytes() 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; -} - // 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. diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h index 9294f2fed4..3f11af1f9e 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h @@ -54,6 +54,7 @@ class AudioEncoderOpus final : public AudioEncoder { explicit AudioEncoderOpus(const CodecInst& codec_inst); ~AudioEncoderOpus() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; size_t Num10MsFramesInNextPacket() const override; @@ -78,7 +79,7 @@ class AudioEncoderOpus final : public AudioEncoder { ApplicationMode application() const { return config_.application; } bool dtx_enabled() const { return config_.dtx_enabled; } - protected: +protected: EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) override; @@ -86,7 +87,6 @@ class AudioEncoderOpus final : public AudioEncoder { private: size_t Num10msFramesPerPacket() const; size_t SamplesPer10msFrame() const; - size_t ApproximateEncodedBytes() const; bool RecreateEncoderInstance(const Config& config); Config config_; 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 e4d7b59b59..4275f54103 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 @@ -35,6 +35,10 @@ AudioEncoderCopyRed::AudioEncoderCopyRed(Config&& config) AudioEncoderCopyRed::~AudioEncoderCopyRed() = default; +size_t AudioEncoderCopyRed::MaxEncodedBytes() const { + return 2 * speech_encoder_->MaxEncodedBytes(); +} + int AudioEncoderCopyRed::SampleRateHz() const { return speech_encoder_->SampleRateHz(); } 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 06d0fdeeca..a67ae486bb 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 @@ -37,6 +37,7 @@ class AudioEncoderCopyRed final : public AudioEncoder { ~AudioEncoderCopyRed() override; + size_t MaxEncodedBytes() const override; int SampleRateHz() const override; size_t NumChannels() const override; int RtpTimestampRateHz() const override; @@ -51,7 +52,7 @@ class AudioEncoderCopyRed final : public AudioEncoder { void SetProjectedPacketLossRate(double fraction) override; void SetTargetBitrate(int target_bps) override; - protected: +protected: EncodedInfo EncodeImpl(uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) override; diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc index 22b2ceb5f7..c73cb9f209 100644 --- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc @@ -26,6 +26,7 @@ using ::testing::MockFunction; namespace webrtc { namespace { +static const size_t kMockMaxEncodedBytes = 1000; static const size_t kMaxNumSamples = 48 * 10 * 2; // 10 ms @ 48 kHz stereo. } @@ -45,6 +46,8 @@ class AudioEncoderCopyRedTest : public ::testing::Test { EXPECT_CALL(*mock_encoder_, NumChannels()).WillRepeatedly(Return(1U)); EXPECT_CALL(*mock_encoder_, SampleRateHz()) .WillRepeatedly(Return(sample_rate_hz_)); + EXPECT_CALL(*mock_encoder_, MaxEncodedBytes()) + .WillRepeatedly(Return(kMockMaxEncodedBytes)); } void TearDown() override { diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 31ffcaa6e9..d5df853905 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -167,6 +167,7 @@ '<(webrtc_root)/tools/tools.gyp:agc_test_utils', ], 'sources': [ + 'audio_coding/codecs/audio_encoder_unittest.cc', 'audio_coding/codecs/cng/audio_encoder_cng_unittest.cc', 'audio_coding/acm2/acm_receiver_unittest_oldapi.cc', 'audio_coding/acm2/audio_coding_module_unittest_oldapi.cc',