blob: 3ca90a76dd44d364d30b210e2771cff0ea5dbf03 [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.org60730cf2014-01-07 17:45:09 +0000300int AudioProcessingImpl::MaybeInitializeLocked(int sample_rate_hz,
301 int num_input_channels, int num_output_channels, int num_reverse_channels) {
302 if (sample_rate_hz == sample_rate_hz_ &&
303 num_input_channels == num_input_channels_ &&
304 num_output_channels == num_output_channels_ &&
305 num_reverse_channels == num_reverse_channels_) {
306 return kNoError;
307 }
308
309 if (sample_rate_hz != kSampleRate8kHz &&
310 sample_rate_hz != kSampleRate16kHz &&
311 sample_rate_hz != kSampleRate32kHz) {
312 return kBadSampleRateError;
313 }
314 if (num_output_channels > num_input_channels) {
315 return kBadNumberChannelsError;
316 }
317 // Only mono and stereo supported currently.
318 if (num_input_channels > 2 || num_input_channels < 1 ||
319 num_output_channels > 2 || num_output_channels < 1 ||
320 num_reverse_channels > 2 || num_reverse_channels < 1) {
321 return kBadNumberChannelsError;
322 }
323 if (echo_control_mobile_->is_enabled() && sample_rate_hz > kSampleRate16kHz) {
324 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
325 return kUnsupportedComponentError;
326 }
327
328 sample_rate_hz_ = sample_rate_hz;
329 samples_per_channel_ = kChunkSizeMs * sample_rate_hz / 1000;
330 num_input_channels_ = num_input_channels;
331 num_output_channels_ = num_output_channels;
332 num_reverse_channels_ = num_reverse_channels;
333
334 if (sample_rate_hz_ == kSampleRate32kHz) {
335 split_sample_rate_hz_ = kSampleRate16kHz;
336 } else {
337 split_sample_rate_hz_ = sample_rate_hz_;
338 }
339
340 return InitializeLocked();
341}
342
niklase@google.com470e71d2011-07-07 08:21:25 +0000343int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000344 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 int err = kNoError;
346
347 if (frame == NULL) {
348 return kNullPointerError;
349 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000350 // TODO(ajm): We now always set the output channels equal to the input
351 // channels here. Remove the ability to downmix entirely.
352 RETURN_ON_ERR(MaybeInitializeLocked(frame->sample_rate_hz_,
353 frame->num_channels_, frame->num_channels_, num_reverse_channels_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000354 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 return kBadDataLengthError;
356 }
357
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000358#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000360 event_msg_->set_type(audioproc::Event::STREAM);
361 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000362 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000363 frame->samples_per_channel_ *
364 frame->num_channels_;
365 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000366 msg->set_delay(stream_delay_ms_);
367 msg->set_drift(echo_cancellation_->stream_drift_samples());
368 msg->set_level(gain_control_->stream_analog_level());
andrew@webrtc.orgce8e0772014-02-12 15:28:30 +0000369 msg->set_keypress(key_pressed_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000371#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000372
373 capture_audio_->DeinterleaveFrom(frame);
374
375 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000376 if (num_output_channels_ < num_input_channels_) {
377 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000378 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 }
380
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000381 bool data_processed = is_data_processed();
382 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000383 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 // Split into a low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000385 WebRtcSpl_AnalysisQMF(capture_audio_->data(i),
386 capture_audio_->samples_per_channel(),
387 capture_audio_->low_pass_split_data(i),
388 capture_audio_->high_pass_split_data(i),
389 capture_audio_->analysis_filter_state1(i),
390 capture_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 }
392 }
393
394 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
395 if (err != kNoError) {
396 return err;
397 }
398
399 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
400 if (err != kNoError) {
401 return err;
402 }
403
404 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
405 if (err != kNoError) {
406 return err;
407 }
408
409 if (echo_control_mobile_->is_enabled() &&
410 noise_suppression_->is_enabled()) {
411 capture_audio_->CopyLowPassToReference();
412 }
413
414 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
415 if (err != kNoError) {
416 return err;
417 }
418
419 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
420 if (err != kNoError) {
421 return err;
422 }
423
424 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
425 if (err != kNoError) {
426 return err;
427 }
428
429 err = gain_control_->ProcessCaptureAudio(capture_audio_);
430 if (err != kNoError) {
431 return err;
432 }
433
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000434 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000435 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 // Recombine low and high bands.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000437 WebRtcSpl_SynthesisQMF(capture_audio_->low_pass_split_data(i),
438 capture_audio_->high_pass_split_data(i),
439 capture_audio_->samples_per_split_channel(),
440 capture_audio_->data(i),
441 capture_audio_->synthesis_filter_state1(i),
442 capture_audio_->synthesis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 }
444 }
445
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000446 // The level estimator operates on the recombined data.
447 err = level_estimator_->ProcessStream(capture_audio_);
448 if (err != kNoError) {
449 return err;
450 }
451
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000452 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000454#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000455 if (debug_file_->Open()) {
456 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000457 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000458 frame->samples_per_channel_ *
459 frame->num_channels_;
460 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000461 err = WriteMessageToDebugFile();
462 if (err != kNoError) {
463 return err;
464 }
465 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000466#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000467
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000468 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000469 return kNoError;
470}
471
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000472// TODO(ajm): Have AnalyzeReverseStream accept sample rates not matching the
473// primary stream and convert ourselves rather than having the user manage it.
474// We can be smarter and use the splitting filter when appropriate. Similarly,
475// perform downmixing here.
niklase@google.com470e71d2011-07-07 08:21:25 +0000476int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000477 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 int err = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 if (frame == NULL) {
480 return kNullPointerError;
481 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000482 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 return kBadSampleRateError;
484 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000485 RETURN_ON_ERR(MaybeInitializeLocked(sample_rate_hz_, num_input_channels_,
486 num_output_channels_, frame->num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000487
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000488#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000490 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
491 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000492 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000493 frame->samples_per_channel_ *
494 frame->num_channels_;
495 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000496 err = WriteMessageToDebugFile();
497 if (err != kNoError) {
498 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 }
500 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000501#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000502
503 render_audio_->DeinterleaveFrom(frame);
504
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000506 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 // Split into low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000508 WebRtcSpl_AnalysisQMF(render_audio_->data(i),
509 render_audio_->samples_per_channel(),
510 render_audio_->low_pass_split_data(i),
511 render_audio_->high_pass_split_data(i),
512 render_audio_->analysis_filter_state1(i),
513 render_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000514 }
515 }
516
517 // TODO(ajm): warnings possible from components?
518 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
519 if (err != kNoError) {
520 return err;
521 }
522
523 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
524 if (err != kNoError) {
525 return err;
526 }
527
528 err = gain_control_->ProcessRenderAudio(render_audio_);
529 if (err != kNoError) {
530 return err;
531 }
532
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 return err; // TODO(ajm): this is for returning warnings; necessary?
534}
535
536int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000537 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000539 delay += delay_offset_ms_;
540
niklase@google.com470e71d2011-07-07 08:21:25 +0000541 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000542 delay = 0;
543 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 }
545
546 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
547 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000548 delay = 500;
549 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 }
551
552 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000553 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554}
555
556int AudioProcessingImpl::stream_delay_ms() const {
557 return stream_delay_ms_;
558}
559
560bool AudioProcessingImpl::was_stream_delay_set() const {
561 return was_stream_delay_set_;
562}
563
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000564void AudioProcessingImpl::set_delay_offset_ms(int offset) {
565 CriticalSectionScoped crit_scoped(crit_);
566 delay_offset_ms_ = offset;
567}
568
569int AudioProcessingImpl::delay_offset_ms() const {
570 return delay_offset_ms_;
571}
572
andrew@webrtc.org75dd2882014-02-11 20:52:30 +0000573void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
574 key_pressed_ = key_pressed;
575}
576
577bool AudioProcessingImpl::stream_key_pressed() const {
578 return key_pressed_;
579}
580
niklase@google.com470e71d2011-07-07 08:21:25 +0000581int AudioProcessingImpl::StartDebugRecording(
582 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000583 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
585
586 if (filename == NULL) {
587 return kNullPointerError;
588 }
589
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000590#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 // Stop any ongoing recording.
592 if (debug_file_->Open()) {
593 if (debug_file_->CloseFile() == -1) {
594 return kFileError;
595 }
596 }
597
598 if (debug_file_->OpenFile(filename, false) == -1) {
599 debug_file_->CloseFile();
600 return kFileError;
601 }
602
ajm@google.com808e0e02011-08-03 21:08:51 +0000603 int err = WriteInitMessage();
604 if (err != kNoError) {
605 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000607 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000608#else
609 return kUnsupportedFunctionError;
610#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000611}
612
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000613int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
614 CriticalSectionScoped crit_scoped(crit_);
615
616 if (handle == NULL) {
617 return kNullPointerError;
618 }
619
620#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
621 // Stop any ongoing recording.
622 if (debug_file_->Open()) {
623 if (debug_file_->CloseFile() == -1) {
624 return kFileError;
625 }
626 }
627
628 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
629 return kFileError;
630 }
631
632 int err = WriteInitMessage();
633 if (err != kNoError) {
634 return err;
635 }
636 return kNoError;
637#else
638 return kUnsupportedFunctionError;
639#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
640}
641
niklase@google.com470e71d2011-07-07 08:21:25 +0000642int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000643 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000644
645#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000646 // We just return if recording hasn't started.
647 if (debug_file_->Open()) {
648 if (debug_file_->CloseFile() == -1) {
649 return kFileError;
650 }
651 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000653#else
654 return kUnsupportedFunctionError;
655#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000656}
657
658EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
659 return echo_cancellation_;
660}
661
662EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
663 return echo_control_mobile_;
664}
665
666GainControl* AudioProcessingImpl::gain_control() const {
667 return gain_control_;
668}
669
670HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
671 return high_pass_filter_;
672}
673
674LevelEstimator* AudioProcessingImpl::level_estimator() const {
675 return level_estimator_;
676}
677
678NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
679 return noise_suppression_;
680}
681
682VoiceDetection* AudioProcessingImpl::voice_detection() const {
683 return voice_detection_;
684}
685
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000686int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000687 return kNoError;
688}
ajm@google.com808e0e02011-08-03 21:08:51 +0000689
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000690bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000691 int enabled_count = 0;
692 std::list<ProcessingComponent*>::const_iterator it;
693 for (it = component_list_.begin(); it != component_list_.end(); it++) {
694 if ((*it)->is_component_enabled()) {
695 enabled_count++;
696 }
697 }
698
699 // Data is unchanged if no components are enabled, or if only level_estimator_
700 // or voice_detection_ is enabled.
701 if (enabled_count == 0) {
702 return false;
703 } else if (enabled_count == 1) {
704 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
705 return false;
706 }
707 } else if (enabled_count == 2) {
708 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
709 return false;
710 }
711 }
712 return true;
713}
714
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000715bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
716 // Check if we've upmixed or downmixed the audio.
717 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000718}
719
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000720bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
721 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
722}
723
724bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
725 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000726 // Only level_estimator_ is enabled.
727 return false;
728 } else if (sample_rate_hz_ == kSampleRate32kHz) {
729 // Something besides level_estimator_ is enabled, and we have super-wb.
730 return true;
731 }
732 return false;
733}
734
735#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000736int AudioProcessingImpl::WriteMessageToDebugFile() {
737 int32_t size = event_msg_->ByteSize();
738 if (size <= 0) {
739 return kUnspecifiedError;
740 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000741#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000742 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
743 // pretty safe in assuming little-endian.
744#endif
745
746 if (!event_msg_->SerializeToString(&event_str_)) {
747 return kUnspecifiedError;
748 }
749
750 // Write message preceded by its size.
751 if (!debug_file_->Write(&size, sizeof(int32_t))) {
752 return kFileError;
753 }
754 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
755 return kFileError;
756 }
757
758 event_msg_->Clear();
759
760 return 0;
761}
762
763int AudioProcessingImpl::WriteInitMessage() {
764 event_msg_->set_type(audioproc::Event::INIT);
765 audioproc::Init* msg = event_msg_->mutable_init();
766 msg->set_sample_rate(sample_rate_hz_);
767 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
768 msg->set_num_input_channels(num_input_channels_);
769 msg->set_num_output_channels(num_output_channels_);
770 msg->set_num_reverse_channels(num_reverse_channels_);
771
772 int err = WriteMessageToDebugFile();
773 if (err != kNoError) {
774 return err;
775 }
776
777 return kNoError;
778}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000779#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000780} // namespace webrtc