Adding initial support for lock-less informing of muting

This CL adds the initial support for letting APM know when its output
will be used or not.
It also adds a new method for passing RuntimeInformation to APM that
returns a bool indicating the success of the passing of information.

Bug: b/177830919
Change-Id: Ic2e1b92c37241d74ca6394b785b91736ca7532aa
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/206061
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33201}
This commit is contained in:
Per Åhgren
2021-02-09 08:47:51 +01:00
committed by Commit Bot
parent 7e225cf6ab
commit 0a144a705a
7 changed files with 73 additions and 45 deletions

View File

@ -158,7 +158,7 @@ void MonoAgc::Initialize() {
target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain;
compression_ = disable_digital_adaptive_ ? 0 : target_compression_; compression_ = disable_digital_adaptive_ ? 0 : target_compression_;
compression_accumulator_ = compression_; compression_accumulator_ = compression_;
capture_muted_ = false; capture_output_used_ = true;
check_volume_on_next_process_ = true; check_volume_on_next_process_ = true;
} }
@ -256,14 +256,14 @@ void MonoAgc::SetMaxLevel(int level) {
<< ", max_compression_gain_=" << max_compression_gain_; << ", max_compression_gain_=" << max_compression_gain_;
} }
void MonoAgc::SetCaptureMuted(bool muted) { void MonoAgc::HandleCaptureOutputUsedChange(bool capture_output_used) {
if (capture_muted_ == muted) { if (capture_output_used_ == capture_output_used) {
return; return;
} }
capture_muted_ = muted; capture_output_used_ = capture_output_used;
if (!muted) { if (capture_output_used) {
// When we unmute, we should reset things to be safe. // When we start using the output, we should reset things to be safe.
check_volume_on_next_process_ = true; check_volume_on_next_process_ = true;
} }
} }
@ -427,7 +427,7 @@ AgcManagerDirect::AgcManagerDirect(int num_capture_channels,
num_capture_channels_(num_capture_channels), num_capture_channels_(num_capture_channels),
disable_digital_adaptive_(disable_digital_adaptive), disable_digital_adaptive_(disable_digital_adaptive),
frames_since_clipped_(kClippedWaitFrames), frames_since_clipped_(kClippedWaitFrames),
capture_muted_(false), capture_output_used_(true),
channel_agcs_(num_capture_channels), channel_agcs_(num_capture_channels),
new_compressions_to_set_(num_capture_channels) { new_compressions_to_set_(num_capture_channels) {
const int min_mic_level = GetMinMicLevel(); const int min_mic_level = GetMinMicLevel();
@ -450,7 +450,7 @@ void AgcManagerDirect::Initialize() {
for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
channel_agcs_[ch]->Initialize(); channel_agcs_[ch]->Initialize();
} }
capture_muted_ = false; capture_output_used_ = true;
AggregateChannelLevels(); AggregateChannelLevels();
} }
@ -485,7 +485,7 @@ void AgcManagerDirect::AnalyzePreProcess(const float* const* audio,
size_t samples_per_channel) { size_t samples_per_channel) {
RTC_DCHECK(audio); RTC_DCHECK(audio);
AggregateChannelLevels(); AggregateChannelLevels();
if (capture_muted_) { if (!capture_output_used_) {
return; return;
} }
@ -520,7 +520,7 @@ void AgcManagerDirect::AnalyzePreProcess(const float* const* audio,
void AgcManagerDirect::Process(const AudioBuffer* audio) { void AgcManagerDirect::Process(const AudioBuffer* audio) {
AggregateChannelLevels(); AggregateChannelLevels();
if (capture_muted_) { if (!capture_output_used_) {
return; return;
} }
@ -549,11 +549,11 @@ absl::optional<int> AgcManagerDirect::GetDigitalComressionGain() {
return new_compressions_to_set_[channel_controlling_gain_]; return new_compressions_to_set_[channel_controlling_gain_];
} }
void AgcManagerDirect::SetCaptureMuted(bool muted) { void AgcManagerDirect::HandleCaptureOutputUsedChange(bool capture_output_used) {
for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
channel_agcs_[ch]->SetCaptureMuted(muted); channel_agcs_[ch]->HandleCaptureOutputUsedChange(capture_output_used);
} }
capture_muted_ = muted; capture_output_used_ = capture_output_used;
} }
float AgcManagerDirect::voice_probability() const { float AgcManagerDirect::voice_probability() const {

View File

@ -51,10 +51,9 @@ class AgcManagerDirect final {
void AnalyzePreProcess(const AudioBuffer* audio); void AnalyzePreProcess(const AudioBuffer* audio);
void Process(const AudioBuffer* audio); void Process(const AudioBuffer* audio);
// Call when the capture stream has been muted/unmuted. This causes the // Call when the capture stream output has been flagged to be used/not-used.
// manager to disregard all incoming audio; chances are good it's background // If unused, the manager disregards all incoming audio.
// noise to which we'd like to avoid adapting. void HandleCaptureOutputUsedChange(bool capture_output_used);
void SetCaptureMuted(bool muted);
float voice_probability() const; float voice_probability() const;
int stream_analog_level() const { return stream_analog_level_; } int stream_analog_level() const { return stream_analog_level_; }
@ -103,7 +102,7 @@ class AgcManagerDirect final {
int frames_since_clipped_; int frames_since_clipped_;
int stream_analog_level_ = 0; int stream_analog_level_ = 0;
bool capture_muted_; bool capture_output_used_;
int channel_controlling_gain_ = 0; int channel_controlling_gain_ = 0;
std::vector<std::unique_ptr<MonoAgc>> channel_agcs_; std::vector<std::unique_ptr<MonoAgc>> channel_agcs_;
@ -122,7 +121,7 @@ class MonoAgc {
MonoAgc& operator=(const MonoAgc&) = delete; MonoAgc& operator=(const MonoAgc&) = delete;
void Initialize(); void Initialize();
void SetCaptureMuted(bool muted); void HandleCaptureOutputUsedChange(bool capture_output_used);
void HandleClipping(); void HandleClipping();
@ -166,7 +165,7 @@ class MonoAgc {
int target_compression_; int target_compression_;
int compression_; int compression_;
float compression_accumulator_; float compression_accumulator_;
bool capture_muted_ = false; bool capture_output_used_ = true;
bool check_volume_on_next_process_ = true; bool check_volume_on_next_process_ = true;
bool startup_ = true; bool startup_ = true;
int startup_min_level_; int startup_min_level_;

View File

@ -375,7 +375,7 @@ TEST_F(AgcManagerDirectTest, CompressorReachesMinimum) {
} }
TEST_F(AgcManagerDirectTest, NoActionWhileMuted) { TEST_F(AgcManagerDirectTest, NoActionWhileMuted) {
manager_.SetCaptureMuted(true); manager_.HandleCaptureOutputUsedChange(false);
manager_.Process(nullptr); manager_.Process(nullptr);
absl::optional<int> new_digital_gain = manager_.GetDigitalComressionGain(); absl::optional<int> new_digital_gain = manager_.GetDigitalComressionGain();
if (new_digital_gain) { if (new_digital_gain) {
@ -386,8 +386,8 @@ TEST_F(AgcManagerDirectTest, NoActionWhileMuted) {
TEST_F(AgcManagerDirectTest, UnmutingChecksVolumeWithoutRaising) { TEST_F(AgcManagerDirectTest, UnmutingChecksVolumeWithoutRaising) {
FirstProcess(); FirstProcess();
manager_.SetCaptureMuted(true); manager_.HandleCaptureOutputUsedChange(false);
manager_.SetCaptureMuted(false); manager_.HandleCaptureOutputUsedChange(true);
ExpectCheckVolumeAndReset(127); ExpectCheckVolumeAndReset(127);
// SetMicVolume should not be called. // SetMicVolume should not be called.
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false)); EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false));
@ -398,8 +398,8 @@ TEST_F(AgcManagerDirectTest, UnmutingChecksVolumeWithoutRaising) {
TEST_F(AgcManagerDirectTest, UnmutingRaisesTooLowVolume) { TEST_F(AgcManagerDirectTest, UnmutingRaisesTooLowVolume) {
FirstProcess(); FirstProcess();
manager_.SetCaptureMuted(true); manager_.HandleCaptureOutputUsedChange(false);
manager_.SetCaptureMuted(false); manager_.HandleCaptureOutputUsedChange(true);
ExpectCheckVolumeAndReset(11); ExpectCheckVolumeAndReset(11);
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false)); EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false));
CallProcess(1); CallProcess(1);

View File

@ -664,35 +664,49 @@ size_t AudioProcessingImpl::num_output_channels() const {
void AudioProcessingImpl::set_output_will_be_muted(bool muted) { void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
MutexLock lock(&mutex_capture_); MutexLock lock(&mutex_capture_);
capture_.output_will_be_muted = muted; HandleCaptureOutputUsedSetting(!muted);
}
void AudioProcessingImpl::HandleCaptureOutputUsedSetting(
bool capture_output_used) {
capture_.capture_output_used = capture_output_used;
if (submodules_.agc_manager.get()) { if (submodules_.agc_manager.get()) {
submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted); submodules_.agc_manager->HandleCaptureOutputUsedChange(
capture_.capture_output_used);
} }
} }
void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) { void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
PostRuntimeSetting(setting);
}
bool AudioProcessingImpl::PostRuntimeSetting(RuntimeSetting setting) {
switch (setting.type()) { switch (setting.type()) {
case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting: case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
case RuntimeSetting::Type::kPlayoutAudioDeviceChange: case RuntimeSetting::Type::kPlayoutAudioDeviceChange:
render_runtime_settings_enqueuer_.Enqueue(setting); return render_runtime_settings_enqueuer_.Enqueue(setting);
return;
case RuntimeSetting::Type::kCapturePreGain: case RuntimeSetting::Type::kCapturePreGain:
case RuntimeSetting::Type::kCaptureCompressionGain: case RuntimeSetting::Type::kCaptureCompressionGain:
case RuntimeSetting::Type::kCaptureFixedPostGain: case RuntimeSetting::Type::kCaptureFixedPostGain:
case RuntimeSetting::Type::kCaptureOutputUsed: case RuntimeSetting::Type::kCaptureOutputUsed:
return capture_runtime_settings_enqueuer_.Enqueue(setting);
case RuntimeSetting::Type::kPlayoutVolumeChange: {
bool enqueueing_successful;
enqueueing_successful =
capture_runtime_settings_enqueuer_.Enqueue(setting); capture_runtime_settings_enqueuer_.Enqueue(setting);
return; enqueueing_successful =
case RuntimeSetting::Type::kPlayoutVolumeChange: render_runtime_settings_enqueuer_.Enqueue(setting) &&
capture_runtime_settings_enqueuer_.Enqueue(setting); enqueueing_successful;
render_runtime_settings_enqueuer_.Enqueue(setting); return enqueueing_successful;
return; }
case RuntimeSetting::Type::kNotSpecified: case RuntimeSetting::Type::kNotSpecified:
RTC_NOTREACHED(); RTC_NOTREACHED();
return; return true;
} }
// The language allows the enum to have a non-enumerator // The language allows the enum to have a non-enumerator
// value. Check that this doesn't happen. // value. Check that this doesn't happen.
RTC_NOTREACHED(); RTC_NOTREACHED();
return true;
} }
AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer( AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer(
@ -704,7 +718,7 @@ AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer(
AudioProcessingImpl::RuntimeSettingEnqueuer::~RuntimeSettingEnqueuer() = AudioProcessingImpl::RuntimeSettingEnqueuer::~RuntimeSettingEnqueuer() =
default; default;
void AudioProcessingImpl::RuntimeSettingEnqueuer::Enqueue( bool AudioProcessingImpl::RuntimeSettingEnqueuer::Enqueue(
RuntimeSetting setting) { RuntimeSetting setting) {
int remaining_attempts = 10; int remaining_attempts = 10;
while (!runtime_settings_.Insert(&setting) && remaining_attempts-- > 0) { while (!runtime_settings_.Insert(&setting) && remaining_attempts-- > 0) {
@ -718,6 +732,7 @@ void AudioProcessingImpl::RuntimeSettingEnqueuer::Enqueue(
RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.ApmRuntimeSettingCannotEnqueue", 1); RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.ApmRuntimeSettingCannotEnqueue", 1);
RTC_LOG(LS_ERROR) << "Cannot enqueue a new runtime setting."; RTC_LOG(LS_ERROR) << "Cannot enqueue a new runtime setting.";
} }
return remaining_attempts == 0;
} }
int AudioProcessingImpl::MaybeInitializeCapture( int AudioProcessingImpl::MaybeInitializeCapture(
@ -844,8 +859,9 @@ void AudioProcessingImpl::HandleCaptureRuntimeSettings() {
RTC_NOTREACHED(); RTC_NOTREACHED();
break; break;
case RuntimeSetting::Type::kCaptureOutputUsed: case RuntimeSetting::Type::kCaptureOutputUsed:
// TODO(b/154437967): Add support for reducing complexity when it is bool value;
// known that the capture output will not be used. setting.GetBool(&value);
HandleCaptureOutputUsedSetting(value);
break; break;
} }
} }
@ -1782,7 +1798,8 @@ void AudioProcessingImpl::InitializeGainController1() {
submodules_.agc_manager->Initialize(); submodules_.agc_manager->Initialize();
submodules_.agc_manager->SetupDigitalGainControl( submodules_.agc_manager->SetupDigitalGainControl(
submodules_.gain_control.get()); submodules_.gain_control.get());
submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted); submodules_.agc_manager->HandleCaptureOutputUsedChange(
capture_.capture_output_used);
} }
void AudioProcessingImpl::InitializeGainController2() { void AudioProcessingImpl::InitializeGainController2() {
@ -1993,7 +2010,7 @@ void AudioProcessingImpl::RecordAudioProcessingState() {
AudioProcessingImpl::ApmCaptureState::ApmCaptureState() AudioProcessingImpl::ApmCaptureState::ApmCaptureState()
: was_stream_delay_set(false), : was_stream_delay_set(false),
output_will_be_muted(false), capture_output_used(true),
key_pressed(false), key_pressed(false),
capture_processing_format(kSampleRate16kHz), capture_processing_format(kSampleRate16kHz),
split_rate(kSampleRate16kHz), split_rate(kSampleRate16kHz),

View File

@ -82,6 +82,7 @@ class AudioProcessingImpl : public AudioProcessing {
void AttachAecDump(std::unique_ptr<AecDump> aec_dump) override; void AttachAecDump(std::unique_ptr<AecDump> aec_dump) override;
void DetachAecDump() override; void DetachAecDump() override;
void SetRuntimeSetting(RuntimeSetting setting) override; void SetRuntimeSetting(RuntimeSetting setting) override;
bool PostRuntimeSetting(RuntimeSetting setting) override;
// Capture-side exclusive methods possibly running APM in a // Capture-side exclusive methods possibly running APM in a
// multi-threaded manner. Acquire the capture lock. // multi-threaded manner. Acquire the capture lock.
@ -96,6 +97,8 @@ class AudioProcessingImpl : public AudioProcessing {
bool GetLinearAecOutput( bool GetLinearAecOutput(
rtc::ArrayView<std::array<float, 160>> linear_output) const override; rtc::ArrayView<std::array<float, 160>> linear_output) const override;
void set_output_will_be_muted(bool muted) override; void set_output_will_be_muted(bool muted) override;
void HandleCaptureOutputUsedSetting(bool capture_output_used)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
int set_stream_delay_ms(int delay) override; int set_stream_delay_ms(int delay) override;
void set_stream_key_pressed(bool key_pressed) override; void set_stream_key_pressed(bool key_pressed) override;
void set_stream_analog_level(int level) override; void set_stream_analog_level(int level) override;
@ -166,7 +169,9 @@ class AudioProcessingImpl : public AudioProcessing {
explicit RuntimeSettingEnqueuer( explicit RuntimeSettingEnqueuer(
SwapQueue<RuntimeSetting>* runtime_settings); SwapQueue<RuntimeSetting>* runtime_settings);
~RuntimeSettingEnqueuer(); ~RuntimeSettingEnqueuer();
void Enqueue(RuntimeSetting setting);
// Enqueue setting and return whether the setting was successfully enqueued.
bool Enqueue(RuntimeSetting setting);
private: private:
SwapQueue<RuntimeSetting>& runtime_settings_; SwapQueue<RuntimeSetting>& runtime_settings_;
@ -421,7 +426,7 @@ class AudioProcessingImpl : public AudioProcessing {
ApmCaptureState(); ApmCaptureState();
~ApmCaptureState(); ~ApmCaptureState();
bool was_stream_delay_set; bool was_stream_delay_set;
bool output_will_be_muted; bool capture_output_used;
bool key_pressed; bool key_pressed;
std::unique_ptr<AudioBuffer> capture_audio; std::unique_ptr<AudioBuffer> capture_audio;
std::unique_ptr<AudioBuffer> capture_fullband_audio; std::unique_ptr<AudioBuffer> capture_fullband_audio;

View File

@ -525,12 +525,18 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface {
// Set to true when the output of AudioProcessing will be muted or in some // Set to true when the output of AudioProcessing will be muted or in some
// other way not used. Ideally, the captured audio would still be processed, // other way not used. Ideally, the captured audio would still be processed,
// but some components may change behavior based on this information. // but some components may change behavior based on this information.
// Default false. // Default false. This method takes a lock. To achieve this in a lock-less
// manner the PostRuntimeSetting can instead be used.
virtual void set_output_will_be_muted(bool muted) = 0; virtual void set_output_will_be_muted(bool muted) = 0;
// Enqueue a runtime setting. // Enqueues a runtime setting.
virtual void SetRuntimeSetting(RuntimeSetting setting) = 0; virtual void SetRuntimeSetting(RuntimeSetting setting) = 0;
// Enqueues a runtime setting. Returns a bool indicating whether the
// enqueueing was successfull.
// TODO(b/177830919): Change this to pure virtual.
virtual bool PostRuntimeSetting(RuntimeSetting setting) { return false; }
// Accepts and produces a 10 ms frame interleaved 16 bit integer audio as // Accepts and produces a 10 ms frame interleaved 16 bit integer audio as
// specified in |input_config| and |output_config|. |src| and |dest| may use // specified in |input_config| and |output_config|. |src| and |dest| may use
// the same memory, if desired. // the same memory, if desired.

View File

@ -96,6 +96,7 @@ class MockAudioProcessing : public AudioProcessing {
MOCK_METHOD(size_t, num_reverse_channels, (), (const, override)); MOCK_METHOD(size_t, num_reverse_channels, (), (const, override));
MOCK_METHOD(void, set_output_will_be_muted, (bool muted), (override)); MOCK_METHOD(void, set_output_will_be_muted, (bool muted), (override));
MOCK_METHOD(void, SetRuntimeSetting, (RuntimeSetting setting), (override)); MOCK_METHOD(void, SetRuntimeSetting, (RuntimeSetting setting), (override));
MOCK_METHOD(bool, PostRuntimeSetting, (RuntimeSetting setting), (override));
MOCK_METHOD(int, MOCK_METHOD(int,
ProcessStream, ProcessStream,
(const int16_t* const src, (const int16_t* const src,