mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
APM: add AudioProcessingImpl::capture_::applied_input_volume(_changed)
The `recommended_stream_analog_level()` getter is used to retrieve both the applied and the recommended input volume. This behavior is error-prone since the caller must know what is returned based on the point in the code (namely, before/after the AGC has changed the last applied input volume into a recommended level). This CL is a first step to make clarity on which input volume is handled in different parts of APM. Next in the pipeline: make `recommended_stream_analog_level()` a trivial getter that always returns the recommended level. Main changes: - When `recommended_stream_analog_level()` is called but `set_stream_analog_level()` is not called, APM logs an error and returns a fall-back volume (which should not be applied since, when `set_stream_analog_level()` is not called, no external input volume is expected to be present - When APM is used without calling the `*_stream_analog_level()` methods (e.g., when the caller does not provide any input volume), the recorded AEC dumps won't store `Stream::applied_input_level` Other changes: - Removed `AudioProcessingImpl::capture_::prev_analog_mic_level` - Removed redundant code in `GainController2` around detecting input volume changes (already done by APM) - Adapted the `audioproc_f` and `unpack_aecdump` tools - Data dumps clean-up: the applied and the recommended input volumes are now recorded in an AGC implementation agnostic way Bug: webrtc:7494, b/241923537 Change-Id: I3cb4a731fd9f3dc19bf6ac679b7ed8c969ea283b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/271544 Reviewed-by: Per Åhgren <peah@webrtc.org> Reviewed-by: Hanna Silen <silen@webrtc.org> Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38054}
This commit is contained in:
parent
0c0c602653
commit
fcf1af3049
14 changed files with 141 additions and 96 deletions
|
@ -114,7 +114,10 @@ rtc_source_set("aec_dump_interface") {
|
|||
":api",
|
||||
":audio_frame_view",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/base:core_headers",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("gain_controller2") {
|
||||
|
|
|
@ -53,7 +53,9 @@ void CaptureStreamInfo::AddAudioProcessingState(
|
|||
auto* stream = event_->mutable_stream();
|
||||
stream->set_delay(state.delay);
|
||||
stream->set_drift(state.drift);
|
||||
stream->set_applied_input_volume(state.applied_input_volume);
|
||||
if (state.applied_input_volume.has_value()) {
|
||||
stream->set_applied_input_volume(*state.applied_input_volume);
|
||||
}
|
||||
stream->set_keypress(state.keypress);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -143,6 +143,8 @@ void PackRenderAudioBufferForEchoDetector(const AudioBuffer& audio,
|
|||
audio.channels_const()[0] + audio.num_frames());
|
||||
}
|
||||
|
||||
constexpr int kUnspecifiedDataDumpInputVolume = -100;
|
||||
|
||||
} // namespace
|
||||
|
||||
// Throughout webrtc, it's assumed that success is represented by zero.
|
||||
|
@ -1073,7 +1075,6 @@ int AudioProcessingImpl::ProcessStream(const int16_t* const src,
|
|||
if (aec_dump_) {
|
||||
RecordProcessedCaptureStream(dest, output_config);
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
|
@ -1088,6 +1089,10 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
RTC_DCHECK_LE(
|
||||
!!submodules_.echo_controller + !!submodules_.echo_control_mobile, 1);
|
||||
|
||||
data_dumper_->DumpRaw(
|
||||
"applied_input_volume",
|
||||
capture_.applied_input_volume.value_or(kUnspecifiedDataDumpInputVolume));
|
||||
|
||||
AudioBuffer* capture_buffer = capture_.capture_audio.get(); // For brevity.
|
||||
AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
|
||||
|
||||
|
@ -1123,16 +1128,16 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
levels.peak, 1, RmsLevel::kMinLevelDb, 64);
|
||||
}
|
||||
|
||||
// Detect an analog gain change.
|
||||
int analog_mic_level = recommended_stream_analog_level_locked();
|
||||
const bool analog_mic_level_changed =
|
||||
capture_.prev_analog_mic_level != analog_mic_level &&
|
||||
capture_.prev_analog_mic_level != -1;
|
||||
capture_.prev_analog_mic_level = analog_mic_level;
|
||||
analog_gain_stats_reporter_.UpdateStatistics(analog_mic_level);
|
||||
if (capture_.applied_input_volume.has_value()) {
|
||||
// Log the applied input volume only when available.
|
||||
input_volume_stats_reporter_.UpdateStatistics(
|
||||
*capture_.applied_input_volume);
|
||||
}
|
||||
|
||||
if (submodules_.echo_controller) {
|
||||
capture_.echo_path_gain_change = analog_mic_level_changed;
|
||||
// Determine if the echo path gain has changed by checking all the gains
|
||||
// applied before AEC.
|
||||
capture_.echo_path_gain_change = capture_.applied_input_volume_changed;
|
||||
|
||||
// Detect and flag any change in the capture level adjustment pre-gain.
|
||||
if (submodules_.capture_levels_adjuster) {
|
||||
|
@ -1141,7 +1146,7 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
capture_.echo_path_gain_change =
|
||||
capture_.echo_path_gain_change ||
|
||||
(capture_.prev_pre_adjustment_gain != pre_adjustment_gain &&
|
||||
capture_.prev_pre_adjustment_gain >= 0.f);
|
||||
capture_.prev_pre_adjustment_gain >= 0.0f);
|
||||
capture_.prev_pre_adjustment_gain = pre_adjustment_gain;
|
||||
}
|
||||
|
||||
|
@ -1312,9 +1317,9 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
}
|
||||
|
||||
if (submodules_.gain_controller2) {
|
||||
submodules_.gain_controller2->NotifyAnalogLevel(
|
||||
recommended_stream_analog_level_locked());
|
||||
submodules_.gain_controller2->Process(voice_probability, capture_buffer);
|
||||
submodules_.gain_controller2->Process(
|
||||
voice_probability, capture_.applied_input_volume_changed,
|
||||
capture_buffer);
|
||||
}
|
||||
|
||||
if (submodules_.capture_post_processor) {
|
||||
|
@ -1333,12 +1338,6 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
levels.peak, 1, RmsLevel::kMinLevelDb, 64);
|
||||
}
|
||||
|
||||
if (submodules_.agc_manager) {
|
||||
int level = recommended_stream_analog_level_locked();
|
||||
data_dumper_->DumpRaw("experimental_gain_control_stream_analog_level", 1,
|
||||
&level);
|
||||
}
|
||||
|
||||
// Compute echo-detector stats.
|
||||
if (submodules_.echo_detector) {
|
||||
auto ed_metrics = submodules_.echo_detector->GetMetrics();
|
||||
|
@ -1388,6 +1387,9 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
|||
capture_.capture_output_used_last_frame = capture_.capture_output_used;
|
||||
|
||||
capture_.was_stream_delay_set = false;
|
||||
|
||||
// TODO(bugs.webrtc.org/7494): Dump recommended input volume.
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
|
@ -1605,14 +1607,13 @@ void AudioProcessingImpl::set_stream_analog_level(int level) {
|
|||
}
|
||||
|
||||
void AudioProcessingImpl::set_stream_analog_level_locked(int level) {
|
||||
// Cache the level for later reporting back as the recommended input volume to
|
||||
// use.
|
||||
capture_.cached_stream_analog_level_ = level;
|
||||
capture_.applied_input_volume_changed =
|
||||
capture_.applied_input_volume.has_value() &&
|
||||
*capture_.applied_input_volume != level;
|
||||
capture_.applied_input_volume = level;
|
||||
|
||||
if (submodules_.agc_manager) {
|
||||
submodules_.agc_manager->set_stream_analog_level(level);
|
||||
data_dumper_->DumpRaw("experimental_gain_control_set_stream_analog_level",
|
||||
1, &level);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1629,6 +1630,10 @@ int AudioProcessingImpl::recommended_stream_analog_level() const {
|
|||
}
|
||||
|
||||
int AudioProcessingImpl::recommended_stream_analog_level_locked() const {
|
||||
if (!capture_.applied_input_volume.has_value()) {
|
||||
RTC_LOG(LS_ERROR) << "set_stream_analog_level has not been called";
|
||||
}
|
||||
|
||||
if (submodules_.agc_manager) {
|
||||
return submodules_.agc_manager->recommended_analog_level();
|
||||
}
|
||||
|
@ -1637,7 +1642,9 @@ int AudioProcessingImpl::recommended_stream_analog_level_locked() const {
|
|||
return submodules_.gain_control->stream_analog_level();
|
||||
}
|
||||
|
||||
return capture_.cached_stream_analog_level_;
|
||||
// Input volume to recommend when `set_stream_analog_level()` is not called.
|
||||
constexpr int kFallBackInputVolume = 255;
|
||||
return capture_.applied_input_volume.value_or(kFallBackInputVolume);
|
||||
}
|
||||
|
||||
bool AudioProcessingImpl::CreateAndAttachAecDump(absl::string_view file_name,
|
||||
|
@ -2137,10 +2144,7 @@ void AudioProcessingImpl::RecordAudioProcessingState() {
|
|||
AecDump::AudioProcessingState audio_proc_state;
|
||||
audio_proc_state.delay = capture_nonlocked_.stream_delay_ms;
|
||||
audio_proc_state.drift = 0;
|
||||
// TODO(bugs.webrtc.org/7494): Refactor to clarify that `stream_analog_level`
|
||||
// is in fact assigned to the applied volume and not to the recommended one.
|
||||
audio_proc_state.applied_input_volume =
|
||||
recommended_stream_analog_level_locked();
|
||||
audio_proc_state.applied_input_volume = capture_.applied_input_volume;
|
||||
audio_proc_state.keypress = capture_.key_pressed;
|
||||
aec_dump_->AddAudioProcessingState(audio_proc_state);
|
||||
}
|
||||
|
@ -2153,10 +2157,10 @@ AudioProcessingImpl::ApmCaptureState::ApmCaptureState()
|
|||
capture_processing_format(kSampleRate16kHz),
|
||||
split_rate(kSampleRate16kHz),
|
||||
echo_path_gain_change(false),
|
||||
prev_analog_mic_level(-1),
|
||||
prev_pre_adjustment_gain(-1.f),
|
||||
prev_pre_adjustment_gain(-1.0f),
|
||||
playout_volume(-1),
|
||||
prev_playout_volume(-1) {}
|
||||
prev_playout_volume(-1),
|
||||
applied_input_volume_changed(false) {}
|
||||
|
||||
AudioProcessingImpl::ApmCaptureState::~ApmCaptureState() = default;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/function_view.h"
|
||||
#include "modules/audio_processing/aec3/echo_canceller3.h"
|
||||
|
@ -466,12 +467,14 @@ class AudioProcessingImpl : public AudioProcessing {
|
|||
StreamConfig capture_processing_format;
|
||||
int split_rate;
|
||||
bool echo_path_gain_change;
|
||||
int prev_analog_mic_level;
|
||||
float prev_pre_adjustment_gain;
|
||||
int playout_volume;
|
||||
int prev_playout_volume;
|
||||
AudioProcessingStats stats;
|
||||
int cached_stream_analog_level_ = 0;
|
||||
// Input volume applied on the audio input device when the audio is
|
||||
// acquired. Unspecified when unknown.
|
||||
absl::optional<int> applied_input_volume;
|
||||
bool applied_input_volume_changed;
|
||||
} capture_ RTC_GUARDED_BY(mutex_capture_);
|
||||
|
||||
struct ApmCaptureNonLockedState {
|
||||
|
@ -532,7 +535,7 @@ class AudioProcessingImpl : public AudioProcessing {
|
|||
RmsLevel capture_output_rms_ RTC_GUARDED_BY(mutex_capture_);
|
||||
int capture_rms_interval_counter_ RTC_GUARDED_BY(mutex_capture_) = 0;
|
||||
|
||||
AnalogGainStatsReporter analog_gain_stats_reporter_
|
||||
AnalogGainStatsReporter input_volume_stats_reporter_
|
||||
RTC_GUARDED_BY(mutex_capture_);
|
||||
|
||||
// Lock protection not needed.
|
||||
|
|
|
@ -955,8 +955,8 @@ TEST_F(ApmTest, PreAmplifier) {
|
|||
EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
|
||||
}
|
||||
|
||||
// This test a simple test that ensures that the emulated analog mic gain
|
||||
// functionality runs without crashing.
|
||||
// Ensures that the emulated analog mic gain functionality runs without
|
||||
// crashing.
|
||||
TEST_F(ApmTest, AnalogMicGainEmulation) {
|
||||
// Fill the audio frame with a sawtooth pattern.
|
||||
rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace {
|
|||
|
||||
using Agc2Config = AudioProcessing::Config::GainController2;
|
||||
|
||||
constexpr int kUnspecifiedAnalogLevel = -1;
|
||||
constexpr int kLogLimiterStatsPeriodMs = 30'000;
|
||||
constexpr int kFrameLengthMs = 10;
|
||||
constexpr int kLogLimiterStatsPeriodNumFrames =
|
||||
|
@ -81,8 +80,7 @@ GainController2::GainController2(const Agc2Config& config,
|
|||
num_channels,
|
||||
&data_dumper_)),
|
||||
limiter_(sample_rate_hz, &data_dumper_, /*histogram_name_prefix=*/"Agc2"),
|
||||
calls_since_last_limiter_log_(0),
|
||||
analog_level_(kUnspecifiedAnalogLevel) {
|
||||
calls_since_last_limiter_log_(0) {
|
||||
RTC_DCHECK(Validate(config));
|
||||
data_dumper_.InitiateNewSetOfRecordings();
|
||||
const bool use_vad = config.adaptive_digital.enabled;
|
||||
|
@ -112,7 +110,6 @@ void GainController2::Initialize(int sample_rate_hz, int num_channels) {
|
|||
}
|
||||
data_dumper_.InitiateNewSetOfRecordings();
|
||||
calls_since_last_limiter_log_ = 0;
|
||||
analog_level_ = kUnspecifiedAnalogLevel;
|
||||
}
|
||||
|
||||
void GainController2::SetFixedGainDb(float gain_db) {
|
||||
|
@ -126,8 +123,14 @@ void GainController2::SetFixedGainDb(float gain_db) {
|
|||
}
|
||||
|
||||
void GainController2::Process(absl::optional<float> speech_probability,
|
||||
bool input_volume_changed,
|
||||
AudioBuffer* audio) {
|
||||
data_dumper_.DumpRaw("agc2_notified_analog_level", analog_level_);
|
||||
data_dumper_.DumpRaw("agc2_applied_input_volume_changed",
|
||||
input_volume_changed);
|
||||
if (input_volume_changed && !!adaptive_digital_controller_) {
|
||||
adaptive_digital_controller_->HandleInputGainChange();
|
||||
}
|
||||
|
||||
AudioFrameView<float> float_frame(audio->channels(), audio->num_channels(),
|
||||
audio->num_frames());
|
||||
if (vad_) {
|
||||
|
@ -159,13 +162,6 @@ void GainController2::Process(absl::optional<float> speech_probability,
|
|||
}
|
||||
}
|
||||
|
||||
void GainController2::NotifyAnalogLevel(int level) {
|
||||
if (analog_level_ != level && adaptive_digital_controller_) {
|
||||
adaptive_digital_controller_->HandleInputGainChange();
|
||||
}
|
||||
analog_level_ = level;
|
||||
}
|
||||
|
||||
bool GainController2::Validate(
|
||||
const AudioProcessing::Config::GainController2& config) {
|
||||
const auto& fixed = config.fixed_digital;
|
||||
|
|
|
@ -50,11 +50,12 @@ class GainController2 {
|
|||
// Applies fixed and adaptive digital gains to `audio` and runs a limiter.
|
||||
// If the internal VAD is used, `speech_probability` is ignored. Otherwise
|
||||
// `speech_probability` is used for digital adaptive gain if it's available
|
||||
// (limited to values [0.0, 1.0]).
|
||||
void Process(absl::optional<float> speech_probability, AudioBuffer* audio);
|
||||
|
||||
// Handles analog level changes.
|
||||
void NotifyAnalogLevel(int level);
|
||||
// (limited to values [0.0, 1.0]). Handles input volume changes; if the caller
|
||||
// cannot determine whether an input volume change occurred, set
|
||||
// `input_volume_changed` to false.
|
||||
void Process(absl::optional<float> speech_probability,
|
||||
bool input_volume_changed,
|
||||
AudioBuffer* audio);
|
||||
|
||||
static bool Validate(const AudioProcessing::Config::GainController2& config);
|
||||
|
||||
|
@ -69,7 +70,6 @@ class GainController2 {
|
|||
std::unique_ptr<AdaptiveDigitalGainController> adaptive_digital_controller_;
|
||||
Limiter limiter_;
|
||||
int calls_since_last_limiter_log_;
|
||||
int analog_level_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -47,7 +47,8 @@ float RunAgc2WithConstantInput(GainController2& agc2,
|
|||
// Give time to the level estimator to converge.
|
||||
for (int i = 0; i < num_frames + 1; ++i) {
|
||||
SetAudioBufferSamples(input_level, ab);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt, &ab);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt,
|
||||
/*input_volume_changed=*/false, &ab);
|
||||
}
|
||||
|
||||
// Return the last sample from the last processed frame.
|
||||
|
@ -283,12 +284,14 @@ TEST(GainController2, CheckFinalGainWithAdaptiveDigitalController) {
|
|||
x *= gain;
|
||||
}
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt, &audio_buffer);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt,
|
||||
/*input_volume_changed=*/false, &audio_buffer);
|
||||
}
|
||||
|
||||
// Estimate the applied gain by processing a probing frame.
|
||||
SetAudioBufferSamples(/*value=*/1.0f, audio_buffer);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt, &audio_buffer);
|
||||
agc2.Process(/*speech_probability=*/absl::nullopt,
|
||||
/*input_volume_changed=*/false, &audio_buffer);
|
||||
const float applied_gain_db =
|
||||
20.0f * std::log10(audio_buffer.channels_const()[0][0]);
|
||||
|
||||
|
@ -343,10 +346,13 @@ TEST(GainController2,
|
|||
x *= gain;
|
||||
}
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
|
||||
agc2.Process(kSpeechProbabilities[j], &audio_buffer);
|
||||
agc2.Process(kSpeechProbabilities[j], /*input_volume_changed=*/false,
|
||||
&audio_buffer);
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame,
|
||||
&audio_buffer_reference);
|
||||
agc2_reference.Process(absl::nullopt, &audio_buffer_reference);
|
||||
agc2_reference.Process(/*speech_probability=*/absl::nullopt,
|
||||
/*input_volume_changed=*/false,
|
||||
&audio_buffer_reference);
|
||||
|
||||
// Check the output buffers.
|
||||
for (int i = 0; i < kStereo; ++i) {
|
||||
|
@ -407,10 +413,13 @@ TEST(GainController2,
|
|||
x *= gain;
|
||||
}
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
|
||||
agc2.Process(kSpeechProbabilities[j], &audio_buffer);
|
||||
agc2.Process(kSpeechProbabilities[j], /*input_volume_changed=*/false,
|
||||
&audio_buffer);
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame,
|
||||
&audio_buffer_reference);
|
||||
agc2_reference.Process(absl::nullopt, &audio_buffer_reference);
|
||||
agc2_reference.Process(/*speech_probability=*/absl::nullopt,
|
||||
/*input_volume_changed=*/false,
|
||||
&audio_buffer_reference);
|
||||
// Check the output buffers.
|
||||
for (int i = 0; i < kStereo; ++i) {
|
||||
for (int j = 0; j < static_cast<int>(audio_buffer.num_frames()); ++j) {
|
||||
|
@ -472,11 +481,13 @@ TEST(GainController2,
|
|||
}
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame,
|
||||
&audio_buffer_reference);
|
||||
agc2_reference.Process(absl::nullopt, &audio_buffer_reference);
|
||||
agc2_reference.Process(absl::nullopt, /*input_volume_changed=*/false,
|
||||
&audio_buffer_reference);
|
||||
test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
|
||||
agc2.Process(vad.Analyze(AudioFrameView<const float>(
|
||||
audio_buffer.channels(), audio_buffer.num_channels(),
|
||||
audio_buffer.num_frames())),
|
||||
float speech_probability = vad.Analyze(AudioFrameView<const float>(
|
||||
audio_buffer.channels(), audio_buffer.num_channels(),
|
||||
audio_buffer.num_frames()));
|
||||
agc2.Process(speech_probability, /*input_volume_changed=*/false,
|
||||
&audio_buffer);
|
||||
// Check the output buffer.
|
||||
for (int i = 0; i < kStereo; ++i) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "modules/audio_processing/include/audio_frame_view.h"
|
||||
#include "modules/audio_processing/include/audio_processing.h"
|
||||
|
||||
|
@ -67,7 +68,7 @@ class AecDump {
|
|||
struct AudioProcessingState {
|
||||
int delay;
|
||||
int drift;
|
||||
int applied_input_volume;
|
||||
absl::optional<int> applied_input_volume;
|
||||
bool keypress;
|
||||
};
|
||||
|
||||
|
|
|
@ -589,9 +589,10 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface {
|
|||
// HAL. Must be within the range [0, 255].
|
||||
virtual void set_stream_analog_level(int level) = 0;
|
||||
|
||||
// When an analog mode is set, this should be called after ProcessStream()
|
||||
// to obtain the recommended new analog level for the audio HAL. It is the
|
||||
// user's responsibility to apply this level.
|
||||
// When an analog mode is set, this should be called after
|
||||
// `set_stream_analog_level()` and `ProcessStream()` to obtain the recommended
|
||||
// new analog level for the audio HAL. It is the user's responsibility to
|
||||
// apply this level.
|
||||
virtual int recommended_stream_analog_level() const = 0;
|
||||
|
||||
// This must be called if and only if echo processing is enabled.
|
||||
|
|
|
@ -174,9 +174,11 @@ void AecDumpBasedSimulator::PrepareProcessStreamCall(
|
|||
}
|
||||
}
|
||||
|
||||
// The stream analog level is always logged in the AEC dumps.
|
||||
RTC_CHECK(msg.has_applied_input_volume());
|
||||
aec_dump_mic_level_ = msg.applied_input_volume();
|
||||
// Set the applied input level if available.
|
||||
aec_dump_applied_input_level_ =
|
||||
msg.has_applied_input_volume()
|
||||
? absl::optional<int>(msg.applied_input_volume())
|
||||
: absl::nullopt;
|
||||
}
|
||||
|
||||
void AecDumpBasedSimulator::VerifyProcessStreamBitExactness(
|
||||
|
|
|
@ -118,7 +118,7 @@ AudioProcessingSimulator::AudioProcessingSimulator(
|
|||
std::unique_ptr<AudioProcessingBuilder> ap_builder)
|
||||
: settings_(settings),
|
||||
ap_(std::move(audio_processing)),
|
||||
analog_mic_level_(settings.initial_mic_level),
|
||||
applied_input_volume_(settings.initial_mic_level),
|
||||
fake_recording_device_(
|
||||
settings.initial_mic_level,
|
||||
settings_.simulate_mic_gain ? *settings.simulated_mic_kind : 0),
|
||||
|
@ -208,29 +208,50 @@ AudioProcessingSimulator::~AudioProcessingSimulator() {
|
|||
}
|
||||
|
||||
void AudioProcessingSimulator::ProcessStream(bool fixed_interface) {
|
||||
// Optionally use the fake recording device to simulate analog gain.
|
||||
// Optionally simulate the input volume.
|
||||
if (settings_.simulate_mic_gain) {
|
||||
RTC_DCHECK(!settings_.use_analog_mic_gain_emulation);
|
||||
if (settings_.aec_dump_input_filename) {
|
||||
// When the analog gain is simulated and an AEC dump is used as input, set
|
||||
// the undo level to `aec_dump_mic_level_` to virtually restore the
|
||||
// unmodified microphone signal level.
|
||||
fake_recording_device_.SetUndoMicLevel(aec_dump_mic_level_);
|
||||
// Set the input volume to simulate.
|
||||
fake_recording_device_.SetMicLevel(applied_input_volume_);
|
||||
|
||||
if (settings_.aec_dump_input_filename &&
|
||||
aec_dump_applied_input_level_.has_value()) {
|
||||
// For AEC dumps, use the applied input level, if recorded, to "virtually
|
||||
// restore" the capture signal level before the input volume was applied.
|
||||
fake_recording_device_.SetUndoMicLevel(*aec_dump_applied_input_level_);
|
||||
}
|
||||
|
||||
// Apply the input volume.
|
||||
if (fixed_interface) {
|
||||
fake_recording_device_.SimulateAnalogGain(fwd_frame_.data);
|
||||
} else {
|
||||
fake_recording_device_.SimulateAnalogGain(in_buf_.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the current mic level to AGC.
|
||||
// Let APM know which input volume was applied.
|
||||
// Keep track of whether `set_stream_analog_level()` is called.
|
||||
bool applied_input_volume_set = false;
|
||||
if (settings_.simulate_mic_gain) {
|
||||
// When the input volume is simulated, use the volume applied for
|
||||
// simulation.
|
||||
ap_->set_stream_analog_level(fake_recording_device_.MicLevel());
|
||||
applied_input_volume_set = true;
|
||||
} else if (!settings_.use_analog_mic_gain_emulation) {
|
||||
// Notify the current mic level to AGC.
|
||||
ap_->set_stream_analog_level(settings_.aec_dump_input_filename
|
||||
? aec_dump_mic_level_
|
||||
: analog_mic_level_);
|
||||
// Ignore the recommended input volume stored in `applied_input_volume_` and
|
||||
// instead notify APM with the recorded input volume (if available).
|
||||
if (settings_.aec_dump_input_filename &&
|
||||
aec_dump_applied_input_level_.has_value()) {
|
||||
// The actually applied input volume is available in the AEC dump.
|
||||
ap_->set_stream_analog_level(*aec_dump_applied_input_level_);
|
||||
applied_input_volume_set = true;
|
||||
} else if (!settings_.aec_dump_input_filename) {
|
||||
// Wav files do not include any information about the actually applied
|
||||
// input volume. Hence, use the recommended input volume stored in
|
||||
// `applied_input_volume_`.
|
||||
ap_->set_stream_analog_level(applied_input_volume_);
|
||||
applied_input_volume_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Post any scheduled runtime settings.
|
||||
|
@ -266,13 +287,12 @@ void AudioProcessingSimulator::ProcessStream(bool fixed_interface) {
|
|||
out_config_, out_buf_->channels()));
|
||||
}
|
||||
|
||||
// Store the mic level suggested by AGC.
|
||||
// Note that when the analog gain is simulated and an AEC dump is used as
|
||||
// input, `analog_mic_level_` will not be used with set_stream_analog_level().
|
||||
analog_mic_level_ = ap_->recommended_stream_analog_level();
|
||||
if (settings_.simulate_mic_gain) {
|
||||
fake_recording_device_.SetMicLevel(analog_mic_level_);
|
||||
// Retrieve the recommended input volume only if `set_stream_analog_level()`
|
||||
// has been called to stick to the APM API contract.
|
||||
if (applied_input_volume_set) {
|
||||
applied_input_volume_ = ap_->recommended_stream_analog_level();
|
||||
}
|
||||
|
||||
if (buffer_memory_writer_) {
|
||||
RTC_CHECK(!buffer_file_writer_);
|
||||
buffer_memory_writer_->Write(*out_buf_);
|
||||
|
|
|
@ -219,7 +219,7 @@ class AudioProcessingSimulator {
|
|||
Int16Frame rev_frame_;
|
||||
Int16Frame fwd_frame_;
|
||||
bool bitexact_output_ = true;
|
||||
int aec_dump_mic_level_ = 0;
|
||||
absl::optional<int> aec_dump_applied_input_level_ = 0;
|
||||
|
||||
protected:
|
||||
size_t output_reset_counter_ = 0;
|
||||
|
@ -235,7 +235,7 @@ class AudioProcessingSimulator {
|
|||
std::unique_ptr<WavWriter> linear_aec_output_file_writer_;
|
||||
ApiCallStatistics api_call_statistics_;
|
||||
std::ofstream residual_echo_likelihood_graph_writer_;
|
||||
int analog_mic_level_;
|
||||
int applied_input_volume_;
|
||||
FakeRecordingDevice fake_recording_device_;
|
||||
|
||||
TaskQueueForTest worker_queue_;
|
||||
|
|
|
@ -121,7 +121,9 @@ void DebugDumpReplayer::OnStreamEvent(const audioproc::Stream& msg) {
|
|||
// APM should have been created.
|
||||
RTC_CHECK(apm_.get());
|
||||
|
||||
apm_->set_stream_analog_level(msg.applied_input_volume());
|
||||
if (msg.has_applied_input_volume()) {
|
||||
apm_->set_stream_analog_level(msg.applied_input_volume());
|
||||
}
|
||||
RTC_CHECK_EQ(AudioProcessing::kNoError,
|
||||
apm_->set_stream_delay_ms(msg.delay()));
|
||||
|
||||
|
|
Loading…
Reference in a new issue