blob: 377f78fe0f191b79e60b10e9784e5bd3418cc6d9 [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),
100 num_output_channels_(1) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000101 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +0000102 component_list_.push_back(echo_cancellation_);
103
104 echo_control_mobile_ = new EchoControlMobileImpl(this);
105 component_list_.push_back(echo_control_mobile_);
106
107 gain_control_ = new GainControlImpl(this);
108 component_list_.push_back(gain_control_);
109
110 high_pass_filter_ = new HighPassFilterImpl(this);
111 component_list_.push_back(high_pass_filter_);
112
113 level_estimator_ = new LevelEstimatorImpl(this);
114 component_list_.push_back(level_estimator_);
115
116 noise_suppression_ = new NoiseSuppressionImpl(this);
117 component_list_.push_back(noise_suppression_);
118
119 voice_detection_ = new VoiceDetectionImpl(this);
120 component_list_.push_back(voice_detection_);
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000121
122 SetExtraOptions(config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000123}
124
125AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000126 {
127 CriticalSectionScoped crit_scoped(crit_);
128 while (!component_list_.empty()) {
129 ProcessingComponent* component = component_list_.front();
130 component->Destroy();
131 delete component;
132 component_list_.pop_front();
133 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000135#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000136 if (debug_file_->Open()) {
137 debug_file_->CloseFile();
138 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000139#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000140
andrew@webrtc.org81865342012-10-27 00:28:27 +0000141 if (render_audio_) {
142 delete render_audio_;
143 render_audio_ = NULL;
144 }
145
146 if (capture_audio_) {
147 delete capture_audio_;
148 capture_audio_ = NULL;
149 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 }
151
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000152 delete crit_;
153 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154}
155
156CriticalSectionWrapper* AudioProcessingImpl::crit() const {
157 return crit_;
158}
159
160int AudioProcessingImpl::split_sample_rate_hz() const {
161 return split_sample_rate_hz_;
162}
163
164int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000165 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 return InitializeLocked();
167}
168
169int AudioProcessingImpl::InitializeLocked() {
170 if (render_audio_ != NULL) {
171 delete render_audio_;
172 render_audio_ = NULL;
173 }
174
175 if (capture_audio_ != NULL) {
176 delete capture_audio_;
177 capture_audio_ = NULL;
178 }
179
ajm@google.com808e0e02011-08-03 21:08:51 +0000180 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000181 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000182 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 samples_per_channel_);
184
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 // Initialize all components.
186 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000187 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 int err = (*it)->Initialize();
189 if (err != kNoError) {
190 return err;
191 }
192 }
193
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000194#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000195 if (debug_file_->Open()) {
196 int err = WriteInitMessage();
197 if (err != kNoError) {
198 return err;
199 }
200 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000201#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000202
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 return kNoError;
204}
205
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000206void AudioProcessingImpl::SetExtraOptions(const Config& config) {
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000207 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000208 std::list<ProcessingComponent*>::iterator it;
209 for (it = component_list_.begin(); it != component_list_.end(); ++it)
210 (*it)->SetExtraOptions(config);
211}
212
aluebs@webrtc.org0b72f582013-11-19 15:17:51 +0000213int AudioProcessingImpl::EnableExperimentalNs(bool enable) {
214 return kNoError;
215}
216
niklase@google.com470e71d2011-07-07 08:21:25 +0000217int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000218 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000219 if (rate == sample_rate_hz_) {
220 return kNoError;
221 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 if (rate != kSampleRate8kHz &&
223 rate != kSampleRate16kHz &&
224 rate != kSampleRate32kHz) {
225 return kBadParameterError;
226 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000227 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
228 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
229 return kUnsupportedComponentError;
230 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000231
232 sample_rate_hz_ = rate;
233 samples_per_channel_ = rate / 100;
234
235 if (sample_rate_hz_ == kSampleRate32kHz) {
236 split_sample_rate_hz_ = kSampleRate16kHz;
237 } else {
238 split_sample_rate_hz_ = sample_rate_hz_;
239 }
240
241 return InitializeLocked();
242}
243
244int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000245 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000246 return sample_rate_hz_;
247}
248
249int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000250 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000251 if (channels == num_reverse_channels_) {
252 return kNoError;
253 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 // Only stereo supported currently.
255 if (channels > 2 || channels < 1) {
256 return kBadParameterError;
257 }
258
ajm@google.com808e0e02011-08-03 21:08:51 +0000259 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
261 return InitializeLocked();
262}
263
264int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000265 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
268int AudioProcessingImpl::set_num_channels(
269 int input_channels,
270 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000271 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000272 if (input_channels == num_input_channels_ &&
273 output_channels == num_output_channels_) {
274 return kNoError;
275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276 if (output_channels > input_channels) {
277 return kBadParameterError;
278 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000280 if (input_channels > 2 || input_channels < 1 ||
281 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 return kBadParameterError;
283 }
284
ajm@google.com808e0e02011-08-03 21:08:51 +0000285 num_input_channels_ = input_channels;
286 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000287
288 return InitializeLocked();
289}
290
291int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000292 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293}
294
295int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000296 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000297}
298
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000299int AudioProcessingImpl::MaybeInitializeLocked(int sample_rate_hz,
300 int num_input_channels, int num_output_channels, int num_reverse_channels) {
301 if (sample_rate_hz == sample_rate_hz_ &&
302 num_input_channels == num_input_channels_ &&
303 num_output_channels == num_output_channels_ &&
304 num_reverse_channels == num_reverse_channels_) {
305 return kNoError;
306 }
307
308 if (sample_rate_hz != kSampleRate8kHz &&
309 sample_rate_hz != kSampleRate16kHz &&
310 sample_rate_hz != kSampleRate32kHz) {
311 return kBadSampleRateError;
312 }
313 if (num_output_channels > num_input_channels) {
314 return kBadNumberChannelsError;
315 }
316 // Only mono and stereo supported currently.
317 if (num_input_channels > 2 || num_input_channels < 1 ||
318 num_output_channels > 2 || num_output_channels < 1 ||
319 num_reverse_channels > 2 || num_reverse_channels < 1) {
320 return kBadNumberChannelsError;
321 }
322 if (echo_control_mobile_->is_enabled() && sample_rate_hz > kSampleRate16kHz) {
323 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
324 return kUnsupportedComponentError;
325 }
326
327 sample_rate_hz_ = sample_rate_hz;
328 samples_per_channel_ = kChunkSizeMs * sample_rate_hz / 1000;
329 num_input_channels_ = num_input_channels;
330 num_output_channels_ = num_output_channels;
331 num_reverse_channels_ = num_reverse_channels;
332
333 if (sample_rate_hz_ == kSampleRate32kHz) {
334 split_sample_rate_hz_ = kSampleRate16kHz;
335 } else {
336 split_sample_rate_hz_ = sample_rate_hz_;
337 }
338
339 return InitializeLocked();
340}
341
niklase@google.com470e71d2011-07-07 08:21:25 +0000342int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000343 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000344 int err = kNoError;
345
346 if (frame == NULL) {
347 return kNullPointerError;
348 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000349 // TODO(ajm): We now always set the output channels equal to the input
350 // channels here. Remove the ability to downmix entirely.
351 RETURN_ON_ERR(MaybeInitializeLocked(frame->sample_rate_hz_,
352 frame->num_channels_, frame->num_channels_, num_reverse_channels_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000353 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 return kBadDataLengthError;
355 }
356
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000357#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000359 event_msg_->set_type(audioproc::Event::STREAM);
360 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000361 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000362 frame->samples_per_channel_ *
363 frame->num_channels_;
364 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000365 msg->set_delay(stream_delay_ms_);
366 msg->set_drift(echo_cancellation_->stream_drift_samples());
367 msg->set_level(gain_control_->stream_analog_level());
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000369#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000370
371 capture_audio_->DeinterleaveFrom(frame);
372
373 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000374 if (num_output_channels_ < num_input_channels_) {
375 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000376 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 }
378
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000379 bool data_processed = is_data_processed();
380 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000381 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 // Split into a low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000383 WebRtcSpl_AnalysisQMF(capture_audio_->data(i),
384 capture_audio_->samples_per_channel(),
385 capture_audio_->low_pass_split_data(i),
386 capture_audio_->high_pass_split_data(i),
387 capture_audio_->analysis_filter_state1(i),
388 capture_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 }
390 }
391
392 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
393 if (err != kNoError) {
394 return err;
395 }
396
397 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
398 if (err != kNoError) {
399 return err;
400 }
401
402 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
403 if (err != kNoError) {
404 return err;
405 }
406
407 if (echo_control_mobile_->is_enabled() &&
408 noise_suppression_->is_enabled()) {
409 capture_audio_->CopyLowPassToReference();
410 }
411
412 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
413 if (err != kNoError) {
414 return err;
415 }
416
417 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
418 if (err != kNoError) {
419 return err;
420 }
421
422 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
423 if (err != kNoError) {
424 return err;
425 }
426
427 err = gain_control_->ProcessCaptureAudio(capture_audio_);
428 if (err != kNoError) {
429 return err;
430 }
431
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000432 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000433 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 // Recombine low and high bands.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000435 WebRtcSpl_SynthesisQMF(capture_audio_->low_pass_split_data(i),
436 capture_audio_->high_pass_split_data(i),
437 capture_audio_->samples_per_split_channel(),
438 capture_audio_->data(i),
439 capture_audio_->synthesis_filter_state1(i),
440 capture_audio_->synthesis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000441 }
442 }
443
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000444 // The level estimator operates on the recombined data.
445 err = level_estimator_->ProcessStream(capture_audio_);
446 if (err != kNoError) {
447 return err;
448 }
449
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000450 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000451
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000452#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000453 if (debug_file_->Open()) {
454 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000455 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000456 frame->samples_per_channel_ *
457 frame->num_channels_;
458 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000459 err = WriteMessageToDebugFile();
460 if (err != kNoError) {
461 return err;
462 }
463 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000464#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000465
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000466 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 return kNoError;
468}
469
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000470// TODO(ajm): Have AnalyzeReverseStream accept sample rates not matching the
471// primary stream and convert ourselves rather than having the user manage it.
472// We can be smarter and use the splitting filter when appropriate. Similarly,
473// perform downmixing here.
niklase@google.com470e71d2011-07-07 08:21:25 +0000474int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000475 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 int err = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 if (frame == NULL) {
478 return kNullPointerError;
479 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000480 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 return kBadSampleRateError;
482 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000483 RETURN_ON_ERR(MaybeInitializeLocked(sample_rate_hz_, num_input_channels_,
484 num_output_channels_, frame->num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000486#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000488 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
489 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000490 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000491 frame->samples_per_channel_ *
492 frame->num_channels_;
493 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 err = WriteMessageToDebugFile();
495 if (err != kNoError) {
496 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 }
498 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000499#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000500
501 render_audio_->DeinterleaveFrom(frame);
502
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000504 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 // Split into low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000506 WebRtcSpl_AnalysisQMF(render_audio_->data(i),
507 render_audio_->samples_per_channel(),
508 render_audio_->low_pass_split_data(i),
509 render_audio_->high_pass_split_data(i),
510 render_audio_->analysis_filter_state1(i),
511 render_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 }
513 }
514
515 // TODO(ajm): warnings possible from components?
516 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
517 if (err != kNoError) {
518 return err;
519 }
520
521 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
522 if (err != kNoError) {
523 return err;
524 }
525
526 err = gain_control_->ProcessRenderAudio(render_audio_);
527 if (err != kNoError) {
528 return err;
529 }
530
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 return err; // TODO(ajm): this is for returning warnings; necessary?
532}
533
534int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000535 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000537 delay += delay_offset_ms_;
538
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000540 delay = 0;
541 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 }
543
544 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
545 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000546 delay = 500;
547 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000548 }
549
550 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000551 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552}
553
554int AudioProcessingImpl::stream_delay_ms() const {
555 return stream_delay_ms_;
556}
557
558bool AudioProcessingImpl::was_stream_delay_set() const {
559 return was_stream_delay_set_;
560}
561
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000562void AudioProcessingImpl::set_delay_offset_ms(int offset) {
563 CriticalSectionScoped crit_scoped(crit_);
564 delay_offset_ms_ = offset;
565}
566
567int AudioProcessingImpl::delay_offset_ms() const {
568 return delay_offset_ms_;
569}
570
andrew@webrtc.org75dd2882014-02-11 20:52:30 +0000571void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
572 key_pressed_ = key_pressed;
573}
574
575bool AudioProcessingImpl::stream_key_pressed() const {
576 return key_pressed_;
577}
578
niklase@google.com470e71d2011-07-07 08:21:25 +0000579int AudioProcessingImpl::StartDebugRecording(
580 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000581 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
583
584 if (filename == NULL) {
585 return kNullPointerError;
586 }
587
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000588#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 // Stop any ongoing recording.
590 if (debug_file_->Open()) {
591 if (debug_file_->CloseFile() == -1) {
592 return kFileError;
593 }
594 }
595
596 if (debug_file_->OpenFile(filename, false) == -1) {
597 debug_file_->CloseFile();
598 return kFileError;
599 }
600
ajm@google.com808e0e02011-08-03 21:08:51 +0000601 int err = WriteInitMessage();
602 if (err != kNoError) {
603 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000606#else
607 return kUnsupportedFunctionError;
608#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000609}
610
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000611int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
612 CriticalSectionScoped crit_scoped(crit_);
613
614 if (handle == NULL) {
615 return kNullPointerError;
616 }
617
618#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
619 // Stop any ongoing recording.
620 if (debug_file_->Open()) {
621 if (debug_file_->CloseFile() == -1) {
622 return kFileError;
623 }
624 }
625
626 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
627 return kFileError;
628 }
629
630 int err = WriteInitMessage();
631 if (err != kNoError) {
632 return err;
633 }
634 return kNoError;
635#else
636 return kUnsupportedFunctionError;
637#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
638}
639
niklase@google.com470e71d2011-07-07 08:21:25 +0000640int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000641 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000642
643#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 // We just return if recording hasn't started.
645 if (debug_file_->Open()) {
646 if (debug_file_->CloseFile() == -1) {
647 return kFileError;
648 }
649 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000651#else
652 return kUnsupportedFunctionError;
653#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000654}
655
656EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
657 return echo_cancellation_;
658}
659
660EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
661 return echo_control_mobile_;
662}
663
664GainControl* AudioProcessingImpl::gain_control() const {
665 return gain_control_;
666}
667
668HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
669 return high_pass_filter_;
670}
671
672LevelEstimator* AudioProcessingImpl::level_estimator() const {
673 return level_estimator_;
674}
675
676NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
677 return noise_suppression_;
678}
679
680VoiceDetection* AudioProcessingImpl::voice_detection() const {
681 return voice_detection_;
682}
683
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000684int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 return kNoError;
686}
ajm@google.com808e0e02011-08-03 21:08:51 +0000687
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000688bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000689 int enabled_count = 0;
690 std::list<ProcessingComponent*>::const_iterator it;
691 for (it = component_list_.begin(); it != component_list_.end(); it++) {
692 if ((*it)->is_component_enabled()) {
693 enabled_count++;
694 }
695 }
696
697 // Data is unchanged if no components are enabled, or if only level_estimator_
698 // or voice_detection_ is enabled.
699 if (enabled_count == 0) {
700 return false;
701 } else if (enabled_count == 1) {
702 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
703 return false;
704 }
705 } else if (enabled_count == 2) {
706 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
707 return false;
708 }
709 }
710 return true;
711}
712
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000713bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
714 // Check if we've upmixed or downmixed the audio.
715 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000716}
717
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000718bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
719 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
720}
721
722bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
723 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000724 // Only level_estimator_ is enabled.
725 return false;
726 } else if (sample_rate_hz_ == kSampleRate32kHz) {
727 // Something besides level_estimator_ is enabled, and we have super-wb.
728 return true;
729 }
730 return false;
731}
732
733#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000734int AudioProcessingImpl::WriteMessageToDebugFile() {
735 int32_t size = event_msg_->ByteSize();
736 if (size <= 0) {
737 return kUnspecifiedError;
738 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000739#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000740 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
741 // pretty safe in assuming little-endian.
742#endif
743
744 if (!event_msg_->SerializeToString(&event_str_)) {
745 return kUnspecifiedError;
746 }
747
748 // Write message preceded by its size.
749 if (!debug_file_->Write(&size, sizeof(int32_t))) {
750 return kFileError;
751 }
752 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
753 return kFileError;
754 }
755
756 event_msg_->Clear();
757
758 return 0;
759}
760
761int AudioProcessingImpl::WriteInitMessage() {
762 event_msg_->set_type(audioproc::Event::INIT);
763 audioproc::Init* msg = event_msg_->mutable_init();
764 msg->set_sample_rate(sample_rate_hz_);
765 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
766 msg->set_num_input_channels(num_input_channels_);
767 msg->set_num_output_channels(num_output_channels_);
768 msg->set_num_reverse_channels(num_reverse_channels_);
769
770 int err = WriteMessageToDebugFile();
771 if (err != kNoError) {
772 return err;
773 }
774
775 return kNoError;
776}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000777#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000778} // namespace webrtc