diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 367586910d..267929a0dd 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -168,7 +168,7 @@ AudioProcessingImpl::AudioProcessingImpl(const Config& config, rtc::CritScope cs_capture(&crit_capture_); public_submodules_->echo_cancellation.reset( - new EchoCancellationImpl(this, &crit_render_, &crit_capture_)); + new EchoCancellationImpl(&crit_render_, &crit_capture_)); public_submodules_->echo_control_mobile.reset( new EchoControlMobileImpl(&crit_render_, &crit_capture_)); public_submodules_->gain_control.reset( @@ -658,6 +658,12 @@ int AudioProcessingImpl::ProcessStream(AudioFrame* frame) { } int AudioProcessingImpl::ProcessStreamLocked() { + // Ensure that not both the AEC and AECM are active at the same time. + // TODO(peah): Simplify once the public API Enable functions for these + // are moved to APM. + RTC_DCHECK(!(public_submodules_->echo_cancellation->is_enabled() && + public_submodules_->echo_control_mobile->is_enabled())); + #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP if (debug_dump_.debug_file->Open()) { audioproc::Stream* msg = debug_dump_.capture.event_msg->mutable_stream(); @@ -694,7 +700,16 @@ int AudioProcessingImpl::ProcessStreamLocked() { public_submodules_->high_pass_filter->ProcessCaptureAudio(ca); RETURN_ON_ERR(public_submodules_->gain_control->AnalyzeCaptureAudio(ca)); public_submodules_->noise_suppression->AnalyzeCaptureAudio(ca); - RETURN_ON_ERR(public_submodules_->echo_cancellation->ProcessCaptureAudio(ca)); + + // Ensure that the stream delay was set before the call to the + // AEC ProcessCaptureAudio function. + if (public_submodules_->echo_cancellation->is_enabled() && + !was_stream_delay_set()) { + return AudioProcessing::kStreamParameterNotSetError; + } + + RETURN_ON_ERR(public_submodules_->echo_cancellation->ProcessCaptureAudio( + ca, stream_delay_ms())); if (public_submodules_->echo_control_mobile->is_enabled() && public_submodules_->noise_suppression->is_enabled()) { @@ -1227,7 +1242,9 @@ void AudioProcessingImpl::InitializeNoiseSuppression() { } void AudioProcessingImpl::InitializeEchoCanceller() { - public_submodules_->echo_cancellation->Initialize(); + public_submodules_->echo_cancellation->Initialize( + proc_sample_rate_hz(), num_reverse_channels(), num_output_channels(), + num_proc_channels()); } void AudioProcessingImpl::InitializeGainController() { diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.cc b/webrtc/modules/audio_processing/echo_cancellation_impl.cc index 44a5a0c773..a323736a56 100644 --- a/webrtc/modules/audio_processing/echo_cancellation_impl.cc +++ b/webrtc/modules/audio_processing/echo_cancellation_impl.cc @@ -57,6 +57,23 @@ static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; static const size_t kMaxNumFramesToBuffer = 100; } // namespace +struct EchoCancellationImpl::StreamProperties { + StreamProperties() = delete; + StreamProperties(int sample_rate_hz, + size_t num_reverse_channels, + size_t num_output_channels, + size_t num_proc_channels) + : sample_rate_hz(sample_rate_hz), + num_reverse_channels(num_reverse_channels), + num_output_channels(num_output_channels), + num_proc_channels(num_proc_channels) {} + + const int sample_rate_hz; + const size_t num_reverse_channels; + const size_t num_output_channels; + const size_t num_proc_channels; +}; + class EchoCancellationImpl::Canceller { public: Canceller() { @@ -83,11 +100,9 @@ class EchoCancellationImpl::Canceller { void* state_; }; -EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, - rtc::CriticalSection* crit_render, +EchoCancellationImpl::EchoCancellationImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture) - : apm_(apm), - crit_render_(crit_render), + : crit_render_(crit_render), crit_capture_(crit_capture), drift_compensation_enabled_(false), metrics_enabled_(false), @@ -100,7 +115,6 @@ EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, delay_agnostic_enabled_(false), aec3_enabled_(false), render_queue_element_max_size_(0) { - RTC_DCHECK(apm); RTC_DCHECK(crit_render); RTC_DCHECK(crit_capture); } @@ -113,17 +127,19 @@ int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { return AudioProcessing::kNoError; } + RTC_DCHECK(stream_properties_); RTC_DCHECK_GE(160u, audio->num_frames_per_band()); - RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels()); - RTC_DCHECK_GE(cancellers_.size(), - apm_->num_output_channels() * audio->num_channels()); + RTC_DCHECK_EQ(audio->num_channels(), + stream_properties_->num_reverse_channels); + RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_output_channels * + audio->num_channels()); int err = AudioProcessing::kNoError; // The ordering convention must be followed to pass to the correct AEC. size_t handle_index = 0; render_queue_buffer_.clear(); - for (size_t i = 0; i < apm_->num_output_channels(); i++) { + for (size_t i = 0; i < stream_properties_->num_output_channels; i++) { for (size_t j = 0; j < audio->num_channels(); j++) { // Retrieve any error code produced by the buffering of the farend // signal. @@ -164,14 +180,16 @@ void EchoCancellationImpl::ReadQueuedRenderData() { return; } + RTC_DCHECK(stream_properties_); while (render_signal_queue_->Remove(&capture_queue_buffer_)) { size_t handle_index = 0; size_t buffer_index = 0; const size_t num_frames_per_band = capture_queue_buffer_.size() / - (apm_->num_output_channels() * apm_->num_reverse_channels()); - for (size_t i = 0; i < apm_->num_output_channels(); i++) { - for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { + (stream_properties_->num_output_channels * + stream_properties_->num_reverse_channels); + for (size_t i = 0; i < stream_properties_->num_output_channels; i++) { + for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) { WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(), &capture_queue_buffer_[buffer_index], num_frames_per_band); @@ -182,22 +200,20 @@ void EchoCancellationImpl::ReadQueuedRenderData() { } } -int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { +int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio, + int stream_delay_ms) { rtc::CritScope cs_capture(crit_capture_); if (!enabled_) { return AudioProcessing::kNoError; } - if (!apm_->was_stream_delay_set()) { - return AudioProcessing::kStreamParameterNotSetError; - } - if (drift_compensation_enabled_ && !was_stream_drift_set_) { return AudioProcessing::kStreamParameterNotSetError; } + RTC_DCHECK(stream_properties_); RTC_DCHECK_GE(160u, audio->num_frames_per_band()); - RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels()); + RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_proc_channels); int err = AudioProcessing::kNoError; @@ -205,12 +221,11 @@ int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { size_t handle_index = 0; stream_has_echo_ = false; for (size_t i = 0; i < audio->num_channels(); i++) { - for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { - err = WebRtcAec_Process(cancellers_[handle_index]->state(), - audio->split_bands_const_f(i), audio->num_bands(), - audio->split_bands_f(i), - audio->num_frames_per_band(), - apm_->stream_delay_ms(), stream_drift_samples_); + for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) { + err = WebRtcAec_Process( + cancellers_[handle_index]->state(), audio->split_bands_const_f(i), + audio->num_bands(), audio->split_bands_f(i), + audio->num_frames_per_band(), stream_delay_ms, stream_drift_samples_); if (err != AudioProcessing::kNoError) { err = MapError(err); @@ -243,16 +258,17 @@ int EchoCancellationImpl::Enable(bool enable) { // Run in a single-threaded manner. rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); - // Ensure AEC and AECM are not both enabled. - // The is_enabled call is safe from a deadlock perspective - // as both locks are already held in the correct order. - if (enable && apm_->echo_control_mobile()->is_enabled()) { - return AudioProcessing::kBadParameterError; - } if (enable && !enabled_) { enabled_ = enable; // Must be set before Initialize() is called. - Initialize(); + + // TODO(peah): Simplify once the Enable function has been removed from + // the public APM API. + RTC_DCHECK(stream_properties_); + Initialize(stream_properties_->sample_rate_hz, + stream_properties_->num_reverse_channels, + stream_properties_->num_output_channels, + stream_properties_->num_proc_channels); } else { enabled_ = enable; } @@ -433,23 +449,30 @@ struct AecCore* EchoCancellationImpl::aec_core() const { return WebRtcAec_aec_core(cancellers_[0]->state()); } -void EchoCancellationImpl::Initialize() { +void EchoCancellationImpl::Initialize(int sample_rate_hz, + size_t num_reverse_channels, + size_t num_output_channels, + size_t num_proc_channels) { rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); + + stream_properties_.reset( + new StreamProperties(sample_rate_hz, num_reverse_channels, + num_output_channels, num_proc_channels)); + if (!enabled_) { return; } - if (num_handles_required() > cancellers_.size()) { + if (NumCancellersRequired() > cancellers_.size()) { const size_t cancellers_old_size = cancellers_.size(); - cancellers_.resize(num_handles_required()); + cancellers_.resize(NumCancellersRequired()); for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { cancellers_[i].reset(new Canceller()); } } - const int sample_rate_hz = apm_->proc_sample_rate_hz(); for (auto& canceller : cancellers_) { canceller->Initialize(sample_rate_hz); } @@ -470,7 +493,7 @@ int EchoCancellationImpl::GetSystemDelayInSamples() const { void EchoCancellationImpl::AllocateRenderQueue() { const size_t new_render_queue_element_max_size = std::max( static_cast(1), - kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); + kMaxAllowedValuesOfSamplesPerFrame * NumCancellersRequired()); rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); @@ -529,9 +552,10 @@ int EchoCancellationImpl::Configure() { return error; } -size_t EchoCancellationImpl::num_handles_required() const { - // Not locked as it only relies on APM public API which is threadsafe. - return apm_->num_output_channels() * apm_->num_reverse_channels(); +size_t EchoCancellationImpl::NumCancellersRequired() const { + RTC_DCHECK(stream_properties_); + return stream_properties_->num_output_channels * + stream_properties_->num_reverse_channels; } } // namespace webrtc diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.h b/webrtc/modules/audio_processing/echo_cancellation_impl.h index dccef332a3..f196bcab3a 100644 --- a/webrtc/modules/audio_processing/echo_cancellation_impl.h +++ b/webrtc/modules/audio_processing/echo_cancellation_impl.h @@ -25,13 +25,12 @@ class AudioBuffer; class EchoCancellationImpl : public EchoCancellation { public: - EchoCancellationImpl(const AudioProcessing* apm, - rtc::CriticalSection* crit_render, + EchoCancellationImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture); virtual ~EchoCancellationImpl(); int ProcessRenderAudio(const AudioBuffer* audio); - int ProcessCaptureAudio(AudioBuffer* audio); + int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms); // EchoCancellation implementation. bool is_enabled() const override; @@ -39,7 +38,10 @@ class EchoCancellationImpl : public EchoCancellation { SuppressionLevel suppression_level() const override; bool is_drift_compensation_enabled() const override; - void Initialize(); + void Initialize(int sample_rate_hz, + size_t num_reverse_channels_, + size_t num_output_channels_, + size_t num_proc_channels_); void SetExtraOptions(const Config& config); bool is_delay_agnostic_enabled() const; bool is_extended_filter_enabled() const; @@ -54,6 +56,7 @@ class EchoCancellationImpl : public EchoCancellation { private: class Canceller; + struct StreamProperties; // EchoCancellation implementation. int Enable(bool enable) override; @@ -73,14 +76,11 @@ class EchoCancellationImpl : public EchoCancellation { struct AecCore* aec_core() const override; - size_t num_handles_required() const; + size_t NumCancellersRequired() const; void AllocateRenderQueue(); int Configure(); - // Not guarded as its public API is thread safe. - const AudioProcessing* apm_; - rtc::CriticalSection* const crit_render_ ACQUIRED_BEFORE(crit_capture_); rtc::CriticalSection* const crit_capture_; @@ -106,6 +106,8 @@ class EchoCancellationImpl : public EchoCancellation { render_signal_queue_; std::vector> cancellers_; + std::unique_ptr stream_properties_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoCancellationImpl); };