blob: c9e4ddc10c5f2aa7a330dc283ea5cd114161075f [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"
39#include "webrtc/modules/interface/module_common_types.h"
40#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
41#include "webrtc/system_wrappers/interface/file_wrapper.h"
42#include "webrtc/system_wrappers/interface/logging.h"
Bjorn Volcker1ca324f2015-06-29 14:57:29 +020043#include "webrtc/system_wrappers/interface/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
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000150AudioProcessing* AudioProcessing::Create() {
151 Config config;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000152 return Create(config, nullptr);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000153}
154
155AudioProcessing* AudioProcessing::Create(const Config& config) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000156 return Create(config, nullptr);
157}
158
159AudioProcessing* AudioProcessing::Create(const Config& config,
Michael Graczykdfa36052015-03-25 16:37:27 -0700160 Beamformer<float>* beamformer) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000161 AudioProcessingImpl* apm = new AudioProcessingImpl(config, beamformer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162 if (apm->Initialize() != kNoError) {
163 delete apm;
164 apm = NULL;
165 }
166
167 return apm;
168}
169
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000170AudioProcessingImpl::AudioProcessingImpl(const Config& config)
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000171 : AudioProcessingImpl(config, nullptr) {}
172
173AudioProcessingImpl::AudioProcessingImpl(const Config& config,
Michael Graczykdfa36052015-03-25 16:37:27 -0700174 Beamformer<float>* beamformer)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000175 : echo_cancellation_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 echo_control_mobile_(NULL),
177 gain_control_(NULL),
178 high_pass_filter_(NULL),
179 level_estimator_(NULL),
180 noise_suppression_(NULL),
181 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 crit_(CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000183#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
184 debug_file_(FileWrapper::Create()),
185 event_msg_(new audioproc::Event()),
186#endif
Michael Graczyk86c6d332015-07-23 11:41:39 -0700187 api_format_({{{kSampleRate16kHz, 1, false},
188 {kSampleRate16kHz, 1, false},
ekmeyerson60d9b332015-08-14 10:35:55 -0700189 {kSampleRate16kHz, 1, false},
Michael Graczyk86c6d332015-07-23 11:41:39 -0700190 {kSampleRate16kHz, 1, false}}}),
aluebs@webrtc.org27d106b2014-12-11 17:09:21 +0000191 fwd_proc_format_(kSampleRate16kHz),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000192 rev_proc_format_(kSampleRate16kHz, 1),
193 split_rate_(kSampleRate16kHz),
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000195 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 was_stream_delay_set_(false),
Bjorn Volcker1ca324f2015-06-29 14:57:29 +0200197 last_stream_delay_ms_(0),
198 last_aec_system_delay_ms_(0),
Bjorn Volcker4e7aa432015-07-07 11:50:05 +0200199 stream_delay_jumps_(-1),
200 aec_system_delay_jumps_(-1),
andrew@webrtc.org38bf2492014-02-13 17:43:44 +0000201 output_will_be_muted_(false),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000202 key_pressed_(false),
203#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
204 use_new_agc_(false),
205#else
206 use_new_agc_(config.Get<ExperimentalAgc>().enabled),
207#endif
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200208 agc_startup_min_volume_(config.Get<ExperimentalAgc>().startup_min_volume),
andrew1c7075f2015-06-24 18:14:14 -0700209#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
210 transient_suppressor_enabled_(false),
211#else
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000212 transient_suppressor_enabled_(config.Get<ExperimentalNs>().enabled),
andrew1c7075f2015-06-24 18:14:14 -0700213#endif
aluebs@webrtc.orgfb7a0392015-01-05 21:58:58 +0000214 beamformer_enabled_(config.Get<Beamforming>().enabled),
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000215 beamformer_(beamformer),
ekmeyerson60d9b332015-08-14 10:35:55 -0700216 array_geometry_(config.Get<Beamforming>().array_geometry),
217 intelligibility_enabled_(config.Get<Intelligibility>().enabled) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000218 echo_cancellation_ = new EchoCancellationImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 component_list_.push_back(echo_cancellation_);
220
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000221 echo_control_mobile_ = new EchoControlMobileImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 component_list_.push_back(echo_control_mobile_);
223
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000224 gain_control_ = new GainControlImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 component_list_.push_back(gain_control_);
226
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000227 high_pass_filter_ = new HighPassFilterImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 component_list_.push_back(high_pass_filter_);
229
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000230 level_estimator_ = new LevelEstimatorImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 component_list_.push_back(level_estimator_);
232
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000233 noise_suppression_ = new NoiseSuppressionImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 component_list_.push_back(noise_suppression_);
235
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000236 voice_detection_ = new VoiceDetectionImpl(this, crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 component_list_.push_back(voice_detection_);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000238
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000239 gain_control_for_new_agc_.reset(new GainControlForNewAgc(gain_control_));
240
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000241 SetExtraOptions(config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000242}
243
244AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000245 {
246 CriticalSectionScoped crit_scoped(crit_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000247 // Depends on gain_control_ and gain_control_for_new_agc_.
248 agc_manager_.reset();
249 // Depends on gain_control_.
250 gain_control_for_new_agc_.reset();
andrew@webrtc.org81865342012-10-27 00:28:27 +0000251 while (!component_list_.empty()) {
252 ProcessingComponent* component = component_list_.front();
253 component->Destroy();
254 delete component;
255 component_list_.pop_front();
256 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000258#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000259 if (debug_file_->Open()) {
260 debug_file_->CloseFile();
261 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000262#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 }
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000264 delete crit_;
265 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
niklase@google.com470e71d2011-07-07 08:21:25 +0000268int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000269 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 return InitializeLocked();
271}
272
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000273int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000274 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700275
276 ProcessingConfig processing_config = api_format_;
277 processing_config.input_stream().set_sample_rate_hz(rate);
278 processing_config.output_stream().set_sample_rate_hz(rate);
279 return InitializeLocked(processing_config);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000280}
281
282int AudioProcessingImpl::Initialize(int input_sample_rate_hz,
283 int output_sample_rate_hz,
284 int reverse_sample_rate_hz,
285 ChannelLayout input_layout,
286 ChannelLayout output_layout,
287 ChannelLayout reverse_layout) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700288 const ProcessingConfig processing_config = {
ekmeyerson60d9b332015-08-14 10:35:55 -0700289 {{input_sample_rate_hz,
290 ChannelsFromLayout(input_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700291 LayoutHasKeyboard(input_layout)},
ekmeyerson60d9b332015-08-14 10:35:55 -0700292 {output_sample_rate_hz,
293 ChannelsFromLayout(output_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700294 LayoutHasKeyboard(output_layout)},
ekmeyerson60d9b332015-08-14 10:35:55 -0700295 {reverse_sample_rate_hz,
296 ChannelsFromLayout(reverse_layout),
297 LayoutHasKeyboard(reverse_layout)},
298 {reverse_sample_rate_hz,
299 ChannelsFromLayout(reverse_layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700300 LayoutHasKeyboard(reverse_layout)}}};
301
302 return Initialize(processing_config);
303}
304
305int AudioProcessingImpl::Initialize(const ProcessingConfig& processing_config) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000306 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700307 return InitializeLocked(processing_config);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000308}
309
niklase@google.com470e71d2011-07-07 08:21:25 +0000310int AudioProcessingImpl::InitializeLocked() {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700311 const int fwd_audio_buffer_channels =
312 beamformer_enabled_ ? api_format_.input_stream().num_channels()
313 : api_format_.output_stream().num_channels();
ekmeyerson60d9b332015-08-14 10:35:55 -0700314 const int rev_audio_buffer_out_num_frames =
315 api_format_.reverse_output_stream().num_frames() == 0
316 ? rev_proc_format_.num_frames()
317 : api_format_.reverse_output_stream().num_frames();
318 if (api_format_.reverse_input_stream().num_channels() > 0) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700319 render_audio_.reset(new AudioBuffer(
ekmeyerson60d9b332015-08-14 10:35:55 -0700320 api_format_.reverse_input_stream().num_frames(),
321 api_format_.reverse_input_stream().num_channels(),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700322 rev_proc_format_.num_frames(), rev_proc_format_.num_channels(),
ekmeyerson60d9b332015-08-14 10:35:55 -0700323 rev_audio_buffer_out_num_frames));
324 if (rev_conversion_needed()) {
325 render_converter_ = AudioConverter::Create(
326 api_format_.reverse_input_stream().num_channels(),
327 api_format_.reverse_input_stream().num_frames(),
328 api_format_.reverse_output_stream().num_channels(),
329 api_format_.reverse_output_stream().num_frames());
330 } else {
331 render_converter_.reset(nullptr);
332 }
Michael Graczyk86c6d332015-07-23 11:41:39 -0700333 } else {
334 render_audio_.reset(nullptr);
ekmeyerson60d9b332015-08-14 10:35:55 -0700335 render_converter_.reset(nullptr);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700336 }
337 capture_audio_.reset(new AudioBuffer(
338 api_format_.input_stream().num_frames(),
339 api_format_.input_stream().num_channels(), fwd_proc_format_.num_frames(),
340 fwd_audio_buffer_channels, api_format_.output_stream().num_frames()));
niklase@google.com470e71d2011-07-07 08:21:25 +0000341
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 // Initialize all components.
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000343 for (auto item : component_list_) {
344 int err = item->Initialize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 if (err != kNoError) {
346 return err;
347 }
348 }
349
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200350 InitializeExperimentalAgc();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000351
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200352 InitializeTransient();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000353
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000354 InitializeBeamformer();
355
ekmeyerson60d9b332015-08-14 10:35:55 -0700356 InitializeIntelligibility();
357
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000358#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000359 if (debug_file_->Open()) {
360 int err = WriteInitMessage();
361 if (err != kNoError) {
362 return err;
363 }
364 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000365#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000366
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 return kNoError;
368}
369
Michael Graczyk86c6d332015-07-23 11:41:39 -0700370int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) {
371 for (const auto& stream : config.streams) {
372 if (stream.num_channels() < 0) {
373 return kBadNumberChannelsError;
374 }
375 if (stream.num_channels() > 0 && stream.sample_rate_hz() <= 0) {
376 return kBadSampleRateError;
377 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000378 }
Michael Graczyk86c6d332015-07-23 11:41:39 -0700379
380 const int num_in_channels = config.input_stream().num_channels();
381 const int num_out_channels = config.output_stream().num_channels();
382
383 // Need at least one input channel.
384 // Need either one output channel or as many outputs as there are inputs.
385 if (num_in_channels == 0 ||
386 !(num_out_channels == 1 || num_out_channels == num_in_channels)) {
Michael Graczykc2047542015-07-22 21:06:11 -0700387 return kBadNumberChannelsError;
388 }
389
Michael Graczyk86c6d332015-07-23 11:41:39 -0700390 if (beamformer_enabled_ &&
391 (static_cast<size_t>(num_in_channels) != array_geometry_.size() ||
392 num_out_channels > 1)) {
393 return kBadNumberChannelsError;
394 }
395
396 api_format_ = config;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000397
398 // We process at the closest native rate >= min(input rate, output rate)...
Michael Graczyk86c6d332015-07-23 11:41:39 -0700399 const int min_proc_rate =
400 std::min(api_format_.input_stream().sample_rate_hz(),
401 api_format_.output_stream().sample_rate_hz());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000402 int fwd_proc_rate;
aluebsb3b79b62015-07-27 10:17:58 -0700403 if (min_proc_rate > kSampleRate32kHz) {
aluebs@webrtc.orgc9ce07e2015-03-02 20:07:31 +0000404 fwd_proc_rate = kSampleRate48kHz;
405 } else if (min_proc_rate > kSampleRate16kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000406 fwd_proc_rate = kSampleRate32kHz;
407 } else if (min_proc_rate > kSampleRate8kHz) {
408 fwd_proc_rate = kSampleRate16kHz;
409 } else {
410 fwd_proc_rate = kSampleRate8kHz;
411 }
412 // ...with one exception.
413 if (echo_control_mobile_->is_enabled() && min_proc_rate > kSampleRate16kHz) {
414 fwd_proc_rate = kSampleRate16kHz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000415 }
416
Michael Graczyk86c6d332015-07-23 11:41:39 -0700417 fwd_proc_format_ = StreamConfig(fwd_proc_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000418
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000419 // We normally process the reverse stream at 16 kHz. Unless...
420 int rev_proc_rate = kSampleRate16kHz;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700421 if (fwd_proc_format_.sample_rate_hz() == kSampleRate8kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000422 // ...the forward stream is at 8 kHz.
423 rev_proc_rate = kSampleRate8kHz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000424 } else {
ekmeyerson60d9b332015-08-14 10:35:55 -0700425 if (api_format_.reverse_input_stream().sample_rate_hz() ==
426 kSampleRate32kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000427 // ...or the input is at 32 kHz, in which case we use the splitting
428 // filter rather than the resampler.
429 rev_proc_rate = kSampleRate32kHz;
430 }
431 }
432
andrew@webrtc.org30be8272014-09-24 20:06:23 +0000433 // Always downmix the reverse stream to mono for analysis. This has been
434 // demonstrated to work well for AEC in most practical scenarios.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700435 rev_proc_format_ = StreamConfig(rev_proc_rate, 1);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000436
Michael Graczyk86c6d332015-07-23 11:41:39 -0700437 if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
438 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000439 split_rate_ = kSampleRate16kHz;
440 } else {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700441 split_rate_ = fwd_proc_format_.sample_rate_hz();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000442 }
443
444 return InitializeLocked();
445}
446
447// Calls InitializeLocked() if any of the audio parameters have changed from
448// their current values.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700449int AudioProcessingImpl::MaybeInitializeLocked(
450 const ProcessingConfig& processing_config) {
451 if (processing_config == api_format_) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000452 return kNoError;
453 }
Michael Graczyk86c6d332015-07-23 11:41:39 -0700454 return InitializeLocked(processing_config);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000455}
456
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000457void AudioProcessingImpl::SetExtraOptions(const Config& config) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000458 CriticalSectionScoped crit_scoped(crit_);
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +0000459 for (auto item : component_list_) {
460 item->SetExtraOptions(config);
461 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000462
463 if (transient_suppressor_enabled_ != config.Get<ExperimentalNs>().enabled) {
464 transient_suppressor_enabled_ = config.Get<ExperimentalNs>().enabled;
465 InitializeTransient();
466 }
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000467}
468
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000469int AudioProcessingImpl::input_sample_rate_hz() const {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000470 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700471 return api_format_.input_stream().sample_rate_hz();
niklase@google.com470e71d2011-07-07 08:21:25 +0000472}
473
andrew@webrtc.org46b31b12014-04-23 03:33:54 +0000474int AudioProcessingImpl::sample_rate_hz() const {
475 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700476 return api_format_.input_stream().sample_rate_hz();
andrew@webrtc.org46b31b12014-04-23 03:33:54 +0000477}
478
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000479int AudioProcessingImpl::proc_sample_rate_hz() const {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700480 return fwd_proc_format_.sample_rate_hz();
niklase@google.com470e71d2011-07-07 08:21:25 +0000481}
482
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000483int AudioProcessingImpl::proc_split_sample_rate_hz() const {
484 return split_rate_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485}
486
487int AudioProcessingImpl::num_reverse_channels() const {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000488 return rev_proc_format_.num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000489}
490
491int AudioProcessingImpl::num_input_channels() const {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700492 return api_format_.input_stream().num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000493}
494
495int AudioProcessingImpl::num_output_channels() const {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700496 return api_format_.output_stream().num_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000497}
498
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000499void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000500 CriticalSectionScoped lock(crit_);
Bjorn Volcker424694c2015-03-27 11:30:43 +0100501 output_will_be_muted_ = muted;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000502 if (agc_manager_.get()) {
503 agc_manager_->SetCaptureMuted(output_will_be_muted_);
504 }
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000505}
506
507bool AudioProcessingImpl::output_will_be_muted() const {
Bjorn Volcker424694c2015-03-27 11:30:43 +0100508 CriticalSectionScoped lock(crit_);
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000509 return output_will_be_muted_;
510}
511
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000512int AudioProcessingImpl::ProcessStream(const float* const* src,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000513 int samples_per_channel,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000514 int input_sample_rate_hz,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000515 ChannelLayout input_layout,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000516 int output_sample_rate_hz,
517 ChannelLayout output_layout,
518 float* const* dest) {
Michael Graczyk4bc66fc2015-08-10 15:26:38 -0700519 CriticalSectionScoped crit_scoped(crit_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700520 StreamConfig input_stream = api_format_.input_stream();
521 input_stream.set_sample_rate_hz(input_sample_rate_hz);
522 input_stream.set_num_channels(ChannelsFromLayout(input_layout));
523 input_stream.set_has_keyboard(LayoutHasKeyboard(input_layout));
524
525 StreamConfig output_stream = api_format_.output_stream();
526 output_stream.set_sample_rate_hz(output_sample_rate_hz);
527 output_stream.set_num_channels(ChannelsFromLayout(output_layout));
528 output_stream.set_has_keyboard(LayoutHasKeyboard(output_layout));
529
530 if (samples_per_channel != input_stream.num_frames()) {
531 return kBadDataLengthError;
532 }
533 return ProcessStream(src, input_stream, output_stream, dest);
534}
535
536int AudioProcessingImpl::ProcessStream(const float* const* src,
537 const StreamConfig& input_config,
538 const StreamConfig& output_config,
539 float* const* dest) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000540 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000541 if (!src || !dest) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 return kNullPointerError;
543 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000544
Michael Graczyk86c6d332015-07-23 11:41:39 -0700545 ProcessingConfig processing_config = api_format_;
546 processing_config.input_stream() = input_config;
547 processing_config.output_stream() = output_config;
548
549 RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
550 assert(processing_config.input_stream().num_frames() ==
551 api_format_.input_stream().num_frames());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000552
553#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
554 if (debug_file_->Open()) {
555 event_msg_->set_type(audioproc::Event::STREAM);
556 audioproc::Stream* msg = event_msg_->mutable_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000557 const size_t channel_size =
Michael Graczyk86c6d332015-07-23 11:41:39 -0700558 sizeof(float) * api_format_.input_stream().num_frames();
559 for (int i = 0; i < api_format_.input_stream().num_channels(); ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000560 msg->add_input_channel(src[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000561 }
562#endif
563
Michael Graczyk86c6d332015-07-23 11:41:39 -0700564 capture_audio_->CopyFrom(src, api_format_.input_stream());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000565 RETURN_ON_ERR(ProcessStreamLocked());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700566 capture_audio_->CopyTo(api_format_.output_stream(), dest);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000567
568#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
569 if (debug_file_->Open()) {
570 audioproc::Stream* msg = event_msg_->mutable_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000571 const size_t channel_size =
Michael Graczyk86c6d332015-07-23 11:41:39 -0700572 sizeof(float) * api_format_.output_stream().num_frames();
573 for (int i = 0; i < api_format_.output_stream().num_channels(); ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000574 msg->add_output_channel(dest[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000575 RETURN_ON_ERR(WriteMessageToDebugFile());
576 }
577#endif
578
579 return kNoError;
580}
581
582int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
583 CriticalSectionScoped crit_scoped(crit_);
584 if (!frame) {
585 return kNullPointerError;
586 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000587 // Must be a native rate.
588 if (frame->sample_rate_hz_ != kSampleRate8kHz &&
589 frame->sample_rate_hz_ != kSampleRate16kHz &&
aluebs@webrtc.org087da132014-11-17 23:01:23 +0000590 frame->sample_rate_hz_ != kSampleRate32kHz &&
591 frame->sample_rate_hz_ != kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000592 return kBadSampleRateError;
593 }
594 if (echo_control_mobile_->is_enabled() &&
595 frame->sample_rate_hz_ > kSampleRate16kHz) {
596 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
597 return kUnsupportedComponentError;
598 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000599
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000600 // TODO(ajm): The input and output rates and channels are currently
601 // constrained to be identical in the int16 interface.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700602 ProcessingConfig processing_config = api_format_;
603 processing_config.input_stream().set_sample_rate_hz(frame->sample_rate_hz_);
604 processing_config.input_stream().set_num_channels(frame->num_channels_);
605 processing_config.output_stream().set_sample_rate_hz(frame->sample_rate_hz_);
606 processing_config.output_stream().set_num_channels(frame->num_channels_);
607
608 RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
609 if (frame->samples_per_channel_ != api_format_.input_stream().num_frames()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 return kBadDataLengthError;
611 }
612
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000613#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000615 event_msg_->set_type(audioproc::Event::STREAM);
616 audioproc::Stream* msg = event_msg_->mutable_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700617 const size_t data_size =
618 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000619 msg->set_input_data(frame->data_, data_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000620 }
621#endif
622
623 capture_audio_->DeinterleaveFrom(frame);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000624 RETURN_ON_ERR(ProcessStreamLocked());
625 capture_audio_->InterleaveTo(frame, output_copy_needed(is_data_processed()));
626
627#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
628 if (debug_file_->Open()) {
629 audioproc::Stream* msg = event_msg_->mutable_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700630 const size_t data_size =
631 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000632 msg->set_output_data(frame->data_, data_size);
633 RETURN_ON_ERR(WriteMessageToDebugFile());
634 }
635#endif
636
637 return kNoError;
638}
639
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000640int AudioProcessingImpl::ProcessStreamLocked() {
641#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
642 if (debug_file_->Open()) {
643 audioproc::Stream* msg = event_msg_->mutable_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000644 msg->set_delay(stream_delay_ms_);
645 msg->set_drift(echo_cancellation_->stream_drift_samples());
bjornv@webrtc.org63da1dd2015-02-06 19:44:21 +0000646 msg->set_level(gain_control()->stream_analog_level());
andrew@webrtc.orgce8e0772014-02-12 15:28:30 +0000647 msg->set_keypress(key_pressed_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000649#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000650
Bjorn Volcker1ca324f2015-06-29 14:57:29 +0200651 MaybeUpdateHistograms();
652
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000653 AudioBuffer* ca = capture_audio_.get(); // For brevity.
ekmeyerson60d9b332015-08-14 10:35:55 -0700654
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000655 if (use_new_agc_ && gain_control_->is_enabled()) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700656 agc_manager_->AnalyzePreProcess(ca->channels()[0], ca->num_channels(),
657 fwd_proc_format_.num_frames());
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000658 }
659
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000660 bool data_processed = is_data_processed();
661 if (analysis_needed(data_processed)) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000662 ca->SplitIntoFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 }
664
ekmeyerson60d9b332015-08-14 10:35:55 -0700665 if (intelligibility_enabled_) {
666 intelligibility_enhancer_->AnalyzeCaptureAudio(
667 ca->split_channels_f(kBand0To8kHz), split_rate_, ca->num_channels());
668 }
669
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000670 if (beamformer_enabled_) {
Michael Graczykdfa36052015-03-25 16:37:27 -0700671 beamformer_->ProcessChunk(*ca->split_data_f(), ca->split_data_f());
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000672 ca->set_num_channels(1);
673 }
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +0000674
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000675 RETURN_ON_ERR(high_pass_filter_->ProcessCaptureAudio(ca));
676 RETURN_ON_ERR(gain_control_->AnalyzeCaptureAudio(ca));
aluebs@webrtc.orga0ce9fa2014-09-24 14:18:03 +0000677 RETURN_ON_ERR(noise_suppression_->AnalyzeCaptureAudio(ca));
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000678 RETURN_ON_ERR(echo_cancellation_->ProcessCaptureAudio(ca));
niklase@google.com470e71d2011-07-07 08:21:25 +0000679
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000680 if (echo_control_mobile_->is_enabled() && noise_suppression_->is_enabled()) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000681 ca->CopyLowPassToReference();
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 }
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000683 RETURN_ON_ERR(noise_suppression_->ProcessCaptureAudio(ca));
684 RETURN_ON_ERR(echo_control_mobile_->ProcessCaptureAudio(ca));
685 RETURN_ON_ERR(voice_detection_->ProcessCaptureAudio(ca));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000686
Michael Graczyk86c6d332015-07-23 11:41:39 -0700687 if (use_new_agc_ && gain_control_->is_enabled() &&
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000688 (!beamformer_enabled_ || beamformer_->is_target_present())) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000689 agc_manager_->Process(ca->split_bands_const(0)[kBand0To8kHz],
Michael Graczyk86c6d332015-07-23 11:41:39 -0700690 ca->num_frames_per_band(), split_rate_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000691 }
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000692 RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca));
niklase@google.com470e71d2011-07-07 08:21:25 +0000693
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000694 if (synthesis_needed(data_processed)) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000695 ca->MergeFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 }
697
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000698 // TODO(aluebs): Investigate if the transient suppression placement should be
699 // before or after the AGC.
700 if (transient_suppressor_enabled_) {
701 float voice_probability =
702 agc_manager_.get() ? agc_manager_->voice_probability() : 1.f;
703
Michael Graczyk86c6d332015-07-23 11:41:39 -0700704 transient_suppressor_->Suppress(
705 ca->channels_f()[0], ca->num_frames(), ca->num_channels(),
706 ca->split_bands_const_f(0)[kBand0To8kHz], ca->num_frames_per_band(),
707 ca->keyboard_data(), ca->num_keyboard_frames(), voice_probability,
708 key_pressed_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000709 }
710
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000711 // The level estimator operates on the recombined data.
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000712 RETURN_ON_ERR(level_estimator_->ProcessStream(ca));
ajm@google.com808e0e02011-08-03 21:08:51 +0000713
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000714 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 return kNoError;
716}
717
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000718int AudioProcessingImpl::AnalyzeReverseStream(const float* const* data,
719 int samples_per_channel,
ekmeyerson60d9b332015-08-14 10:35:55 -0700720 int rev_sample_rate_hz,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000721 ChannelLayout layout) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700722 const StreamConfig reverse_config = {
ekmeyerson60d9b332015-08-14 10:35:55 -0700723 rev_sample_rate_hz, ChannelsFromLayout(layout), LayoutHasKeyboard(layout),
Michael Graczyk86c6d332015-07-23 11:41:39 -0700724 };
725 if (samples_per_channel != reverse_config.num_frames()) {
726 return kBadDataLengthError;
727 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700728 return AnalyzeReverseStream(data, reverse_config, reverse_config);
729}
730
731int AudioProcessingImpl::ProcessReverseStream(
732 const float* const* src,
733 const StreamConfig& reverse_input_config,
734 const StreamConfig& reverse_output_config,
735 float* const* dest) {
736 RETURN_ON_ERR(
737 AnalyzeReverseStream(src, reverse_input_config, reverse_output_config));
738 if (is_rev_processed()) {
739 render_audio_->CopyTo(api_format_.reverse_output_stream(), dest);
740 } else if (rev_conversion_needed()) {
741 render_converter_->Convert(src, reverse_input_config.num_samples(), dest,
742 reverse_output_config.num_samples());
743 } else {
744 CopyAudioIfNeeded(src, reverse_input_config.num_frames(),
745 reverse_input_config.num_channels(), dest);
746 }
747
748 return kNoError;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700749}
750
751int AudioProcessingImpl::AnalyzeReverseStream(
ekmeyerson60d9b332015-08-14 10:35:55 -0700752 const float* const* src,
753 const StreamConfig& reverse_input_config,
754 const StreamConfig& reverse_output_config) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000755 CriticalSectionScoped crit_scoped(crit_);
ekmeyerson60d9b332015-08-14 10:35:55 -0700756 if (src == NULL) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000757 return kNullPointerError;
758 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000759
ekmeyerson60d9b332015-08-14 10:35:55 -0700760 if (reverse_input_config.num_channels() <= 0) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700761 return kBadNumberChannelsError;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000762 }
763
Michael Graczyk86c6d332015-07-23 11:41:39 -0700764 ProcessingConfig processing_config = api_format_;
ekmeyerson60d9b332015-08-14 10:35:55 -0700765 processing_config.reverse_input_stream() = reverse_input_config;
766 processing_config.reverse_output_stream() = reverse_output_config;
Michael Graczyk86c6d332015-07-23 11:41:39 -0700767
768 RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
ekmeyerson60d9b332015-08-14 10:35:55 -0700769 assert(reverse_input_config.num_frames() ==
770 api_format_.reverse_input_stream().num_frames());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700771
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000772#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
773 if (debug_file_->Open()) {
774 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
775 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
aluebs@webrtc.org59a1b1b2014-08-28 10:43:09 +0000776 const size_t channel_size =
ekmeyerson60d9b332015-08-14 10:35:55 -0700777 sizeof(float) * api_format_.reverse_input_stream().num_frames();
778 for (int i = 0; i < api_format_.reverse_input_stream().num_channels(); ++i)
779 msg->add_channel(src[i], channel_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000780 RETURN_ON_ERR(WriteMessageToDebugFile());
781 }
782#endif
783
ekmeyerson60d9b332015-08-14 10:35:55 -0700784 render_audio_->CopyFrom(src, api_format_.reverse_input_stream());
785 return ProcessReverseStreamLocked();
786}
787
788int AudioProcessingImpl::ProcessReverseStream(AudioFrame* frame) {
789 RETURN_ON_ERR(AnalyzeReverseStream(frame));
790 if (is_rev_processed()) {
791 render_audio_->InterleaveTo(frame, true);
792 }
793
794 return kNoError;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000795}
796
niklase@google.com470e71d2011-07-07 08:21:25 +0000797int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000798 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 if (frame == NULL) {
800 return kNullPointerError;
801 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000802 // Must be a native rate.
803 if (frame->sample_rate_hz_ != kSampleRate8kHz &&
804 frame->sample_rate_hz_ != kSampleRate16kHz &&
aluebs@webrtc.org087da132014-11-17 23:01:23 +0000805 frame->sample_rate_hz_ != kSampleRate32kHz &&
806 frame->sample_rate_hz_ != kSampleRate48kHz) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000807 return kBadSampleRateError;
808 }
809 // This interface does not tolerate different forward and reverse rates.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700810 if (frame->sample_rate_hz_ != api_format_.input_stream().sample_rate_hz()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 return kBadSampleRateError;
812 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000813
Michael Graczyk86c6d332015-07-23 11:41:39 -0700814 if (frame->num_channels_ <= 0) {
815 return kBadNumberChannelsError;
816 }
817
818 ProcessingConfig processing_config = api_format_;
ekmeyerson60d9b332015-08-14 10:35:55 -0700819 processing_config.reverse_input_stream().set_sample_rate_hz(
820 frame->sample_rate_hz_);
821 processing_config.reverse_input_stream().set_num_channels(
822 frame->num_channels_);
823 processing_config.reverse_output_stream().set_sample_rate_hz(
824 frame->sample_rate_hz_);
825 processing_config.reverse_output_stream().set_num_channels(
826 frame->num_channels_);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700827
828 RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
829 if (frame->samples_per_channel_ !=
ekmeyerson60d9b332015-08-14 10:35:55 -0700830 api_format_.reverse_input_stream().num_frames()) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000831 return kBadDataLengthError;
832 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000833
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000834#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000836 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
837 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
Michael Graczyk86c6d332015-07-23 11:41:39 -0700838 const size_t data_size =
839 sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000840 msg->set_data(frame->data_, data_size);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000841 RETURN_ON_ERR(WriteMessageToDebugFile());
niklase@google.com470e71d2011-07-07 08:21:25 +0000842 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000843#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 render_audio_->DeinterleaveFrom(frame);
ekmeyerson60d9b332015-08-14 10:35:55 -0700845 return ProcessReverseStreamLocked();
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000846}
niklase@google.com470e71d2011-07-07 08:21:25 +0000847
ekmeyerson60d9b332015-08-14 10:35:55 -0700848int AudioProcessingImpl::ProcessReverseStreamLocked() {
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000849 AudioBuffer* ra = render_audio_.get(); // For brevity.
Michael Graczyk86c6d332015-07-23 11:41:39 -0700850 if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz) {
aluebs@webrtc.orgbe05c742014-11-14 22:18:10 +0000851 ra->SplitIntoFrequencyBands();
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 }
853
ekmeyerson60d9b332015-08-14 10:35:55 -0700854 if (intelligibility_enabled_) {
855 intelligibility_enhancer_->ProcessRenderAudio(
856 ra->split_channels_f(kBand0To8kHz), split_rate_, ra->num_channels());
857 }
858
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000859 RETURN_ON_ERR(echo_cancellation_->ProcessRenderAudio(ra));
860 RETURN_ON_ERR(echo_control_mobile_->ProcessRenderAudio(ra));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000861 if (!use_new_agc_) {
862 RETURN_ON_ERR(gain_control_->ProcessRenderAudio(ra));
863 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000864
ekmeyerson60d9b332015-08-14 10:35:55 -0700865 if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz &&
866 is_rev_processed()) {
867 ra->MergeFrequencyBands();
868 }
869
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000870 return kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000871}
872
873int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000874 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000876 delay += delay_offset_ms_;
877
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000879 delay = 0;
880 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 }
882
883 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
884 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000885 delay = 500;
886 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000887 }
888
889 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000890 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000891}
892
893int AudioProcessingImpl::stream_delay_ms() const {
894 return stream_delay_ms_;
895}
896
897bool AudioProcessingImpl::was_stream_delay_set() const {
898 return was_stream_delay_set_;
899}
900
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000901void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
902 key_pressed_ = key_pressed;
903}
904
905bool AudioProcessingImpl::stream_key_pressed() const {
906 return key_pressed_;
907}
908
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000909void AudioProcessingImpl::set_delay_offset_ms(int offset) {
910 CriticalSectionScoped crit_scoped(crit_);
911 delay_offset_ms_ = offset;
912}
913
914int AudioProcessingImpl::delay_offset_ms() const {
915 return delay_offset_ms_;
916}
917
niklase@google.com470e71d2011-07-07 08:21:25 +0000918int AudioProcessingImpl::StartDebugRecording(
919 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000920 CriticalSectionScoped crit_scoped(crit_);
André Susano Pinto664cdaf2015-05-20 11:11:07 +0200921 static_assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize, "");
niklase@google.com470e71d2011-07-07 08:21:25 +0000922
923 if (filename == NULL) {
924 return kNullPointerError;
925 }
926
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000927#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 // Stop any ongoing recording.
929 if (debug_file_->Open()) {
930 if (debug_file_->CloseFile() == -1) {
931 return kFileError;
932 }
933 }
934
935 if (debug_file_->OpenFile(filename, false) == -1) {
936 debug_file_->CloseFile();
937 return kFileError;
938 }
939
ajm@google.com808e0e02011-08-03 21:08:51 +0000940 int err = WriteInitMessage();
941 if (err != kNoError) {
942 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000945#else
946 return kUnsupportedFunctionError;
947#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000948}
949
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000950int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
951 CriticalSectionScoped crit_scoped(crit_);
952
953 if (handle == NULL) {
954 return kNullPointerError;
955 }
956
957#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
958 // Stop any ongoing recording.
959 if (debug_file_->Open()) {
960 if (debug_file_->CloseFile() == -1) {
961 return kFileError;
962 }
963 }
964
965 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
966 return kFileError;
967 }
968
969 int err = WriteInitMessage();
970 if (err != kNoError) {
971 return err;
972 }
973 return kNoError;
974#else
975 return kUnsupportedFunctionError;
976#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
977}
978
xians@webrtc.orge46bc772014-10-10 08:36:56 +0000979int AudioProcessingImpl::StartDebugRecordingForPlatformFile(
980 rtc::PlatformFile handle) {
981 FILE* stream = rtc::FdopenPlatformFileForWriting(handle);
982 return StartDebugRecording(stream);
983}
984
niklase@google.com470e71d2011-07-07 08:21:25 +0000985int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000986 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000987
988#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000989 // We just return if recording hasn't started.
990 if (debug_file_->Open()) {
991 if (debug_file_->CloseFile() == -1) {
992 return kFileError;
993 }
994 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000995 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000996#else
997 return kUnsupportedFunctionError;
998#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000999}
1000
1001EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
1002 return echo_cancellation_;
1003}
1004
1005EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
1006 return echo_control_mobile_;
1007}
1008
1009GainControl* AudioProcessingImpl::gain_control() const {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001010 if (use_new_agc_) {
1011 return gain_control_for_new_agc_.get();
1012 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 return gain_control_;
1014}
1015
1016HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
1017 return high_pass_filter_;
1018}
1019
1020LevelEstimator* AudioProcessingImpl::level_estimator() const {
1021 return level_estimator_;
1022}
1023
1024NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
1025 return noise_suppression_;
1026}
1027
1028VoiceDetection* AudioProcessingImpl::voice_detection() const {
1029 return voice_detection_;
1030}
1031
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001032bool AudioProcessingImpl::is_data_processed() const {
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001033 if (beamformer_enabled_) {
1034 return true;
1035 }
1036
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001037 int enabled_count = 0;
mgraczyk@chromium.orge5340862015-03-12 23:23:38 +00001038 for (auto item : component_list_) {
1039 if (item->is_component_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001040 enabled_count++;
1041 }
1042 }
1043
1044 // Data is unchanged if no components are enabled, or if only level_estimator_
1045 // or voice_detection_ is enabled.
1046 if (enabled_count == 0) {
1047 return false;
1048 } else if (enabled_count == 1) {
1049 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
1050 return false;
1051 }
1052 } else if (enabled_count == 2) {
1053 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
1054 return false;
1055 }
1056 }
1057 return true;
1058}
1059
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001060bool AudioProcessingImpl::output_copy_needed(bool is_data_processed) const {
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001061 // Check if we've upmixed or downmixed the audio.
Michael Graczyk86c6d332015-07-23 11:41:39 -07001062 return ((api_format_.output_stream().num_channels() !=
1063 api_format_.input_stream().num_channels()) ||
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001064 is_data_processed || transient_suppressor_enabled_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001065}
1066
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001067bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
Michael Graczyk86c6d332015-07-23 11:41:39 -07001068 return (is_data_processed &&
1069 (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
1070 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz));
andrew@webrtc.org369166a2012-04-24 18:38:03 +00001071}
1072
1073bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001074 if (!is_data_processed && !voice_detection_->is_enabled() &&
1075 !transient_suppressor_enabled_) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001076 // Only level_estimator_ is enabled.
1077 return false;
Michael Graczyk86c6d332015-07-23 11:41:39 -07001078 } else if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
1079 fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001080 // Something besides level_estimator_ is enabled, and we have super-wb.
1081 return true;
1082 }
1083 return false;
1084}
1085
ekmeyerson60d9b332015-08-14 10:35:55 -07001086bool AudioProcessingImpl::is_rev_processed() const {
1087 return intelligibility_enabled_ && intelligibility_enhancer_->active();
1088}
1089
1090bool AudioProcessingImpl::rev_conversion_needed() const {
1091 return (api_format_.reverse_input_stream() !=
1092 api_format_.reverse_output_stream());
1093}
1094
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001095void AudioProcessingImpl::InitializeExperimentalAgc() {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001096 if (use_new_agc_) {
1097 if (!agc_manager_.get()) {
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001098 agc_manager_.reset(new AgcManagerDirect(gain_control_,
1099 gain_control_for_new_agc_.get(),
1100 agc_startup_min_volume_));
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001101 }
1102 agc_manager_->Initialize();
1103 agc_manager_->SetCaptureMuted(output_will_be_muted_);
1104 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001105}
1106
Bjorn Volckeradc46c42015-04-15 11:42:40 +02001107void AudioProcessingImpl::InitializeTransient() {
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001108 if (transient_suppressor_enabled_) {
1109 if (!transient_suppressor_.get()) {
1110 transient_suppressor_.reset(new TransientSuppressor());
1111 }
Michael Graczyk86c6d332015-07-23 11:41:39 -07001112 transient_suppressor_->Initialize(
1113 fwd_proc_format_.sample_rate_hz(), split_rate_,
1114 api_format_.output_stream().num_channels());
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001115 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001116}
1117
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001118void AudioProcessingImpl::InitializeBeamformer() {
1119 if (beamformer_enabled_) {
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +00001120 if (!beamformer_) {
mgraczyk@chromium.org0f663de2015-03-13 00:13:32 +00001121 beamformer_.reset(new NonlinearBeamformer(array_geometry_));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +00001122 }
1123 beamformer_->Initialize(kChunkSizeMs, split_rate_);
aluebs@webrtc.orgae643ce2014-12-19 19:57:34 +00001124 }
1125}
1126
ekmeyerson60d9b332015-08-14 10:35:55 -07001127void AudioProcessingImpl::InitializeIntelligibility() {
1128 if (intelligibility_enabled_) {
1129 IntelligibilityEnhancer::Config config;
1130 config.sample_rate_hz = split_rate_;
1131 config.num_capture_channels = capture_audio_->num_channels();
1132 config.num_render_channels = render_audio_->num_channels();
1133 intelligibility_enhancer_.reset(new IntelligibilityEnhancer(config));
1134 }
1135}
1136
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001137void AudioProcessingImpl::MaybeUpdateHistograms() {
Bjorn Volckerd92f2672015-07-05 10:46:01 +02001138 static const int kMinDiffDelayMs = 60;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001139
1140 if (echo_cancellation()->is_enabled()) {
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001141 // Activate delay_jumps_ counters if we know echo_cancellation is runnning.
1142 // If a stream has echo we know that the echo_cancellation is in process.
1143 if (stream_delay_jumps_ == -1 && echo_cancellation()->stream_has_echo()) {
1144 stream_delay_jumps_ = 0;
1145 }
1146 if (aec_system_delay_jumps_ == -1 &&
1147 echo_cancellation()->stream_has_echo()) {
1148 aec_system_delay_jumps_ = 0;
1149 }
1150
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001151 // Detect a jump in platform reported system delay and log the difference.
1152 const int diff_stream_delay_ms = stream_delay_ms_ - last_stream_delay_ms_;
1153 if (diff_stream_delay_ms > kMinDiffDelayMs && last_stream_delay_ms_ != 0) {
1154 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.PlatformReportedStreamDelayJump",
1155 diff_stream_delay_ms, kMinDiffDelayMs, 1000, 100);
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001156 if (stream_delay_jumps_ == -1) {
1157 stream_delay_jumps_ = 0; // Activate counter if needed.
1158 }
1159 stream_delay_jumps_++;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001160 }
1161 last_stream_delay_ms_ = stream_delay_ms_;
1162
1163 // Detect a jump in AEC system delay and log the difference.
1164 const int frames_per_ms = rtc::CheckedDivExact(split_rate_, 1000);
1165 const int aec_system_delay_ms =
1166 WebRtcAec_system_delay(echo_cancellation()->aec_core()) / frames_per_ms;
Michael Graczyk86c6d332015-07-23 11:41:39 -07001167 const int diff_aec_system_delay_ms =
1168 aec_system_delay_ms - last_aec_system_delay_ms_;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001169 if (diff_aec_system_delay_ms > kMinDiffDelayMs &&
1170 last_aec_system_delay_ms_ != 0) {
1171 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecSystemDelayJump",
1172 diff_aec_system_delay_ms, kMinDiffDelayMs, 1000,
1173 100);
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001174 if (aec_system_delay_jumps_ == -1) {
1175 aec_system_delay_jumps_ = 0; // Activate counter if needed.
1176 }
1177 aec_system_delay_jumps_++;
Bjorn Volcker1ca324f2015-06-29 14:57:29 +02001178 }
1179 last_aec_system_delay_ms_ = aec_system_delay_ms;
1180 }
1181}
1182
Bjorn Volcker4e7aa432015-07-07 11:50:05 +02001183void AudioProcessingImpl::UpdateHistogramsOnCallEnd() {
1184 CriticalSectionScoped crit_scoped(crit_);
1185 if (stream_delay_jumps_ > -1) {
1186 RTC_HISTOGRAM_ENUMERATION(
1187 "WebRTC.Audio.NumOfPlatformReportedStreamDelayJumps",
1188 stream_delay_jumps_, 51);
1189 }
1190 stream_delay_jumps_ = -1;
1191 last_stream_delay_ms_ = 0;
1192
1193 if (aec_system_delay_jumps_ > -1) {
1194 RTC_HISTOGRAM_ENUMERATION("WebRTC.Audio.NumOfAecSystemDelayJumps",
1195 aec_system_delay_jumps_, 51);
1196 }
1197 aec_system_delay_jumps_ = -1;
1198 last_aec_system_delay_ms_ = 0;
1199}
1200
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001201#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +00001202int AudioProcessingImpl::WriteMessageToDebugFile() {
1203 int32_t size = event_msg_->ByteSize();
1204 if (size <= 0) {
1205 return kUnspecifiedError;
1206 }
andrew@webrtc.org621df672013-10-22 10:27:23 +00001207#if defined(WEBRTC_ARCH_BIG_ENDIAN)
Michael Graczyk86c6d332015-07-23 11:41:39 -07001208// TODO(ajm): Use little-endian "on the wire". For the moment, we can be
1209// pretty safe in assuming little-endian.
ajm@google.com808e0e02011-08-03 21:08:51 +00001210#endif
1211
1212 if (!event_msg_->SerializeToString(&event_str_)) {
1213 return kUnspecifiedError;
1214 }
1215
1216 // Write message preceded by its size.
1217 if (!debug_file_->Write(&size, sizeof(int32_t))) {
1218 return kFileError;
1219 }
1220 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
1221 return kFileError;
1222 }
1223
1224 event_msg_->Clear();
1225
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001226 return kNoError;
ajm@google.com808e0e02011-08-03 21:08:51 +00001227}
1228
1229int AudioProcessingImpl::WriteInitMessage() {
1230 event_msg_->set_type(audioproc::Event::INIT);
1231 audioproc::Init* msg = event_msg_->mutable_init();
Michael Graczyk86c6d332015-07-23 11:41:39 -07001232 msg->set_sample_rate(api_format_.input_stream().sample_rate_hz());
1233 msg->set_num_input_channels(api_format_.input_stream().num_channels());
1234 msg->set_num_output_channels(api_format_.output_stream().num_channels());
ekmeyerson60d9b332015-08-14 10:35:55 -07001235 msg->set_num_reverse_channels(
1236 api_format_.reverse_input_stream().num_channels());
1237 msg->set_reverse_sample_rate(
1238 api_format_.reverse_input_stream().sample_rate_hz());
Michael Graczyk86c6d332015-07-23 11:41:39 -07001239 msg->set_output_sample_rate(api_format_.output_stream().sample_rate_hz());
ekmeyerson60d9b332015-08-14 10:35:55 -07001240 // TODO(ekmeyerson): Add reverse output fields to event_msg_.
ajm@google.com808e0e02011-08-03 21:08:51 +00001241
1242 int err = WriteMessageToDebugFile();
1243 if (err != kNoError) {
1244 return err;
1245 }
1246
1247 return kNoError;
1248}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001249#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001250
niklase@google.com470e71d2011-07-07 08:21:25 +00001251} // namespace webrtc