blob: ac5fa9bb72815a23c30a89f2634f5a5bbd804035 [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
50void AudioProcessing::Destroy(AudioProcessing* apm) {
51 delete static_cast<AudioProcessingImpl*>(apm);
52}
53
54AudioProcessingImpl::AudioProcessingImpl(int id)
55 : id_(id),
56 echo_cancellation_(NULL),
57 echo_control_mobile_(NULL),
58 gain_control_(NULL),
59 high_pass_filter_(NULL),
60 level_estimator_(NULL),
61 noise_suppression_(NULL),
62 voice_detection_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000063 crit_(CriticalSectionWrapper::CreateCriticalSection()),
64 render_audio_(NULL),
65 capture_audio_(NULL),
andrew@webrtc.org7bf26462011-12-03 00:03:31 +000066#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
67 debug_file_(FileWrapper::Create()),
68 event_msg_(new audioproc::Event()),
69#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000070 sample_rate_hz_(kSampleRate16kHz),
71 split_sample_rate_hz_(kSampleRate16kHz),
72 samples_per_channel_(sample_rate_hz_ / 100),
73 stream_delay_ms_(0),
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +000074 delay_offset_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000075 was_stream_delay_set_(false),
ajm@google.com808e0e02011-08-03 21:08:51 +000076 num_reverse_channels_(1),
77 num_input_channels_(1),
78 num_output_channels_(1) {
andrew@webrtc.org61e596f2013-07-25 18:28:29 +000079 echo_cancellation_ = EchoCancellationImplWrapper::Create(this);
niklase@google.com470e71d2011-07-07 08:21:25 +000080 component_list_.push_back(echo_cancellation_);
81
82 echo_control_mobile_ = new EchoControlMobileImpl(this);
83 component_list_.push_back(echo_control_mobile_);
84
85 gain_control_ = new GainControlImpl(this);
86 component_list_.push_back(gain_control_);
87
88 high_pass_filter_ = new HighPassFilterImpl(this);
89 component_list_.push_back(high_pass_filter_);
90
91 level_estimator_ = new LevelEstimatorImpl(this);
92 component_list_.push_back(level_estimator_);
93
94 noise_suppression_ = new NoiseSuppressionImpl(this);
95 component_list_.push_back(noise_suppression_);
96
97 voice_detection_ = new VoiceDetectionImpl(this);
98 component_list_.push_back(voice_detection_);
99}
100
101AudioProcessingImpl::~AudioProcessingImpl() {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000102 {
103 CriticalSectionScoped crit_scoped(crit_);
104 while (!component_list_.empty()) {
105 ProcessingComponent* component = component_list_.front();
106 component->Destroy();
107 delete component;
108 component_list_.pop_front();
109 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000111#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
andrew@webrtc.org81865342012-10-27 00:28:27 +0000112 if (debug_file_->Open()) {
113 debug_file_->CloseFile();
114 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000115#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000116
andrew@webrtc.org81865342012-10-27 00:28:27 +0000117 if (render_audio_) {
118 delete render_audio_;
119 render_audio_ = NULL;
120 }
121
122 if (capture_audio_) {
123 delete capture_audio_;
124 capture_audio_ = NULL;
125 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 }
127
andrew@webrtc.org16cfbe22012-08-29 16:58:25 +0000128 delete crit_;
129 crit_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130}
131
132CriticalSectionWrapper* AudioProcessingImpl::crit() const {
133 return crit_;
134}
135
136int AudioProcessingImpl::split_sample_rate_hz() const {
137 return split_sample_rate_hz_;
138}
139
140int AudioProcessingImpl::Initialize() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000141 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 return InitializeLocked();
143}
144
145int AudioProcessingImpl::InitializeLocked() {
146 if (render_audio_ != NULL) {
147 delete render_audio_;
148 render_audio_ = NULL;
149 }
150
151 if (capture_audio_ != NULL) {
152 delete capture_audio_;
153 capture_audio_ = NULL;
154 }
155
ajm@google.com808e0e02011-08-03 21:08:51 +0000156 render_audio_ = new AudioBuffer(num_reverse_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 samples_per_channel_);
ajm@google.com808e0e02011-08-03 21:08:51 +0000158 capture_audio_ = new AudioBuffer(num_input_channels_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 samples_per_channel_);
160
161 was_stream_delay_set_ = false;
162
163 // Initialize all components.
164 std::list<ProcessingComponent*>::iterator it;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000165 for (it = component_list_.begin(); it != component_list_.end(); ++it) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 int err = (*it)->Initialize();
167 if (err != kNoError) {
168 return err;
169 }
170 }
171
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000172#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000173 if (debug_file_->Open()) {
174 int err = WriteInitMessage();
175 if (err != kNoError) {
176 return err;
177 }
178 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000179#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000180
niklase@google.com470e71d2011-07-07 08:21:25 +0000181 return kNoError;
182}
183
andrew@webrtc.org61e596f2013-07-25 18:28:29 +0000184void AudioProcessingImpl::SetExtraOptions(const Config& config) {
185 std::list<ProcessingComponent*>::iterator it;
186 for (it = component_list_.begin(); it != component_list_.end(); ++it)
187 (*it)->SetExtraOptions(config);
188}
189
niklase@google.com470e71d2011-07-07 08:21:25 +0000190int AudioProcessingImpl::set_sample_rate_hz(int rate) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000191 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000192 if (rate == sample_rate_hz_) {
193 return kNoError;
194 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 if (rate != kSampleRate8kHz &&
196 rate != kSampleRate16kHz &&
197 rate != kSampleRate32kHz) {
198 return kBadParameterError;
199 }
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000200 if (echo_control_mobile_->is_enabled() && rate > kSampleRate16kHz) {
201 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
202 return kUnsupportedComponentError;
203 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000204
205 sample_rate_hz_ = rate;
206 samples_per_channel_ = rate / 100;
207
208 if (sample_rate_hz_ == kSampleRate32kHz) {
209 split_sample_rate_hz_ = kSampleRate16kHz;
210 } else {
211 split_sample_rate_hz_ = sample_rate_hz_;
212 }
213
214 return InitializeLocked();
215}
216
217int AudioProcessingImpl::sample_rate_hz() const {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000218 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 return sample_rate_hz_;
220}
221
222int AudioProcessingImpl::set_num_reverse_channels(int channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000223 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000224 if (channels == num_reverse_channels_) {
225 return kNoError;
226 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 // Only stereo supported currently.
228 if (channels > 2 || channels < 1) {
229 return kBadParameterError;
230 }
231
ajm@google.com808e0e02011-08-03 21:08:51 +0000232 num_reverse_channels_ = channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
234 return InitializeLocked();
235}
236
237int AudioProcessingImpl::num_reverse_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000238 return num_reverse_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
240
241int AudioProcessingImpl::set_num_channels(
242 int input_channels,
243 int output_channels) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000244 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000245 if (input_channels == num_input_channels_ &&
246 output_channels == num_output_channels_) {
247 return kNoError;
248 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 if (output_channels > input_channels) {
250 return kBadParameterError;
251 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 // Only stereo supported currently.
andrew@webrtc.org81865342012-10-27 00:28:27 +0000253 if (input_channels > 2 || input_channels < 1 ||
254 output_channels > 2 || output_channels < 1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 return kBadParameterError;
256 }
257
ajm@google.com808e0e02011-08-03 21:08:51 +0000258 num_input_channels_ = input_channels;
259 num_output_channels_ = output_channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
261 return InitializeLocked();
262}
263
264int AudioProcessingImpl::num_input_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000265 return num_input_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
268int AudioProcessingImpl::num_output_channels() const {
ajm@google.com808e0e02011-08-03 21:08:51 +0000269 return num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000270}
271
272int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000273 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 int err = kNoError;
275
276 if (frame == NULL) {
277 return kNullPointerError;
278 }
279
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000280 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 return kBadSampleRateError;
282 }
283
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000284 if (frame->num_channels_ != num_input_channels_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 return kBadNumberChannelsError;
286 }
287
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000288 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 return kBadDataLengthError;
290 }
291
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000292#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000294 event_msg_->set_type(audioproc::Event::STREAM);
295 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000296 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000297 frame->samples_per_channel_ *
298 frame->num_channels_;
299 msg->set_input_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000300 msg->set_delay(stream_delay_ms_);
301 msg->set_drift(echo_cancellation_->stream_drift_samples());
302 msg->set_level(gain_control_->stream_analog_level());
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000304#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000305
306 capture_audio_->DeinterleaveFrom(frame);
307
308 // TODO(ajm): experiment with mixing and AEC placement.
ajm@google.com808e0e02011-08-03 21:08:51 +0000309 if (num_output_channels_ < num_input_channels_) {
310 capture_audio_->Mix(num_output_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000311 frame->num_channels_ = num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 }
313
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000314 bool data_processed = is_data_processed();
315 if (analysis_needed(data_processed)) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000316 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 // Split into a low and high band.
318 SplittingFilterAnalysis(capture_audio_->data(i),
319 capture_audio_->low_pass_split_data(i),
320 capture_audio_->high_pass_split_data(i),
321 capture_audio_->analysis_filter_state1(i),
322 capture_audio_->analysis_filter_state2(i));
323 }
324 }
325
326 err = high_pass_filter_->ProcessCaptureAudio(capture_audio_);
327 if (err != kNoError) {
328 return err;
329 }
330
331 err = gain_control_->AnalyzeCaptureAudio(capture_audio_);
332 if (err != kNoError) {
333 return err;
334 }
335
336 err = echo_cancellation_->ProcessCaptureAudio(capture_audio_);
337 if (err != kNoError) {
338 return err;
339 }
340
341 if (echo_control_mobile_->is_enabled() &&
342 noise_suppression_->is_enabled()) {
343 capture_audio_->CopyLowPassToReference();
344 }
345
346 err = noise_suppression_->ProcessCaptureAudio(capture_audio_);
347 if (err != kNoError) {
348 return err;
349 }
350
351 err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_);
352 if (err != kNoError) {
353 return err;
354 }
355
356 err = voice_detection_->ProcessCaptureAudio(capture_audio_);
357 if (err != kNoError) {
358 return err;
359 }
360
361 err = gain_control_->ProcessCaptureAudio(capture_audio_);
362 if (err != kNoError) {
363 return err;
364 }
365
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000366 if (synthesis_needed(data_processed)) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000367 for (int i = 0; i < num_output_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 // Recombine low and high bands.
369 SplittingFilterSynthesis(capture_audio_->low_pass_split_data(i),
370 capture_audio_->high_pass_split_data(i),
371 capture_audio_->data(i),
372 capture_audio_->synthesis_filter_state1(i),
373 capture_audio_->synthesis_filter_state2(i));
374 }
375 }
376
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000377 // The level estimator operates on the recombined data.
378 err = level_estimator_->ProcessStream(capture_audio_);
379 if (err != kNoError) {
380 return err;
381 }
382
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000383 capture_audio_->InterleaveTo(frame, interleave_needed(data_processed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000384
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000385#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000386 if (debug_file_->Open()) {
387 audioproc::Stream* msg = event_msg_->mutable_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000388 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000389 frame->samples_per_channel_ *
390 frame->num_channels_;
391 msg->set_output_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000392 err = WriteMessageToDebugFile();
393 if (err != kNoError) {
394 return err;
395 }
396 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000397#endif
ajm@google.com808e0e02011-08-03 21:08:51 +0000398
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000399 was_stream_delay_set_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 return kNoError;
401}
402
403int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000404 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 int err = kNoError;
406
407 if (frame == NULL) {
408 return kNullPointerError;
409 }
410
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000411 if (frame->sample_rate_hz_ != sample_rate_hz_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 return kBadSampleRateError;
413 }
414
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000415 if (frame->num_channels_ != num_reverse_channels_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 return kBadNumberChannelsError;
417 }
418
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000419 if (frame->samples_per_channel_ != samples_per_channel_) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 return kBadDataLengthError;
421 }
422
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000423#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 if (debug_file_->Open()) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000425 event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
426 audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000427 const size_t data_size = sizeof(int16_t) *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000428 frame->samples_per_channel_ *
429 frame->num_channels_;
430 msg->set_data(frame->data_, data_size);
ajm@google.com808e0e02011-08-03 21:08:51 +0000431 err = WriteMessageToDebugFile();
432 if (err != kNoError) {
433 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 }
435 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000436#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000437
438 render_audio_->DeinterleaveFrom(frame);
439
440 // TODO(ajm): turn the splitting filter into a component?
441 if (sample_rate_hz_ == kSampleRate32kHz) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000442 for (int i = 0; i < num_reverse_channels_; i++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 // Split into low and high band.
444 SplittingFilterAnalysis(render_audio_->data(i),
445 render_audio_->low_pass_split_data(i),
446 render_audio_->high_pass_split_data(i),
447 render_audio_->analysis_filter_state1(i),
448 render_audio_->analysis_filter_state2(i));
449 }
450 }
451
452 // TODO(ajm): warnings possible from components?
453 err = echo_cancellation_->ProcessRenderAudio(render_audio_);
454 if (err != kNoError) {
455 return err;
456 }
457
458 err = echo_control_mobile_->ProcessRenderAudio(render_audio_);
459 if (err != kNoError) {
460 return err;
461 }
462
463 err = gain_control_->ProcessRenderAudio(render_audio_);
464 if (err != kNoError) {
465 return err;
466 }
467
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 return err; // TODO(ajm): this is for returning warnings; necessary?
469}
470
471int AudioProcessingImpl::set_stream_delay_ms(int delay) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000472 Error retval = kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 was_stream_delay_set_ = true;
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000474 delay += delay_offset_ms_;
475
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 if (delay < 0) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000477 delay = 0;
478 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 }
480
481 // TODO(ajm): the max is rather arbitrarily chosen; investigate.
482 if (delay > 500) {
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000483 delay = 500;
484 retval = kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 }
486
487 stream_delay_ms_ = delay;
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000488 return retval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000489}
490
491int AudioProcessingImpl::stream_delay_ms() const {
492 return stream_delay_ms_;
493}
494
495bool AudioProcessingImpl::was_stream_delay_set() const {
496 return was_stream_delay_set_;
497}
498
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000499void AudioProcessingImpl::set_delay_offset_ms(int offset) {
500 CriticalSectionScoped crit_scoped(crit_);
501 delay_offset_ms_ = offset;
502}
503
504int AudioProcessingImpl::delay_offset_ms() const {
505 return delay_offset_ms_;
506}
507
niklase@google.com470e71d2011-07-07 08:21:25 +0000508int AudioProcessingImpl::StartDebugRecording(
509 const char filename[AudioProcessing::kMaxFilenameSize]) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000510 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize);
512
513 if (filename == NULL) {
514 return kNullPointerError;
515 }
516
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000517#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 // Stop any ongoing recording.
519 if (debug_file_->Open()) {
520 if (debug_file_->CloseFile() == -1) {
521 return kFileError;
522 }
523 }
524
525 if (debug_file_->OpenFile(filename, false) == -1) {
526 debug_file_->CloseFile();
527 return kFileError;
528 }
529
ajm@google.com808e0e02011-08-03 21:08:51 +0000530 int err = WriteInitMessage();
531 if (err != kNoError) {
532 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000535#else
536 return kUnsupportedFunctionError;
537#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000538}
539
540int AudioProcessingImpl::StopDebugRecording() {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000541 CriticalSectionScoped crit_scoped(crit_);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000542
543#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 // We just return if recording hasn't started.
545 if (debug_file_->Open()) {
546 if (debug_file_->CloseFile() == -1) {
547 return kFileError;
548 }
549 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 return kNoError;
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000551#else
552 return kUnsupportedFunctionError;
553#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000554}
555
556EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
557 return echo_cancellation_;
558}
559
560EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
561 return echo_control_mobile_;
562}
563
564GainControl* AudioProcessingImpl::gain_control() const {
565 return gain_control_;
566}
567
568HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
569 return high_pass_filter_;
570}
571
572LevelEstimator* AudioProcessingImpl::level_estimator() const {
573 return level_estimator_;
574}
575
576NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
577 return noise_suppression_;
578}
579
580VoiceDetection* AudioProcessingImpl::voice_detection() const {
581 return voice_detection_;
582}
583
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000584int32_t AudioProcessingImpl::ChangeUniqueId(const int32_t id) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000585 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 id_ = id;
587
588 return kNoError;
589}
ajm@google.com808e0e02011-08-03 21:08:51 +0000590
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000591bool AudioProcessingImpl::is_data_processed() const {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000592 int enabled_count = 0;
593 std::list<ProcessingComponent*>::const_iterator it;
594 for (it = component_list_.begin(); it != component_list_.end(); it++) {
595 if ((*it)->is_component_enabled()) {
596 enabled_count++;
597 }
598 }
599
600 // Data is unchanged if no components are enabled, or if only level_estimator_
601 // or voice_detection_ is enabled.
602 if (enabled_count == 0) {
603 return false;
604 } else if (enabled_count == 1) {
605 if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
606 return false;
607 }
608 } else if (enabled_count == 2) {
609 if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
610 return false;
611 }
612 }
613 return true;
614}
615
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000616bool AudioProcessingImpl::interleave_needed(bool is_data_processed) const {
617 // Check if we've upmixed or downmixed the audio.
618 return (num_output_channels_ != num_input_channels_ || is_data_processed);
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000619}
620
andrew@webrtc.org369166a2012-04-24 18:38:03 +0000621bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
622 return (is_data_processed && sample_rate_hz_ == kSampleRate32kHz);
623}
624
625bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
626 if (!is_data_processed && !voice_detection_->is_enabled()) {
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000627 // Only level_estimator_ is enabled.
628 return false;
629 } else if (sample_rate_hz_ == kSampleRate32kHz) {
630 // Something besides level_estimator_ is enabled, and we have super-wb.
631 return true;
632 }
633 return false;
634}
635
636#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ajm@google.com808e0e02011-08-03 21:08:51 +0000637int AudioProcessingImpl::WriteMessageToDebugFile() {
638 int32_t size = event_msg_->ByteSize();
639 if (size <= 0) {
640 return kUnspecifiedError;
641 }
642#if defined(WEBRTC_BIG_ENDIAN)
643 // TODO(ajm): Use little-endian "on the wire". For the moment, we can be
644 // pretty safe in assuming little-endian.
645#endif
646
647 if (!event_msg_->SerializeToString(&event_str_)) {
648 return kUnspecifiedError;
649 }
650
651 // Write message preceded by its size.
652 if (!debug_file_->Write(&size, sizeof(int32_t))) {
653 return kFileError;
654 }
655 if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
656 return kFileError;
657 }
658
659 event_msg_->Clear();
660
661 return 0;
662}
663
664int AudioProcessingImpl::WriteInitMessage() {
665 event_msg_->set_type(audioproc::Event::INIT);
666 audioproc::Init* msg = event_msg_->mutable_init();
667 msg->set_sample_rate(sample_rate_hz_);
668 msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz());
669 msg->set_num_input_channels(num_input_channels_);
670 msg->set_num_output_channels(num_output_channels_);
671 msg->set_num_reverse_channels(num_reverse_channels_);
672
673 int err = WriteMessageToDebugFile();
674 if (err != kNoError) {
675 return err;
676 }
677
678 return kNoError;
679}
andrew@webrtc.org7bf26462011-12-03 00:03:31 +0000680#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000681} // namespace webrtc