blob: 75bfb20a9002ff41a3c435b1576b434ae41f637c [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org40654032012-01-30 20:51:15 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000011#include "webrtc/modules/audio_processing/audio_processing_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
ajm@google.com808e0e02011-08-03 21:08:51 +000013#include <assert.h>
Michael Graczyk86c6d332015-07-23 11:41:39 -070014#include <algorithm>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
Bjorn Volcker1ca324f2015-06-29 14:57:29 +020016#include "webrtc/base/checks.h"
xians@webrtc.orge46bc772014-10-10 08:36:56 +000017#include "webrtc/base/platform_file.h"
ekmeyerson60d9b332015-08-14 10:35:55 -070018#include "webrtc/common_audio/audio_converter.h"
Michael Graczykdfa36052015-03-25 16:37:27 -070019#include "webrtc/common_audio/channel_buffer.h"
ekmeyerson60d9b332015-08-14 10:35:55 -070020#include "webrtc/common_audio/include/audio_util.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000021#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
Bjorn Volcker1ca324f2015-06-29 14:57:29 +020022extern "C" {
23#include "webrtc/modules/audio_processing/aec/aec_core.h"
24}
pbos@webrtc.org788acd12014-12-15 09:41:24 +000025#include "webrtc/modules/audio_processing/agc/agc_manager_direct.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000026#include "webrtc/modules/audio_processing/audio_buffer.h"
mgraczyk@chromium.org0f663de2015-03-13 00:13:32 +000027#include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000028#include "webrtc/modules/audio_processing/common.h"
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000029#include "webrtc/modules/audio_processing/echo_cancellation_impl.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000030#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
31#include "webrtc/modules/audio_processing/gain_control_impl.h"
32#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
ekmeyerson60d9b332015-08-14 10:35:55 -070033#include "webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000034#include "webrtc/modules/audio_processing/level_estimator_impl.h"
35#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
36#include "webrtc/modules/audio_processing/processing_component.h"
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +000037#include "webrtc/modules/audio_processing/transient/transient_suppressor.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000038#include "webrtc/modules/audio_processing/voice_detection_impl.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010039#include "webrtc/modules/include/module_common_types.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010040#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
41#include "webrtc/system_wrappers/include/file_wrapper.h"
42#include "webrtc/system_wrappers/include/logging.h"
43#include "webrtc/system_wrappers/include/metrics.h"
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000044
45#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
46// Files generated at build-time by the protobuf compiler.
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000047#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000048#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000049#else
ajm@google.com808e0e02011-08-03 21:08:51 +000050#include "webrtc/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000051#endif
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000052#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000053
Michael Graczyk86c6d332015-07-23 11:41:39 -070054#define RETURN_ON_ERR(expr) \
55 do { \
56 int err = (expr); \
57 if (err != kNoError) { \
58 return err; \
59 } \
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000060 } while (0)
61
niklase@google.com470e71d2011-07-07 08:21:25 +000062namespace webrtc {
Michael Graczyk86c6d332015-07-23 11:41:39 -070063namespace {
64
65static bool LayoutHasKeyboard(AudioProcessing::ChannelLayout layout) {
66 switch (layout) {
67 case AudioProcessing::kMono:
68 case AudioProcessing::kStereo:
69 return false;
70 case AudioProcessing::kMonoAndKeyboard:
71 case AudioProcessing::kStereoAndKeyboard:
72 return true;
73 }
74
75 assert(false);
76 return false;
77}
78
79} // namespace
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000080
81// Throughout webrtc, it's assumed that success is represented by zero.
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +000082static_assert(AudioProcessing::kNoError == 0, "kNoError must be zero");
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000083
pbos@webrtc.org788acd12014-12-15 09:41:24 +000084// This class has two main functionalities:
85//
86// 1) It is returned instead of the real GainControl after the new AGC has been
87// enabled in order to prevent an outside user from overriding compression
88// settings. It doesn't do anything in its implementation, except for
89// delegating the const methods and Enable calls to the real GainControl, so
90// AGC can still be disabled.
91//
92// 2) It is injected into AgcManagerDirect and implements volume callbacks for
93// getting and setting the volume level. It just caches this value to be used
94// in VoiceEngine later.
95class GainControlForNewAgc : public GainControl, public VolumeCallbacks {
96 public:
97 explicit GainControlForNewAgc(GainControlImpl* gain_control)
Michael Graczyk86c6d332015-07-23 11:41:39 -070098 : real_gain_control_(gain_control), volume_(0) {}
pbos@webrtc.org788acd12014-12-15 09:41:24 +000099
100 // GainControl implementation.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000101 int Enable(bool enable) override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000102 return real_gain_control_->Enable(enable);
103 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000104 bool is_enabled() const override { return real_gain_control_->is_enabled(); }
105 int set_stream_analog_level(int level) override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000106 volume_ = level;
107 return AudioProcessing::kNoError;
108 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000109 int stream_analog_level() override { return volume_; }
110 int set_mode(Mode mode) override { return AudioProcessing::kNoError; }
111 Mode mode() const override { return GainControl::kAdaptiveAnalog; }
112 int set_target_level_dbfs(int level) override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000113 return AudioProcessing::kNoError;
114 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000115 int target_level_dbfs() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000116 return real_gain_control_->target_level_dbfs();
117 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000118 int set_compression_gain_db(int gain) override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000119 return AudioProcessing::kNoError;
120 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000121 int compression_gain_db() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000122 return real_gain_control_->compression_gain_db();
123 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000124 int enable_limiter(bool enable) override { return AudioProcessing::kNoError; }
125 bool is_limiter_enabled() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000126 return real_gain_control_->is_limiter_enabled();
127 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000128 int set_analog_level_limits(int minimum, int maximum) override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000129 return AudioProcessing::kNoError;
130 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000131 int analog_level_minimum() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000132 return real_gain_control_->analog_level_minimum();
133 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000134 int analog_level_maximum() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000135 return real_gain_control_->analog_level_maximum();
136 }
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000137 bool stream_is_saturated() const override {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000138 return real_gain_control_->stream_is_saturated();
139 }
140
141 // VolumeCallbacks implementation.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000142 void SetMicVolume(int volume) override { volume_ = volume; }
143 int GetMicVolume() override { return volume_; }
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000144
145 private:
146 GainControl* real_gain_control_;
147 int volume_;
148};
149
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700150const int AudioProcessing::kNativeSampleRatesHz[] = {
151 AudioProcessing::kSampleRate8kHz,
152 AudioProcessing::kSampleRate16kHz,
153 AudioProcessing::kSampleRate32kHz,
154 AudioProcessing::kSampleRate48kHz};
155const size_t AudioProcessing::kNumNativeSampleRates =
156 arraysize(AudioProcessing::kNativeSampleRatesHz);
157const int AudioProcessing::kMaxNativeSampleRateHz = AudioProcessing::
158 kNativeSampleRatesHz[AudioProcessing::kNumNativeSampleRates - 1];
159const int AudioProcessing::kMaxAECMSampleRateHz = kSampleRate16kHz;
160
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000161AudioProcessing* AudioProcessing::Create() {
162 Config config;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000163 return Create(config, nullptr);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000164}
165
166AudioProcessing* AudioProcessing::Create(const Config& config) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000167 return Create(config, nullptr);
168}
169
170AudioProcessing* AudioProcessing::Create(const Config& config,
Michael Graczykdfa36052015-03-25 16:37:27 -0700171 Beamformer<float>* beamformer) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000172 AudioProcessingImpl* apm = new AudioProcessingImpl(config, beamformer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 if (apm->Initialize() != kNoError) {
174 delete apm;
175 apm = NULL;
176 }
177
178 return apm;
179}
180
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000181AudioProcessingImpl::AudioProcessingImpl(const Config& config)
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000182 : AudioProcessingImpl(config, nullptr) {}
183
184AudioProcessingImpl::AudioProcessingImpl(const Config& config,
Michael Graczykdfa36052015-03-25 16:37:27 -0700185 Beamformer<float>* beamformer)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000186 : echo_cancellation_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 echo_control_mobile_(NULL),
188 gain_control_(NULL),
189 high_pass_filter_(NULL),
190 level_estimator_(NULL),
191 noise_suppression_(NULL),
192 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 crit_(CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000194#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
195 debug_file_(FileWrapper::Create()),
196 event_msg_(new audioproc::Event()),
197#endif
aluebs@webrtc.org27d106b2014-12-11 17:09:21 +0000198 fwd_proc_format_(kSampleRate16kHz),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000199 rev_proc_format_(kSampleRate16kHz, 1),
200 split_rate_(kSampleRate16kHz),
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000202 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 was_stream_delay_set_(false),
Bjorn Volcker1ca324f2015-06-29 14:57:29 +0200204 last_stream_delay_ms_(0),
205 last_aec_system_delay_ms_(0),
Bjorn Volcker4e7aa432015-07-07 11:50:05 +0200206 stream_delay_jumps_(-1),
207 aec_system_delay_jumps_(-1),
andrew@webrtc.org38bf2492014-02-13 17:43:44 +0000208 output_will_be_muted_(false),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000209 key_pressed_(false),
210#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
211 use_new_agc_(false),
212#else
213 use_new_agc_(config.Get<ExperimentalAgc>().enabled),
214#endif
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200215 agc_startup_min_volume_(config.Get<ExperimentalAgc>().startup_min_volume),
andrew1c7075f2015-06-24 18:14:14 -0700216#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
217 transient_suppressor_enabled_(false),
218#else
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000219 transient_suppressor_enabled_(config.Get<ExperimentalNs>().enabled),
andrew1c7075f2015-06-24 18:14:14 -0700220#endif
aluebs@webrtc.orgfb7a0392015-01-05 21:58:58 +0000221 beamformer_enabled_(config.Get<Beamforming>().enabled),
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000222 beamformer_(beamformer),
ekmeyerson60d9b332015-08-14 10:35:55 -0700223 array_geometry_(config.Get<Beamforming>().array_geometry),
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700224 target_direction_(config.Get<Beamforming>().target_direction),
ekmeyerson60d9b332015-08-14 10:35:55 -0700225 intelligibility_enabled_(config.Get<Intelligibility>().enabled) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000226 echo_cancellation_ = new EchoCancellationImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 component_list_.push_back(echo_cancellation_);
228
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000229 echo_control_mobile_ = new EchoControlMobileImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000230 component_list_.push_back(echo_control_mobile_);
231
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000232 gain_control_ = new GainControlImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 component_list_.push_back(gain_control_);
234
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000235 high_pass_filter_ = new HighPassFilterImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 component_list_.push_back(high_pass_filter_);
237
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000238 level_estimator_ = new LevelEstimatorImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 component_list_.push_back(level_estimator_);
240
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000241 noise_suppression_ = new NoiseSuppressionImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 component_list_.push_back(noise_suppression_);
243
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000244 voice_detection_ = new VoiceDetectionImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 component_list_.push_back(voice_detection_);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000246
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000247 gain_control_for_new_agc_.reset(new GainControlForNewAgc(gain_control_));
248
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000249 SetExtraOptions(config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000250}
251
252AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000253 {
254 CriticalSectionScoped crit_scoped(crit_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000255 // Depends on gain_control_ and gain_control_for_new_agc_.
256 agc_manager_.reset();
257 // Depends on gain_control_.
258 gain_control_for_new_agc_.reset();
andrew@webrtc.org81865342012-10-27 00:28:27 +0000259 while (!component_list_.empty()) {
260 ProcessingComponent* component = component_list_.front();
261 component->Destroy();
262 delete component;
263 component_list_.pop_front();
264 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000265
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000266#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000267 if (debug_file_->Open()) {
268 debug_file_->CloseFile();
269 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000270#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 }
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000272 delete crit_;
273 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274}
275
niklase@google.com470e71d2011-07-07 08:21:25 +0000276int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000277 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 return InitializeLocked();
279}
280
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000281int AudioProcessingImpl::Initialize(int input_sample_rate_hz,
282 int output_sample_rate_hz,
283 int reverse_sample_rate_hz,
284 ChannelLayout input_layout,
285 ChannelLayout output_layout,
286 ChannelLayout reverse_layout) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700287 const ProcessingConfig processing_config = {
ekmeyerson60d9b332015-08-14 10:35:55 -0700288 {{input_sample_rate_hz,
289 ChannelsFromLayout(input_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700290 LayoutHasKeyboard(input_layout)},
ekmeyerson60d9b332015-08-14 10:35:55 -0700291 {output_sample_rate_hz,
292 ChannelsFromLayout(output_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700293 LayoutHasKeyboard(output_layout)},
ekmeyerson60d9b332015-08-14 10:35:55 -0700294 {reverse_sample_rate_hz,
295 ChannelsFromLayout(reverse_layout),
296 LayoutHasKeyboard(reverse_layout)},
297 {reverse_sample_rate_hz,
298 ChannelsFromLayout(reverse_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700299 LayoutHasKeyboard(reverse_layout)}}};
300
301 return Initialize(processing_config);
302}
303
304int AudioProcessingImpl::Initialize(const ProcessingConfig& processing_config) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000305 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700306 return InitializeLocked(processing_config);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000307}
308
peah81b9bfe2015-11-27 02:47:28 -0800309int AudioProcessingImpl::MaybeInitializeLockedRender(
310 const ProcessingConfig& processing_config) {
311 return MaybeInitializeLocked(processing_config);
312}
313
314int AudioProcessingImpl::MaybeInitializeLockedCapture(
315 const ProcessingConfig& processing_config) {
316 return MaybeInitializeLocked(processing_config);
317}
318
peah192164e2015-11-17 02:16:45 -0800319// Calls InitializeLocked() if any of the audio parameters have changed from
320// their current values.
321int AudioProcessingImpl::MaybeInitializeLocked(
322 const ProcessingConfig& processing_config) {
323 if (processing_config == shared_state_.api_format_) {
324 return kNoError;
325 }
326 return InitializeLocked(processing_config);
327}
328
niklase@google.com470e71d2011-07-07 08:21:25 +0000329int AudioProcessingImpl::InitializeLocked() {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700330 const int fwd_audio_buffer_channels =
peah192164e2015-11-17 02:16:45 -0800331 beamformer_enabled_
332 ? shared_state_.api_format_.input_stream().num_channels()
333 : shared_state_.api_format_.output_stream().num_channels();
ekmeyerson60d9b332015-08-14 10:35:55 -0700334 const int rev_audio_buffer_out_num_frames =
peah192164e2015-11-17 02:16:45 -0800335 shared_state_.api_format_.reverse_output_stream().num_frames() == 0
ekmeyerson60d9b332015-08-14 10:35:55 -0700336 ? rev_proc_format_.num_frames()
peah192164e2015-11-17 02:16:45 -0800337 : shared_state_.api_format_.reverse_output_stream().num_frames();
338 if (shared_state_.api_format_.reverse_input_stream().num_channels() > 0) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700339 render_audio_.reset(new AudioBuffer(
peah192164e2015-11-17 02:16:45 -0800340 shared_state_.api_format_.reverse_input_stream().num_frames(),
341 shared_state_.api_format_.reverse_input_stream().num_channels(),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700342 rev_proc_format_.num_frames(), rev_proc_format_.num_channels(),
ekmeyerson60d9b332015-08-14 10:35:55 -0700343 rev_audio_buffer_out_num_frames));
344 if (rev_conversion_needed()) {
345 render_converter_ = AudioConverter::Create(
peah192164e2015-11-17 02:16:45 -0800346 shared_state_.api_format_.reverse_input_stream().num_channels(),
347 shared_state_.api_format_.reverse_input_stream().num_frames(),
348 shared_state_.api_format_.reverse_output_stream().num_channels(),
349 shared_state_.api_format_.reverse_output_stream().num_frames());
ekmeyerson60d9b332015-08-14 10:35:55 -0700350 } else {
351 render_converter_.reset(nullptr);
352 }
Michael Graczyk86c6d332015-07-23 11:41:39 -0700353 } else {
354 render_audio_.reset(nullptr);
ekmeyerson60d9b332015-08-14 10:35:55 -0700355 render_converter_.reset(nullptr);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700356 }
peah192164e2015-11-17 02:16:45 -0800357 capture_audio_.reset(
358 new AudioBuffer(shared_state_.api_format_.input_stream().num_frames(),
359 shared_state_.api_format_.input_stream().num_channels(),
360 fwd_proc_format_.num_frames(), fwd_audio_buffer_channels,
361 shared_state_.api_format_.output_stream().num_frames()));
niklase@google.com470e71d2011-07-07 08:21:25 +0000362
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 // Initialize all components.
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000364 for (auto item : component_list_) {
365 int err = item->Initialize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000366 if (err != kNoError) {
367 return err;
368 }
369 }
370
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200371 InitializeExperimentalAgc();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000372
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200373 InitializeTransient();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000374
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000375 InitializeBeamformer();
376
ekmeyerson60d9b332015-08-14 10:35:55 -0700377 InitializeIntelligibility();
378
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000379#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000380 if (debug_file_->Open()) {
381 int err = WriteInitMessage();
382 if (err != kNoError) {
383 return err;
384 }
385 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000386#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000387
niklase@google.com470e71d2011-07-07 08:21:25 +0000388 return kNoError;
389}
390
Michael Graczyk86c6d332015-07-23 11:41:39 -0700391int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) {
peah81b9bfe2015-11-27 02:47:28 -0800392 // TODO(peah): Refactor to be allowed to verify using thread annotations.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700393 for (const auto& stream : config.streams) {
394 if (stream.num_channels() < 0) {
395 return kBadNumberChannelsError;
396 }
397 if (stream.num_channels() > 0 && stream.sample_rate_hz() <= 0) {
398 return kBadSampleRateError;
399 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000400 }
Michael Graczyk86c6d332015-07-23 11:41:39 -0700401
402 const int num_in_channels = config.input_stream().num_channels();
403 const int num_out_channels = config.output_stream().num_channels();
404
405 // Need at least one input channel.
406 // Need either one output channel or as many outputs as there are inputs.
407 if (num_in_channels == 0 ||
408 !(num_out_channels == 1 || num_out_channels == num_in_channels)) {
Michael Graczykc2047542015-07-22 21:06:11 -0700409 return kBadNumberChannelsError;
410 }
411
Michael Graczyk86c6d332015-07-23 11:41:39 -0700412 if (beamformer_enabled_ &&
413 (static_cast<size_t>(num_in_channels) != array_geometry_.size() ||
414 num_out_channels > 1)) {
415 return kBadNumberChannelsError;
416 }
417
peah192164e2015-11-17 02:16:45 -0800418 shared_state_.api_format_ = config;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000419
420 // We process at the closest native rate >= min(input rate, output rate)...
Michael Graczyk86c6d332015-07-23 11:41:39 -0700421 const int min_proc_rate =
peah192164e2015-11-17 02:16:45 -0800422 std::min(shared_state_.api_format_.input_stream().sample_rate_hz(),
423 shared_state_.api_format_.output_stream().sample_rate_hz());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000424 int fwd_proc_rate;
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700425 for (size_t i = 0; i < kNumNativeSampleRates; ++i) {
426 fwd_proc_rate = kNativeSampleRatesHz[i];
427 if (fwd_proc_rate >= min_proc_rate) {
428 break;
429 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000430 }
431 // ...with one exception.
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700432 if (echo_control_mobile_->is_enabled() &&
433 min_proc_rate > kMaxAECMSampleRateHz) {
434 fwd_proc_rate = kMaxAECMSampleRateHz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000435 }
436
Michael Graczyk86c6d332015-07-23 11:41:39 -0700437 fwd_proc_format_ = StreamConfig(fwd_proc_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000438
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000439 // We normally process the reverse stream at 16 kHz. Unless...
440 int rev_proc_rate = kSampleRate16kHz;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700441 if (fwd_proc_format_.sample_rate_hz() == kSampleRate8kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000442 // ...the forward stream is at 8 kHz.
443 rev_proc_rate = kSampleRate8kHz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000444 } else {
peah192164e2015-11-17 02:16:45 -0800445 if (shared_state_.api_format_.reverse_input_stream().sample_rate_hz() ==
ekmeyerson60d9b332015-08-14 10:35:55 -0700446 kSampleRate32kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000447 // ...or the input is at 32 kHz, in which case we use the splitting
448 // filter rather than the resampler.
449 rev_proc_rate = kSampleRate32kHz;
450 }
451 }
452
andrew@webrtc.org30be8272014-09-24 20:06:23 +0000453 // Always downmix the reverse stream to mono for analysis. This has been
454 // demonstrated to work well for AEC in most practical scenarios.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700455 rev_proc_format_ = StreamConfig(rev_proc_rate, 1);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000456
Michael Graczyk86c6d332015-07-23 11:41:39 -0700457 if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
458 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000459 split_rate_ = kSampleRate16kHz;
460 } else {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700461 split_rate_ = fwd_proc_format_.sample_rate_hz();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000462 }
463
464 return InitializeLocked();
465}
466
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000467void AudioProcessingImpl::SetExtraOptions(const Config& config) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000468 CriticalSectionScoped crit_scoped(crit_);
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000469 for (auto item : component_list_) {
470 item->SetExtraOptions(config);
471 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000472
473 if (transient_suppressor_enabled_ != config.Get<ExperimentalNs>().enabled) {
474 transient_suppressor_enabled_ = config.Get<ExperimentalNs>().enabled;
475 InitializeTransient();
476 }
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000477}
478
andrew@webrtc.org46b31b12014-04-23 03:33:54 +0000479
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000480int AudioProcessingImpl::proc_sample_rate_hz() const {
peah81b9bfe2015-11-27 02:47:28 -0800481 // TODO(peah): Refactor to be allowed to verify using thread annotations.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700482 return fwd_proc_format_.sample_rate_hz();
niklase@google.com470e71d2011-07-07 08:21:25 +0000483}
484
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000485int AudioProcessingImpl::proc_split_sample_rate_hz() const {
peah81b9bfe2015-11-27 02:47:28 -0800486 // TODO(peah): Refactor to be allowed to verify using thread annotations.
487
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000488 return split_rate_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000489}
490
491int AudioProcessingImpl::num_reverse_channels() const {
peah81b9bfe2015-11-27 02:47:28 -0800492 // TODO(peah): Refactor to be allowed to verify using thread annotations.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000493 return rev_proc_format_.num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000494}
495
496int AudioProcessingImpl::num_input_channels() const {
peah192164e2015-11-17 02:16:45 -0800497 return shared_state_.api_format_.input_stream().num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000498}
499
500int AudioProcessingImpl::num_output_channels() const {
peah81b9bfe2015-11-27 02:47:28 -0800501 // TODO(peah): Refactor to be allowed to verify using thread annotations.
peah192164e2015-11-17 02:16:45 -0800502 return shared_state_.api_format_.output_stream().num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000503}
504
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000505void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000506 CriticalSectionScoped lock(crit_);
Bjorn Volcker424694c2015-03-27 11:30:43 +0100507 output_will_be_muted_ = muted;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000508 if (agc_manager_.get()) {
509 agc_manager_->SetCaptureMuted(output_will_be_muted_);
510 }
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000511}
512
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000513
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000514int AudioProcessingImpl::ProcessStream(const float* const* src,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700515 size_t samples_per_channel,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000516 int input_sample_rate_hz,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000517 ChannelLayout input_layout,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000518 int output_sample_rate_hz,
519 ChannelLayout output_layout,
520 float* const* dest) {
Michael Graczyk4bc66fc2015-08-10 15:26:38 -0700521 CriticalSectionScoped crit_scoped(crit_);
peah192164e2015-11-17 02:16:45 -0800522 StreamConfig input_stream = shared_state_.api_format_.input_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700523 input_stream.set_sample_rate_hz(input_sample_rate_hz);
524 input_stream.set_num_channels(ChannelsFromLayout(input_layout));
525 input_stream.set_has_keyboard(LayoutHasKeyboard(input_layout));
526
peah192164e2015-11-17 02:16:45 -0800527 StreamConfig output_stream = shared_state_.api_format_.output_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700528 output_stream.set_sample_rate_hz(output_sample_rate_hz);
529 output_stream.set_num_channels(ChannelsFromLayout(output_layout));
530 output_stream.set_has_keyboard(LayoutHasKeyboard(output_layout));
531
532 if (samples_per_channel != input_stream.num_frames()) {
533 return kBadDataLengthError;
534 }
535 return ProcessStream(src, input_stream, output_stream, dest);
536}
537
538int AudioProcessingImpl::ProcessStream(const float* const* src,
539 const StreamConfig& input_config,
540 const StreamConfig& output_config,
541 float* const* dest) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000542 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000543 if (!src || !dest) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 return kNullPointerError;
545 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000546
peahfa6228e2015-11-16 16:27:42 -0800547 echo_cancellation_->ReadQueuedRenderData();
548 echo_control_mobile_->ReadQueuedRenderData();
peah4d291f72015-11-16 23:52:25 -0800549 gain_control_->ReadQueuedRenderData();
peahfa6228e2015-11-16 16:27:42 -0800550
peah192164e2015-11-17 02:16:45 -0800551 ProcessingConfig processing_config = shared_state_.api_format_;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700552 processing_config.input_stream() = input_config;
553 processing_config.output_stream() = output_config;
554
peah81b9bfe2015-11-27 02:47:28 -0800555 RETURN_ON_ERR(MaybeInitializeLockedCapture(processing_config));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700556 assert(processing_config.input_stream().num_frames() ==
peah192164e2015-11-17 02:16:45 -0800557 shared_state_.api_format_.input_stream().num_frames());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000558
559#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
560 if (debug_file_->Open()) {
Minyue13b96ba2015-10-03 00:39:14 +0200561 RETURN_ON_ERR(WriteConfigMessage(false));
562
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000563 event_msg_->set_type(audioproc::Event::STREAM);
564 audioproc::Stream* msg = event_msg_->mutable_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000565 const size_t channel_size =
peah192164e2015-11-17 02:16:45 -0800566 sizeof(float) * shared_state_.api_format_.input_stream().num_frames();
567 for (int i = 0; i < shared_state_.api_format_.input_stream().num_channels();
568 ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000569 msg->add_input_channel(src[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000570 }
571#endif
572
peah192164e2015-11-17 02:16:45 -0800573 capture_audio_->CopyFrom(src, shared_state_.api_format_.input_stream());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000574 RETURN_ON_ERR(ProcessStreamLocked());
peah192164e2015-11-17 02:16:45 -0800575 capture_audio_->CopyTo(shared_state_.api_format_.output_stream(), dest);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000576
577#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
578 if (debug_file_->Open()) {
579 audioproc::Stream* msg = event_msg_->mutable_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000580 const size_t channel_size =
peah192164e2015-11-17 02:16:45 -0800581 sizeof(float) * shared_state_.api_format_.output_stream().num_frames();
582 for (int i = 0;
583 i < shared_state_.api_format_.output_stream().num_channels(); ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000584 msg->add_output_channel(dest[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000585 RETURN_ON_ERR(WriteMessageToDebugFile());
586 }
587#endif
588
589 return kNoError;
590}
591
592int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
593 CriticalSectionScoped crit_scoped(crit_);
peahfa6228e2015-11-16 16:27:42 -0800594 echo_cancellation_->ReadQueuedRenderData();
595 echo_control_mobile_->ReadQueuedRenderData();
peah4d291f72015-11-16 23:52:25 -0800596 gain_control_->ReadQueuedRenderData();
peahfa6228e2015-11-16 16:27:42 -0800597
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000598 if (!frame) {
599 return kNullPointerError;
600 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000601 // Must be a native rate.
602 if (frame->sample_rate_hz_ != kSampleRate8kHz &&
603 frame->sample_rate_hz_ != kSampleRate16kHz &&
aluebs@webrtc.org087da132014-11-17 23:01:23 +0000604 frame->sample_rate_hz_ != kSampleRate32kHz &&
605 frame->sample_rate_hz_ != kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000606 return kBadSampleRateError;
607 }
peah192164e2015-11-17 02:16:45 -0800608
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000609 if (echo_control_mobile_->is_enabled() &&
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700610 frame->sample_rate_hz_ > kMaxAECMSampleRateHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000611 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
612 return kUnsupportedComponentError;
613 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000614
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000615 // TODO(ajm): The input and output rates and channels are currently
616 // constrained to be identical in the int16 interface.
peah192164e2015-11-17 02:16:45 -0800617 ProcessingConfig processing_config = shared_state_.api_format_;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700618 processing_config.input_stream().set_sample_rate_hz(frame->sample_rate_hz_);
619 processing_config.input_stream().set_num_channels(frame->num_channels_);
620 processing_config.output_stream().set_sample_rate_hz(frame->sample_rate_hz_);
621 processing_config.output_stream().set_num_channels(frame->num_channels_);
622
peah81b9bfe2015-11-27 02:47:28 -0800623 RETURN_ON_ERR(MaybeInitializeLockedCapture(processing_config));
peah192164e2015-11-17 02:16:45 -0800624 if (frame->samples_per_channel_ !=
625 shared_state_.api_format_.input_stream().num_frames()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 return kBadDataLengthError;
627 }
628
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000629#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000631 event_msg_->set_type(audioproc::Event::STREAM);
632 audioproc::Stream* msg = event_msg_->mutable_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700633 const size_t data_size =
634 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000635 msg->set_input_data(frame->data_, data_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000636 }
637#endif
638
639 capture_audio_->DeinterleaveFrom(frame);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000640 RETURN_ON_ERR(ProcessStreamLocked());
641 capture_audio_->InterleaveTo(frame, output_copy_needed(is_data_processed()));
642
643#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
644 if (debug_file_->Open()) {
645 audioproc::Stream* msg = event_msg_->mutable_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700646 const size_t data_size =
647 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000648 msg->set_output_data(frame->data_, data_size);
649 RETURN_ON_ERR(WriteMessageToDebugFile());
650 }
651#endif
652
653 return kNoError;
654}
655
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000656int AudioProcessingImpl::ProcessStreamLocked() {
657#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
658 if (debug_file_->Open()) {
659 audioproc::Stream* msg = event_msg_->mutable_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000660 msg->set_delay(stream_delay_ms_);
661 msg->set_drift(echo_cancellation_->stream_drift_samples());
bjornv@webrtc.org63da1dd2015-02-06 19:44:21 +0000662 msg->set_level(gain_control()->stream_analog_level());
andrew@webrtc.orgce8e0772014-02-12 15:28:30 +0000663 msg->set_keypress(key_pressed_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000665#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000666
Bjorn Volcker1ca324f2015-06-29 14:57:29 +0200667 MaybeUpdateHistograms();
668
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000669 AudioBuffer* ca = capture_audio_.get(); // For brevity.
ekmeyerson60d9b332015-08-14 10:35:55 -0700670
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000671 if (use_new_agc_ && gain_control_->is_enabled()) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700672 agc_manager_->AnalyzePreProcess(ca->channels()[0], ca->num_channels(),
673 fwd_proc_format_.num_frames());
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000674 }
675
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000676 bool data_processed = is_data_processed();
677 if (analysis_needed(data_processed)) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000678 ca->SplitIntoFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 }
680
ekmeyerson60d9b332015-08-14 10:35:55 -0700681 if (intelligibility_enabled_) {
682 intelligibility_enhancer_->AnalyzeCaptureAudio(
683 ca->split_channels_f(kBand0To8kHz), split_rate_, ca->num_channels());
684 }
685
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000686 if (beamformer_enabled_) {
Michael Graczykdfa36052015-03-25 16:37:27 -0700687 beamformer_->ProcessChunk(*ca->split_data_f(), ca->split_data_f());
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000688 ca->set_num_channels(1);
689 }
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000690
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000691 RETURN_ON_ERR(high_pass_filter_->ProcessCaptureAudio(ca));
692 RETURN_ON_ERR(gain_control_->AnalyzeCaptureAudio(ca));
aluebs@webrtc.orga0ce9fa2014-09-24 14:18:03 +0000693 RETURN_ON_ERR(noise_suppression_->AnalyzeCaptureAudio(ca));
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000694 RETURN_ON_ERR(echo_cancellation_->ProcessCaptureAudio(ca));
niklase@google.com470e71d2011-07-07 08:21:25 +0000695
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000696 if (echo_control_mobile_->is_enabled() && noise_suppression_->is_enabled()) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000697 ca->CopyLowPassToReference();
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000699 RETURN_ON_ERR(noise_suppression_->ProcessCaptureAudio(ca));
700 RETURN_ON_ERR(echo_control_mobile_->ProcessCaptureAudio(ca));
701 RETURN_ON_ERR(voice_detection_->ProcessCaptureAudio(ca));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000702
Michael Graczyk86c6d332015-07-23 11:41:39 -0700703 if (use_new_agc_ && gain_control_->is_enabled() &&
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000704 (!beamformer_enabled_ || beamformer_->is_target_present())) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000705 agc_manager_->Process(ca->split_bands_const(0)[kBand0To8kHz],
Michael Graczyk86c6d332015-07-23 11:41:39 -0700706 ca->num_frames_per_band(), split_rate_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000707 }
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000708 RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca));
niklase@google.com470e71d2011-07-07 08:21:25 +0000709
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000710 if (synthesis_needed(data_processed)) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000711 ca->MergeFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 }
713
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000714 // TODO(aluebs): Investigate if the transient suppression placement should be
715 // before or after the AGC.
716 if (transient_suppressor_enabled_) {
717 float voice_probability =
718 agc_manager_.get() ? agc_manager_->voice_probability() : 1.f;
719
Michael Graczyk86c6d332015-07-23 11:41:39 -0700720 transient_suppressor_->Suppress(
721 ca->channels_f()[0], ca->num_frames(), ca->num_channels(),
722 ca->split_bands_const_f(0)[kBand0To8kHz], ca->num_frames_per_band(),
723 ca->keyboard_data(), ca->num_keyboard_frames(), voice_probability,
724 key_pressed_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000725 }
726
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000727 // The level estimator operates on the recombined data.
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000728 RETURN_ON_ERR(level_estimator_->ProcessStream(ca));
ajm@google.com808e0e02011-08-03 21:08:51 +0000729
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000730 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 return kNoError;
732}
733
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000734int AudioProcessingImpl::AnalyzeReverseStream(const float* const* data,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700735 size_t samples_per_channel,
ekmeyerson60d9b332015-08-14 10:35:55 -0700736 int rev_sample_rate_hz,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000737 ChannelLayout layout) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700738 const StreamConfig reverse_config = {
ekmeyerson60d9b332015-08-14 10:35:55 -0700739 rev_sample_rate_hz, ChannelsFromLayout(layout), LayoutHasKeyboard(layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700740 };
741 if (samples_per_channel != reverse_config.num_frames()) {
742 return kBadDataLengthError;
743 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700744 return AnalyzeReverseStream(data, reverse_config, reverse_config);
745}
746
747int AudioProcessingImpl::ProcessReverseStream(
748 const float* const* src,
749 const StreamConfig& reverse_input_config,
750 const StreamConfig& reverse_output_config,
751 float* const* dest) {
752 RETURN_ON_ERR(
753 AnalyzeReverseStream(src, reverse_input_config, reverse_output_config));
754 if (is_rev_processed()) {
peah192164e2015-11-17 02:16:45 -0800755 render_audio_->CopyTo(shared_state_.api_format_.reverse_output_stream(),
756 dest);
peah81b9bfe2015-11-27 02:47:28 -0800757 } else if (render_check_rev_conversion_needed()) {
ekmeyerson60d9b332015-08-14 10:35:55 -0700758 render_converter_->Convert(src, reverse_input_config.num_samples(), dest,
759 reverse_output_config.num_samples());
760 } else {
761 CopyAudioIfNeeded(src, reverse_input_config.num_frames(),
762 reverse_input_config.num_channels(), dest);
763 }
764
765 return kNoError;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700766}
767
768int AudioProcessingImpl::AnalyzeReverseStream(
ekmeyerson60d9b332015-08-14 10:35:55 -0700769 const float* const* src,
770 const StreamConfig& reverse_input_config,
771 const StreamConfig& reverse_output_config) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000772 CriticalSectionScoped crit_scoped(crit_);
ekmeyerson60d9b332015-08-14 10:35:55 -0700773 if (src == NULL) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000774 return kNullPointerError;
775 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000776
ekmeyerson60d9b332015-08-14 10:35:55 -0700777 if (reverse_input_config.num_channels() <= 0) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700778 return kBadNumberChannelsError;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000779 }
780
peah192164e2015-11-17 02:16:45 -0800781 ProcessingConfig processing_config = shared_state_.api_format_;
ekmeyerson60d9b332015-08-14 10:35:55 -0700782 processing_config.reverse_input_stream() = reverse_input_config;
783 processing_config.reverse_output_stream() = reverse_output_config;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700784
peah81b9bfe2015-11-27 02:47:28 -0800785 RETURN_ON_ERR(MaybeInitializeLockedRender(processing_config));
ekmeyerson60d9b332015-08-14 10:35:55 -0700786 assert(reverse_input_config.num_frames() ==
peah192164e2015-11-17 02:16:45 -0800787 shared_state_.api_format_.reverse_input_stream().num_frames());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700788
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000789#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
790 if (debug_file_->Open()) {
791 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
792 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000793 const size_t channel_size =
peah192164e2015-11-17 02:16:45 -0800794 sizeof(float) *
795 shared_state_.api_format_.reverse_input_stream().num_frames();
796 for (int i = 0;
797 i < shared_state_.api_format_.reverse_input_stream().num_channels();
798 ++i)
ekmeyerson60d9b332015-08-14 10:35:55 -0700799 msg->add_channel(src[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000800 RETURN_ON_ERR(WriteMessageToDebugFile());
801 }
802#endif
803
peah192164e2015-11-17 02:16:45 -0800804 render_audio_->CopyFrom(src,
805 shared_state_.api_format_.reverse_input_stream());
ekmeyerson60d9b332015-08-14 10:35:55 -0700806 return ProcessReverseStreamLocked();
807}
808
809int AudioProcessingImpl::ProcessReverseStream(AudioFrame* frame) {
810 RETURN_ON_ERR(AnalyzeReverseStream(frame));
811 if (is_rev_processed()) {
812 render_audio_->InterleaveTo(frame, true);
813 }
814
815 return kNoError;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000816}
817
niklase@google.com470e71d2011-07-07 08:21:25 +0000818int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000819 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000820 if (frame == NULL) {
821 return kNullPointerError;
822 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000823 // Must be a native rate.
824 if (frame->sample_rate_hz_ != kSampleRate8kHz &&
825 frame->sample_rate_hz_ != kSampleRate16kHz &&
aluebs@webrtc.org087da132014-11-17 23:01:23 +0000826 frame->sample_rate_hz_ != kSampleRate32kHz &&
827 frame->sample_rate_hz_ != kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000828 return kBadSampleRateError;
829 }
830 // This interface does not tolerate different forward and reverse rates.
peah192164e2015-11-17 02:16:45 -0800831 if (frame->sample_rate_hz_ !=
832 shared_state_.api_format_.input_stream().sample_rate_hz()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 return kBadSampleRateError;
834 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000835
Michael Graczyk86c6d332015-07-23 11:41:39 -0700836 if (frame->num_channels_ <= 0) {
837 return kBadNumberChannelsError;
838 }
839
peah192164e2015-11-17 02:16:45 -0800840 ProcessingConfig processing_config = shared_state_.api_format_;
ekmeyerson60d9b332015-08-14 10:35:55 -0700841 processing_config.reverse_input_stream().set_sample_rate_hz(
842 frame->sample_rate_hz_);
843 processing_config.reverse_input_stream().set_num_channels(
844 frame->num_channels_);
845 processing_config.reverse_output_stream().set_sample_rate_hz(
846 frame->sample_rate_hz_);
847 processing_config.reverse_output_stream().set_num_channels(
848 frame->num_channels_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700849
peah81b9bfe2015-11-27 02:47:28 -0800850 RETURN_ON_ERR(MaybeInitializeLockedRender(processing_config));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700851 if (frame->samples_per_channel_ !=
peah192164e2015-11-17 02:16:45 -0800852 shared_state_.api_format_.reverse_input_stream().num_frames()) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000853 return kBadDataLengthError;
854 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000855
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000856#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000857 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000858 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
859 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700860 const size_t data_size =
861 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000862 msg->set_data(frame->data_, data_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000863 RETURN_ON_ERR(WriteMessageToDebugFile());
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000865#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 render_audio_->DeinterleaveFrom(frame);
ekmeyerson60d9b332015-08-14 10:35:55 -0700867 return ProcessReverseStreamLocked();
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000868}
niklase@google.com470e71d2011-07-07 08:21:25 +0000869
ekmeyerson60d9b332015-08-14 10:35:55 -0700870int AudioProcessingImpl::ProcessReverseStreamLocked() {
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000871 AudioBuffer* ra = render_audio_.get(); // For brevity.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700872 if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000873 ra->SplitIntoFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 }
875
ekmeyerson60d9b332015-08-14 10:35:55 -0700876 if (intelligibility_enabled_) {
877 intelligibility_enhancer_->ProcessRenderAudio(
878 ra->split_channels_f(kBand0To8kHz), split_rate_, ra->num_channels());
879 }
880
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000881 RETURN_ON_ERR(echo_cancellation_->ProcessRenderAudio(ra));
882 RETURN_ON_ERR(echo_control_mobile_->ProcessRenderAudio(ra));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000883 if (!use_new_agc_) {
884 RETURN_ON_ERR(gain_control_->ProcessRenderAudio(ra));
885 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000886
ekmeyerson60d9b332015-08-14 10:35:55 -0700887 if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz &&
888 is_rev_processed()) {
889 ra->MergeFrequencyBands();
890 }
891
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000892 return kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000893}
894
895int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000896 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000898 delay += delay_offset_ms_;
899
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000901 delay = 0;
902 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 }
904
905 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
906 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000907 delay = 500;
908 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 }
910
911 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000912 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000913}
914
915int AudioProcessingImpl::stream_delay_ms() const {
916 return stream_delay_ms_;
917}
918
919bool AudioProcessingImpl::was_stream_delay_set() const {
920 return was_stream_delay_set_;
921}
922
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000923void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
924 key_pressed_ = key_pressed;
925}
926
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000927void AudioProcessingImpl::set_delay_offset_ms(int offset) {
928 CriticalSectionScoped crit_scoped(crit_);
929 delay_offset_ms_ = offset;
930}
931
932int AudioProcessingImpl::delay_offset_ms() const {
933 return delay_offset_ms_;
934}
935
niklase@google.com470e71d2011-07-07 08:21:25 +0000936int AudioProcessingImpl::StartDebugRecording(
937 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000938 CriticalSectionScoped crit_scoped(crit_);
André Susano Pinto664cdaf2015-05-20 11:11:07 +0200939 static_assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize, "");
niklase@google.com470e71d2011-07-07 08:21:25 +0000940
941 if (filename == NULL) {
942 return kNullPointerError;
943 }
944
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000945#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 // Stop any ongoing recording.
947 if (debug_file_->Open()) {
948 if (debug_file_->CloseFile() == -1) {
949 return kFileError;
950 }
951 }
952
953 if (debug_file_->OpenFile(filename, false) == -1) {
954 debug_file_->CloseFile();
955 return kFileError;
956 }
957
Minyue13b96ba2015-10-03 00:39:14 +0200958 RETURN_ON_ERR(WriteConfigMessage(true));
959 RETURN_ON_ERR(WriteInitMessage());
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000961#else
962 return kUnsupportedFunctionError;
963#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000964}
965
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000966int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
967 CriticalSectionScoped crit_scoped(crit_);
968
969 if (handle == NULL) {
970 return kNullPointerError;
971 }
972
973#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
974 // Stop any ongoing recording.
975 if (debug_file_->Open()) {
976 if (debug_file_->CloseFile() == -1) {
977 return kFileError;
978 }
979 }
980
981 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
982 return kFileError;
983 }
984
Minyue13b96ba2015-10-03 00:39:14 +0200985 RETURN_ON_ERR(WriteConfigMessage(true));
986 RETURN_ON_ERR(WriteInitMessage());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000987 return kNoError;
988#else
989 return kUnsupportedFunctionError;
990#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
991}
992
xians@webrtc.orge46bc772014-10-10 08:36:56 +0000993int AudioProcessingImpl::StartDebugRecordingForPlatformFile(
994 rtc::PlatformFile handle) {
995 FILE* stream = rtc::FdopenPlatformFileForWriting(handle);
996 return StartDebugRecording(stream);
997}
998
niklase@google.com470e71d2011-07-07 08:21:25 +0000999int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +00001000 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001001
1002#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 // We just return if recording hasn't started.
1004 if (debug_file_->Open()) {
1005 if (debug_file_->CloseFile() == -1) {
1006 return kFileError;
1007 }
1008 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001010#else
1011 return kUnsupportedFunctionError;
1012#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001013}
1014
1015EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
1016 return echo_cancellation_;
1017}
1018
1019EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
1020 return echo_control_mobile_;
1021}
1022
1023GainControl* AudioProcessingImpl::gain_control() const {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001024 if (use_new_agc_) {
1025 return gain_control_for_new_agc_.get();
1026 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 return gain_control_;
1028}
1029
1030HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
1031 return high_pass_filter_;
1032}
1033
1034LevelEstimator* AudioProcessingImpl::level_estimator() const {
1035 return level_estimator_;
1036}
1037
1038NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
1039 return noise_suppression_;
1040}
1041
1042VoiceDetection* AudioProcessingImpl::voice_detection() const {
1043 return voice_detection_;
1044}
1045
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001046bool AudioProcessingImpl::is_data_processed() const {
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001047 if (beamformer_enabled_) {
1048 return true;
1049 }
1050
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001051 int enabled_count = 0;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +00001052 for (auto item : component_list_) {
1053 if (item->is_component_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001054 enabled_count++;
1055 }
1056 }
1057
1058 // Data is unchanged if no components are enabled, or if only level_estimator_
1059 // or voice_detection_ is enabled.
1060 if (enabled_count == 0) {
1061 return false;
1062 } else if (enabled_count == 1) {
1063 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
1064 return false;
1065 }
1066 } else if (enabled_count == 2) {
1067 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
1068 return false;
1069 }
1070 }
1071 return true;
1072}
1073
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001074bool AudioProcessingImpl::output_copy_needed(bool is_data_processed) const {
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001075 // Check if we've upmixed or downmixed the audio.
peah192164e2015-11-17 02:16:45 -08001076 return ((shared_state_.api_format_.output_stream().num_channels() !=
1077 shared_state_.api_format_.input_stream().num_channels()) ||
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001078 is_data_processed || transient_suppressor_enabled_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001079}
1080
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001081bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
Michael Graczyk86c6d332015-07-23 11:41:39 -07001082 return (is_data_processed &&
1083 (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
1084 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz));
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001085}
1086
1087bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001088 if (!is_data_processed && !voice_detection_->is_enabled() &&
1089 !transient_suppressor_enabled_) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001090 // Only level_estimator_ is enabled.
1091 return false;
Michael Graczyk86c6d332015-07-23 11:41:39 -07001092 } else if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
1093 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001094 // Something besides level_estimator_ is enabled, and we have super-wb.
1095 return true;
1096 }
1097 return false;
1098}
1099
ekmeyerson60d9b332015-08-14 10:35:55 -07001100bool AudioProcessingImpl::is_rev_processed() const {
1101 return intelligibility_enabled_ && intelligibility_enhancer_->active();
1102}
1103
peah81b9bfe2015-11-27 02:47:28 -08001104bool AudioProcessingImpl::render_check_rev_conversion_needed() const {
1105 return rev_conversion_needed();
1106}
1107
ekmeyerson60d9b332015-08-14 10:35:55 -07001108bool AudioProcessingImpl::rev_conversion_needed() const {
peah81b9bfe2015-11-27 02:47:28 -08001109 // TODO(peah): Refactor to be allowed to verify using thread annotations.
peah192164e2015-11-17 02:16:45 -08001110 return (shared_state_.api_format_.reverse_input_stream() !=
1111 shared_state_.api_format_.reverse_output_stream());
ekmeyerson60d9b332015-08-14 10:35:55 -07001112}
1113
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001114void AudioProcessingImpl::InitializeExperimentalAgc() {
peah81b9bfe2015-11-27 02:47:28 -08001115 // TODO(peah): Refactor to be allowed to verify using thread annotations.
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001116 if (use_new_agc_) {
1117 if (!agc_manager_.get()) {
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001118 agc_manager_.reset(new AgcManagerDirect(gain_control_,
1119 gain_control_for_new_agc_.get(),
1120 agc_startup_min_volume_));
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001121 }
1122 agc_manager_->Initialize();
1123 agc_manager_->SetCaptureMuted(output_will_be_muted_);
1124 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001125}
1126
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001127void AudioProcessingImpl::InitializeTransient() {
peah81b9bfe2015-11-27 02:47:28 -08001128 // TODO(peah): Refactor to be allowed to verify using thread annotations.
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001129 if (transient_suppressor_enabled_) {
1130 if (!transient_suppressor_.get()) {
1131 transient_suppressor_.reset(new TransientSuppressor());
1132 }
Michael Graczyk86c6d332015-07-23 11:41:39 -07001133 transient_suppressor_->Initialize(
1134 fwd_proc_format_.sample_rate_hz(), split_rate_,
peah192164e2015-11-17 02:16:45 -08001135 shared_state_.api_format_.output_stream().num_channels());
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001136 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001137}
1138
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001139void AudioProcessingImpl::InitializeBeamformer() {
peah81b9bfe2015-11-27 02:47:28 -08001140 // TODO(peah): Refactor to be allowed to verify using thread annotations.
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001141 if (beamformer_enabled_) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +00001142 if (!beamformer_) {
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -07001143 beamformer_.reset(
1144 new NonlinearBeamformer(array_geometry_, target_direction_));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +00001145 }
1146 beamformer_->Initialize(kChunkSizeMs, split_rate_);
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001147 }
1148}
1149
ekmeyerson60d9b332015-08-14 10:35:55 -07001150void AudioProcessingImpl::InitializeIntelligibility() {
peah81b9bfe2015-11-27 02:47:28 -08001151 // TODO(peah): Refactor to be allowed to verify using thread annotations.
ekmeyerson60d9b332015-08-14 10:35:55 -07001152 if (intelligibility_enabled_) {
1153 IntelligibilityEnhancer::Config config;
1154 config.sample_rate_hz = split_rate_;
1155 config.num_capture_channels = capture_audio_->num_channels();
1156 config.num_render_channels = render_audio_->num_channels();
1157 intelligibility_enhancer_.reset(new IntelligibilityEnhancer(config));
1158 }
1159}
1160
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001161void AudioProcessingImpl::MaybeUpdateHistograms() {
Bjorn Volckerd92f2672015-07-05 10:46:01 +02001162 static const int kMinDiffDelayMs = 60;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001163
1164 if (echo_cancellation()->is_enabled()) {
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001165 // Activate delay_jumps_ counters if we know echo_cancellation is runnning.
1166 // If a stream has echo we know that the echo_cancellation is in process.
1167 if (stream_delay_jumps_ == -1 && echo_cancellation()->stream_has_echo()) {
1168 stream_delay_jumps_ = 0;
1169 }
1170 if (aec_system_delay_jumps_ == -1 &&
1171 echo_cancellation()->stream_has_echo()) {
1172 aec_system_delay_jumps_ = 0;
1173 }
1174
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001175 // Detect a jump in platform reported system delay and log the difference.
1176 const int diff_stream_delay_ms = stream_delay_ms_ - last_stream_delay_ms_;
1177 if (diff_stream_delay_ms > kMinDiffDelayMs && last_stream_delay_ms_ != 0) {
1178 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.PlatformReportedStreamDelayJump",
1179 diff_stream_delay_ms, kMinDiffDelayMs, 1000, 100);
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001180 if (stream_delay_jumps_ == -1) {
1181 stream_delay_jumps_ = 0; // Activate counter if needed.
1182 }
1183 stream_delay_jumps_++;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001184 }
1185 last_stream_delay_ms_ = stream_delay_ms_;
1186
1187 // Detect a jump in AEC system delay and log the difference.
1188 const int frames_per_ms = rtc::CheckedDivExact(split_rate_, 1000);
1189 const int aec_system_delay_ms =
1190 WebRtcAec_system_delay(echo_cancellation()->aec_core()) / frames_per_ms;
Michael Graczyk86c6d332015-07-23 11:41:39 -07001191 const int diff_aec_system_delay_ms =
1192 aec_system_delay_ms - last_aec_system_delay_ms_;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001193 if (diff_aec_system_delay_ms > kMinDiffDelayMs &&
1194 last_aec_system_delay_ms_ != 0) {
1195 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecSystemDelayJump",
1196 diff_aec_system_delay_ms, kMinDiffDelayMs, 1000,
1197 100);
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001198 if (aec_system_delay_jumps_ == -1) {
1199 aec_system_delay_jumps_ = 0; // Activate counter if needed.
1200 }
1201 aec_system_delay_jumps_++;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001202 }
1203 last_aec_system_delay_ms_ = aec_system_delay_ms;
1204 }
1205}
1206
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001207void AudioProcessingImpl::UpdateHistogramsOnCallEnd() {
1208 CriticalSectionScoped crit_scoped(crit_);
1209 if (stream_delay_jumps_ > -1) {
1210 RTC_HISTOGRAM_ENUMERATION(
1211 "WebRTC.Audio.NumOfPlatformReportedStreamDelayJumps",
1212 stream_delay_jumps_, 51);
1213 }
1214 stream_delay_jumps_ = -1;
1215 last_stream_delay_ms_ = 0;
1216
1217 if (aec_system_delay_jumps_ > -1) {
1218 RTC_HISTOGRAM_ENUMERATION("WebRTC.Audio.NumOfAecSystemDelayJumps",
1219 aec_system_delay_jumps_, 51);
1220 }
1221 aec_system_delay_jumps_ = -1;
1222 last_aec_system_delay_ms_ = 0;
1223}
1224
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001225#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +00001226int AudioProcessingImpl::WriteMessageToDebugFile() {
1227 int32_t size = event_msg_->ByteSize();
1228 if (size <= 0) {
1229 return kUnspecifiedError;
1230 }
andrew@webrtc.org621df672013-10-22 10:27:23 +00001231#if defined(WEBRTC_ARCH_BIG_ENDIAN)
Michael Graczyk86c6d332015-07-23 11:41:39 -07001232// TODO(ajm): Use little-endian "on the wire". For the moment, we can be
1233// pretty safe in assuming little-endian.
ajm@google.com808e0e02011-08-03 21:08:51 +00001234#endif
1235
1236 if (!event_msg_->SerializeToString(&event_str_)) {
1237 return kUnspecifiedError;
1238 }
1239
1240 // Write message preceded by its size.
1241 if (!debug_file_->Write(&size, sizeof(int32_t))) {
1242 return kFileError;
1243 }
1244 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
1245 return kFileError;
1246 }
1247
1248 event_msg_->Clear();
1249
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001250 return kNoError;
ajm@google.com808e0e02011-08-03 21:08:51 +00001251}
1252
1253int AudioProcessingImpl::WriteInitMessage() {
peah81b9bfe2015-11-27 02:47:28 -08001254 // TODO(peah): Refactor to be allowed to verify using thread annotations.
ajm@google.com808e0e02011-08-03 21:08:51 +00001255 event_msg_->set_type(audioproc::Event::INIT);
1256 audioproc::Init* msg = event_msg_->mutable_init();
peah192164e2015-11-17 02:16:45 -08001257 msg->set_sample_rate(
1258 shared_state_.api_format_.input_stream().sample_rate_hz());
1259 msg->set_num_input_channels(
1260 shared_state_.api_format_.input_stream().num_channels());
1261 msg->set_num_output_channels(
1262 shared_state_.api_format_.output_stream().num_channels());
ekmeyerson60d9b332015-08-14 10:35:55 -07001263 msg->set_num_reverse_channels(
peah192164e2015-11-17 02:16:45 -08001264 shared_state_.api_format_.reverse_input_stream().num_channels());
ekmeyerson60d9b332015-08-14 10:35:55 -07001265 msg->set_reverse_sample_rate(
peah192164e2015-11-17 02:16:45 -08001266 shared_state_.api_format_.reverse_input_stream().sample_rate_hz());
1267 msg->set_output_sample_rate(
1268 shared_state_.api_format_.output_stream().sample_rate_hz());
ekmeyerson60d9b332015-08-14 10:35:55 -07001269 // TODO(ekmeyerson): Add reverse output fields to event_msg_.
ajm@google.com808e0e02011-08-03 21:08:51 +00001270
Minyue13b96ba2015-10-03 00:39:14 +02001271 RETURN_ON_ERR(WriteMessageToDebugFile());
1272 return kNoError;
1273}
1274
1275int AudioProcessingImpl::WriteConfigMessage(bool forced) {
1276 audioproc::Config config;
1277
1278 config.set_aec_enabled(echo_cancellation_->is_enabled());
1279 config.set_aec_delay_agnostic_enabled(
1280 echo_cancellation_->is_delay_agnostic_enabled());
1281 config.set_aec_drift_compensation_enabled(
1282 echo_cancellation_->is_drift_compensation_enabled());
1283 config.set_aec_extended_filter_enabled(
1284 echo_cancellation_->is_extended_filter_enabled());
1285 config.set_aec_suppression_level(
1286 static_cast<int>(echo_cancellation_->suppression_level()));
1287
1288 config.set_aecm_enabled(echo_control_mobile_->is_enabled());
1289 config.set_aecm_comfort_noise_enabled(
1290 echo_control_mobile_->is_comfort_noise_enabled());
1291 config.set_aecm_routing_mode(
1292 static_cast<int>(echo_control_mobile_->routing_mode()));
1293
1294 config.set_agc_enabled(gain_control_->is_enabled());
1295 config.set_agc_mode(static_cast<int>(gain_control_->mode()));
1296 config.set_agc_limiter_enabled(gain_control_->is_limiter_enabled());
1297 config.set_noise_robust_agc_enabled(use_new_agc_);
1298
1299 config.set_hpf_enabled(high_pass_filter_->is_enabled());
1300
1301 config.set_ns_enabled(noise_suppression_->is_enabled());
1302 config.set_ns_level(static_cast<int>(noise_suppression_->level()));
1303
1304 config.set_transient_suppression_enabled(transient_suppressor_enabled_);
1305
1306 std::string serialized_config = config.SerializeAsString();
1307 if (!forced && last_serialized_config_ == serialized_config) {
1308 return kNoError;
ajm@google.com808e0e02011-08-03 21:08:51 +00001309 }
1310
Minyue13b96ba2015-10-03 00:39:14 +02001311 last_serialized_config_ = serialized_config;
1312
1313 event_msg_->set_type(audioproc::Event::CONFIG);
1314 event_msg_->mutable_config()->CopyFrom(config);
1315
1316 RETURN_ON_ERR(WriteMessageToDebugFile());
ajm@google.com808e0e02011-08-03 21:08:51 +00001317 return kNoError;
1318}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001319#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001320
niklase@google.com470e71d2011-07-07 08:21:25 +00001321} // namespace webrtc