Add field trials for configuring Opus encoder packet loss rate.
Add options to: 1. Bypass optimization (use reported packet loss). 2. Set a maximum value. 3. Set a coefficient. Bug: webrtc:9866 Change-Id: I3fef43e5186a4f0f50fda3506e445860518cfbd7 Reviewed-on: https://webrtc-review.googlesource.com/c/105304 Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25161}
This commit is contained in:

committed by
Commit Bot

parent
fcebe0e1ca
commit
83bd37cda4
@ -214,6 +214,14 @@ int GetBitrateBps(const AudioEncoderOpusConfig& config) {
|
|||||||
return *config.bitrate_bps;
|
return *config.bitrate_bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValidPacketLossRate(int value) {
|
||||||
|
return value >= 0 && value <= 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ToFraction(int percent) {
|
||||||
|
return static_cast<float>(percent) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
float GetMinPacketLossRate() {
|
float GetMinPacketLossRate() {
|
||||||
constexpr char kPacketLossFieldTrial[] = "WebRTC-Audio-OpusMinPacketLossRate";
|
constexpr char kPacketLossFieldTrial[] = "WebRTC-Audio-OpusMinPacketLossRate";
|
||||||
const bool use_opus_min_packet_loss_rate =
|
const bool use_opus_min_packet_loss_rate =
|
||||||
@ -224,19 +232,62 @@ float GetMinPacketLossRate() {
|
|||||||
constexpr int kDefaultMinPacketLossRate = 1;
|
constexpr int kDefaultMinPacketLossRate = 1;
|
||||||
int value = kDefaultMinPacketLossRate;
|
int value = kDefaultMinPacketLossRate;
|
||||||
if (sscanf(field_trial_string.c_str(), "Enabled-%d", &value) == 1 &&
|
if (sscanf(field_trial_string.c_str(), "Enabled-%d", &value) == 1 &&
|
||||||
(value < 0 || value > 100)) {
|
!IsValidPacketLossRate(value)) {
|
||||||
RTC_LOG(LS_WARNING) << "Invalid parameter for " << kPacketLossFieldTrial
|
RTC_LOG(LS_WARNING) << "Invalid parameter for " << kPacketLossFieldTrial
|
||||||
<< ", using default value: "
|
<< ", using default value: "
|
||||||
<< kDefaultMinPacketLossRate;
|
<< kDefaultMinPacketLossRate;
|
||||||
value = kDefaultMinPacketLossRate;
|
value = kDefaultMinPacketLossRate;
|
||||||
}
|
}
|
||||||
return static_cast<float>(value) / 100;
|
return ToFraction(value);
|
||||||
}
|
}
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AudioEncoderOpusImpl::NewPacketLossRateOptimizer>
|
||||||
|
GetNewPacketLossRateOptimizer() {
|
||||||
|
constexpr char kPacketLossOptimizationName[] =
|
||||||
|
"WebRTC-Audio-NewOpusPacketLossRateOptimization";
|
||||||
|
const bool use_new_packet_loss_optimization =
|
||||||
|
webrtc::field_trial::IsEnabled(kPacketLossOptimizationName);
|
||||||
|
if (use_new_packet_loss_optimization) {
|
||||||
|
const std::string field_trial_string =
|
||||||
|
webrtc::field_trial::FindFullName(kPacketLossOptimizationName);
|
||||||
|
int min_rate;
|
||||||
|
int max_rate;
|
||||||
|
float slope;
|
||||||
|
if (sscanf(field_trial_string.c_str(), "Enabled-%d-%d-%f", &min_rate,
|
||||||
|
&max_rate, &slope) == 3 &&
|
||||||
|
IsValidPacketLossRate(min_rate) && IsValidPacketLossRate(max_rate)) {
|
||||||
|
return absl::make_unique<
|
||||||
|
AudioEncoderOpusImpl::NewPacketLossRateOptimizer>(
|
||||||
|
ToFraction(min_rate), ToFraction(max_rate), slope);
|
||||||
|
}
|
||||||
|
RTC_LOG(LS_WARNING) << "Invalid parameters for "
|
||||||
|
<< kPacketLossOptimizationName
|
||||||
|
<< ", using default values.";
|
||||||
|
return absl::make_unique<
|
||||||
|
AudioEncoderOpusImpl::NewPacketLossRateOptimizer>();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
AudioEncoderOpusImpl::NewPacketLossRateOptimizer::NewPacketLossRateOptimizer(
|
||||||
|
float min_packet_loss_rate,
|
||||||
|
float max_packet_loss_rate,
|
||||||
|
float slope)
|
||||||
|
: min_packet_loss_rate_(min_packet_loss_rate),
|
||||||
|
max_packet_loss_rate_(max_packet_loss_rate),
|
||||||
|
slope_(slope) {}
|
||||||
|
|
||||||
|
float AudioEncoderOpusImpl::NewPacketLossRateOptimizer::OptimizePacketLossRate(
|
||||||
|
float packet_loss_rate) const {
|
||||||
|
packet_loss_rate = slope_ * packet_loss_rate;
|
||||||
|
return std::min(std::max(packet_loss_rate, min_packet_loss_rate_),
|
||||||
|
max_packet_loss_rate_);
|
||||||
|
}
|
||||||
|
|
||||||
void AudioEncoderOpusImpl::AppendSupportedEncoders(
|
void AudioEncoderOpusImpl::AppendSupportedEncoders(
|
||||||
std::vector<AudioCodecSpec>* specs) {
|
std::vector<AudioCodecSpec>* specs) {
|
||||||
const SdpAudioFormat fmt = {
|
const SdpAudioFormat fmt = {
|
||||||
@ -424,6 +475,7 @@ AudioEncoderOpusImpl::AudioEncoderOpusImpl(
|
|||||||
bitrate_changed_(true),
|
bitrate_changed_(true),
|
||||||
packet_loss_rate_(0.0),
|
packet_loss_rate_(0.0),
|
||||||
min_packet_loss_rate_(GetMinPacketLossRate()),
|
min_packet_loss_rate_(GetMinPacketLossRate()),
|
||||||
|
new_packet_loss_optimizer_(GetNewPacketLossRateOptimizer()),
|
||||||
inst_(nullptr),
|
inst_(nullptr),
|
||||||
packet_loss_fraction_smoother_(new PacketLossFractionSmoother()),
|
packet_loss_fraction_smoother_(new PacketLossFractionSmoother()),
|
||||||
audio_network_adaptor_creator_(audio_network_adaptor_creator),
|
audio_network_adaptor_creator_(audio_network_adaptor_creator),
|
||||||
@ -761,10 +813,14 @@ void AudioEncoderOpusImpl::SetNumChannelsToEncode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioEncoderOpusImpl::SetProjectedPacketLossRate(float fraction) {
|
void AudioEncoderOpusImpl::SetProjectedPacketLossRate(float fraction) {
|
||||||
float opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_);
|
if (new_packet_loss_optimizer_) {
|
||||||
opt_loss_rate = std::max(opt_loss_rate, min_packet_loss_rate_);
|
fraction = new_packet_loss_optimizer_->OptimizePacketLossRate(fraction);
|
||||||
if (packet_loss_rate_ != opt_loss_rate) {
|
} else {
|
||||||
packet_loss_rate_ = opt_loss_rate;
|
fraction = OptimizePacketLossRate(fraction, packet_loss_rate_);
|
||||||
|
fraction = std::max(fraction, min_packet_loss_rate_);
|
||||||
|
}
|
||||||
|
if (packet_loss_rate_ != fraction) {
|
||||||
|
packet_loss_rate_ = fraction;
|
||||||
RTC_CHECK_EQ(
|
RTC_CHECK_EQ(
|
||||||
0, WebRtcOpus_SetPacketLossRate(
|
0, WebRtcOpus_SetPacketLossRate(
|
||||||
inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5)));
|
inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5)));
|
||||||
|
@ -34,6 +34,26 @@ struct CodecInst;
|
|||||||
|
|
||||||
class AudioEncoderOpusImpl final : public AudioEncoder {
|
class AudioEncoderOpusImpl final : public AudioEncoder {
|
||||||
public:
|
public:
|
||||||
|
class NewPacketLossRateOptimizer {
|
||||||
|
public:
|
||||||
|
NewPacketLossRateOptimizer(float min_packet_loss_rate = 0.01,
|
||||||
|
float max_packet_loss_rate = 0.2,
|
||||||
|
float slope = 1.0);
|
||||||
|
|
||||||
|
float OptimizePacketLossRate(float packet_loss_rate) const;
|
||||||
|
|
||||||
|
// Getters for testing.
|
||||||
|
float min_packet_loss_rate() const { return min_packet_loss_rate_; };
|
||||||
|
float max_packet_loss_rate() const { return max_packet_loss_rate_; };
|
||||||
|
float slope() const { return slope_; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
const float min_packet_loss_rate_;
|
||||||
|
const float max_packet_loss_rate_;
|
||||||
|
const float slope_;
|
||||||
|
RTC_DISALLOW_COPY_AND_ASSIGN(NewPacketLossRateOptimizer);
|
||||||
|
};
|
||||||
|
|
||||||
static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst);
|
static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst);
|
||||||
|
|
||||||
// Returns empty if the current bitrate falls within the hysteresis window,
|
// Returns empty if the current bitrate falls within the hysteresis window,
|
||||||
@ -110,6 +130,9 @@ class AudioEncoderOpusImpl final : public AudioEncoder {
|
|||||||
|
|
||||||
// Getters for testing.
|
// Getters for testing.
|
||||||
float packet_loss_rate() const { return packet_loss_rate_; }
|
float packet_loss_rate() const { return packet_loss_rate_; }
|
||||||
|
NewPacketLossRateOptimizer* new_packet_loss_optimizer() const {
|
||||||
|
return new_packet_loss_optimizer_.get();
|
||||||
|
}
|
||||||
AudioEncoderOpusConfig::ApplicationMode application() const {
|
AudioEncoderOpusConfig::ApplicationMode application() const {
|
||||||
return config_.application;
|
return config_.application;
|
||||||
}
|
}
|
||||||
@ -159,6 +182,7 @@ class AudioEncoderOpusImpl final : public AudioEncoder {
|
|||||||
bool bitrate_changed_;
|
bool bitrate_changed_;
|
||||||
float packet_loss_rate_;
|
float packet_loss_rate_;
|
||||||
const float min_packet_loss_rate_;
|
const float min_packet_loss_rate_;
|
||||||
|
const std::unique_ptr<NewPacketLossRateOptimizer> new_packet_loss_optimizer_;
|
||||||
std::vector<int16_t> input_buffer_;
|
std::vector<int16_t> input_buffer_;
|
||||||
OpusEncInst* inst_;
|
OpusEncInst* inst_;
|
||||||
uint32_t first_timestamp_in_buffer_;
|
uint32_t first_timestamp_in_buffer_;
|
||||||
|
@ -273,7 +273,7 @@ TEST(AudioEncoderOpusTest, PacketLossRateOptimized) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(AudioEncoderOpusTest, PacketLossRateLowerBounded) {
|
TEST(AudioEncoderOpusTest, PacketLossRateLowerBounded) {
|
||||||
test::ScopedFieldTrials override_field_trails(
|
test::ScopedFieldTrials override_field_trials(
|
||||||
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-5/");
|
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-5/");
|
||||||
auto states = CreateCodec(1);
|
auto states = CreateCodec(1);
|
||||||
auto I = [](float a, float b) { return IntervalSteps(a, b, 10); };
|
auto I = [](float a, float b) { return IntervalSteps(a, b, 10); };
|
||||||
@ -294,6 +294,29 @@ TEST(AudioEncoderOpusTest, PacketLossRateLowerBounded) {
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AudioEncoderOpusTest, NewPacketLossRateOptimization) {
|
||||||
|
{
|
||||||
|
test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-5-15-0.5/");
|
||||||
|
auto states = CreateCodec(1);
|
||||||
|
|
||||||
|
TestSetPacketLossRate(states.get(), {0.00f}, 0.05f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.12f}, 0.06f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.22f}, 0.11f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.50f}, 0.15f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/");
|
||||||
|
auto states = CreateCodec(1);
|
||||||
|
|
||||||
|
TestSetPacketLossRate(states.get(), {0.00f}, 0.01f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.12f}, 0.12f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.22f}, 0.20f);
|
||||||
|
TestSetPacketLossRate(states.get(), {0.50f}, 0.20f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) {
|
TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) {
|
||||||
auto states = CreateCodec(2);
|
auto states = CreateCodec(2);
|
||||||
// Before calling to |SetReceiverFrameLengthRange|,
|
// Before calling to |SetReceiverFrameLengthRange|,
|
||||||
@ -471,19 +494,19 @@ TEST(AudioEncoderOpusTest, BitrateBounded) {
|
|||||||
TEST(AudioEncoderOpusTest, MinPacketLossRate) {
|
TEST(AudioEncoderOpusTest, MinPacketLossRate) {
|
||||||
constexpr float kDefaultMinPacketLossRate = 0.01;
|
constexpr float kDefaultMinPacketLossRate = 0.01;
|
||||||
{
|
{
|
||||||
test::ScopedFieldTrials override_field_trails(
|
test::ScopedFieldTrials override_field_trials(
|
||||||
"WebRTC-Audio-OpusMinPacketLossRate/Enabled/");
|
"WebRTC-Audio-OpusMinPacketLossRate/Enabled/");
|
||||||
auto states = CreateCodec(1);
|
auto states = CreateCodec(1);
|
||||||
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
|
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
test::ScopedFieldTrials override_field_trails(
|
test::ScopedFieldTrials override_field_trials(
|
||||||
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-200/");
|
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-200/");
|
||||||
auto states = CreateCodec(1);
|
auto states = CreateCodec(1);
|
||||||
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
|
EXPECT_EQ(kDefaultMinPacketLossRate, states->encoder->packet_loss_rate());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
test::ScopedFieldTrials override_field_trails(
|
test::ScopedFieldTrials override_field_trials(
|
||||||
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-50/");
|
"WebRTC-Audio-OpusMinPacketLossRate/Enabled-50/");
|
||||||
constexpr float kMinPacketLossRate = 0.5;
|
constexpr float kMinPacketLossRate = 0.5;
|
||||||
auto states = CreateCodec(1);
|
auto states = CreateCodec(1);
|
||||||
@ -491,6 +514,34 @@ TEST(AudioEncoderOpusTest, MinPacketLossRate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AudioEncoderOpusTest, NewPacketLossRateOptimizer) {
|
||||||
|
{
|
||||||
|
auto states = CreateCodec(1);
|
||||||
|
auto optimizer = states->encoder->new_packet_loss_optimizer();
|
||||||
|
EXPECT_EQ(nullptr, optimizer);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled/");
|
||||||
|
auto states = CreateCodec(1);
|
||||||
|
auto optimizer = states->encoder->new_packet_loss_optimizer();
|
||||||
|
ASSERT_NE(nullptr, optimizer);
|
||||||
|
EXPECT_FLOAT_EQ(0.01, optimizer->min_packet_loss_rate());
|
||||||
|
EXPECT_FLOAT_EQ(0.20, optimizer->max_packet_loss_rate());
|
||||||
|
EXPECT_FLOAT_EQ(1.00, optimizer->slope());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
test::ScopedFieldTrials override_field_trials(
|
||||||
|
"WebRTC-Audio-NewOpusPacketLossRateOptimization/Enabled-2-50-0.7/");
|
||||||
|
auto states = CreateCodec(1);
|
||||||
|
auto optimizer = states->encoder->new_packet_loss_optimizer();
|
||||||
|
ASSERT_NE(nullptr, optimizer);
|
||||||
|
EXPECT_FLOAT_EQ(0.02, optimizer->min_packet_loss_rate());
|
||||||
|
EXPECT_FLOAT_EQ(0.50, optimizer->max_packet_loss_rate());
|
||||||
|
EXPECT_FLOAT_EQ(0.70, optimizer->slope());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verifies that the complexity adaptation in the config works as intended.
|
// Verifies that the complexity adaptation in the config works as intended.
|
||||||
TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) {
|
TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) {
|
||||||
AudioEncoderOpusConfig config;
|
AudioEncoderOpusConfig config;
|
||||||
|
Reference in New Issue
Block a user