blob: b33049e48e2da66b349b1dda0b951c8c7d6ac22e [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.org78693fe2013-03-01 16:36:19 +000015#include "webrtc/modules/audio_processing/audio_buffer.h"
andrew@webrtc.org61e596f2013-07-25 18:28:29 +000016#include "webrtc/modules/audio_processing/echo_cancellation_impl_wrapper.h"
andrew@webrtc.org78693fe2013-03-01 16:36:19 +000017#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
18#include "webrtc/modules/audio_processing/gain_control_impl.h"
19#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
20#include "webrtc/modules/audio_processing/level_estimator_impl.h"
21#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
22#include "webrtc/modules/audio_processing/processing_component.h"
23#include "webrtc/modules/audio_processing/splitting_filter.h"
24#include "webrtc/modules/audio_processing/voice_detection_impl.h"
25#include "webrtc/modules/interface/module_common_types.h"
26#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/file_wrapper.h"
28#include "webrtc/system_wrappers/interface/logging.h"
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000029
30#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
31// Files generated at build-time by the protobuf compiler.
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000032#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000033#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000034#else
ajm@google.com808e0e02011-08-03 21:08:51 +000035#include "webrtc/audio_processing/debug.pb.h"
leozwang@google.comce9bfbb2011-08-03 23:34:31 +000036#endif
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000037#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000038
39namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000040AudioProcessing* AudioProcessing::Create(int id) {
niklase@google.com470e71d2011-07-07 08:21:25 +000041 AudioProcessingImpl* apm = new AudioProcessingImpl(id);
42 if (apm->Initialize() != kNoError) {
43 delete apm;
44 apm = NULL;
45 }
46
47 return apm;
48}
49
pbos@webrtc.org91620802013-08-02 11:44:11 +000050int32_t AudioProcessing::TimeUntilNextProcess() { return -1; }
51int32_t AudioProcessing::Process() { return -1; }
52
niklase@google.com470e71d2011-07-07 08:21:25 +000053AudioProcessingImpl::AudioProcessingImpl(int id)
54 : id_(id),
55 echo_cancellation_(NULL),
56 echo_control_mobile_(NULL),
57 gain_control_(NULL),
58 high_pass_filter_(NULL),
59 level_estimator_(NULL),
60 noise_suppression_(NULL),
61 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000062 crit_(CriticalSectionWrapper::CreateCriticalSection()),
63 render_audio_(NULL),
64 capture_audio_(NULL),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000065#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
66 debug_file_(FileWrapper::Create()),
67 event_msg_(new audioproc::Event()),
68#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000069 sample_rate_hz_(kSampleRate16kHz),
70 split_sample_rate_hz_(kSampleRate16kHz),
71 samples_per_channel_(sample_rate_hz_ / 100),
72 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +000073 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000074 was_stream_delay_set_(false),
ajm@google.com808e0e02011-08-03 21:08:51 +000075 num_reverse_channels_(1),
76 num_input_channels_(1),
77 num_output_channels_(1) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +000078 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +000079 component_list_.push_back(echo_cancellation_);
80
81 echo_control_mobile_ = new EchoControlMobileImpl(this);
82 component_list_.push_back(echo_control_mobile_);
83
84 gain_control_ = new GainControlImpl(this);
85 component_list_.push_back(gain_control_);
86
87 high_pass_filter_ = new HighPassFilterImpl(this);
88 component_list_.push_back(high_pass_filter_);
89
90 level_estimator_ = new LevelEstimatorImpl(this);
91 component_list_.push_back(level_estimator_);
92
93 noise_suppression_ = new NoiseSuppressionImpl(this);
94 component_list_.push_back(noise_suppression_);
95
96 voice_detection_ = new VoiceDetectionImpl(this);
97 component_list_.push_back(voice_detection_);
98}
99
100AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000101 {
102 CriticalSectionScoped crit_scoped(crit_);
103 while (!component_list_.empty()) {
104 ProcessingComponent* component = component_list_.front();
105 component->Destroy();
106 delete component;
107 component_list_.pop_front();
108 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000110#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000111 if (debug_file_->Open()) {
112 debug_file_->CloseFile();
113 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000114#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000115
andrew@webrtc.org81865342012-10-27 00:28:27 +0000116 if (render_audio_) {
117 delete render_audio_;
118 render_audio_ = NULL;
119 }
120
121 if (capture_audio_) {
122 delete capture_audio_;
123 capture_audio_ = NULL;
124 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 }
126
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000127 delete crit_;
128 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129}
130
131CriticalSectionWrapper* AudioProcessingImpl::crit() const {
132 return crit_;
133}
134
135int AudioProcessingImpl::split_sample_rate_hz() const {
136 return split_sample_rate_hz_;
137}
138
139int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000140 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 return InitializeLocked();
142}
143
144int AudioProcessingImpl::InitializeLocked() {
145 if (render_audio_ != NULL) {
146 delete render_audio_;
147 render_audio_ = NULL;
148 }
149
150 if (capture_audio_ != NULL) {
151 delete capture_audio_;
152 capture_audio_ = NULL;
153 }
154
ajm@google.com808e0e02011-08-03 21:08:51 +0000155 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000157 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 samples_per_channel_);
159
160 was_stream_delay_set_ = false;
161
162 // Initialize all components.
163 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000164 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 int err = (*it)->Initialize();
166 if (err != kNoError) {
167 return err;
168 }
169 }
170
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000171#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000172 if (debug_file_->Open()) {
173 int err = WriteInitMessage();
174 if (err != kNoError) {
175 return err;
176 }
177 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000178#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000179
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 return kNoError;
181}
182
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000183void AudioProcessingImpl::SetExtraOptions(const Config& config) {
184 std::list<ProcessingComponent*>::iterator it;
185 for (it = component_list_.begin(); it != component_list_.end(); ++it)
186 (*it)->SetExtraOptions(config);
187}
188
niklase@google.com470e71d2011-07-07 08:21:25 +0000189int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000190 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000191 if (rate == sample_rate_hz_) {
192 return kNoError;
193 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 if (rate != kSampleRate8kHz &&
195 rate != kSampleRate16kHz &&
196 rate != kSampleRate32kHz) {
197 return kBadParameterError;
198 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000199 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
200 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
201 return kUnsupportedComponentError;
202 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
204 sample_rate_hz_ = rate;
205 samples_per_channel_ = rate / 100;
206
207 if (sample_rate_hz_ == kSampleRate32kHz) {
208 split_sample_rate_hz_ = kSampleRate16kHz;
209 } else {
210 split_sample_rate_hz_ = sample_rate_hz_;
211 }
212
213 return InitializeLocked();
214}
215
216int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000217 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 return sample_rate_hz_;
219}
220
221int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000222 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000223 if (channels == num_reverse_channels_) {
224 return kNoError;
225 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 // Only stereo supported currently.
227 if (channels > 2 || channels < 1) {
228 return kBadParameterError;
229 }
230
ajm@google.com808e0e02011-08-03 21:08:51 +0000231 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
233 return InitializeLocked();
234}
235
236int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000237 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000238}
239
240int AudioProcessingImpl::set_num_channels(
241 int input_channels,
242 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000243 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000244 if (input_channels == num_input_channels_ &&
245 output_channels == num_output_channels_) {
246 return kNoError;
247 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 if (output_channels > input_channels) {
249 return kBadParameterError;
250 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000252 if (input_channels > 2 || input_channels < 1 ||
253 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 return kBadParameterError;
255 }
256
ajm@google.com808e0e02011-08-03 21:08:51 +0000257 num_input_channels_ = input_channels;
258 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
260 return InitializeLocked();
261}
262
263int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000264 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000265}
266
267int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000268 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269}
270
271int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000272 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 int err = kNoError;
274
275 if (frame == NULL) {
276 return kNullPointerError;
277 }
278
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000279 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 return kBadSampleRateError;
281 }
282
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000283 if (frame->num_channels_ != num_input_channels_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 return kBadNumberChannelsError;
285 }
286
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000287 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000288 return kBadDataLengthError;
289 }
290
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000291#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000293 event_msg_->set_type(audioproc::Event::STREAM);
294 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000295 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000296 frame->samples_per_channel_ *
297 frame->num_channels_;
298 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000299 msg->set_delay(stream_delay_ms_);
300 msg->set_drift(echo_cancellation_->stream_drift_samples());
301 msg->set_level(gain_control_->stream_analog_level());
niklase@google.com470e71d2011-07-07 08:21:25 +0000302 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000303#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
305 capture_audio_->DeinterleaveFrom(frame);
306
307 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000308 if (num_output_channels_ < num_input_channels_) {
309 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000310 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 }
312
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000313 bool data_processed = is_data_processed();
314 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000315 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000316 // Split into a low and high band.
317 SplittingFilterAnalysis(capture_audio_->data(i),
318 capture_audio_->low_pass_split_data(i),
319 capture_audio_->high_pass_split_data(i),
320 capture_audio_->analysis_filter_state1(i),
321 capture_audio_->analysis_filter_state2(i));
322 }
323 }
324
325 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
326 if (err != kNoError) {
327 return err;
328 }
329
330 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
331 if (err != kNoError) {
332 return err;
333 }
334
335 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
336 if (err != kNoError) {
337 return err;
338 }
339
340 if (echo_control_mobile_->is_enabled() &&
341 noise_suppression_->is_enabled()) {
342 capture_audio_->CopyLowPassToReference();
343 }
344
345 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
346 if (err != kNoError) {
347 return err;
348 }
349
350 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
351 if (err != kNoError) {
352 return err;
353 }
354
355 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
356 if (err != kNoError) {
357 return err;
358 }
359
360 err = gain_control_->ProcessCaptureAudio(capture_audio_);
361 if (err != kNoError) {
362 return err;
363 }
364
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000365 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000366 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 // Recombine low and high bands.
368 SplittingFilterSynthesis(capture_audio_->low_pass_split_data(i),
369 capture_audio_->high_pass_split_data(i),
370 capture_audio_->data(i),
371 capture_audio_->synthesis_filter_state1(i),
372 capture_audio_->synthesis_filter_state2(i));
373 }
374 }
375
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000376 // The level estimator operates on the recombined data.
377 err = level_estimator_->ProcessStream(capture_audio_);
378 if (err != kNoError) {
379 return err;
380 }
381
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000382 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000383
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000384#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000385 if (debug_file_->Open()) {
386 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000387 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000388 frame->samples_per_channel_ *
389 frame->num_channels_;
390 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000391 err = WriteMessageToDebugFile();
392 if (err != kNoError) {
393 return err;
394 }
395 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000396#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000397
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000398 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 return kNoError;
400}
401
402int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000403 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 int err = kNoError;
405
406 if (frame == NULL) {
407 return kNullPointerError;
408 }
409
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000410 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 return kBadSampleRateError;
412 }
413
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000414 if (frame->num_channels_ != num_reverse_channels_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 return kBadNumberChannelsError;
416 }
417
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000418 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 return kBadDataLengthError;
420 }
421
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000422#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000424 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
425 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000426 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000427 frame->samples_per_channel_ *
428 frame->num_channels_;
429 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000430 err = WriteMessageToDebugFile();
431 if (err != kNoError) {
432 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 }
434 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000435#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000436
437 render_audio_->DeinterleaveFrom(frame);
438
439 // TODO(ajm): turn the splitting filter into a component?
440 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000441 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 // Split into low and high band.
443 SplittingFilterAnalysis(render_audio_->data(i),
444 render_audio_->low_pass_split_data(i),
445 render_audio_->high_pass_split_data(i),
446 render_audio_->analysis_filter_state1(i),
447 render_audio_->analysis_filter_state2(i));
448 }
449 }
450
451 // TODO(ajm): warnings possible from components?
452 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
453 if (err != kNoError) {
454 return err;
455 }
456
457 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
458 if (err != kNoError) {
459 return err;
460 }
461
462 err = gain_control_->ProcessRenderAudio(render_audio_);
463 if (err != kNoError) {
464 return err;
465 }
466
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 return err; // TODO(ajm): this is for returning warnings; necessary?
468}
469
470int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000471 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000473 delay += delay_offset_ms_;
474
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000476 delay = 0;
477 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 }
479
480 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
481 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000482 delay = 500;
483 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 }
485
486 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000487 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000488}
489
490int AudioProcessingImpl::stream_delay_ms() const {
491 return stream_delay_ms_;
492}
493
494bool AudioProcessingImpl::was_stream_delay_set() const {
495 return was_stream_delay_set_;
496}
497
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000498void AudioProcessingImpl::set_delay_offset_ms(int offset) {
499 CriticalSectionScoped crit_scoped(crit_);
500 delay_offset_ms_ = offset;
501}
502
503int AudioProcessingImpl::delay_offset_ms() const {
504 return delay_offset_ms_;
505}
506
niklase@google.com470e71d2011-07-07 08:21:25 +0000507int AudioProcessingImpl::StartDebugRecording(
508 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000509 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
511
512 if (filename == NULL) {
513 return kNullPointerError;
514 }
515
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000516#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000517 // Stop any ongoing recording.
518 if (debug_file_->Open()) {
519 if (debug_file_->CloseFile() == -1) {
520 return kFileError;
521 }
522 }
523
524 if (debug_file_->OpenFile(filename, false) == -1) {
525 debug_file_->CloseFile();
526 return kFileError;
527 }
528
ajm@google.com808e0e02011-08-03 21:08:51 +0000529 int err = WriteInitMessage();
530 if (err != kNoError) {
531 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000532 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000534#else
535 return kUnsupportedFunctionError;
536#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000537}
538
539int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000540 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000541
542#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000543 // We just return if recording hasn't started.
544 if (debug_file_->Open()) {
545 if (debug_file_->CloseFile() == -1) {
546 return kFileError;
547 }
548 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000550#else
551 return kUnsupportedFunctionError;
552#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000553}
554
555EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
556 return echo_cancellation_;
557}
558
559EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
560 return echo_control_mobile_;
561}
562
563GainControl* AudioProcessingImpl::gain_control() const {
564 return gain_control_;
565}
566
567HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
568 return high_pass_filter_;
569}
570
571LevelEstimator* AudioProcessingImpl::level_estimator() const {
572 return level_estimator_;
573}
574
575NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
576 return noise_suppression_;
577}
578
579VoiceDetection* AudioProcessingImpl::voice_detection() const {
580 return voice_detection_;
581}
582
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000583int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000584 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000585 id_ = id;
586
587 return kNoError;
588}
ajm@google.com808e0e02011-08-03 21:08:51 +0000589
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000590bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000591 int enabled_count = 0;
592 std::list<ProcessingComponent*>::const_iterator it;
593 for (it = component_list_.begin(); it != component_list_.end(); it++) {
594 if ((*it)->is_component_enabled()) {
595 enabled_count++;
596 }
597 }
598
599 // Data is unchanged if no components are enabled, or if only level_estimator_
600 // or voice_detection_ is enabled.
601 if (enabled_count == 0) {
602 return false;
603 } else if (enabled_count == 1) {
604 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
605 return false;
606 }
607 } else if (enabled_count == 2) {
608 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
609 return false;
610 }
611 }
612 return true;
613}
614
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000615bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
616 // Check if we've upmixed or downmixed the audio.
617 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000618}
619
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000620bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
621 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
622}
623
624bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
625 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000626 // Only level_estimator_ is enabled.
627 return false;
628 } else if (sample_rate_hz_ == kSampleRate32kHz) {
629 // Something besides level_estimator_ is enabled, and we have super-wb.
630 return true;
631 }
632 return false;
633}
634
635#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000636int AudioProcessingImpl::WriteMessageToDebugFile() {
637 int32_t size = event_msg_->ByteSize();
638 if (size <= 0) {
639 return kUnspecifiedError;
640 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000641#if defined(WEBRTC_ARCH_BIG_ENDIAN)
ajm@google.com808e0e02011-08-03 21:08:51 +0000642 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
643 // pretty safe in assuming little-endian.
644#endif
645
646 if (!event_msg_->SerializeToString(&event_str_)) {
647 return kUnspecifiedError;
648 }
649
650 // Write message preceded by its size.
651 if (!debug_file_->Write(&size, sizeof(int32_t))) {
652 return kFileError;
653 }
654 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
655 return kFileError;
656 }
657
658 event_msg_->Clear();
659
660 return 0;
661}
662
663int AudioProcessingImpl::WriteInitMessage() {
664 event_msg_->set_type(audioproc::Event::INIT);
665 audioproc::Init* msg = event_msg_->mutable_init();
666 msg->set_sample_rate(sample_rate_hz_);
667 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
668 msg->set_num_input_channels(num_input_channels_);
669 msg->set_num_output_channels(num_output_channels_);
670 msg->set_num_reverse_channels(num_reverse_channels_);
671
672 int err = WriteMessageToDebugFile();
673 if (err != kNoError) {
674 return err;
675 }
676
677 return kNoError;
678}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000679#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000680} // namespace webrtc