blob: 48297fcd060f196d217ee82c050f79fe6bc9136f [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
andrew@webrtc.orge84978f2014-01-25 02:09:06 +000074AudioProcessingImpl::AudioProcessingImpl(const Config& config)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000075 : echo_cancellation_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000076 echo_control_mobile_(NULL),
77 gain_control_(NULL),
78 high_pass_filter_(NULL),
79 level_estimator_(NULL),
80 noise_suppression_(NULL),
81 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000082 crit_(CriticalSectionWrapper::CreateCriticalSection()),
83 render_audio_(NULL),
84 capture_audio_(NULL),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000085#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
86 debug_file_(FileWrapper::Create()),
87 event_msg_(new audioproc::Event()),
88#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000089 sample_rate_hz_(kSampleRate16kHz),
90 split_sample_rate_hz_(kSampleRate16kHz),
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000091 samples_per_channel_(kChunkSizeMs * sample_rate_hz_ / 1000),
niklase@google.com470e71d2011-07-07 08:21:25 +000092 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +000093 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000094 was_stream_delay_set_(false),
ajm@google.com808e0e02011-08-03 21:08:51 +000095 num_reverse_channels_(1),
96 num_input_channels_(1),
andrew@webrtc.org07b59502014-02-12 16:41:13 +000097 num_output_channels_(1),
andrew@webrtc.org38bf2492014-02-13 17:43:44 +000098 output_will_be_muted_(false),
andrew@webrtc.org07b59502014-02-12 16:41:13 +000099 key_pressed_(false) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000100 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 component_list_.push_back(echo_cancellation_);
102
103 echo_control_mobile_ = new EchoControlMobileImpl(this);
104 component_list_.push_back(echo_control_mobile_);
105
106 gain_control_ = new GainControlImpl(this);
107 component_list_.push_back(gain_control_);
108
109 high_pass_filter_ = new HighPassFilterImpl(this);
110 component_list_.push_back(high_pass_filter_);
111
112 level_estimator_ = new LevelEstimatorImpl(this);
113 component_list_.push_back(level_estimator_);
114
115 noise_suppression_ = new NoiseSuppressionImpl(this);
116 component_list_.push_back(noise_suppression_);
117
118 voice_detection_ = new VoiceDetectionImpl(this);
119 component_list_.push_back(voice_detection_);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000120
121 SetExtraOptions(config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
124AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000125 {
126 CriticalSectionScoped crit_scoped(crit_);
127 while (!component_list_.empty()) {
128 ProcessingComponent* component = component_list_.front();
129 component->Destroy();
130 delete component;
131 component_list_.pop_front();
132 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000133
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000134#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000135 if (debug_file_->Open()) {
136 debug_file_->CloseFile();
137 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000138#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000139
andrew@webrtc.org81865342012-10-27 00:28:27 +0000140 if (render_audio_) {
141 delete render_audio_;
142 render_audio_ = NULL;
143 }
144
145 if (capture_audio_) {
146 delete capture_audio_;
147 capture_audio_ = NULL;
148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 }
150
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000151 delete crit_;
152 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000153}
154
155CriticalSectionWrapper* AudioProcessingImpl::crit() const {
156 return crit_;
157}
158
159int AudioProcessingImpl::split_sample_rate_hz() const {
160 return split_sample_rate_hz_;
161}
162
163int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000164 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 return InitializeLocked();
166}
167
168int AudioProcessingImpl::InitializeLocked() {
169 if (render_audio_ != NULL) {
170 delete render_audio_;
171 render_audio_ = NULL;
172 }
173
174 if (capture_audio_ != NULL) {
175 delete capture_audio_;
176 capture_audio_ = NULL;
177 }
178
ajm@google.com808e0e02011-08-03 21:08:51 +0000179 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000181 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 samples_per_channel_);
183
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 // Initialize all components.
185 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000186 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 int err = (*it)->Initialize();
188 if (err != kNoError) {
189 return err;
190 }
191 }
192
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000193#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000194 if (debug_file_->Open()) {
195 int err = WriteInitMessage();
196 if (err != kNoError) {
197 return err;
198 }
199 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000200#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000201
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 return kNoError;
203}
204
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000205void AudioProcessingImpl::SetExtraOptions(const Config& config) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000206 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000207 std::list<ProcessingComponent*>::iterator it;
208 for (it = component_list_.begin(); it != component_list_.end(); ++it)
209 (*it)->SetExtraOptions(config);
210}
211
aluebs@webrtc.org0b72f582013-11-19 15:17:51 +0000212int AudioProcessingImpl::EnableExperimentalNs(bool enable) {
213 return kNoError;
214}
215
niklase@google.com470e71d2011-07-07 08:21:25 +0000216int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000217 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000218 if (rate == sample_rate_hz_) {
219 return kNoError;
220 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 if (rate != kSampleRate8kHz &&
222 rate != kSampleRate16kHz &&
223 rate != kSampleRate32kHz) {
224 return kBadParameterError;
225 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000226 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
227 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
228 return kUnsupportedComponentError;
229 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
231 sample_rate_hz_ = rate;
232 samples_per_channel_ = rate / 100;
233
234 if (sample_rate_hz_ == kSampleRate32kHz) {
235 split_sample_rate_hz_ = kSampleRate16kHz;
236 } else {
237 split_sample_rate_hz_ = sample_rate_hz_;
238 }
239
240 return InitializeLocked();
241}
242
243int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000244 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 return sample_rate_hz_;
246}
247
248int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000249 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000250 if (channels == num_reverse_channels_) {
251 return kNoError;
252 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 // Only stereo supported currently.
254 if (channels > 2 || channels < 1) {
255 return kBadParameterError;
256 }
257
ajm@google.com808e0e02011-08-03 21:08:51 +0000258 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
260 return InitializeLocked();
261}
262
263int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000264 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000265}
266
267int AudioProcessingImpl::set_num_channels(
268 int input_channels,
269 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000270 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000271 if (input_channels == num_input_channels_ &&
272 output_channels == num_output_channels_) {
273 return kNoError;
274 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 if (output_channels > input_channels) {
276 return kBadParameterError;
277 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000279 if (input_channels > 2 || input_channels < 1 ||
280 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 return kBadParameterError;
282 }
283
ajm@google.com808e0e02011-08-03 21:08:51 +0000284 num_input_channels_ = input_channels;
285 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000286
287 return InitializeLocked();
288}
289
290int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000291 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000292}
293
294int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000295 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000296}
297
andrew@webrtc.org17342e52014-02-12 22:28:31 +0000298void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
299 output_will_be_muted_ = muted;
300}
301
302bool AudioProcessingImpl::output_will_be_muted() const {
303 return output_will_be_muted_;
304}
305
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000306int AudioProcessingImpl::MaybeInitializeLocked(int sample_rate_hz,
307 int num_input_channels, int num_output_channels, int num_reverse_channels) {
308 if (sample_rate_hz == sample_rate_hz_ &&
309 num_input_channels == num_input_channels_ &&
310 num_output_channels == num_output_channels_ &&
311 num_reverse_channels == num_reverse_channels_) {
312 return kNoError;
313 }
314
315 if (sample_rate_hz != kSampleRate8kHz &&
316 sample_rate_hz != kSampleRate16kHz &&
317 sample_rate_hz != kSampleRate32kHz) {
318 return kBadSampleRateError;
319 }
320 if (num_output_channels > num_input_channels) {
321 return kBadNumberChannelsError;
322 }
323 // Only mono and stereo supported currently.
324 if (num_input_channels > 2 || num_input_channels < 1 ||
325 num_output_channels > 2 || num_output_channels < 1 ||
326 num_reverse_channels > 2 || num_reverse_channels < 1) {
327 return kBadNumberChannelsError;
328 }
329 if (echo_control_mobile_->is_enabled() && sample_rate_hz > kSampleRate16kHz) {
330 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
331 return kUnsupportedComponentError;
332 }
333
334 sample_rate_hz_ = sample_rate_hz;
335 samples_per_channel_ = kChunkSizeMs * sample_rate_hz / 1000;
336 num_input_channels_ = num_input_channels;
337 num_output_channels_ = num_output_channels;
338 num_reverse_channels_ = num_reverse_channels;
339
340 if (sample_rate_hz_ == kSampleRate32kHz) {
341 split_sample_rate_hz_ = kSampleRate16kHz;
342 } else {
343 split_sample_rate_hz_ = sample_rate_hz_;
344 }
345
346 return InitializeLocked();
347}
348
niklase@google.com470e71d2011-07-07 08:21:25 +0000349int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000350 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 int err = kNoError;
352
353 if (frame == NULL) {
354 return kNullPointerError;
355 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000356 // TODO(ajm): We now always set the output channels equal to the input
357 // channels here. Remove the ability to downmix entirely.
358 RETURN_ON_ERR(MaybeInitializeLocked(frame->sample_rate_hz_,
359 frame->num_channels_, frame->num_channels_, num_reverse_channels_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000360 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000361 return kBadDataLengthError;
362 }
363
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000364#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000366 event_msg_->set_type(audioproc::Event::STREAM);
367 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000368 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000369 frame->samples_per_channel_ *
370 frame->num_channels_;
371 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000372 msg->set_delay(stream_delay_ms_);
373 msg->set_drift(echo_cancellation_->stream_drift_samples());
374 msg->set_level(gain_control_->stream_analog_level());
andrew@webrtc.orgce8e0772014-02-12 15:28:30 +0000375 msg->set_keypress(key_pressed_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000377#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
379 capture_audio_->DeinterleaveFrom(frame);
380
381 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000382 if (num_output_channels_ < num_input_channels_) {
383 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000384 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 }
386
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000387 bool data_processed = is_data_processed();
388 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000389 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 // Split into a low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000391 WebRtcSpl_AnalysisQMF(capture_audio_->data(i),
392 capture_audio_->samples_per_channel(),
393 capture_audio_->low_pass_split_data(i),
394 capture_audio_->high_pass_split_data(i),
395 capture_audio_->analysis_filter_state1(i),
396 capture_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 }
398 }
399
400 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
401 if (err != kNoError) {
402 return err;
403 }
404
405 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
406 if (err != kNoError) {
407 return err;
408 }
409
410 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
411 if (err != kNoError) {
412 return err;
413 }
414
415 if (echo_control_mobile_->is_enabled() &&
416 noise_suppression_->is_enabled()) {
417 capture_audio_->CopyLowPassToReference();
418 }
419
420 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
421 if (err != kNoError) {
422 return err;
423 }
424
425 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
426 if (err != kNoError) {
427 return err;
428 }
429
430 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
431 if (err != kNoError) {
432 return err;
433 }
434
435 err = gain_control_->ProcessCaptureAudio(capture_audio_);
436 if (err != kNoError) {
437 return err;
438 }
439
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000440 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000441 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 // Recombine low and high bands.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000443 WebRtcSpl_SynthesisQMF(capture_audio_->low_pass_split_data(i),
444 capture_audio_->high_pass_split_data(i),
445 capture_audio_->samples_per_split_channel(),
446 capture_audio_->data(i),
447 capture_audio_->synthesis_filter_state1(i),
448 capture_audio_->synthesis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 }
450 }
451
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000452 // The level estimator operates on the recombined data.
453 err = level_estimator_->ProcessStream(capture_audio_);
454 if (err != kNoError) {
455 return err;
456 }
457
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000458 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000459
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000460#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000461 if (debug_file_->Open()) {
462 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000463 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000464 frame->samples_per_channel_ *
465 frame->num_channels_;
466 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000467 err = WriteMessageToDebugFile();
468 if (err != kNoError) {
469 return err;
470 }
471 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000472#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000473
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000474 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 return kNoError;
476}
477
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000478// TODO(ajm): Have AnalyzeReverseStream accept sample rates not matching the
479// primary stream and convert ourselves rather than having the user manage it.
480// We can be smarter and use the splitting filter when appropriate. Similarly,
481// perform downmixing here.
niklase@google.com470e71d2011-07-07 08:21:25 +0000482int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000483 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 int err = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 if (frame == NULL) {
486 return kNullPointerError;
487 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000488 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 return kBadSampleRateError;
490 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000491 RETURN_ON_ERR(MaybeInitializeLocked(sample_rate_hz_, num_input_channels_,
492 num_output_channels_, frame->num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000493
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000494#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000495 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000496 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
497 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000498 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000499 frame->samples_per_channel_ *
500 frame->num_channels_;
501 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000502 err = WriteMessageToDebugFile();
503 if (err != kNoError) {
504 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 }
506 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000507#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000508
509 render_audio_->DeinterleaveFrom(frame);
510
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000512 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 // Split into low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000514 WebRtcSpl_AnalysisQMF(render_audio_->data(i),
515 render_audio_->samples_per_channel(),
516 render_audio_->low_pass_split_data(i),
517 render_audio_->high_pass_split_data(i),
518 render_audio_->analysis_filter_state1(i),
519 render_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000520 }
521 }
522
523 // TODO(ajm): warnings possible from components?
524 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
525 if (err != kNoError) {
526 return err;
527 }
528
529 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
530 if (err != kNoError) {
531 return err;
532 }
533
534 err = gain_control_->ProcessRenderAudio(render_audio_);
535 if (err != kNoError) {
536 return err;
537 }
538
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 return err; // TODO(ajm): this is for returning warnings; necessary?
540}
541
542int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000543 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000545 delay += delay_offset_ms_;
546
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000548 delay = 0;
549 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 }
551
552 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
553 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000554 delay = 500;
555 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 }
557
558 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000559 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000560}
561
562int AudioProcessingImpl::stream_delay_ms() const {
563 return stream_delay_ms_;
564}
565
566bool AudioProcessingImpl::was_stream_delay_set() const {
567 return was_stream_delay_set_;
568}
569
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000570void AudioProcessingImpl::set_delay_offset_ms(int offset) {
571 CriticalSectionScoped crit_scoped(crit_);
572 delay_offset_ms_ = offset;
573}
574
575int AudioProcessingImpl::delay_offset_ms() const {
576 return delay_offset_ms_;
577}
578
andrew@webrtc.org75dd2882014-02-11 20:52:30 +0000579void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
580 key_pressed_ = key_pressed;
581}
582
583bool AudioProcessingImpl::stream_key_pressed() const {
584 return key_pressed_;
585}
586
niklase@google.com470e71d2011-07-07 08:21:25 +0000587int AudioProcessingImpl::StartDebugRecording(
588 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000589 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000590 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
591
592 if (filename == NULL) {
593 return kNullPointerError;
594 }
595
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000596#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 // Stop any ongoing recording.
598 if (debug_file_->Open()) {
599 if (debug_file_->CloseFile() == -1) {
600 return kFileError;
601 }
602 }
603
604 if (debug_file_->OpenFile(filename, false) == -1) {
605 debug_file_->CloseFile();
606 return kFileError;
607 }
608
ajm@google.com808e0e02011-08-03 21:08:51 +0000609 int err = WriteInitMessage();
610 if (err != kNoError) {
611 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000614#else
615 return kUnsupportedFunctionError;
616#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000617}
618
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000619int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
620 CriticalSectionScoped crit_scoped(crit_);
621
622 if (handle == NULL) {
623 return kNullPointerError;
624 }
625
626#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
627 // Stop any ongoing recording.
628 if (debug_file_->Open()) {
629 if (debug_file_->CloseFile() == -1) {
630 return kFileError;
631 }
632 }
633
634 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
635 return kFileError;
636 }
637
638 int err = WriteInitMessage();
639 if (err != kNoError) {
640 return err;
641 }
642 return kNoError;
643#else
644 return kUnsupportedFunctionError;
645#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
646}
647
niklase@google.com470e71d2011-07-07 08:21:25 +0000648int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000649 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000650
651#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 // We just return if recording hasn't started.
653 if (debug_file_->Open()) {
654 if (debug_file_->CloseFile() == -1) {
655 return kFileError;
656 }
657 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000659#else
660 return kUnsupportedFunctionError;
661#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000662}
663
664EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
665 return echo_cancellation_;
666}
667
668EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
669 return echo_control_mobile_;
670}
671
672GainControl* AudioProcessingImpl::gain_control() const {
673 return gain_control_;
674}
675
676HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
677 return high_pass_filter_;
678}
679
680LevelEstimator* AudioProcessingImpl::level_estimator() const {
681 return level_estimator_;
682}
683
684NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
685 return noise_suppression_;
686}
687
688VoiceDetection* AudioProcessingImpl::voice_detection() const {
689 return voice_detection_;
690}
691
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000692bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000693 int enabled_count = 0;
694 std::list<ProcessingComponent*>::const_iterator it;
695 for (it = component_list_.begin(); it != component_list_.end(); it++) {
696 if ((*it)->is_component_enabled()) {
697 enabled_count++;
698 }
699 }
700
701 // Data is unchanged if no components are enabled, or if only level_estimator_
702 // or voice_detection_ is enabled.
703 if (enabled_count == 0) {
704 return false;
705 } else if (enabled_count == 1) {
706 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
707 return false;
708 }
709 } else if (enabled_count == 2) {
710 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
711 return false;
712 }
713 }
714 return true;
715}
716
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000717bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
718 // Check if we've upmixed or downmixed the audio.
719 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000720}
721
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000722bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
723 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
724}
725
726bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
727 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000728 // Only level_estimator_ is enabled.
729 return false;
730 } else if (sample_rate_hz_ == kSampleRate32kHz) {
731 // Something besides level_estimator_ is enabled, and we have super-wb.
732 return true;
733 }
734 return false;
735}
736
737#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000738int AudioProcessingImpl::WriteMessageToDebugFile() {
739 int32_t size = event_msg_->ByteSize();
740 if (size <= 0) {
741 return kUnspecifiedError;
742 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000743#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000744 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
745 // pretty safe in assuming little-endian.
746#endif
747
748 if (!event_msg_->SerializeToString(&event_str_)) {
749 return kUnspecifiedError;
750 }
751
752 // Write message preceded by its size.
753 if (!debug_file_->Write(&size, sizeof(int32_t))) {
754 return kFileError;
755 }
756 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
757 return kFileError;
758 }
759
760 event_msg_->Clear();
761
762 return 0;
763}
764
765int AudioProcessingImpl::WriteInitMessage() {
766 event_msg_->set_type(audioproc::Event::INIT);
767 audioproc::Init* msg = event_msg_->mutable_init();
768 msg->set_sample_rate(sample_rate_hz_);
769 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
770 msg->set_num_input_channels(num_input_channels_);
771 msg->set_num_output_channels(num_output_channels_);
772 msg->set_num_reverse_channels(num_reverse_channels_);
773
774 int err = WriteMessageToDebugFile();
775 if (err != kNoError) {
776 return err;
777 }
778
779 return kNoError;
780}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000781#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000782} // namespace webrtc