blob: fd2316caa342610ff1433c0f476cc9211264f44c [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>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000015#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000016#include "webrtc/modules/audio_processing/audio_buffer.h"
andrew@webrtc.org61e596f2013-07-25 18:28:29 +000017#include "webrtc/modules/audio_processing/echo_cancellation_impl_wrapper.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000018#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
19#include "webrtc/modules/audio_processing/gain_control_impl.h"
20#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
21#include "webrtc/modules/audio_processing/level_estimator_impl.h"
22#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
23#include "webrtc/modules/audio_processing/processing_component.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000024#include "webrtc/modules/audio_processing/voice_detection_impl.h"
25#include "webrtc/modules/interface/module_common_types.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000026#include "webrtc/system_wrappers/interface/compile_assert.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000027#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
28#include "webrtc/system_wrappers/interface/file_wrapper.h"
29#include "webrtc/system_wrappers/interface/logging.h"
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000030
31#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
32// Files generated at build-time by the protobuf compiler.
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000033#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000034#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000035#else
ajm@google.com808e0e02011-08-03 21:08:51 +000036#include "webrtc/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000037#endif
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000038#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000039
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000040static const int kChunkSizeMs = 10;
41
42#define RETURN_ON_ERR(expr) \
43 do { \
44 int err = expr; \
45 if (err != kNoError) { \
46 return err; \
47 } \
48 } while (0)
49
niklase@google.com470e71d2011-07-07 08:21:25 +000050namespace webrtc {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000051
52// Throughout webrtc, it's assumed that success is represented by zero.
53COMPILE_ASSERT(AudioProcessing::kNoError == 0, no_error_must_be_zero);
54
niklase@google.com470e71d2011-07-07 08:21:25 +000055AudioProcessing* AudioProcessing::Create(int id) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +000056 return Create();
57}
58
59AudioProcessing* AudioProcessing::Create() {
60 Config config;
61 return Create(config);
62}
63
64AudioProcessing* AudioProcessing::Create(const Config& config) {
65 AudioProcessingImpl* apm = new AudioProcessingImpl(config);
niklase@google.com470e71d2011-07-07 08:21:25 +000066 if (apm->Initialize() != kNoError) {
67 delete apm;
68 apm = NULL;
69 }
70
71 return apm;
72}
73
pbos@webrtc.org91620802013-08-02 11:44:11 +000074int32_t AudioProcessing::TimeUntilNextProcess() { return -1; }
75int32_t AudioProcessing::Process() { return -1; }
76
andrew@webrtc.orge84978f2014-01-25 02:09:06 +000077AudioProcessingImpl::AudioProcessingImpl(const Config& config)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000078 : echo_cancellation_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000079 echo_control_mobile_(NULL),
80 gain_control_(NULL),
81 high_pass_filter_(NULL),
82 level_estimator_(NULL),
83 noise_suppression_(NULL),
84 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000085 crit_(CriticalSectionWrapper::CreateCriticalSection()),
86 render_audio_(NULL),
87 capture_audio_(NULL),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000088#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
89 debug_file_(FileWrapper::Create()),
90 event_msg_(new audioproc::Event()),
91#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000092 sample_rate_hz_(kSampleRate16kHz),
93 split_sample_rate_hz_(kSampleRate16kHz),
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000094 samples_per_channel_(kChunkSizeMs * sample_rate_hz_ / 1000),
niklase@google.com470e71d2011-07-07 08:21:25 +000095 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +000096 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000097 was_stream_delay_set_(false),
ajm@google.com808e0e02011-08-03 21:08:51 +000098 num_reverse_channels_(1),
99 num_input_channels_(1),
andrew@webrtc.org07b59502014-02-12 16:41:13 +0000100 num_output_channels_(1),
101 key_pressed_(false) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000102 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 component_list_.push_back(echo_cancellation_);
104
105 echo_control_mobile_ = new EchoControlMobileImpl(this);
106 component_list_.push_back(echo_control_mobile_);
107
108 gain_control_ = new GainControlImpl(this);
109 component_list_.push_back(gain_control_);
110
111 high_pass_filter_ = new HighPassFilterImpl(this);
112 component_list_.push_back(high_pass_filter_);
113
114 level_estimator_ = new LevelEstimatorImpl(this);
115 component_list_.push_back(level_estimator_);
116
117 noise_suppression_ = new NoiseSuppressionImpl(this);
118 component_list_.push_back(noise_suppression_);
119
120 voice_detection_ = new VoiceDetectionImpl(this);
121 component_list_.push_back(voice_detection_);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000122
123 SetExtraOptions(config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124}
125
126AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 {
128 CriticalSectionScoped crit_scoped(crit_);
129 while (!component_list_.empty()) {
130 ProcessingComponent* component = component_list_.front();
131 component->Destroy();
132 delete component;
133 component_list_.pop_front();
134 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000136#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000137 if (debug_file_->Open()) {
138 debug_file_->CloseFile();
139 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000140#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000141
andrew@webrtc.org81865342012-10-27 00:28:27 +0000142 if (render_audio_) {
143 delete render_audio_;
144 render_audio_ = NULL;
145 }
146
147 if (capture_audio_) {
148 delete capture_audio_;
149 capture_audio_ = NULL;
150 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 }
152
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000153 delete crit_;
154 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000155}
156
157CriticalSectionWrapper* AudioProcessingImpl::crit() const {
158 return crit_;
159}
160
161int AudioProcessingImpl::split_sample_rate_hz() const {
162 return split_sample_rate_hz_;
163}
164
165int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000166 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167 return InitializeLocked();
168}
169
170int AudioProcessingImpl::InitializeLocked() {
171 if (render_audio_ != NULL) {
172 delete render_audio_;
173 render_audio_ = NULL;
174 }
175
176 if (capture_audio_ != NULL) {
177 delete capture_audio_;
178 capture_audio_ = NULL;
179 }
180
ajm@google.com808e0e02011-08-03 21:08:51 +0000181 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000183 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 samples_per_channel_);
185
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 // Initialize all components.
187 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000188 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 int err = (*it)->Initialize();
190 if (err != kNoError) {
191 return err;
192 }
193 }
194
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000195#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000196 if (debug_file_->Open()) {
197 int err = WriteInitMessage();
198 if (err != kNoError) {
199 return err;
200 }
201 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000202#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000203
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 return kNoError;
205}
206
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000207void AudioProcessingImpl::SetExtraOptions(const Config& config) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000208 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000209 std::list<ProcessingComponent*>::iterator it;
210 for (it = component_list_.begin(); it != component_list_.end(); ++it)
211 (*it)->SetExtraOptions(config);
212}
213
aluebs@webrtc.org0b72f582013-11-19 15:17:51 +0000214int AudioProcessingImpl::EnableExperimentalNs(bool enable) {
215 return kNoError;
216}
217
niklase@google.com470e71d2011-07-07 08:21:25 +0000218int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000219 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000220 if (rate == sample_rate_hz_) {
221 return kNoError;
222 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 if (rate != kSampleRate8kHz &&
224 rate != kSampleRate16kHz &&
225 rate != kSampleRate32kHz) {
226 return kBadParameterError;
227 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000228 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
229 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
230 return kUnsupportedComponentError;
231 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
233 sample_rate_hz_ = rate;
234 samples_per_channel_ = rate / 100;
235
236 if (sample_rate_hz_ == kSampleRate32kHz) {
237 split_sample_rate_hz_ = kSampleRate16kHz;
238 } else {
239 split_sample_rate_hz_ = sample_rate_hz_;
240 }
241
242 return InitializeLocked();
243}
244
245int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000246 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 return sample_rate_hz_;
248}
249
250int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000251 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000252 if (channels == num_reverse_channels_) {
253 return kNoError;
254 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 // Only stereo supported currently.
256 if (channels > 2 || channels < 1) {
257 return kBadParameterError;
258 }
259
ajm@google.com808e0e02011-08-03 21:08:51 +0000260 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261
262 return InitializeLocked();
263}
264
265int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000266 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267}
268
269int AudioProcessingImpl::set_num_channels(
270 int input_channels,
271 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000272 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000273 if (input_channels == num_input_channels_ &&
274 output_channels == num_output_channels_) {
275 return kNoError;
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 if (output_channels > input_channels) {
278 return kBadParameterError;
279 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000281 if (input_channels > 2 || input_channels < 1 ||
282 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 return kBadParameterError;
284 }
285
ajm@google.com808e0e02011-08-03 21:08:51 +0000286 num_input_channels_ = input_channels;
287 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000288
289 return InitializeLocked();
290}
291
292int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000293 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000294}
295
296int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000297 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000298}
299
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000300void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
301 output_will_be_muted_ = muted;
302}
303
304bool AudioProcessingImpl::output_will_be_muted() const {
305 return output_will_be_muted_;
306}
307
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000308int AudioProcessingImpl::MaybeInitializeLocked(int sample_rate_hz,
309 int num_input_channels, int num_output_channels, int num_reverse_channels) {
310 if (sample_rate_hz == sample_rate_hz_ &&
311 num_input_channels == num_input_channels_ &&
312 num_output_channels == num_output_channels_ &&
313 num_reverse_channels == num_reverse_channels_) {
314 return kNoError;
315 }
316
317 if (sample_rate_hz != kSampleRate8kHz &&
318 sample_rate_hz != kSampleRate16kHz &&
319 sample_rate_hz != kSampleRate32kHz) {
320 return kBadSampleRateError;
321 }
322 if (num_output_channels > num_input_channels) {
323 return kBadNumberChannelsError;
324 }
325 // Only mono and stereo supported currently.
326 if (num_input_channels > 2 || num_input_channels < 1 ||
327 num_output_channels > 2 || num_output_channels < 1 ||
328 num_reverse_channels > 2 || num_reverse_channels < 1) {
329 return kBadNumberChannelsError;
330 }
331 if (echo_control_mobile_->is_enabled() && sample_rate_hz > kSampleRate16kHz) {
332 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
333 return kUnsupportedComponentError;
334 }
335
336 sample_rate_hz_ = sample_rate_hz;
337 samples_per_channel_ = kChunkSizeMs * sample_rate_hz / 1000;
338 num_input_channels_ = num_input_channels;
339 num_output_channels_ = num_output_channels;
340 num_reverse_channels_ = num_reverse_channels;
341
342 if (sample_rate_hz_ == kSampleRate32kHz) {
343 split_sample_rate_hz_ = kSampleRate16kHz;
344 } else {
345 split_sample_rate_hz_ = sample_rate_hz_;
346 }
347
348 return InitializeLocked();
349}
350
niklase@google.com470e71d2011-07-07 08:21:25 +0000351int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000352 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 int err = kNoError;
354
355 if (frame == NULL) {
356 return kNullPointerError;
357 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000358 // TODO(ajm): We now always set the output channels equal to the input
359 // channels here. Remove the ability to downmix entirely.
360 RETURN_ON_ERR(MaybeInitializeLocked(frame->sample_rate_hz_,
361 frame->num_channels_, frame->num_channels_, num_reverse_channels_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000362 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 return kBadDataLengthError;
364 }
365
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000366#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000368 event_msg_->set_type(audioproc::Event::STREAM);
369 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000370 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000371 frame->samples_per_channel_ *
372 frame->num_channels_;
373 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000374 msg->set_delay(stream_delay_ms_);
375 msg->set_drift(echo_cancellation_->stream_drift_samples());
376 msg->set_level(gain_control_->stream_analog_level());
andrew@webrtc.orgce8e0772014-02-12 15:28:30 +0000377 msg->set_keypress(key_pressed_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000379#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
381 capture_audio_->DeinterleaveFrom(frame);
382
383 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000384 if (num_output_channels_ < num_input_channels_) {
385 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000386 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 }
388
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000389 bool data_processed = is_data_processed();
390 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000391 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 // Split into a low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000393 WebRtcSpl_AnalysisQMF(capture_audio_->data(i),
394 capture_audio_->samples_per_channel(),
395 capture_audio_->low_pass_split_data(i),
396 capture_audio_->high_pass_split_data(i),
397 capture_audio_->analysis_filter_state1(i),
398 capture_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 }
400 }
401
402 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
403 if (err != kNoError) {
404 return err;
405 }
406
407 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
408 if (err != kNoError) {
409 return err;
410 }
411
412 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
413 if (err != kNoError) {
414 return err;
415 }
416
417 if (echo_control_mobile_->is_enabled() &&
418 noise_suppression_->is_enabled()) {
419 capture_audio_->CopyLowPassToReference();
420 }
421
422 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
423 if (err != kNoError) {
424 return err;
425 }
426
427 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
428 if (err != kNoError) {
429 return err;
430 }
431
432 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
433 if (err != kNoError) {
434 return err;
435 }
436
437 err = gain_control_->ProcessCaptureAudio(capture_audio_);
438 if (err != kNoError) {
439 return err;
440 }
441
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000442 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000443 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 // Recombine low and high bands.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000445 WebRtcSpl_SynthesisQMF(capture_audio_->low_pass_split_data(i),
446 capture_audio_->high_pass_split_data(i),
447 capture_audio_->samples_per_split_channel(),
448 capture_audio_->data(i),
449 capture_audio_->synthesis_filter_state1(i),
450 capture_audio_->synthesis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 }
452 }
453
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000454 // The level estimator operates on the recombined data.
455 err = level_estimator_->ProcessStream(capture_audio_);
456 if (err != kNoError) {
457 return err;
458 }
459
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000460 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000461
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000462#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000463 if (debug_file_->Open()) {
464 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000465 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000466 frame->samples_per_channel_ *
467 frame->num_channels_;
468 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000469 err = WriteMessageToDebugFile();
470 if (err != kNoError) {
471 return err;
472 }
473 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000474#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000475
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000476 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 return kNoError;
478}
479
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000480// TODO(ajm): Have AnalyzeReverseStream accept sample rates not matching the
481// primary stream and convert ourselves rather than having the user manage it.
482// We can be smarter and use the splitting filter when appropriate. Similarly,
483// perform downmixing here.
niklase@google.com470e71d2011-07-07 08:21:25 +0000484int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000485 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 int err = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 if (frame == NULL) {
488 return kNullPointerError;
489 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000490 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 return kBadSampleRateError;
492 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000493 RETURN_ON_ERR(MaybeInitializeLocked(sample_rate_hz_, num_input_channels_,
494 num_output_channels_, frame->num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000496#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000498 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
499 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000500 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000501 frame->samples_per_channel_ *
502 frame->num_channels_;
503 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000504 err = WriteMessageToDebugFile();
505 if (err != kNoError) {
506 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 }
508 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000509#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000510
511 render_audio_->DeinterleaveFrom(frame);
512
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000514 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 // Split into low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000516 WebRtcSpl_AnalysisQMF(render_audio_->data(i),
517 render_audio_->samples_per_channel(),
518 render_audio_->low_pass_split_data(i),
519 render_audio_->high_pass_split_data(i),
520 render_audio_->analysis_filter_state1(i),
521 render_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 }
523 }
524
525 // TODO(ajm): warnings possible from components?
526 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
527 if (err != kNoError) {
528 return err;
529 }
530
531 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
532 if (err != kNoError) {
533 return err;
534 }
535
536 err = gain_control_->ProcessRenderAudio(render_audio_);
537 if (err != kNoError) {
538 return err;
539 }
540
niklase@google.com470e71d2011-07-07 08:21:25 +0000541 return err; // TODO(ajm): this is for returning warnings; necessary?
542}
543
544int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000545 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000547 delay += delay_offset_ms_;
548
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000550 delay = 0;
551 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 }
553
554 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
555 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000556 delay = 500;
557 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 }
559
560 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000561 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562}
563
564int AudioProcessingImpl::stream_delay_ms() const {
565 return stream_delay_ms_;
566}
567
568bool AudioProcessingImpl::was_stream_delay_set() const {
569 return was_stream_delay_set_;
570}
571
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000572void AudioProcessingImpl::set_delay_offset_ms(int offset) {
573 CriticalSectionScoped crit_scoped(crit_);
574 delay_offset_ms_ = offset;
575}
576
577int AudioProcessingImpl::delay_offset_ms() const {
578 return delay_offset_ms_;
579}
580
andrew@webrtc.org75dd2882014-02-11 20:52:30 +0000581void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
582 key_pressed_ = key_pressed;
583}
584
585bool AudioProcessingImpl::stream_key_pressed() const {
586 return key_pressed_;
587}
588
niklase@google.com470e71d2011-07-07 08:21:25 +0000589int AudioProcessingImpl::StartDebugRecording(
590 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000591 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
593
594 if (filename == NULL) {
595 return kNullPointerError;
596 }
597
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000598#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 // Stop any ongoing recording.
600 if (debug_file_->Open()) {
601 if (debug_file_->CloseFile() == -1) {
602 return kFileError;
603 }
604 }
605
606 if (debug_file_->OpenFile(filename, false) == -1) {
607 debug_file_->CloseFile();
608 return kFileError;
609 }
610
ajm@google.com808e0e02011-08-03 21:08:51 +0000611 int err = WriteInitMessage();
612 if (err != kNoError) {
613 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000615 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000616#else
617 return kUnsupportedFunctionError;
618#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000619}
620
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000621int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
622 CriticalSectionScoped crit_scoped(crit_);
623
624 if (handle == NULL) {
625 return kNullPointerError;
626 }
627
628#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
629 // Stop any ongoing recording.
630 if (debug_file_->Open()) {
631 if (debug_file_->CloseFile() == -1) {
632 return kFileError;
633 }
634 }
635
636 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
637 return kFileError;
638 }
639
640 int err = WriteInitMessage();
641 if (err != kNoError) {
642 return err;
643 }
644 return kNoError;
645#else
646 return kUnsupportedFunctionError;
647#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
648}
649
niklase@google.com470e71d2011-07-07 08:21:25 +0000650int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000651 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000652
653#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 // We just return if recording hasn't started.
655 if (debug_file_->Open()) {
656 if (debug_file_->CloseFile() == -1) {
657 return kFileError;
658 }
659 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000661#else
662 return kUnsupportedFunctionError;
663#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000664}
665
666EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
667 return echo_cancellation_;
668}
669
670EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
671 return echo_control_mobile_;
672}
673
674GainControl* AudioProcessingImpl::gain_control() const {
675 return gain_control_;
676}
677
678HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
679 return high_pass_filter_;
680}
681
682LevelEstimator* AudioProcessingImpl::level_estimator() const {
683 return level_estimator_;
684}
685
686NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
687 return noise_suppression_;
688}
689
690VoiceDetection* AudioProcessingImpl::voice_detection() const {
691 return voice_detection_;
692}
693
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000694int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 return kNoError;
696}
ajm@google.com808e0e02011-08-03 21:08:51 +0000697
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000698bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000699 int enabled_count = 0;
700 std::list<ProcessingComponent*>::const_iterator it;
701 for (it = component_list_.begin(); it != component_list_.end(); it++) {
702 if ((*it)->is_component_enabled()) {
703 enabled_count++;
704 }
705 }
706
707 // Data is unchanged if no components are enabled, or if only level_estimator_
708 // or voice_detection_ is enabled.
709 if (enabled_count == 0) {
710 return false;
711 } else if (enabled_count == 1) {
712 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
713 return false;
714 }
715 } else if (enabled_count == 2) {
716 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
717 return false;
718 }
719 }
720 return true;
721}
722
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000723bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
724 // Check if we've upmixed or downmixed the audio.
725 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000726}
727
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000728bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
729 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
730}
731
732bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
733 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000734 // Only level_estimator_ is enabled.
735 return false;
736 } else if (sample_rate_hz_ == kSampleRate32kHz) {
737 // Something besides level_estimator_ is enabled, and we have super-wb.
738 return true;
739 }
740 return false;
741}
742
743#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000744int AudioProcessingImpl::WriteMessageToDebugFile() {
745 int32_t size = event_msg_->ByteSize();
746 if (size <= 0) {
747 return kUnspecifiedError;
748 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000749#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000750 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
751 // pretty safe in assuming little-endian.
752#endif
753
754 if (!event_msg_->SerializeToString(&event_str_)) {
755 return kUnspecifiedError;
756 }
757
758 // Write message preceded by its size.
759 if (!debug_file_->Write(&size, sizeof(int32_t))) {
760 return kFileError;
761 }
762 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
763 return kFileError;
764 }
765
766 event_msg_->Clear();
767
768 return 0;
769}
770
771int AudioProcessingImpl::WriteInitMessage() {
772 event_msg_->set_type(audioproc::Event::INIT);
773 audioproc::Init* msg = event_msg_->mutable_init();
774 msg->set_sample_rate(sample_rate_hz_);
775 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
776 msg->set_num_input_channels(num_input_channels_);
777 msg->set_num_output_channels(num_output_channels_);
778 msg->set_num_reverse_channels(num_reverse_channels_);
779
780 int err = WriteMessageToDebugFile();
781 if (err != kNoError) {
782 return err;
783 }
784
785 return kNoError;
786}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000787#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000788} // namespace webrtc