InputVolumeController: Remove two unit test helper functions

Remove deprecated unit test helper functions CallPreProcessAudioBuffer()
and CallPreProcForChangingAudio(). Replace the use of these functions
with CallAgcSequence(). Remove a duplicate unit test using one of these
functions. The new calls follow the API contract.

Bug: webrtc:7494
Change-Id: Idc033cb48f4fab1814c4c6e0f23edc4a6a9faa64
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/285960
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Commit-Queue: Hanna Silen <silen@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38826}
This commit is contained in:
Hanna Silen 2022-12-06 13:08:33 +01:00 committed by WebRTC LUCI CQ
parent 38a6002548
commit fcbf3724eb

View File

@ -81,45 +81,6 @@ std::unique_ptr<InputVolumeController> CreateInputVolumeController(
config); config);
} }
// Deprecated.
// TODO(bugs.webrtc.org/7494): Delete this helper, use
// `InputVolumeControllerTestHelper::CallAgcSequence()` instead.
// Calls `AnalyzePreProcess()` on `controller` `num_calls` times. `peak_ratio`
// is a value in [0, 1] which determines the amplitude of the samples (1 maps to
// full scale). The first half of the calls is made on frames which are half
// filled with zeros in order to simulate a signal with different crest factors.
void CallPreProcessAudioBuffer(int num_calls,
float peak_ratio,
InputVolumeController& controller) {
RTC_DCHECK_LE(peak_ratio, 1.0f);
AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
kNumChannels, kSampleRateHz, kNumChannels);
const int num_channels = audio_buffer.num_channels();
const int num_frames = audio_buffer.num_frames();
// Make half of the calls with half zeroed frames.
for (int ch = 0; ch < num_channels; ++ch) {
// 50% of the samples in one frame are zero.
for (int i = 0; i < num_frames; i += 2) {
audio_buffer.channels()[ch][i] = peak_ratio * 32767.0f;
audio_buffer.channels()[ch][i + 1] = 0.0f;
}
}
for (int n = 0; n < num_calls / 2; ++n) {
controller.AnalyzePreProcess(audio_buffer);
}
// Make the remaining half of the calls with frames whose samples are all set.
for (int ch = 0; ch < num_channels; ++ch) {
for (int i = 0; i < num_frames; ++i) {
audio_buffer.channels()[ch][i] = peak_ratio * 32767.0f;
}
}
for (int n = 0; n < num_calls - num_calls / 2; ++n) {
controller.AnalyzePreProcess(audio_buffer);
}
}
constexpr char kMinInputVolumeFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume"; constexpr char kMinInputVolumeFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume";
std::string GetAgcMinInputVolumeFieldTrial(const std::string& value) { std::string GetAgcMinInputVolumeFieldTrial(const std::string& value) {
@ -172,17 +133,33 @@ void WriteAudioBufferSamples(float samples_value,
} }
} }
// (Over)writes samples in `audio_buffer`. Alternates samples `samples_value`
// and zero.
void WriteAlternatingAudioBufferSamples(float samples_value,
AudioBuffer& audio_buffer) {
RTC_DCHECK_GE(samples_value, kMinSample);
RTC_DCHECK_LE(samples_value, kMaxSample);
const int num_channels = audio_buffer.num_channels();
const int num_frames = audio_buffer.num_frames();
for (int ch = 0; ch < num_channels; ++ch) {
for (int i = 0; i < num_frames; i += 2) {
audio_buffer.channels()[ch][i] = samples_value;
audio_buffer.channels()[ch][i + 1] = 0.0f;
}
}
}
// Deprecated. // Deprecated.
// TODO(bugs.webrtc.org/7494): Delete this helper, use // TODO(bugs.webrtc.org/7494): Delete this helper, use
// `InputVolumeControllerTestHelper::CallAgcSequence()` instead. // `InputVolumeControllerTestHelper::CallAgcSequence()` instead.
void CallPreProcessAndProcess(int num_calls, void CallPreProcessAndProcess(int num_calls,
const AudioBuffer& audio_buffer, const AudioBuffer& audio_buffer,
float speech_probability, float speech_probability,
absl::optional<float> speech_level, absl::optional<float> speech_level_dbfs,
InputVolumeController& controller) { InputVolumeController& controller) {
for (int n = 0; n < num_calls; ++n) { for (int n = 0; n < num_calls; ++n) {
controller.AnalyzePreProcess(audio_buffer); controller.AnalyzePreProcess(audio_buffer);
controller.Process(speech_probability, speech_level); controller.Process(speech_probability, speech_level_dbfs);
} }
} }
@ -214,12 +191,12 @@ class SpeechSamplesReader {
// `gain_db` and feeds the frames into `controller` by calling // `gain_db` and feeds the frames into `controller` by calling
// `AnalyzePreProcess()` and `Process()` for each frame. Reads the number of // `AnalyzePreProcess()` and `Process()` for each frame. Reads the number of
// 10 ms frames available in the PCM file if `num_frames` is too large - i.e., // 10 ms frames available in the PCM file if `num_frames` is too large - i.e.,
// does not loop. `speech_probability` and `speech_level` are passed to // does not loop. `speech_probability` and `speech_level_dbfs` are passed to
// `Process()`. // `Process()`.
void Feed(int num_frames, void Feed(int num_frames,
int gain_db, int gain_db,
float speech_probability, float speech_probability,
absl::optional<float> speech_level, absl::optional<float> speech_level_dbfs,
InputVolumeController& controller) { InputVolumeController& controller) {
float gain = std::pow(10.0f, gain_db / 20.0f); // From dB to linear gain. float gain = std::pow(10.0f, gain_db / 20.0f); // From dB to linear gain.
is_.seekg(0, is_.beg); // Start from the beginning of the PCM file. is_.seekg(0, is_.beg); // Start from the beginning of the PCM file.
@ -239,7 +216,7 @@ class SpeechSamplesReader {
}); });
controller.AnalyzePreProcess(audio_buffer_); controller.AnalyzePreProcess(audio_buffer_);
controller.Process(speech_probability, speech_level); controller.Process(speech_probability, speech_level_dbfs);
} }
} }
@ -289,15 +266,16 @@ constexpr InputVolumeControllerConfig GetInputVolumeControllerTestConfig() {
class InputVolumeControllerTestHelper { class InputVolumeControllerTestHelper {
public: public:
// Ctor. Initializes `audio_buffer` with zeros. // Ctor. Initializes `audio_buffer` with zeros.
InputVolumeControllerTestHelper() // TODO(bugs.webrtc.org/7494): Remove the default argument.
InputVolumeControllerTestHelper(const InputVolumeController::Config& config =
GetInputVolumeControllerTestConfig())
: audio_buffer(kSampleRateHz, : audio_buffer(kSampleRateHz,
kNumChannels, kNumChannels,
kSampleRateHz, kSampleRateHz,
kNumChannels, kNumChannels,
kSampleRateHz, kSampleRateHz,
kNumChannels), kNumChannels),
controller(/*num_capture_channels=*/1, controller(/*num_capture_channels=*/1, config) {
GetInputVolumeControllerTestConfig()) {
controller.Initialize(); controller.Initialize();
WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.0f, WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.0f,
audio_buffer); audio_buffer);
@ -310,12 +288,18 @@ class InputVolumeControllerTestHelper {
// Returns the recommended input volume. // Returns the recommended input volume.
int CallAgcSequence(int applied_input_volume, int CallAgcSequence(int applied_input_volume,
float speech_probability, float speech_probability,
absl::optional<float> speech_level) { absl::optional<float> speech_level_dbfs,
controller.set_stream_analog_level(applied_input_volume); int num_calls = 1) {
controller.AnalyzePreProcess(audio_buffer); RTC_DCHECK_GE(num_calls, 1);
controller.Process(speech_probability, speech_level); int volume = applied_input_volume;
return controller.recommended_analog_level(); for (int i = 0; i < num_calls; ++i) {
controller.set_stream_analog_level(volume);
controller.AnalyzePreProcess(audio_buffer);
controller.Process(speech_probability, speech_level_dbfs);
volume = controller.recommended_analog_level();
}
return volume;
} }
// Deprecated. // Deprecated.
@ -323,9 +307,9 @@ class InputVolumeControllerTestHelper {
// `CallAgcSequence()`. // `CallAgcSequence()`.
void CallProcess(int num_calls, void CallProcess(int num_calls,
float speech_probability, float speech_probability,
absl::optional<float> speech_level) { absl::optional<float> speech_level_dbfs) {
for (int i = 0; i < num_calls; ++i) { for (int i = 0; i < num_calls; ++i) {
controller.Process(speech_probability, speech_level); controller.Process(speech_probability, speech_level_dbfs);
} }
} }
@ -342,36 +326,6 @@ class InputVolumeControllerTestHelper {
} }
} }
// Deprecated.
// TODO(bugs.webrtc.org/7494): Let the caller write `audio_buffer` and use
// `CallAgcSequence()`.
void CallPreProcForChangingAudio(int num_calls, float peak_ratio) {
RTC_DCHECK_GE(peak_ratio, 0.0f);
RTC_DCHECK_LE(peak_ratio, 1.0f);
const float samples_value = peak_ratio * 32767.0f;
// Make half of the calls on a frame where the samples alternate
// `sample_values` and zeros.
WriteAudioBufferSamples(samples_value, /*clipped_ratio=*/0.0f,
audio_buffer);
for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
for (size_t k = 1; k < audio_buffer.num_frames(); k += 2) {
audio_buffer.channels()[ch][k] = 0.0f;
}
}
for (int i = 0; i < num_calls / 2; ++i) {
controller.AnalyzePreProcess(audio_buffer);
}
// Make half of thecalls on a frame where all the samples equal
// `sample_values`.
WriteAudioBufferSamples(samples_value, /*clipped_ratio=*/0.0f,
audio_buffer);
for (int i = 0; i < num_calls - num_calls / 2; ++i) {
controller.AnalyzePreProcess(audio_buffer);
}
}
AudioBuffer audio_buffer; AudioBuffer audio_buffer;
InputVolumeController controller; InputVolumeController controller;
}; };
@ -745,28 +699,23 @@ TEST_P(InputVolumeControllerParametrizedTest, TakesNoActionOnZeroMicVolume) {
TEST_P(InputVolumeControllerParametrizedTest, ClippingDetectionLowersVolume) { TEST_P(InputVolumeControllerParametrizedTest, ClippingDetectionLowersVolume) {
InputVolumeControllerTestHelper helper; InputVolumeControllerTestHelper helper;
helper.CallAgcSequence(/*applied_input_volume=*/255, kHighSpeechProbability, int volume = helper.CallAgcSequence(/*applied_input_volume=*/255,
kSpeechLevel); kHighSpeechProbability, kSpeechLevel,
/*num_calls=*/1);
EXPECT_EQ(helper.controller.recommended_analog_level(), 255); EXPECT_EQ(volume, 255);
helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f);
EXPECT_EQ(helper.controller.recommended_analog_level(), 255);
helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/1.0f);
EXPECT_EQ(helper.controller.recommended_analog_level(), 240);
}
TEST_P(InputVolumeControllerParametrizedTest, WriteAlternatingAudioBufferSamples(0.99f * kMaxSample, helper.audio_buffer);
DisabledClippingPredictorDoesNotLowerVolume) { volume = helper.CallAgcSequence(volume, kHighSpeechProbability, kSpeechLevel,
InputVolumeControllerTestHelper helper; /*num_calls=*/100);
helper.CallAgcSequence(/*applied_input_volume=*/255, kHighSpeechProbability,
kSpeechLevel);
EXPECT_FALSE(helper.controller.clipping_predictor_enabled()); EXPECT_EQ(volume, 255);
EXPECT_EQ(helper.controller.recommended_analog_level(), 255);
helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f); WriteAlternatingAudioBufferSamples(kMaxSample, helper.audio_buffer);
EXPECT_EQ(helper.controller.recommended_analog_level(), 255); volume = helper.CallAgcSequence(volume, kHighSpeechProbability, kSpeechLevel,
helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f); /*num_calls=*/100);
EXPECT_EQ(helper.controller.recommended_analog_level(), 255);
EXPECT_EQ(volume, 240);
} }
TEST(InputVolumeControllerTest, MinInputVolumeDefault) { TEST(InputVolumeControllerTest, MinInputVolumeDefault) {
@ -866,10 +815,10 @@ TEST(InputVolumeControllerTest, MinInputVolumeCheckMinLevelWithClipping) {
// adjustment of the analog gain. Use low speech probability to limit the // adjustment of the analog gain. Use low speech probability to limit the
// volume changes to clipping handling. // volume changes to clipping handling.
CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer, CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
kLowSpeechProbability, /*speech_level=*/-42.0f, kLowSpeechProbability, /*speech_level_dbfs=*/-42.0f,
*controller); *controller);
CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer, CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
kLowSpeechProbability, /*speech_level=*/-42.0f, kLowSpeechProbability, /*speech_level_dbfs=*/-42.0f,
*manager_with_override); *manager_with_override);
// Make sure that an adaptation occurred. // Make sure that an adaptation occurred.
@ -922,10 +871,10 @@ TEST(InputVolumeControllerTest,
// adjustment of the analog gain. // adjustment of the analog gain.
CallPreProcessAndProcess( CallPreProcessAndProcess(
/*num_calls=*/400, audio_buffer, kHighSpeechProbability, /*num_calls=*/400, audio_buffer, kHighSpeechProbability,
/*speech_level=*/-18.0f, *controller); /*speech_level_dbfs=*/-18.0f, *controller);
CallPreProcessAndProcess( CallPreProcessAndProcess(
/*num_calls=*/400, audio_buffer, kHighSpeechProbability, /*num_calls=*/400, audio_buffer, kHighSpeechProbability,
/*speech_level=*/-18.0f, *manager_with_override); /*speech_level_dbfs=*/-18.0f, *manager_with_override);
// Make sure that an adaptation occurred. // Make sure that an adaptation occurred.
ASSERT_GT(controller->recommended_analog_level(), 0); ASSERT_GT(controller->recommended_analog_level(), 0);
@ -981,10 +930,10 @@ TEST(InputVolumeControllerTest, MinInputVolumeCompareMicLevelWithClipping) {
// adjustment of the analog gain. Use low speech probability to limit the // adjustment of the analog gain. Use low speech probability to limit the
// volume changes to clipping handling. // volume changes to clipping handling.
CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer, CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
kLowSpeechProbability, /*speech_level=*/-18, kLowSpeechProbability, /*speech_level_dbfs=*/-18,
*controller); *controller);
CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer, CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
kLowSpeechProbability, /*speech_level=*/-18, kLowSpeechProbability, /*speech_level_dbfs=*/-18,
*manager_with_override); *manager_with_override);
// Make sure that an adaptation occurred. // Make sure that an adaptation occurred.
@ -1045,11 +994,11 @@ TEST(InputVolumeControllerTest,
CallPreProcessAndProcess( CallPreProcessAndProcess(
/*num_calls=*/400, audio_buffer, /*num_calls=*/400, audio_buffer,
/*speech_probability=*/0.7f, /*speech_probability=*/0.7f,
/*speech_level=*/-18.0f, *controller); /*speech_level_dbfs=*/-18.0f, *controller);
CallPreProcessAndProcess( CallPreProcessAndProcess(
/*num_calls=*/400, audio_buffer, /*num_calls=*/400, audio_buffer,
/*speech_probability=*/0.7f, /*speech_probability=*/0.7f,
/*speech_level=*/-18.0f, *manager_with_override); /*speech_level_dbfs=*/-18.0f, *manager_with_override);
// Make sure that an adaptation occurred. // Make sure that an adaptation occurred.
ASSERT_GT(controller->recommended_analog_level(), 0); ASSERT_GT(controller->recommended_analog_level(), 0);
@ -1112,134 +1061,187 @@ TEST_P(InputVolumeControllerParametrizedTest,
TEST_P(InputVolumeControllerParametrizedTest, TEST_P(InputVolumeControllerParametrizedTest,
DisableClippingPredictorDoesNotLowerVolume) { DisableClippingPredictorDoesNotLowerVolume) {
AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz, int volume = 255;
kNumChannels, kSampleRateHz, kNumChannels);
InputVolumeControllerConfig config = GetInputVolumeControllerTestConfig(); InputVolumeControllerConfig config = GetInputVolumeControllerTestConfig();
config.enable_clipping_predictor = false; config.enable_clipping_predictor = false;
InputVolumeController controller(/*num_capture_channels=*/1, config); auto helper = InputVolumeControllerTestHelper(config);
controller.Initialize(); helper.controller.Initialize();
controller.set_stream_analog_level(/*level=*/255);
EXPECT_FALSE(controller.clipping_predictor_enabled()); EXPECT_FALSE(helper.controller.clipping_predictor_enabled());
EXPECT_FALSE(controller.use_clipping_predictor_step()); EXPECT_FALSE(helper.controller.use_clipping_predictor_step());
EXPECT_EQ(controller.recommended_analog_level(), 255);
controller.Process(kHighSpeechProbability, kSpeechLevel); // Expect no change if clipping prediction is enabled.
CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, controller); for (int j = 0; j < 31; ++j) {
EXPECT_EQ(controller.recommended_analog_level(), 255); WriteAlternatingAudioBufferSamples(0.99f * kMaxSample, helper.audio_buffer);
CallPreProcessAudioBuffer(/*num_calls=*/300, /*peak_ratio=*/0.99f, volume = helper.CallAgcSequence(volume, kLowSpeechProbability, kSpeechLevel,
controller); /*num_calls=*/5);
EXPECT_EQ(controller.recommended_analog_level(), 255);
CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, controller); WriteAudioBufferSamples(0.99f * kMaxSample, /*clipped_ratio=*/0.0f,
EXPECT_EQ(controller.recommended_analog_level(), 255); helper.audio_buffer);
volume = helper.CallAgcSequence(volume, kLowSpeechProbability, kSpeechLevel,
/*num_calls=*/5);
EXPECT_EQ(volume, 255);
}
} }
// TODO(bugs.webrtc.org/7494): Split into several smaller tests.
TEST_P(InputVolumeControllerParametrizedTest, TEST_P(InputVolumeControllerParametrizedTest,
UsedClippingPredictionsProduceLowerAnalogLevels) { UsedClippingPredictionsProduceLowerAnalogLevels) {
AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
kNumChannels, kSampleRateHz, kNumChannels);
InputVolumeControllerConfig config_with_prediction =
GetInputVolumeControllerTestConfig();
config_with_prediction.enable_clipping_predictor = true;
InputVolumeControllerConfig config_without_prediction =
GetInputVolumeControllerTestConfig();
config_without_prediction.enable_clipping_predictor = false;
InputVolumeController manager_without_prediction(/*num_capture_channels=*/1,
config_without_prediction);
InputVolumeController manager_with_prediction(/*num_capture_channels=*/1,
config_with_prediction);
manager_with_prediction.Initialize();
manager_without_prediction.Initialize();
constexpr int kInitialLevel = 255; constexpr int kInitialLevel = 255;
constexpr float kClippingPeakRatio = 1.0f;
constexpr float kCloseToClippingPeakRatio = 0.99f; constexpr float kCloseToClippingPeakRatio = 0.99f;
constexpr float kZeroPeakRatio = 0.0f; int volume_1 = kInitialLevel;
manager_with_prediction.set_stream_analog_level(kInitialLevel); int volume_2 = kInitialLevel;
manager_without_prediction.set_stream_analog_level(kInitialLevel);
manager_with_prediction.Process(kHighSpeechProbability, kSpeechLevel); // Create two helpers, one with clipping prediction and one without.
manager_without_prediction.Process(kHighSpeechProbability, kSpeechLevel); auto config_1 = GetInputVolumeControllerTestConfig();
auto config_2 = GetInputVolumeControllerTestConfig();
config_1.enable_clipping_predictor = true;
config_2.enable_clipping_predictor = false;
auto helper_1 = InputVolumeControllerTestHelper(config_1);
auto helper_2 = InputVolumeControllerTestHelper(config_2);
helper_1.controller.Initialize();
helper_2.controller.Initialize();
EXPECT_TRUE(manager_with_prediction.clipping_predictor_enabled()); EXPECT_TRUE(helper_1.controller.clipping_predictor_enabled());
EXPECT_FALSE(manager_without_prediction.clipping_predictor_enabled()); EXPECT_FALSE(helper_2.controller.clipping_predictor_enabled());
EXPECT_TRUE(manager_with_prediction.use_clipping_predictor_step()); EXPECT_TRUE(helper_1.controller.use_clipping_predictor_step());
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), kInitialLevel);
EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
kInitialLevel);
// Expect a change in the analog level when the prediction step is used. // Expect a change if clipping prediction is enabled.
CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio, WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
manager_with_prediction); helper_1.audio_buffer);
CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio, WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
manager_without_prediction); helper_2.audio_buffer);
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kInitialLevel - kClippedLevelStep); kSpeechLevel, 5);
EXPECT_EQ(manager_without_prediction.recommended_analog_level(), volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kInitialLevel); kSpeechLevel, 5);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_1.audio_buffer);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_2.audio_buffer);
volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kSpeechLevel, 5);
volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
EXPECT_EQ(volume_1, kInitialLevel - kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel);
// Expect no change during waiting. // Expect no change during waiting.
CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio, for (int i = 0; i < kClippedWaitFrames / 10; ++i) {
manager_with_prediction); WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio, helper_1.audio_buffer);
manager_without_prediction); WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), helper_2.audio_buffer);
kInitialLevel - kClippedLevelStep); volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
EXPECT_EQ(manager_without_prediction.recommended_analog_level(), kSpeechLevel, 5);
kInitialLevel); volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_1.audio_buffer);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_2.audio_buffer);
volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kSpeechLevel, 5);
volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
EXPECT_EQ(volume_1, kInitialLevel - kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel);
}
// Expect a change when the prediction step is used. // Expect a change when the prediction step is used.
CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio, WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
manager_with_prediction); helper_1.audio_buffer);
CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio, WriteAlternatingAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
manager_without_prediction); helper_2.audio_buffer);
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kInitialLevel - 2 * kClippedLevelStep); kSpeechLevel, 5);
EXPECT_EQ(manager_without_prediction.recommended_analog_level(), volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kInitialLevel); kSpeechLevel, 5);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_1.audio_buffer);
WriteAudioBufferSamples(kCloseToClippingPeakRatio * kMaxSample,
/*clipped_ratio=*/0.0f, helper_2.audio_buffer);
volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kSpeechLevel, 5);
volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
EXPECT_EQ(volume_1, kInitialLevel - 2 * kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel);
// Expect no change when clipping is not detected or predicted. // Expect no change when clipping is not detected or predicted.
CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio, for (int i = 0; i < 2 * kClippedWaitFrames / 10; ++i) {
manager_with_prediction); WriteAlternatingAudioBufferSamples(/*samples_value=*/0.0f,
CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio, helper_1.audio_buffer);
manager_without_prediction); WriteAlternatingAudioBufferSamples(/*samples_value=*/0.0f,
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), helper_2.audio_buffer);
kInitialLevel - 2 * kClippedLevelStep); volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
EXPECT_EQ(manager_without_prediction.recommended_analog_level(), kSpeechLevel, 5);
kInitialLevel); volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.0f,
helper_1.audio_buffer);
WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.0f,
helper_2.audio_buffer);
volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kSpeechLevel, 5);
volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
}
EXPECT_EQ(volume_1, kInitialLevel - 2 * kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel);
// Expect a change for clipping frames. // Expect a change for clipping frames.
CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio, WriteAlternatingAudioBufferSamples(kMaxSample, helper_1.audio_buffer);
manager_with_prediction); WriteAlternatingAudioBufferSamples(kMaxSample, helper_2.audio_buffer);
CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio, volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
manager_without_prediction); kSpeechLevel, 1);
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kInitialLevel - 3 * kClippedLevelStep); kSpeechLevel, 1);
EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
kInitialLevel - kClippedLevelStep); EXPECT_EQ(volume_1, kInitialLevel - 3 * kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel - kClippedLevelStep);
// Expect no change during waiting. // Expect no change during waiting.
CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio, for (int i = 0; i < kClippedWaitFrames / 10; ++i) {
manager_with_prediction); WriteAlternatingAudioBufferSamples(kMaxSample, helper_1.audio_buffer);
CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio, WriteAlternatingAudioBufferSamples(kMaxSample, helper_2.audio_buffer);
manager_without_prediction); volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), kSpeechLevel, 5);
kInitialLevel - 3 * kClippedLevelStep); volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
EXPECT_EQ(manager_without_prediction.recommended_analog_level(), kSpeechLevel, 5);
kInitialLevel - kClippedLevelStep);
WriteAudioBufferSamples(kMaxSample, /*clipped_ratio=*/1.0f,
helper_1.audio_buffer);
WriteAudioBufferSamples(kMaxSample, /*clipped_ratio=*/1.0f,
helper_2.audio_buffer);
volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
kSpeechLevel, 5);
volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kSpeechLevel, 5);
}
EXPECT_EQ(volume_1, kInitialLevel - 3 * kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel - kClippedLevelStep);
// Expect a change for clipping frames. // Expect a change for clipping frames.
CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio, WriteAlternatingAudioBufferSamples(kMaxSample, helper_1.audio_buffer);
manager_with_prediction); WriteAlternatingAudioBufferSamples(kMaxSample, helper_2.audio_buffer);
CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio, volume_1 = helper_1.CallAgcSequence(volume_1, kLowSpeechProbability,
manager_without_prediction); kSpeechLevel, 1);
EXPECT_EQ(manager_with_prediction.recommended_analog_level(), volume_2 = helper_2.CallAgcSequence(volume_2, kLowSpeechProbability,
kInitialLevel - 4 * kClippedLevelStep); kSpeechLevel, 1);
EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
kInitialLevel - 2 * kClippedLevelStep); EXPECT_EQ(volume_1, kInitialLevel - 4 * kClippedLevelStep);
EXPECT_EQ(volume_2, kInitialLevel - 2 * kClippedLevelStep);
} }
// Checks that passing an empty speech level has no effect on the input volume. // Checks that passing an empty speech level has no effect on the input volume.
@ -1285,18 +1287,18 @@ TEST(InputVolumeControllerTest, UpdateInputVolumeWaitFramesIsEffective) {
SpeechSamplesReader reader_1; SpeechSamplesReader reader_1;
SpeechSamplesReader reader_2; SpeechSamplesReader reader_2;
reader_1.Feed(/*num_frames=*/99, /*gain_db=*/0, kHighSpeechProbability, reader_1.Feed(/*num_frames=*/99, /*gain_db=*/0, kHighSpeechProbability,
/*speech_level=*/-42.0f, *controller_wait_0); /*speech_level_dbfs=*/-42.0f, *controller_wait_0);
reader_2.Feed(/*num_frames=*/99, /*gain_db=*/0, kHighSpeechProbability, reader_2.Feed(/*num_frames=*/99, /*gain_db=*/0, kHighSpeechProbability,
/*speech_level=*/-42.0f, *controller_wait_100); /*speech_level_dbfs=*/-42.0f, *controller_wait_100);
// Check that adaptation only occurs if enough frames have been processed. // Check that adaptation only occurs if enough frames have been processed.
ASSERT_GT(controller_wait_0->recommended_analog_level(), kInputVolume); ASSERT_GT(controller_wait_0->recommended_analog_level(), kInputVolume);
ASSERT_EQ(controller_wait_100->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_wait_100->recommended_analog_level(), kInputVolume);
reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0, kHighSpeechProbability, reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0, kHighSpeechProbability,
/*speech_level=*/-42.0f, *controller_wait_0); /*speech_level_dbfs=*/-42.0f, *controller_wait_0);
reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0, kHighSpeechProbability, reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0, kHighSpeechProbability,
/*speech_level=*/-42.0f, *controller_wait_100); /*speech_level_dbfs=*/-42.0f, *controller_wait_100);
// Check that adaptation only occurs when enough frames have been processed. // Check that adaptation only occurs when enough frames have been processed.
ASSERT_GT(controller_wait_0->recommended_analog_level(), kInputVolume); ASSERT_GT(controller_wait_0->recommended_analog_level(), kInputVolume);
@ -1326,30 +1328,30 @@ TEST(InputVolumeControllerTest, SpeechRatioThresholdIsEffective) {
SpeechSamplesReader reader_2; SpeechSamplesReader reader_2;
reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0,
/*speech_probability=*/0.7f, /*speech_level=*/-42.0f, /*speech_probability=*/0.7f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0,
/*speech_probability=*/0.4f, /*speech_level=*/-42.0f, /*speech_probability=*/0.4f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume);
ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume);
reader_1.Feed(/*num_frames=*/2, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/2, /*gain_db=*/0,
/*speech_probability=*/0.4f, /*speech_level=*/-42.0f, /*speech_probability=*/0.4f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/2, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/2, /*gain_db=*/0,
/*speech_probability=*/0.4f, /*speech_level=*/-42.0f, /*speech_probability=*/0.4f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume);
ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume);
reader_1.Feed(/*num_frames=*/7, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/7, /*gain_db=*/0,
/*speech_probability=*/0.7f, /*speech_level=*/-42.0f, /*speech_probability=*/0.7f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/7, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/7, /*gain_db=*/0,
/*speech_probability=*/0.7f, /*speech_level=*/-42.0f, /*speech_probability=*/0.7f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_GT(controller_1->recommended_analog_level(), kInputVolume); ASSERT_GT(controller_1->recommended_analog_level(), kInputVolume);
@ -1383,30 +1385,30 @@ TEST(InputVolumeControllerTest, SpeechProbabilityThresholdIsEffective) {
// processsed and `reader_2` to process inputs that won't make the volume // processsed and `reader_2` to process inputs that won't make the volume
// to be adjusted. // to be adjusted.
reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/1, /*gain_db=*/0,
/*speech_probability=*/0.5f, /*speech_level=*/-42.0f, /*speech_probability=*/0.5f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/1, /*gain_db=*/0,
/*speech_probability=*/0.49f, /*speech_level=*/-42.0f, /*speech_probability=*/0.49f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume);
ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume);
reader_1.Feed(/*num_frames=*/2, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/2, /*gain_db=*/0,
/*speech_probability=*/0.49f, /*speech_level=*/-42.0f, /*speech_probability=*/0.49f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/2, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/2, /*gain_db=*/0,
/*speech_probability=*/0.49f, /*speech_level=*/-42.0f, /*speech_probability=*/0.49f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_1->recommended_analog_level(), kInputVolume);
ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume); ASSERT_EQ(controller_2->recommended_analog_level(), kInputVolume);
reader_1.Feed(/*num_frames=*/7, /*gain_db=*/0, reader_1.Feed(/*num_frames=*/7, /*gain_db=*/0,
/*speech_probability=*/0.5f, /*speech_level=*/-42.0f, /*speech_probability=*/0.5f, /*speech_level_dbfs=*/-42.0f,
*controller_1); *controller_1);
reader_2.Feed(/*num_frames=*/7, /*gain_db=*/0, reader_2.Feed(/*num_frames=*/7, /*gain_db=*/0,
/*speech_probability=*/0.5f, /*speech_level=*/-42.0f, /*speech_probability=*/0.5f, /*speech_level_dbfs=*/-42.0f,
*controller_2); *controller_2);
ASSERT_GT(controller_1->recommended_analog_level(), kInputVolume); ASSERT_GT(controller_1->recommended_analog_level(), kInputVolume);