diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 32ebb0a7c0..367586910d 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -170,7 +170,7 @@ AudioProcessingImpl::AudioProcessingImpl(const Config& config, public_submodules_->echo_cancellation.reset( new EchoCancellationImpl(this, &crit_render_, &crit_capture_)); public_submodules_->echo_control_mobile.reset( - new EchoControlMobileImpl(this, &crit_render_, &crit_capture_)); + new EchoControlMobileImpl(&crit_render_, &crit_capture_)); public_submodules_->gain_control.reset( new GainControlImpl(&crit_capture_, &crit_capture_)); public_submodules_->high_pass_filter.reset( @@ -706,8 +706,17 @@ int AudioProcessingImpl::ProcessStreamLocked() { public_submodules_->intelligibility_enhancer->SetCaptureNoiseEstimate( public_submodules_->noise_suppression->NoiseEstimate()); } - RETURN_ON_ERR( - public_submodules_->echo_control_mobile->ProcessCaptureAudio(ca)); + + // Ensure that the stream delay was set before the call to the + // AECM ProcessCaptureAudio function. + if (public_submodules_->echo_control_mobile->is_enabled() && + !was_stream_delay_set()) { + return AudioProcessing::kStreamParameterNotSetError; + } + + RETURN_ON_ERR(public_submodules_->echo_control_mobile->ProcessCaptureAudio( + ca, stream_delay_ms())); + public_submodules_->voice_detection->ProcessCaptureAudio(ca); if (constants_.use_experimental_agc && @@ -1227,7 +1236,8 @@ void AudioProcessingImpl::InitializeGainController() { } void AudioProcessingImpl::InitializeEchoControlMobile() { - public_submodules_->echo_control_mobile->Initialize(); + public_submodules_->echo_control_mobile->Initialize( + proc_sample_rate_hz(), num_reverse_channels(), num_output_channels()); } void AudioProcessingImpl::InitializeLevelEstimator() { diff --git a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc index ad25fa2ca6..d3fe17a352 100644 --- a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc +++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc @@ -64,6 +64,20 @@ size_t EchoControlMobile::echo_path_size_bytes() { return WebRtcAecm_echo_path_size_bytes(); } +struct EchoControlMobileImpl::StreamProperties { + StreamProperties() = delete; + StreamProperties(int sample_rate_hz, + size_t num_reverse_channels, + size_t num_output_channels) + : sample_rate_hz(sample_rate_hz), + num_reverse_channels(num_reverse_channels), + num_output_channels(num_output_channels) {} + + int sample_rate_hz; + size_t num_reverse_channels; + size_t num_output_channels; +}; + class EchoControlMobileImpl::Canceller { public: Canceller() { @@ -99,17 +113,14 @@ class EchoControlMobileImpl::Canceller { RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); }; -EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm, - rtc::CriticalSection* crit_render, +EchoControlMobileImpl::EchoControlMobileImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture) - : apm_(apm), - crit_render_(crit_render), + : crit_render_(crit_render), crit_capture_(crit_capture), routing_mode_(kSpeakerphone), comfort_noise_enabled_(true), external_echo_path_(NULL), render_queue_element_max_size_(0) { - RTC_DCHECK(apm); RTC_DCHECK(crit_render); RTC_DCHECK(crit_capture); } @@ -127,10 +138,12 @@ int EchoControlMobileImpl::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 AECM. @@ -170,6 +183,7 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { // a queue. All the data chunks are buffered into the farend signal of the AEC. void EchoControlMobileImpl::ReadQueuedRenderData() { rtc::CritScope cs_capture(crit_capture_); + RTC_DCHECK(stream_properties_); if (!enabled_) { return; @@ -177,9 +191,9 @@ void EchoControlMobileImpl::ReadQueuedRenderData() { while (render_signal_queue_->Remove(&capture_queue_buffer_)) { size_t buffer_index = 0; - size_t num_frames_per_band = - capture_queue_buffer_.size() / - (apm_->num_output_channels() * apm_->num_reverse_channels()); + size_t num_frames_per_band = capture_queue_buffer_.size() / + (stream_properties_->num_output_channels * + stream_properties_->num_reverse_channels); for (auto& canceller : cancellers_) { WebRtcAecm_BufferFarend(canceller->state(), @@ -191,20 +205,18 @@ void EchoControlMobileImpl::ReadQueuedRenderData() { } } -int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { +int EchoControlMobileImpl::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; - } - + RTC_DCHECK(stream_properties_); RTC_DCHECK_GE(160u, audio->num_frames_per_band()); - RTC_DCHECK_EQ(audio->num_channels(), apm_->num_output_channels()); - RTC_DCHECK_GE(cancellers_.size(), - apm_->num_reverse_channels() * audio->num_channels()); + RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); + RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels * + audio->num_channels()); int err = AudioProcessing::kNoError; @@ -219,11 +231,11 @@ int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { noisy = clean; clean = NULL; } - for (size_t render = 0; render < apm_->num_reverse_channels(); ++render) { + for (size_t render = 0; render < stream_properties_->num_reverse_channels; + ++render) { err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, audio->split_bands(capture)[kBand0To8kHz], - audio->num_frames_per_band(), - apm_->stream_delay_ms()); + audio->num_frames_per_band(), stream_delay_ms); if (err != AudioProcessing::kNoError) { return MapError(err); @@ -239,20 +251,21 @@ int EchoControlMobileImpl::Enable(bool enable) { // Ensure AEC and AECM are not both enabled. rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); - // The is_enabled call is safe from a deadlock perspective - // as both locks are allready held in the correct order. - if (enable && apm_->echo_cancellation()->is_enabled()) { - return AudioProcessing::kBadParameterError; - } + RTC_DCHECK(stream_properties_); if (enable && - apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { + stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { return AudioProcessing::kBadSampleRateError; } 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. + Initialize(stream_properties_->sample_rate_hz, + stream_properties_->num_reverse_channels, + stream_properties_->num_output_channels); } else { enabled_ = enable; } @@ -314,7 +327,12 @@ int EchoControlMobileImpl::SetEchoPath(const void* echo_path, memcpy(external_echo_path_, echo_path, size_bytes); } - 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); return AudioProcessing::kNoError; } @@ -342,18 +360,23 @@ int EchoControlMobileImpl::GetEchoPath(void* echo_path, return AudioProcessing::kNoError; } -void EchoControlMobileImpl::Initialize() { +void EchoControlMobileImpl::Initialize(int sample_rate_hz, + size_t num_reverse_channels, + size_t num_output_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)); + if (!enabled_) { return; } - if (apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { + if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; } - int sample_rate_hz = apm_->proc_sample_rate_hz(); cancellers_.resize(num_handles_required()); for (auto& canceller : cancellers_) { if (!canceller) { @@ -412,7 +435,8 @@ int EchoControlMobileImpl::Configure() { } size_t EchoControlMobileImpl::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(); + 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_control_mobile_impl.h b/webrtc/modules/audio_processing/echo_control_mobile_impl.h index f565ab225e..b86af72fdf 100644 --- a/webrtc/modules/audio_processing/echo_control_mobile_impl.h +++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.h @@ -25,27 +25,29 @@ class AudioBuffer; class EchoControlMobileImpl : public EchoControlMobile { public: - EchoControlMobileImpl(const AudioProcessing* apm, - rtc::CriticalSection* crit_render, + EchoControlMobileImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture); virtual ~EchoControlMobileImpl(); int ProcessRenderAudio(const AudioBuffer* audio); - int ProcessCaptureAudio(AudioBuffer* audio); + int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms); // EchoControlMobile implementation. bool is_enabled() const override; RoutingMode routing_mode() const override; bool is_comfort_noise_enabled() const override; - void Initialize(); + void Initialize(int sample_rate_hz, + size_t num_reverse_channels, + size_t num_output_channels); // Reads render side data that has been queued on the render call. void ReadQueuedRenderData(); private: class Canceller; + struct StreamProperties; // EchoControlMobile implementation. int Enable(bool enable) override; @@ -59,9 +61,6 @@ class EchoControlMobileImpl : public EchoControlMobile { 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_; @@ -84,6 +83,8 @@ class EchoControlMobileImpl : public EchoControlMobile { render_signal_queue_; std::vector> cancellers_; + std::unique_ptr stream_properties_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoControlMobileImpl); }; } // namespace webrtc