iSAC encoder: Make it possible to change target bitrate at any time

Not just at construction time.

Bug: webrtc:11704
Change-Id: I952c7dbe20774cc976065c7d2f992a80074ebf63
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177663
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31550}
This commit is contained in:
Karl Wiberg
2020-06-22 15:06:25 +02:00
committed by Commit Bot
parent 09867d37ed
commit 30a3e78794
5 changed files with 130 additions and 4 deletions

View File

@ -386,6 +386,8 @@ rtc_source_set("isac_common") {
"../../api/units:time_delta", "../../api/units:time_delta",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_approved",
"../../rtc_base:safe_minmax",
"../../system_wrappers:field_trial",
] ]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
} }

View File

@ -19,6 +19,7 @@
#include "api/scoped_refptr.h" #include "api/scoped_refptr.h"
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "rtc_base/constructor_magic.h" #include "rtc_base/constructor_magic.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc { namespace webrtc {
@ -48,6 +49,13 @@ class AudioEncoderIsacT final : public AudioEncoder {
size_t Num10MsFramesInNextPacket() const override; size_t Num10MsFramesInNextPacket() const override;
size_t Max10MsFramesInAPacket() const override; size_t Max10MsFramesInAPacket() const override;
int GetTargetBitrate() const override; int GetTargetBitrate() const override;
void SetTargetBitrate(int target_bps) override;
void OnReceivedTargetAudioBitrate(int target_bps) override;
void OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
absl::optional<int64_t> bwe_period_ms) override;
void OnReceivedUplinkAllocation(BitrateAllocationUpdate update) override;
void OnReceivedOverhead(size_t overhead_bytes_per_packet) override;
EncodedInfo EncodeImpl(uint32_t rtp_timestamp, EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> audio, rtc::ArrayView<const int16_t> audio,
rtc::Buffer* encoded) override; rtc::Buffer* encoded) override;
@ -60,7 +68,13 @@ class AudioEncoderIsacT final : public AudioEncoder {
// STREAM_MAXW16_60MS for iSAC fix (60 ms). // STREAM_MAXW16_60MS for iSAC fix (60 ms).
static const size_t kSufficientEncodeBufferSizeBytes = 400; static const size_t kSufficientEncodeBufferSizeBytes = 400;
static const int kDefaultBitRate = 32000; static constexpr int kDefaultBitRate = 32000;
static constexpr int kMinBitrateBps = 10000;
static constexpr int MaxBitrateBps(int sample_rate_hz) {
return sample_rate_hz == 32000 ? 56000 : 32000;
}
void SetTargetBitrate(int target_bps, bool subtract_per_packet_overhead);
// Recreate the iSAC encoder instance with the given settings, and save them. // Recreate the iSAC encoder instance with the given settings, and save them.
void RecreateEncoderInstance(const Config& config); void RecreateEncoderInstance(const Config& config);
@ -77,6 +91,15 @@ class AudioEncoderIsacT final : public AudioEncoder {
// Timestamp of the previously encoded packet. // Timestamp of the previously encoded packet.
uint32_t last_encoded_timestamp_; uint32_t last_encoded_timestamp_;
// Cache the value of the "WebRTC-SendSideBwe-WithOverhead" field trial.
const bool send_side_bwe_with_overhead_ =
field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead");
// When we send a packet, expect this many bytes of headers to be added to it.
// Start out with a reasonable default that we can use until we receive a real
// value.
DataSize overhead_per_packet_ = DataSize::Bytes(28);
RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT); RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
}; };

View File

@ -12,6 +12,7 @@
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"
namespace webrtc { namespace webrtc {
@ -80,6 +81,51 @@ int AudioEncoderIsacT<T>::GetTargetBitrate() const {
return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate; return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
} }
template <typename T>
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps) {
// Set target bitrate directly without subtracting per-packet overhead,
// because that's what AudioEncoderOpus does.
SetTargetBitrate(target_bps,
/*subtract_per_packet_overhead=*/false);
}
template <typename T>
void AudioEncoderIsacT<T>::OnReceivedTargetAudioBitrate(int target_bps) {
// Set target bitrate directly without subtracting per-packet overhead,
// because that's what AudioEncoderOpus does.
SetTargetBitrate(target_bps,
/*subtract_per_packet_overhead=*/false);
}
template <typename T>
void AudioEncoderIsacT<T>::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
absl::optional<int64_t> /*bwe_period_ms*/) {
// Set target bitrate, subtracting the per-packet overhead if
// WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
// AudioEncoderOpus does.
SetTargetBitrate(
target_audio_bitrate_bps,
/*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
}
template <typename T>
void AudioEncoderIsacT<T>::OnReceivedUplinkAllocation(
BitrateAllocationUpdate update) {
// Set target bitrate, subtracting the per-packet overhead if
// WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
// AudioEncoderOpus does.
SetTargetBitrate(
update.target_bitrate.bps<int>(),
/*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
}
template <typename T>
void AudioEncoderIsacT<T>::OnReceivedOverhead(
size_t overhead_bytes_per_packet) {
overhead_per_packet_ = DataSize::Bytes(overhead_bytes_per_packet);
}
template <typename T> template <typename T>
AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeImpl( AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeImpl(
uint32_t rtp_timestamp, uint32_t rtp_timestamp,
@ -126,6 +172,21 @@ AudioEncoderIsacT<T>::GetFrameLengthRange() const {
TimeDelta::Millis(config_.frame_size_ms)}}; TimeDelta::Millis(config_.frame_size_ms)}};
} }
template <typename T>
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps,
bool subtract_per_packet_overhead) {
if (subtract_per_packet_overhead) {
const DataRate overhead_rate =
overhead_per_packet_ / TimeDelta::Millis(config_.frame_size_ms);
target_bps -= overhead_rate.bps();
}
target_bps = rtc::SafeClamp(target_bps, kMinBitrateBps,
MaxBitrateBps(config_.sample_rate_hz));
int result = T::Control(isac_state_, target_bps, config_.frame_size_ms);
RTC_DCHECK_EQ(result, 0);
config_.bit_rate = target_bps;
}
template <typename T> template <typename T>
void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) { void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
RTC_CHECK(config.IsOk()); RTC_CHECK(config.IsOk());

View File

@ -9,6 +9,7 @@
*/ */
#include <array> #include <array>
#include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -159,6 +160,33 @@ TEST_P(EncoderTest, TestDifferentBitrates) {
EXPECT_LT(num_bytes_low, num_bytes_high); EXPECT_LT(num_bytes_low, num_bytes_high);
} }
// Encodes an input audio sequence first with a low, then with a high target
// bitrate *using the same encoder* and checks that the number of emitted bytes
// in the first case is less than in the second case.
TEST_P(EncoderTest, TestDynamicBitrateChange) {
constexpr int kLowBps = 20000;
constexpr int kHighBps = 25000;
constexpr int kStartBps = 30000;
auto encoder = CreateEncoder(GetIsacImpl(), GetSampleRateHz(),
GetFrameSizeMs(), kStartBps);
std::map<int, int> num_bytes;
constexpr int kNumFrames = 200; // 2 seconds.
for (int bitrate_bps : {kLowBps, kHighBps}) {
auto pcm_file = GetPcmTestFileReader(GetSampleRateHz());
encoder->OnReceivedTargetAudioBitrate(bitrate_bps);
for (int i = 0; i < kNumFrames; ++i) {
AudioFrame in;
pcm_file->Read10MsData(in);
rtc::Buffer buf;
encoder->Encode(/*rtp_timestamp=*/0, AudioFrameToView(in), &buf);
num_bytes[bitrate_bps] += buf.size();
}
}
// kHighBps / kLowBps == 1.25, so require the high-bitrate run to produce at
// least 1.2 times the number of bytes.
EXPECT_LT(1.2 * num_bytes[kLowBps], num_bytes[kHighBps]);
}
// Checks that, given a target bitrate, the encoder does not overshoot too much. // Checks that, given a target bitrate, the encoder does not overshoot too much.
TEST_P(EncoderTest, DoNotOvershootTargetBitrate) { TEST_P(EncoderTest, DoNotOvershootTargetBitrate) {
for (int bitrate_bps : {10000, 15000, 20000, 26000, 32000}) { for (int bitrate_bps : {10000, 15000, 20000, 26000, 32000}) {

View File

@ -536,7 +536,11 @@ TEST_F(AudioDecoderIsacFloatTest, EncodeDecode) {
} }
TEST_F(AudioDecoderIsacFloatTest, SetTargetBitrate) { TEST_F(AudioDecoderIsacFloatTest, SetTargetBitrate) {
TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 9999));
EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 10000));
EXPECT_EQ(23456, SetAndGetTargetBitrate(audio_encoder_.get(), 23456));
EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder_.get(), 32000));
EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder_.get(), 32001));
} }
TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) { TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) {
@ -549,7 +553,11 @@ TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) {
} }
TEST_F(AudioDecoderIsacSwbTest, SetTargetBitrate) { TEST_F(AudioDecoderIsacSwbTest, SetTargetBitrate) {
TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 9999));
EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 10000));
EXPECT_EQ(23456, SetAndGetTargetBitrate(audio_encoder_.get(), 23456));
EXPECT_EQ(56000, SetAndGetTargetBitrate(audio_encoder_.get(), 56000));
EXPECT_EQ(56000, SetAndGetTargetBitrate(audio_encoder_.get(), 56001));
} }
TEST_F(AudioDecoderIsacFixTest, EncodeDecode) { TEST_F(AudioDecoderIsacFixTest, EncodeDecode) {
@ -569,7 +577,11 @@ TEST_F(AudioDecoderIsacFixTest, EncodeDecode) {
} }
TEST_F(AudioDecoderIsacFixTest, SetTargetBitrate) { TEST_F(AudioDecoderIsacFixTest, SetTargetBitrate) {
TestSetAndGetTargetBitratesWithFixedCodec(audio_encoder_.get(), 32000); EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 9999));
EXPECT_EQ(10000, SetAndGetTargetBitrate(audio_encoder_.get(), 10000));
EXPECT_EQ(23456, SetAndGetTargetBitrate(audio_encoder_.get(), 23456));
EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder_.get(), 32000));
EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder_.get(), 32001));
} }
TEST_F(AudioDecoderG722Test, EncodeDecode) { TEST_F(AudioDecoderG722Test, EncodeDecode) {