Line data Source code
1 : /*
2 : * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 : *
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 :
11 : #include "webrtc/voice_engine/voe_audio_processing_impl.h"
12 :
13 : #include "webrtc/base/logging.h"
14 : #include "webrtc/modules/audio_processing/include/audio_processing.h"
15 : #include "webrtc/system_wrappers/include/trace.h"
16 : #include "webrtc/voice_engine/channel.h"
17 : #include "webrtc/voice_engine/include/voe_errors.h"
18 : #include "webrtc/voice_engine/transmit_mixer.h"
19 : #include "webrtc/voice_engine/voice_engine_impl.h"
20 :
21 : // TODO(andrew): move to a common place.
22 : #define WEBRTC_VOICE_INIT_CHECK() \
23 : do { \
24 : if (!_shared->statistics().Initialized()) { \
25 : _shared->SetLastError(VE_NOT_INITED, kTraceError); \
26 : return -1; \
27 : } \
28 : } while (0)
29 :
30 : #define WEBRTC_VOICE_INIT_CHECK_BOOL() \
31 : do { \
32 : if (!_shared->statistics().Initialized()) { \
33 : _shared->SetLastError(VE_NOT_INITED, kTraceError); \
34 : return false; \
35 : } \
36 : } while (0)
37 :
38 : namespace webrtc {
39 :
40 : #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
41 : static const EcModes kDefaultEcMode = kEcAecm;
42 : #else
43 : static const EcModes kDefaultEcMode = kEcAec;
44 : #endif
45 :
46 0 : VoEAudioProcessing* VoEAudioProcessing::GetInterface(VoiceEngine* voiceEngine) {
47 0 : if (NULL == voiceEngine) {
48 0 : return NULL;
49 : }
50 0 : VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
51 0 : s->AddRef();
52 0 : return s;
53 : }
54 :
55 0 : VoEAudioProcessingImpl::VoEAudioProcessingImpl(voe::SharedData* shared)
56 0 : : _isAecMode(kDefaultEcMode == kEcAec), _shared(shared) {
57 : WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
58 : "VoEAudioProcessingImpl::VoEAudioProcessingImpl() - ctor");
59 0 : }
60 :
61 0 : VoEAudioProcessingImpl::~VoEAudioProcessingImpl() {
62 : WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
63 : "VoEAudioProcessingImpl::~VoEAudioProcessingImpl() - dtor");
64 0 : }
65 :
66 0 : int VoEAudioProcessingImpl::SetNsStatus(bool enable, NsModes mode) {
67 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
68 : "SetNsStatus(enable=%d, mode=%d)", enable, mode);
69 0 : if (!_shared->statistics().Initialized()) {
70 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
71 0 : return -1;
72 : }
73 :
74 0 : NoiseSuppression::Level nsLevel = kDefaultNsMode;
75 0 : switch (mode) {
76 : case kNsDefault:
77 0 : nsLevel = kDefaultNsMode;
78 0 : break;
79 : case kNsUnchanged:
80 0 : nsLevel = _shared->audio_processing()->noise_suppression()->level();
81 0 : break;
82 : case kNsConference:
83 0 : nsLevel = NoiseSuppression::kHigh;
84 0 : break;
85 : case kNsLowSuppression:
86 0 : nsLevel = NoiseSuppression::kLow;
87 0 : break;
88 : case kNsModerateSuppression:
89 0 : nsLevel = NoiseSuppression::kModerate;
90 0 : break;
91 : case kNsHighSuppression:
92 0 : nsLevel = NoiseSuppression::kHigh;
93 0 : break;
94 : case kNsVeryHighSuppression:
95 0 : nsLevel = NoiseSuppression::kVeryHigh;
96 0 : break;
97 : }
98 :
99 0 : if (_shared->audio_processing()->noise_suppression()->set_level(nsLevel) !=
100 : 0) {
101 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
102 0 : "SetNsStatus() failed to set Ns mode");
103 0 : return -1;
104 : }
105 0 : if (_shared->audio_processing()->noise_suppression()->Enable(enable) != 0) {
106 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
107 0 : "SetNsStatus() failed to set Ns state");
108 0 : return -1;
109 : }
110 :
111 0 : return 0;
112 : }
113 :
114 0 : int VoEAudioProcessingImpl::GetNsStatus(bool& enabled, NsModes& mode) {
115 0 : if (!_shared->statistics().Initialized()) {
116 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
117 0 : return -1;
118 : }
119 :
120 0 : enabled = _shared->audio_processing()->noise_suppression()->is_enabled();
121 : NoiseSuppression::Level nsLevel =
122 0 : _shared->audio_processing()->noise_suppression()->level();
123 :
124 0 : switch (nsLevel) {
125 : case NoiseSuppression::kLow:
126 0 : mode = kNsLowSuppression;
127 0 : break;
128 : case NoiseSuppression::kModerate:
129 0 : mode = kNsModerateSuppression;
130 0 : break;
131 : case NoiseSuppression::kHigh:
132 0 : mode = kNsHighSuppression;
133 0 : break;
134 : case NoiseSuppression::kVeryHigh:
135 0 : mode = kNsVeryHighSuppression;
136 0 : break;
137 : }
138 0 : return 0;
139 : }
140 :
141 0 : int VoEAudioProcessingImpl::SetAgcStatus(bool enable, AgcModes mode) {
142 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
143 : "SetAgcStatus(enable=%d, mode=%d)", enable, mode);
144 0 : if (!_shared->statistics().Initialized()) {
145 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
146 0 : return -1;
147 : }
148 :
149 : #if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID)
150 : if (mode == kAgcAdaptiveAnalog) {
151 : _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
152 : "SetAgcStatus() invalid Agc mode for mobile device");
153 : return -1;
154 : }
155 : #endif
156 :
157 0 : GainControl::Mode agcMode = kDefaultAgcMode;
158 0 : switch (mode) {
159 : case kAgcDefault:
160 0 : agcMode = kDefaultAgcMode;
161 0 : break;
162 : case kAgcUnchanged:
163 0 : agcMode = _shared->audio_processing()->gain_control()->mode();
164 0 : break;
165 : case kAgcFixedDigital:
166 0 : agcMode = GainControl::kFixedDigital;
167 0 : break;
168 : case kAgcAdaptiveAnalog:
169 0 : agcMode = GainControl::kAdaptiveAnalog;
170 0 : break;
171 : case kAgcAdaptiveDigital:
172 0 : agcMode = GainControl::kAdaptiveDigital;
173 0 : break;
174 : }
175 :
176 0 : if (_shared->audio_processing()->gain_control()->set_mode(agcMode) != 0) {
177 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
178 0 : "SetAgcStatus() failed to set Agc mode");
179 0 : return -1;
180 : }
181 0 : if (_shared->audio_processing()->gain_control()->Enable(enable) != 0) {
182 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
183 0 : "SetAgcStatus() failed to set Agc state");
184 0 : return -1;
185 : }
186 :
187 0 : if (agcMode != GainControl::kFixedDigital) {
188 : // Set Agc state in the ADM when adaptive Agc mode has been selected.
189 : // Note that we also enable the ADM Agc when Adaptive Digital mode is
190 : // used since we want to be able to provide the APM with updated mic
191 : // levels when the user modifies the mic level manually.
192 0 : if (_shared->audio_device()->SetAGC(enable) != 0) {
193 0 : _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
194 0 : "SetAgcStatus() failed to set Agc mode");
195 : }
196 : }
197 :
198 0 : return 0;
199 : }
200 :
201 0 : int VoEAudioProcessingImpl::GetAgcStatus(bool& enabled, AgcModes& mode) {
202 0 : if (!_shared->statistics().Initialized()) {
203 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
204 0 : return -1;
205 : }
206 :
207 0 : enabled = _shared->audio_processing()->gain_control()->is_enabled();
208 : GainControl::Mode agcMode =
209 0 : _shared->audio_processing()->gain_control()->mode();
210 :
211 0 : switch (agcMode) {
212 : case GainControl::kFixedDigital:
213 0 : mode = kAgcFixedDigital;
214 0 : break;
215 : case GainControl::kAdaptiveAnalog:
216 0 : mode = kAgcAdaptiveAnalog;
217 0 : break;
218 : case GainControl::kAdaptiveDigital:
219 0 : mode = kAgcAdaptiveDigital;
220 0 : break;
221 : }
222 :
223 0 : return 0;
224 : }
225 :
226 0 : int VoEAudioProcessingImpl::SetAgcConfig(AgcConfig config) {
227 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
228 : "SetAgcConfig()");
229 0 : if (!_shared->statistics().Initialized()) {
230 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
231 0 : return -1;
232 : }
233 :
234 0 : if (_shared->audio_processing()->gain_control()->set_target_level_dbfs(
235 0 : config.targetLeveldBOv) != 0) {
236 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
237 : "SetAgcConfig() failed to set target peak |level|"
238 0 : " (or envelope) of the Agc");
239 0 : return -1;
240 : }
241 0 : if (_shared->audio_processing()->gain_control()->set_compression_gain_db(
242 0 : config.digitalCompressionGaindB) != 0) {
243 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
244 : "SetAgcConfig() failed to set the range in |gain| "
245 0 : "the digital compression stage may apply");
246 0 : return -1;
247 : }
248 0 : if (_shared->audio_processing()->gain_control()->enable_limiter(
249 0 : config.limiterEnable) != 0) {
250 0 : _shared->SetLastError(
251 : VE_APM_ERROR, kTraceError,
252 0 : "SetAgcConfig() failed to set hard limiter to the signal");
253 0 : return -1;
254 : }
255 :
256 0 : return 0;
257 : }
258 :
259 0 : int VoEAudioProcessingImpl::GetAgcConfig(AgcConfig& config) {
260 0 : if (!_shared->statistics().Initialized()) {
261 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
262 0 : return -1;
263 : }
264 :
265 0 : config.targetLeveldBOv =
266 0 : _shared->audio_processing()->gain_control()->target_level_dbfs();
267 0 : config.digitalCompressionGaindB =
268 0 : _shared->audio_processing()->gain_control()->compression_gain_db();
269 0 : config.limiterEnable =
270 0 : _shared->audio_processing()->gain_control()->is_limiter_enabled();
271 :
272 0 : return 0;
273 : }
274 :
275 0 : bool VoEAudioProcessing::DriftCompensationSupported() {
276 : #if defined(WEBRTC_DRIFT_COMPENSATION_SUPPORTED)
277 : return true;
278 : #else
279 0 : return false;
280 : #endif
281 : }
282 :
283 0 : int VoEAudioProcessingImpl::EnableDriftCompensation(bool enable) {
284 0 : WEBRTC_VOICE_INIT_CHECK();
285 :
286 0 : if (!DriftCompensationSupported()) {
287 0 : _shared->SetLastError(
288 : VE_APM_ERROR, kTraceWarning,
289 0 : "Drift compensation is not supported on this platform.");
290 0 : return -1;
291 : }
292 :
293 0 : EchoCancellation* aec = _shared->audio_processing()->echo_cancellation();
294 0 : if (aec->enable_drift_compensation(enable) != 0) {
295 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
296 0 : "aec->enable_drift_compensation() failed");
297 0 : return -1;
298 : }
299 0 : return 0;
300 : }
301 :
302 0 : bool VoEAudioProcessingImpl::DriftCompensationEnabled() {
303 0 : WEBRTC_VOICE_INIT_CHECK_BOOL();
304 :
305 0 : EchoCancellation* aec = _shared->audio_processing()->echo_cancellation();
306 0 : return aec->is_drift_compensation_enabled();
307 : }
308 :
309 0 : int VoEAudioProcessingImpl::SetEcStatus(bool enable, EcModes mode) {
310 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
311 : "SetEcStatus(enable=%d, mode=%d)", enable, mode);
312 0 : if (!_shared->statistics().Initialized()) {
313 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
314 0 : return -1;
315 : }
316 :
317 : // AEC mode
318 0 : if ((mode == kEcDefault) || (mode == kEcConference) || (mode == kEcAec) ||
319 0 : ((mode == kEcUnchanged) && (_isAecMode == true))) {
320 0 : if (enable) {
321 : // Disable the AECM before enable the AEC
322 0 : if (_shared->audio_processing()->echo_control_mobile()->is_enabled()) {
323 0 : _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
324 0 : "SetEcStatus() disable AECM before enabling AEC");
325 0 : if (_shared->audio_processing()->echo_control_mobile()->Enable(false) !=
326 : 0) {
327 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
328 0 : "SetEcStatus() failed to disable AECM");
329 0 : return -1;
330 : }
331 : }
332 : }
333 0 : if (_shared->audio_processing()->echo_cancellation()->Enable(enable) != 0) {
334 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
335 0 : "SetEcStatus() failed to set AEC state");
336 0 : return -1;
337 : }
338 0 : if (mode == kEcConference) {
339 0 : if (_shared->audio_processing()
340 0 : ->echo_cancellation()
341 0 : ->set_suppression_level(EchoCancellation::kHighSuppression) !=
342 : 0) {
343 0 : _shared->SetLastError(
344 : VE_APM_ERROR, kTraceError,
345 0 : "SetEcStatus() failed to set aggressiveness to high");
346 0 : return -1;
347 : }
348 : } else {
349 0 : if (_shared->audio_processing()
350 0 : ->echo_cancellation()
351 0 : ->set_suppression_level(EchoCancellation::kModerateSuppression) !=
352 : 0) {
353 0 : _shared->SetLastError(
354 : VE_APM_ERROR, kTraceError,
355 0 : "SetEcStatus() failed to set aggressiveness to moderate");
356 0 : return -1;
357 : }
358 : }
359 :
360 0 : _isAecMode = true;
361 0 : } else if ((mode == kEcAecm) ||
362 0 : ((mode == kEcUnchanged) && (_isAecMode == false))) {
363 0 : if (enable) {
364 : // Disable the AEC before enable the AECM
365 0 : if (_shared->audio_processing()->echo_cancellation()->is_enabled()) {
366 0 : _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
367 0 : "SetEcStatus() disable AEC before enabling AECM");
368 0 : if (_shared->audio_processing()->echo_cancellation()->Enable(false) !=
369 : 0) {
370 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
371 0 : "SetEcStatus() failed to disable AEC");
372 0 : return -1;
373 : }
374 : }
375 : }
376 0 : if (_shared->audio_processing()->echo_control_mobile()->Enable(enable) !=
377 : 0) {
378 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
379 0 : "SetEcStatus() failed to set AECM state");
380 0 : return -1;
381 : }
382 0 : _isAecMode = false;
383 : } else {
384 0 : _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
385 0 : "SetEcStatus() invalid EC mode");
386 0 : return -1;
387 : }
388 :
389 0 : return 0;
390 : }
391 :
392 0 : int VoEAudioProcessingImpl::GetEcStatus(bool& enabled, EcModes& mode) {
393 0 : if (!_shared->statistics().Initialized()) {
394 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
395 0 : return -1;
396 : }
397 :
398 0 : if (_isAecMode == true) {
399 0 : mode = kEcAec;
400 0 : enabled = _shared->audio_processing()->echo_cancellation()->is_enabled();
401 : } else {
402 0 : mode = kEcAecm;
403 0 : enabled = _shared->audio_processing()->echo_control_mobile()->is_enabled();
404 : }
405 :
406 0 : return 0;
407 : }
408 :
409 0 : void VoEAudioProcessingImpl::SetDelayOffsetMs(int offset) {
410 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
411 : "SetDelayOffsetMs(offset = %d)", offset);
412 0 : _shared->audio_processing()->set_delay_offset_ms(offset);
413 0 : }
414 :
415 0 : int VoEAudioProcessingImpl::DelayOffsetMs() {
416 0 : return _shared->audio_processing()->delay_offset_ms();
417 : }
418 :
419 0 : int VoEAudioProcessingImpl::SetAecmMode(AecmModes mode, bool enableCNG) {
420 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
421 : "SetAECMMode(mode = %d)", mode);
422 0 : if (!_shared->statistics().Initialized()) {
423 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
424 0 : return -1;
425 : }
426 :
427 : EchoControlMobile::RoutingMode aecmMode(
428 0 : EchoControlMobile::kQuietEarpieceOrHeadset);
429 :
430 0 : switch (mode) {
431 : case kAecmQuietEarpieceOrHeadset:
432 0 : aecmMode = EchoControlMobile::kQuietEarpieceOrHeadset;
433 0 : break;
434 : case kAecmEarpiece:
435 0 : aecmMode = EchoControlMobile::kEarpiece;
436 0 : break;
437 : case kAecmLoudEarpiece:
438 0 : aecmMode = EchoControlMobile::kLoudEarpiece;
439 0 : break;
440 : case kAecmSpeakerphone:
441 0 : aecmMode = EchoControlMobile::kSpeakerphone;
442 0 : break;
443 : case kAecmLoudSpeakerphone:
444 0 : aecmMode = EchoControlMobile::kLoudSpeakerphone;
445 0 : break;
446 : }
447 :
448 0 : if (_shared->audio_processing()->echo_control_mobile()->set_routing_mode(
449 0 : aecmMode) != 0) {
450 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
451 0 : "SetAECMMode() failed to set AECM routing mode");
452 0 : return -1;
453 : }
454 0 : if (_shared->audio_processing()->echo_control_mobile()->enable_comfort_noise(
455 0 : enableCNG) != 0) {
456 0 : _shared->SetLastError(
457 : VE_APM_ERROR, kTraceError,
458 0 : "SetAECMMode() failed to set comfort noise state for AECM");
459 0 : return -1;
460 : }
461 :
462 0 : return 0;
463 : }
464 :
465 0 : int VoEAudioProcessingImpl::GetAecmMode(AecmModes& mode, bool& enabledCNG) {
466 0 : if (!_shared->statistics().Initialized()) {
467 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
468 0 : return -1;
469 : }
470 :
471 0 : enabledCNG = false;
472 :
473 : EchoControlMobile::RoutingMode aecmMode =
474 0 : _shared->audio_processing()->echo_control_mobile()->routing_mode();
475 0 : enabledCNG = _shared->audio_processing()
476 0 : ->echo_control_mobile()
477 0 : ->is_comfort_noise_enabled();
478 :
479 0 : switch (aecmMode) {
480 : case EchoControlMobile::kQuietEarpieceOrHeadset:
481 0 : mode = kAecmQuietEarpieceOrHeadset;
482 0 : break;
483 : case EchoControlMobile::kEarpiece:
484 0 : mode = kAecmEarpiece;
485 0 : break;
486 : case EchoControlMobile::kLoudEarpiece:
487 0 : mode = kAecmLoudEarpiece;
488 0 : break;
489 : case EchoControlMobile::kSpeakerphone:
490 0 : mode = kAecmSpeakerphone;
491 0 : break;
492 : case EchoControlMobile::kLoudSpeakerphone:
493 0 : mode = kAecmLoudSpeakerphone;
494 0 : break;
495 : }
496 :
497 0 : return 0;
498 : }
499 :
500 0 : int VoEAudioProcessingImpl::EnableHighPassFilter(bool enable) {
501 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
502 : "EnableHighPassFilter(%d)", enable);
503 0 : if (_shared->audio_processing()->high_pass_filter()->Enable(enable) !=
504 : AudioProcessing::kNoError) {
505 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
506 0 : "HighPassFilter::Enable() failed.");
507 0 : return -1;
508 : }
509 :
510 0 : return 0;
511 : }
512 :
513 0 : bool VoEAudioProcessingImpl::IsHighPassFilterEnabled() {
514 0 : return _shared->audio_processing()->high_pass_filter()->is_enabled();
515 : }
516 :
517 0 : int VoEAudioProcessingImpl::VoiceActivityIndicator(int channel) {
518 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
519 : "VoiceActivityIndicator(channel=%d)", channel);
520 0 : if (!_shared->statistics().Initialized()) {
521 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
522 0 : return -1;
523 : }
524 :
525 0 : voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
526 0 : voe::Channel* channelPtr = ch.channel();
527 0 : if (channelPtr == NULL) {
528 0 : _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
529 0 : "VoiceActivityIndicator() failed to locate channel");
530 0 : return -1;
531 : }
532 0 : int activity(-1);
533 0 : channelPtr->VoiceActivityIndicator(activity);
534 :
535 0 : return activity;
536 : }
537 :
538 0 : int VoEAudioProcessingImpl::SetEcMetricsStatus(bool enable) {
539 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
540 : "SetEcMetricsStatus(enable=%d)", enable);
541 0 : if (!_shared->statistics().Initialized()) {
542 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
543 0 : return -1;
544 : }
545 :
546 0 : if ((_shared->audio_processing()->echo_cancellation()->enable_metrics(
547 0 : enable) != 0) ||
548 0 : (_shared->audio_processing()->echo_cancellation()->enable_delay_logging(
549 0 : enable) != 0)) {
550 0 : _shared->SetLastError(VE_APM_ERROR, kTraceError,
551 0 : "SetEcMetricsStatus() unable to set EC metrics mode");
552 0 : return -1;
553 : }
554 0 : return 0;
555 : }
556 :
557 0 : int VoEAudioProcessingImpl::GetEcMetricsStatus(bool& enabled) {
558 0 : if (!_shared->statistics().Initialized()) {
559 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
560 0 : return -1;
561 : }
562 :
563 : bool echo_mode =
564 0 : _shared->audio_processing()->echo_cancellation()->are_metrics_enabled();
565 0 : bool delay_mode = _shared->audio_processing()
566 0 : ->echo_cancellation()
567 0 : ->is_delay_logging_enabled();
568 :
569 0 : if (echo_mode != delay_mode) {
570 0 : _shared->SetLastError(
571 : VE_APM_ERROR, kTraceError,
572 0 : "GetEcMetricsStatus() delay logging and echo mode are not the same");
573 0 : return -1;
574 : }
575 :
576 0 : enabled = echo_mode;
577 :
578 0 : return 0;
579 : }
580 :
581 0 : int VoEAudioProcessingImpl::GetEchoMetrics(int& ERL,
582 : int& ERLE,
583 : int& RERL,
584 : int& A_NLP) {
585 0 : if (!_shared->statistics().Initialized()) {
586 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
587 0 : return -1;
588 : }
589 0 : if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) {
590 0 : _shared->SetLastError(
591 : VE_APM_ERROR, kTraceWarning,
592 0 : "GetEchoMetrics() AudioProcessingModule AEC is not enabled");
593 0 : return -1;
594 : }
595 :
596 : // Get Echo Metrics from Audio Processing Module.
597 0 : EchoCancellation::Metrics echoMetrics;
598 0 : if (_shared->audio_processing()->echo_cancellation()->GetMetrics(
599 0 : &echoMetrics)) {
600 : WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
601 : "GetEchoMetrics(), AudioProcessingModule metrics error");
602 0 : return -1;
603 : }
604 :
605 : // Echo quality metrics.
606 0 : ERL = echoMetrics.echo_return_loss.instant;
607 0 : ERLE = echoMetrics.echo_return_loss_enhancement.instant;
608 0 : RERL = echoMetrics.residual_echo_return_loss.instant;
609 0 : A_NLP = echoMetrics.a_nlp.instant;
610 :
611 0 : return 0;
612 : }
613 :
614 0 : int VoEAudioProcessingImpl::GetEcDelayMetrics(int& delay_median,
615 : int& delay_std,
616 : float& fraction_poor_delays) {
617 0 : if (!_shared->statistics().Initialized()) {
618 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
619 0 : return -1;
620 : }
621 0 : if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) {
622 0 : _shared->SetLastError(
623 : VE_APM_ERROR, kTraceWarning,
624 0 : "GetEcDelayMetrics() AudioProcessingModule AEC is not enabled");
625 0 : return -1;
626 : }
627 :
628 0 : int median = 0;
629 0 : int std = 0;
630 0 : float poor_fraction = 0;
631 : // Get delay-logging values from Audio Processing Module.
632 0 : if (_shared->audio_processing()->echo_cancellation()->GetDelayMetrics(
633 0 : &median, &std, &poor_fraction)) {
634 : WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
635 : "GetEcDelayMetrics(), AudioProcessingModule delay-logging "
636 : "error");
637 0 : return -1;
638 : }
639 :
640 : // EC delay-logging metrics
641 0 : delay_median = median;
642 0 : delay_std = std;
643 0 : fraction_poor_delays = poor_fraction;
644 :
645 0 : return 0;
646 : }
647 :
648 0 : int VoEAudioProcessingImpl::StartDebugRecording(const char* fileNameUTF8) {
649 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
650 : "StartDebugRecording()");
651 0 : if (!_shared->statistics().Initialized()) {
652 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
653 0 : return -1;
654 : }
655 :
656 0 : return _shared->audio_processing()->StartDebugRecording(fileNameUTF8, -1);
657 : }
658 :
659 0 : int VoEAudioProcessingImpl::StartDebugRecording(FILE* file_handle) {
660 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
661 : "StartDebugRecording()");
662 0 : if (!_shared->statistics().Initialized()) {
663 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
664 0 : return -1;
665 : }
666 :
667 0 : return _shared->audio_processing()->StartDebugRecording(file_handle, -1);
668 : }
669 :
670 0 : int VoEAudioProcessingImpl::StopDebugRecording() {
671 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
672 : "StopDebugRecording()");
673 0 : if (!_shared->statistics().Initialized()) {
674 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
675 0 : return -1;
676 : }
677 :
678 0 : return _shared->audio_processing()->StopDebugRecording();
679 : }
680 :
681 0 : int VoEAudioProcessingImpl::SetTypingDetectionStatus(bool enable) {
682 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
683 : "SetTypingDetectionStatus()");
684 : #if !WEBRTC_VOICE_ENGINE_TYPING_DETECTION
685 : NOT_SUPPORTED(_shared->statistics());
686 : #else
687 0 : if (!_shared->statistics().Initialized()) {
688 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
689 0 : return -1;
690 : }
691 :
692 : // Just use the VAD state to determine if we should enable typing detection
693 : // or not
694 :
695 0 : if (_shared->audio_processing()->voice_detection()->Enable(enable)) {
696 0 : _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
697 0 : "SetTypingDetectionStatus() failed to set VAD state");
698 0 : return -1;
699 : }
700 0 : if (_shared->audio_processing()->voice_detection()->set_likelihood(
701 0 : VoiceDetection::kVeryLowLikelihood)) {
702 0 : _shared->SetLastError(
703 : VE_APM_ERROR, kTraceWarning,
704 0 : "SetTypingDetectionStatus() failed to set VAD likelihood to low");
705 0 : return -1;
706 : }
707 :
708 0 : return 0;
709 : #endif
710 : }
711 :
712 0 : int VoEAudioProcessingImpl::GetTypingDetectionStatus(bool& enabled) {
713 0 : if (!_shared->statistics().Initialized()) {
714 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
715 0 : return -1;
716 : }
717 : // Just use the VAD state to determine if we should enable typing
718 : // detection or not
719 :
720 0 : enabled = _shared->audio_processing()->voice_detection()->is_enabled();
721 :
722 0 : return 0;
723 : }
724 :
725 0 : int VoEAudioProcessingImpl::TimeSinceLastTyping(int& seconds) {
726 : #if !WEBRTC_VOICE_ENGINE_TYPING_DETECTION
727 : NOT_SUPPORTED(_shared->statistics());
728 : #else
729 0 : if (!_shared->statistics().Initialized()) {
730 0 : _shared->SetLastError(VE_NOT_INITED, kTraceError);
731 0 : return -1;
732 : }
733 : // Check if typing detection is enabled
734 0 : bool enabled = _shared->audio_processing()->voice_detection()->is_enabled();
735 0 : if (enabled) {
736 0 : _shared->transmit_mixer()->TimeSinceLastTyping(seconds);
737 0 : return 0;
738 : } else {
739 0 : _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
740 0 : "SetTypingDetectionStatus is not enabled");
741 0 : return -1;
742 : }
743 : #endif
744 : }
745 :
746 0 : int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow,
747 : int costPerTyping,
748 : int reportingThreshold,
749 : int penaltyDecay,
750 : int typeEventDelay) {
751 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
752 : "SetTypingDetectionParameters()");
753 : #if !WEBRTC_VOICE_ENGINE_TYPING_DETECTION
754 : NOT_SUPPORTED(_shared->statistics());
755 : #else
756 0 : if (!_shared->statistics().Initialized()) {
757 0 : _shared->statistics().SetLastError(VE_NOT_INITED, kTraceError);
758 0 : return -1;
759 : }
760 0 : return (_shared->transmit_mixer()->SetTypingDetectionParameters(
761 : timeWindow, costPerTyping, reportingThreshold, penaltyDecay,
762 0 : typeEventDelay));
763 : #endif
764 : }
765 :
766 0 : void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) {
767 0 : _shared->transmit_mixer()->EnableStereoChannelSwapping(enable);
768 0 : }
769 :
770 0 : bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() {
771 0 : return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled();
772 : }
773 :
774 : } // namespace webrtc
|