blob: 6a89b9cade25d18352423ec48716d70cad92d122 [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.org60730cf2014-01-07 17:45:09 +000056 AudioProcessingImpl* apm = new AudioProcessingImpl();
niklase@google.com470e71d2011-07-07 08:21:25 +000057 if (apm->Initialize() != kNoError) {
58 delete apm;
59 apm = NULL;
60 }
61
62 return apm;
63}
64
pbos@webrtc.org91620802013-08-02 11:44:11 +000065int32_t AudioProcessing::TimeUntilNextProcess() { return -1; }
66int32_t AudioProcessing::Process() { return -1; }
67
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000068AudioProcessingImpl::AudioProcessingImpl()
69 : echo_cancellation_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000070 echo_control_mobile_(NULL),
71 gain_control_(NULL),
72 high_pass_filter_(NULL),
73 level_estimator_(NULL),
74 noise_suppression_(NULL),
75 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000076 crit_(CriticalSectionWrapper::CreateCriticalSection()),
77 render_audio_(NULL),
78 capture_audio_(NULL),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000079#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
80 debug_file_(FileWrapper::Create()),
81 event_msg_(new audioproc::Event()),
82#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000083 sample_rate_hz_(kSampleRate16kHz),
84 split_sample_rate_hz_(kSampleRate16kHz),
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000085 samples_per_channel_(kChunkSizeMs * sample_rate_hz_ / 1000),
niklase@google.com470e71d2011-07-07 08:21:25 +000086 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +000087 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000088 was_stream_delay_set_(false),
ajm@google.com808e0e02011-08-03 21:08:51 +000089 num_reverse_channels_(1),
90 num_input_channels_(1),
91 num_output_channels_(1) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +000092 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +000093 component_list_.push_back(echo_cancellation_);
94
95 echo_control_mobile_ = new EchoControlMobileImpl(this);
96 component_list_.push_back(echo_control_mobile_);
97
98 gain_control_ = new GainControlImpl(this);
99 component_list_.push_back(gain_control_);
100
101 high_pass_filter_ = new HighPassFilterImpl(this);
102 component_list_.push_back(high_pass_filter_);
103
104 level_estimator_ = new LevelEstimatorImpl(this);
105 component_list_.push_back(level_estimator_);
106
107 noise_suppression_ = new NoiseSuppressionImpl(this);
108 component_list_.push_back(noise_suppression_);
109
110 voice_detection_ = new VoiceDetectionImpl(this);
111 component_list_.push_back(voice_detection_);
112}
113
114AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000115 {
116 CriticalSectionScoped crit_scoped(crit_);
117 while (!component_list_.empty()) {
118 ProcessingComponent* component = component_list_.front();
119 component->Destroy();
120 delete component;
121 component_list_.pop_front();
122 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000124#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000125 if (debug_file_->Open()) {
126 debug_file_->CloseFile();
127 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000128#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000129
andrew@webrtc.org81865342012-10-27 00:28:27 +0000130 if (render_audio_) {
131 delete render_audio_;
132 render_audio_ = NULL;
133 }
134
135 if (capture_audio_) {
136 delete capture_audio_;
137 capture_audio_ = NULL;
138 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 }
140
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000141 delete crit_;
142 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000143}
144
145CriticalSectionWrapper* AudioProcessingImpl::crit() const {
146 return crit_;
147}
148
149int AudioProcessingImpl::split_sample_rate_hz() const {
150 return split_sample_rate_hz_;
151}
152
153int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000154 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 return InitializeLocked();
156}
157
158int AudioProcessingImpl::InitializeLocked() {
159 if (render_audio_ != NULL) {
160 delete render_audio_;
161 render_audio_ = NULL;
162 }
163
164 if (capture_audio_ != NULL) {
165 delete capture_audio_;
166 capture_audio_ = NULL;
167 }
168
ajm@google.com808e0e02011-08-03 21:08:51 +0000169 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000171 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 samples_per_channel_);
173
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 // Initialize all components.
175 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000176 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 int err = (*it)->Initialize();
178 if (err != kNoError) {
179 return err;
180 }
181 }
182
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000183#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000184 if (debug_file_->Open()) {
185 int err = WriteInitMessage();
186 if (err != kNoError) {
187 return err;
188 }
189 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000190#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000191
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 return kNoError;
193}
194
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000195void AudioProcessingImpl::SetExtraOptions(const Config& config) {
196 std::list<ProcessingComponent*>::iterator it;
197 for (it = component_list_.begin(); it != component_list_.end(); ++it)
198 (*it)->SetExtraOptions(config);
199}
200
aluebs@webrtc.org0b72f582013-11-19 15:17:51 +0000201int AudioProcessingImpl::EnableExperimentalNs(bool enable) {
202 return kNoError;
203}
204
niklase@google.com470e71d2011-07-07 08:21:25 +0000205int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000206 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000207 if (rate == sample_rate_hz_) {
208 return kNoError;
209 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 if (rate != kSampleRate8kHz &&
211 rate != kSampleRate16kHz &&
212 rate != kSampleRate32kHz) {
213 return kBadParameterError;
214 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000215 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
216 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
217 return kUnsupportedComponentError;
218 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000219
220 sample_rate_hz_ = rate;
221 samples_per_channel_ = rate / 100;
222
223 if (sample_rate_hz_ == kSampleRate32kHz) {
224 split_sample_rate_hz_ = kSampleRate16kHz;
225 } else {
226 split_sample_rate_hz_ = sample_rate_hz_;
227 }
228
229 return InitializeLocked();
230}
231
232int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000233 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 return sample_rate_hz_;
235}
236
237int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000238 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000239 if (channels == num_reverse_channels_) {
240 return kNoError;
241 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 // Only stereo supported currently.
243 if (channels > 2 || channels < 1) {
244 return kBadParameterError;
245 }
246
ajm@google.com808e0e02011-08-03 21:08:51 +0000247 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248
249 return InitializeLocked();
250}
251
252int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000253 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254}
255
256int AudioProcessingImpl::set_num_channels(
257 int input_channels,
258 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000259 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000260 if (input_channels == num_input_channels_ &&
261 output_channels == num_output_channels_) {
262 return kNoError;
263 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 if (output_channels > input_channels) {
265 return kBadParameterError;
266 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000268 if (input_channels > 2 || input_channels < 1 ||
269 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 return kBadParameterError;
271 }
272
ajm@google.com808e0e02011-08-03 21:08:51 +0000273 num_input_channels_ = input_channels;
274 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275
276 return InitializeLocked();
277}
278
279int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000280 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
282
283int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000284 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000287int AudioProcessingImpl::MaybeInitializeLocked(int sample_rate_hz,
288 int num_input_channels, int num_output_channels, int num_reverse_channels) {
289 if (sample_rate_hz == sample_rate_hz_ &&
290 num_input_channels == num_input_channels_ &&
291 num_output_channels == num_output_channels_ &&
292 num_reverse_channels == num_reverse_channels_) {
293 return kNoError;
294 }
295
296 if (sample_rate_hz != kSampleRate8kHz &&
297 sample_rate_hz != kSampleRate16kHz &&
298 sample_rate_hz != kSampleRate32kHz) {
299 return kBadSampleRateError;
300 }
301 if (num_output_channels > num_input_channels) {
302 return kBadNumberChannelsError;
303 }
304 // Only mono and stereo supported currently.
305 if (num_input_channels > 2 || num_input_channels < 1 ||
306 num_output_channels > 2 || num_output_channels < 1 ||
307 num_reverse_channels > 2 || num_reverse_channels < 1) {
308 return kBadNumberChannelsError;
309 }
310 if (echo_control_mobile_->is_enabled() && sample_rate_hz > kSampleRate16kHz) {
311 LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
312 return kUnsupportedComponentError;
313 }
314
315 sample_rate_hz_ = sample_rate_hz;
316 samples_per_channel_ = kChunkSizeMs * sample_rate_hz / 1000;
317 num_input_channels_ = num_input_channels;
318 num_output_channels_ = num_output_channels;
319 num_reverse_channels_ = num_reverse_channels;
320
321 if (sample_rate_hz_ == kSampleRate32kHz) {
322 split_sample_rate_hz_ = kSampleRate16kHz;
323 } else {
324 split_sample_rate_hz_ = sample_rate_hz_;
325 }
326
327 return InitializeLocked();
328}
329
niklase@google.com470e71d2011-07-07 08:21:25 +0000330int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000331 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 int err = kNoError;
333
334 if (frame == NULL) {
335 return kNullPointerError;
336 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000337 // TODO(ajm): We now always set the output channels equal to the input
338 // channels here. Remove the ability to downmix entirely.
339 RETURN_ON_ERR(MaybeInitializeLocked(frame->sample_rate_hz_,
340 frame->num_channels_, frame->num_channels_, num_reverse_channels_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000341 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 return kBadDataLengthError;
343 }
344
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000345#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000347 event_msg_->set_type(audioproc::Event::STREAM);
348 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000349 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000350 frame->samples_per_channel_ *
351 frame->num_channels_;
352 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000353 msg->set_delay(stream_delay_ms_);
354 msg->set_drift(echo_cancellation_->stream_drift_samples());
355 msg->set_level(gain_control_->stream_analog_level());
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000357#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000358
359 capture_audio_->DeinterleaveFrom(frame);
360
361 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000362 if (num_output_channels_ < num_input_channels_) {
363 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000364 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 }
366
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000367 bool data_processed = is_data_processed();
368 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000369 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 // Split into a low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000371 WebRtcSpl_AnalysisQMF(capture_audio_->data(i),
372 capture_audio_->samples_per_channel(),
373 capture_audio_->low_pass_split_data(i),
374 capture_audio_->high_pass_split_data(i),
375 capture_audio_->analysis_filter_state1(i),
376 capture_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 }
378 }
379
380 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
381 if (err != kNoError) {
382 return err;
383 }
384
385 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
386 if (err != kNoError) {
387 return err;
388 }
389
390 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
391 if (err != kNoError) {
392 return err;
393 }
394
395 if (echo_control_mobile_->is_enabled() &&
396 noise_suppression_->is_enabled()) {
397 capture_audio_->CopyLowPassToReference();
398 }
399
400 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
401 if (err != kNoError) {
402 return err;
403 }
404
405 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
406 if (err != kNoError) {
407 return err;
408 }
409
410 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
411 if (err != kNoError) {
412 return err;
413 }
414
415 err = gain_control_->ProcessCaptureAudio(capture_audio_);
416 if (err != kNoError) {
417 return err;
418 }
419
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000420 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000421 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 // Recombine low and high bands.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000423 WebRtcSpl_SynthesisQMF(capture_audio_->low_pass_split_data(i),
424 capture_audio_->high_pass_split_data(i),
425 capture_audio_->samples_per_split_channel(),
426 capture_audio_->data(i),
427 capture_audio_->synthesis_filter_state1(i),
428 capture_audio_->synthesis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 }
430 }
431
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000432 // The level estimator operates on the recombined data.
433 err = level_estimator_->ProcessStream(capture_audio_);
434 if (err != kNoError) {
435 return err;
436 }
437
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000438 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000439
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000440#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000441 if (debug_file_->Open()) {
442 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000443 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000444 frame->samples_per_channel_ *
445 frame->num_channels_;
446 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000447 err = WriteMessageToDebugFile();
448 if (err != kNoError) {
449 return err;
450 }
451 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000452#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000453
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000454 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 return kNoError;
456}
457
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000458// TODO(ajm): Have AnalyzeReverseStream accept sample rates not matching the
459// primary stream and convert ourselves rather than having the user manage it.
460// We can be smarter and use the splitting filter when appropriate. Similarly,
461// perform downmixing here.
niklase@google.com470e71d2011-07-07 08:21:25 +0000462int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000463 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 int err = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 if (frame == NULL) {
466 return kNullPointerError;
467 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000468 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000469 return kBadSampleRateError;
470 }
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000471 RETURN_ON_ERR(MaybeInitializeLocked(sample_rate_hz_, num_input_channels_,
472 num_output_channels_, frame->num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000473
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000474#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000476 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
477 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000478 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000479 frame->samples_per_channel_ *
480 frame->num_channels_;
481 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000482 err = WriteMessageToDebugFile();
483 if (err != kNoError) {
484 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 }
486 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000487#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000488
489 render_audio_->DeinterleaveFrom(frame);
490
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000492 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 // Split into low and high band.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000494 WebRtcSpl_AnalysisQMF(render_audio_->data(i),
495 render_audio_->samples_per_channel(),
496 render_audio_->low_pass_split_data(i),
497 render_audio_->high_pass_split_data(i),
498 render_audio_->analysis_filter_state1(i),
499 render_audio_->analysis_filter_state2(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000500 }
501 }
502
503 // TODO(ajm): warnings possible from components?
504 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
505 if (err != kNoError) {
506 return err;
507 }
508
509 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
510 if (err != kNoError) {
511 return err;
512 }
513
514 err = gain_control_->ProcessRenderAudio(render_audio_);
515 if (err != kNoError) {
516 return err;
517 }
518
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 return err; // TODO(ajm): this is for returning warnings; necessary?
520}
521
522int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000523 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000525 delay += delay_offset_ms_;
526
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000528 delay = 0;
529 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 }
531
532 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
533 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000534 delay = 500;
535 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 }
537
538 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000539 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000540}
541
542int AudioProcessingImpl::stream_delay_ms() const {
543 return stream_delay_ms_;
544}
545
546bool AudioProcessingImpl::was_stream_delay_set() const {
547 return was_stream_delay_set_;
548}
549
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000550void AudioProcessingImpl::set_delay_offset_ms(int offset) {
551 CriticalSectionScoped crit_scoped(crit_);
552 delay_offset_ms_ = offset;
553}
554
555int AudioProcessingImpl::delay_offset_ms() const {
556 return delay_offset_ms_;
557}
558
niklase@google.com470e71d2011-07-07 08:21:25 +0000559int AudioProcessingImpl::StartDebugRecording(
560 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000561 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
563
564 if (filename == NULL) {
565 return kNullPointerError;
566 }
567
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000568#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000569 // Stop any ongoing recording.
570 if (debug_file_->Open()) {
571 if (debug_file_->CloseFile() == -1) {
572 return kFileError;
573 }
574 }
575
576 if (debug_file_->OpenFile(filename, false) == -1) {
577 debug_file_->CloseFile();
578 return kFileError;
579 }
580
ajm@google.com808e0e02011-08-03 21:08:51 +0000581 int err = WriteInitMessage();
582 if (err != kNoError) {
583 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000585 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000586#else
587 return kUnsupportedFunctionError;
588#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000589}
590
henrikg@webrtc.org863b5362013-12-06 16:05:17 +0000591int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
592 CriticalSectionScoped crit_scoped(crit_);
593
594 if (handle == NULL) {
595 return kNullPointerError;
596 }
597
598#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
599 // Stop any ongoing recording.
600 if (debug_file_->Open()) {
601 if (debug_file_->CloseFile() == -1) {
602 return kFileError;
603 }
604 }
605
606 if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
607 return kFileError;
608 }
609
610 int err = WriteInitMessage();
611 if (err != kNoError) {
612 return err;
613 }
614 return kNoError;
615#else
616 return kUnsupportedFunctionError;
617#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
618}
619
niklase@google.com470e71d2011-07-07 08:21:25 +0000620int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000621 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000622
623#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000624 // We just return if recording hasn't started.
625 if (debug_file_->Open()) {
626 if (debug_file_->CloseFile() == -1) {
627 return kFileError;
628 }
629 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000631#else
632 return kUnsupportedFunctionError;
633#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000634}
635
636EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
637 return echo_cancellation_;
638}
639
640EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
641 return echo_control_mobile_;
642}
643
644GainControl* AudioProcessingImpl::gain_control() const {
645 return gain_control_;
646}
647
648HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
649 return high_pass_filter_;
650}
651
652LevelEstimator* AudioProcessingImpl::level_estimator() const {
653 return level_estimator_;
654}
655
656NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
657 return noise_suppression_;
658}
659
660VoiceDetection* AudioProcessingImpl::voice_detection() const {
661 return voice_detection_;
662}
663
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000664int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 return kNoError;
666}
ajm@google.com808e0e02011-08-03 21:08:51 +0000667
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000668bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000669 int enabled_count = 0;
670 std::list<ProcessingComponent*>::const_iterator it;
671 for (it = component_list_.begin(); it != component_list_.end(); it++) {
672 if ((*it)->is_component_enabled()) {
673 enabled_count++;
674 }
675 }
676
677 // Data is unchanged if no components are enabled, or if only level_estimator_
678 // or voice_detection_ is enabled.
679 if (enabled_count == 0) {
680 return false;
681 } else if (enabled_count == 1) {
682 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
683 return false;
684 }
685 } else if (enabled_count == 2) {
686 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
687 return false;
688 }
689 }
690 return true;
691}
692
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000693bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
694 // Check if we've upmixed or downmixed the audio.
695 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000696}
697
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000698bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
699 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
700}
701
702bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
703 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000704 // Only level_estimator_ is enabled.
705 return false;
706 } else if (sample_rate_hz_ == kSampleRate32kHz) {
707 // Something besides level_estimator_ is enabled, and we have super-wb.
708 return true;
709 }
710 return false;
711}
712
713#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000714int AudioProcessingImpl::WriteMessageToDebugFile() {
715 int32_t size = event_msg_->ByteSize();
716 if (size <= 0) {
717 return kUnspecifiedError;
718 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000719#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000720 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
721 // pretty safe in assuming little-endian.
722#endif
723
724 if (!event_msg_->SerializeToString(&event_str_)) {
725 return kUnspecifiedError;
726 }
727
728 // Write message preceded by its size.
729 if (!debug_file_->Write(&size, sizeof(int32_t))) {
730 return kFileError;
731 }
732 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
733 return kFileError;
734 }
735
736 event_msg_->Clear();
737
738 return 0;
739}
740
741int AudioProcessingImpl::WriteInitMessage() {
742 event_msg_->set_type(audioproc::Event::INIT);
743 audioproc::Init* msg = event_msg_->mutable_init();
744 msg->set_sample_rate(sample_rate_hz_);
745 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
746 msg->set_num_input_channels(num_input_channels_);
747 msg->set_num_output_channels(num_output_channels_);
748 msg->set_num_reverse_channels(num_reverse_channels_);
749
750 int err = WriteMessageToDebugFile();
751 if (err != kNoError) {
752 return err;
753 }
754
755 return kNoError;
756}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000757#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000758} // namespace webrtc