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/critical_section_wrapper.h"
16 #include "webrtc/system_wrappers/include/trace.h"
17 #include "webrtc/voice_engine/channel.h"
18 #include "webrtc/voice_engine/include/voe_errors.h"
19 #include "webrtc/voice_engine/transmit_mixer.h"
20 #include "webrtc/voice_engine/voice_engine_impl.h"
21 
22 // TODO(andrew): move to a common place.
23 #define WEBRTC_VOICE_INIT_CHECK()                        \
24   do {                                                   \
25     if (!_shared->statistics().Initialized()) {          \
26       _shared->SetLastError(VE_NOT_INITED, kTraceError); \
27       return -1;                                         \
28     }                                                    \
29   } while (0)
30 
31 #define WEBRTC_VOICE_INIT_CHECK_BOOL()                   \
32   do {                                                   \
33     if (!_shared->statistics().Initialized()) {          \
34       _shared->SetLastError(VE_NOT_INITED, kTraceError); \
35       return false;                                      \
36     }                                                    \
37   } while (0)
38 
39 namespace webrtc {
40 
41 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
42 static const EcModes kDefaultEcMode = kEcAecm;
43 #else
44 static const EcModes kDefaultEcMode = kEcAec;
45 #endif
46 
GetInterface(VoiceEngine * voiceEngine)47 VoEAudioProcessing* VoEAudioProcessing::GetInterface(VoiceEngine* voiceEngine) {
48 #ifndef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API
49   return NULL;
50 #else
51   if (NULL == voiceEngine) {
52     return NULL;
53   }
54   VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
55   s->AddRef();
56   return s;
57 #endif
58 }
59 
60 #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API
VoEAudioProcessingImpl(voe::SharedData * shared)61 VoEAudioProcessingImpl::VoEAudioProcessingImpl(voe::SharedData* shared)
62     : _isAecMode(kDefaultEcMode == kEcAec), _shared(shared) {
63   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
64                "VoEAudioProcessingImpl::VoEAudioProcessingImpl() - ctor");
65 }
66 
~VoEAudioProcessingImpl()67 VoEAudioProcessingImpl::~VoEAudioProcessingImpl() {
68   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
69                "VoEAudioProcessingImpl::~VoEAudioProcessingImpl() - dtor");
70 }
71 
SetNsStatus(bool enable,NsModes mode)72 int VoEAudioProcessingImpl::SetNsStatus(bool enable, NsModes mode) {
73   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
74                "SetNsStatus(enable=%d, mode=%d)", enable, mode);
75 #ifdef WEBRTC_VOICE_ENGINE_NR
76   if (!_shared->statistics().Initialized()) {
77     _shared->SetLastError(VE_NOT_INITED, kTraceError);
78     return -1;
79   }
80 
81   NoiseSuppression::Level nsLevel = kDefaultNsMode;
82   switch (mode) {
83     case kNsDefault:
84       nsLevel = kDefaultNsMode;
85       break;
86     case kNsUnchanged:
87       nsLevel = _shared->audio_processing()->noise_suppression()->level();
88       break;
89     case kNsConference:
90       nsLevel = NoiseSuppression::kHigh;
91       break;
92     case kNsLowSuppression:
93       nsLevel = NoiseSuppression::kLow;
94       break;
95     case kNsModerateSuppression:
96       nsLevel = NoiseSuppression::kModerate;
97       break;
98     case kNsHighSuppression:
99       nsLevel = NoiseSuppression::kHigh;
100       break;
101     case kNsVeryHighSuppression:
102       nsLevel = NoiseSuppression::kVeryHigh;
103       break;
104   }
105 
106   if (_shared->audio_processing()->noise_suppression()->set_level(nsLevel) !=
107       0) {
108     _shared->SetLastError(VE_APM_ERROR, kTraceError,
109                           "SetNsStatus() failed to set Ns mode");
110     return -1;
111   }
112   if (_shared->audio_processing()->noise_suppression()->Enable(enable) != 0) {
113     _shared->SetLastError(VE_APM_ERROR, kTraceError,
114                           "SetNsStatus() failed to set Ns state");
115     return -1;
116   }
117 
118   return 0;
119 #else
120   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
121                         "SetNsStatus() Ns is not supported");
122   return -1;
123 #endif
124 }
125 
GetNsStatus(bool & enabled,NsModes & mode)126 int VoEAudioProcessingImpl::GetNsStatus(bool& enabled, NsModes& mode) {
127 #ifdef WEBRTC_VOICE_ENGINE_NR
128   if (!_shared->statistics().Initialized()) {
129     _shared->SetLastError(VE_NOT_INITED, kTraceError);
130     return -1;
131   }
132 
133   enabled = _shared->audio_processing()->noise_suppression()->is_enabled();
134   NoiseSuppression::Level nsLevel =
135       _shared->audio_processing()->noise_suppression()->level();
136 
137   switch (nsLevel) {
138     case NoiseSuppression::kLow:
139       mode = kNsLowSuppression;
140       break;
141     case NoiseSuppression::kModerate:
142       mode = kNsModerateSuppression;
143       break;
144     case NoiseSuppression::kHigh:
145       mode = kNsHighSuppression;
146       break;
147     case NoiseSuppression::kVeryHigh:
148       mode = kNsVeryHighSuppression;
149       break;
150   }
151   return 0;
152 #else
153   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
154                         "GetNsStatus() Ns is not supported");
155   return -1;
156 #endif
157 }
158 
SetAgcStatus(bool enable,AgcModes mode)159 int VoEAudioProcessingImpl::SetAgcStatus(bool enable, AgcModes mode) {
160   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
161                "SetAgcStatus(enable=%d, mode=%d)", enable, mode);
162 #ifdef WEBRTC_VOICE_ENGINE_AGC
163   if (!_shared->statistics().Initialized()) {
164     _shared->SetLastError(VE_NOT_INITED, kTraceError);
165     return -1;
166   }
167 
168 #if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID)
169   if (mode == kAgcAdaptiveAnalog) {
170     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
171                           "SetAgcStatus() invalid Agc mode for mobile device");
172     return -1;
173   }
174 #endif
175 
176   GainControl::Mode agcMode = kDefaultAgcMode;
177   switch (mode) {
178     case kAgcDefault:
179       agcMode = kDefaultAgcMode;
180       break;
181     case kAgcUnchanged:
182       agcMode = _shared->audio_processing()->gain_control()->mode();
183       break;
184     case kAgcFixedDigital:
185       agcMode = GainControl::kFixedDigital;
186       break;
187     case kAgcAdaptiveAnalog:
188       agcMode = GainControl::kAdaptiveAnalog;
189       break;
190     case kAgcAdaptiveDigital:
191       agcMode = GainControl::kAdaptiveDigital;
192       break;
193   }
194 
195   if (_shared->audio_processing()->gain_control()->set_mode(agcMode) != 0) {
196     _shared->SetLastError(VE_APM_ERROR, kTraceError,
197                           "SetAgcStatus() failed to set Agc mode");
198     return -1;
199   }
200   if (_shared->audio_processing()->gain_control()->Enable(enable) != 0) {
201     _shared->SetLastError(VE_APM_ERROR, kTraceError,
202                           "SetAgcStatus() failed to set Agc state");
203     return -1;
204   }
205 
206   if (agcMode != GainControl::kFixedDigital) {
207     // Set Agc state in the ADM when adaptive Agc mode has been selected.
208     // Note that we also enable the ADM Agc when Adaptive Digital mode is
209     // used since we want to be able to provide the APM with updated mic
210     // levels when the user modifies the mic level manually.
211     if (_shared->audio_device()->SetAGC(enable) != 0) {
212       _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
213                             "SetAgcStatus() failed to set Agc mode");
214     }
215   }
216 
217   return 0;
218 #else
219   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
220                         "SetAgcStatus() Agc is not supported");
221   return -1;
222 #endif
223 }
224 
GetAgcStatus(bool & enabled,AgcModes & mode)225 int VoEAudioProcessingImpl::GetAgcStatus(bool& enabled, AgcModes& mode) {
226 #ifdef WEBRTC_VOICE_ENGINE_AGC
227   if (!_shared->statistics().Initialized()) {
228     _shared->SetLastError(VE_NOT_INITED, kTraceError);
229     return -1;
230   }
231 
232   enabled = _shared->audio_processing()->gain_control()->is_enabled();
233   GainControl::Mode agcMode =
234       _shared->audio_processing()->gain_control()->mode();
235 
236   switch (agcMode) {
237     case GainControl::kFixedDigital:
238       mode = kAgcFixedDigital;
239       break;
240     case GainControl::kAdaptiveAnalog:
241       mode = kAgcAdaptiveAnalog;
242       break;
243     case GainControl::kAdaptiveDigital:
244       mode = kAgcAdaptiveDigital;
245       break;
246   }
247 
248   return 0;
249 #else
250   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
251                         "GetAgcStatus() Agc is not supported");
252   return -1;
253 #endif
254 }
255 
SetAgcConfig(AgcConfig config)256 int VoEAudioProcessingImpl::SetAgcConfig(AgcConfig config) {
257   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
258                "SetAgcConfig()");
259 #ifdef WEBRTC_VOICE_ENGINE_AGC
260   if (!_shared->statistics().Initialized()) {
261     _shared->SetLastError(VE_NOT_INITED, kTraceError);
262     return -1;
263   }
264 
265   if (_shared->audio_processing()->gain_control()->set_target_level_dbfs(
266           config.targetLeveldBOv) != 0) {
267     _shared->SetLastError(VE_APM_ERROR, kTraceError,
268                           "SetAgcConfig() failed to set target peak |level|"
269                           " (or envelope) of the Agc");
270     return -1;
271   }
272   if (_shared->audio_processing()->gain_control()->set_compression_gain_db(
273           config.digitalCompressionGaindB) != 0) {
274     _shared->SetLastError(VE_APM_ERROR, kTraceError,
275                           "SetAgcConfig() failed to set the range in |gain| "
276                           "the digital compression stage may apply");
277     return -1;
278   }
279   if (_shared->audio_processing()->gain_control()->enable_limiter(
280           config.limiterEnable) != 0) {
281     _shared->SetLastError(
282         VE_APM_ERROR, kTraceError,
283         "SetAgcConfig() failed to set hard limiter to the signal");
284     return -1;
285   }
286 
287   return 0;
288 #else
289   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
290                         "SetAgcConfig() EC is not supported");
291   return -1;
292 #endif
293 }
294 
GetAgcConfig(AgcConfig & config)295 int VoEAudioProcessingImpl::GetAgcConfig(AgcConfig& config) {
296 #ifdef WEBRTC_VOICE_ENGINE_AGC
297   if (!_shared->statistics().Initialized()) {
298     _shared->SetLastError(VE_NOT_INITED, kTraceError);
299     return -1;
300   }
301 
302   config.targetLeveldBOv =
303       _shared->audio_processing()->gain_control()->target_level_dbfs();
304   config.digitalCompressionGaindB =
305       _shared->audio_processing()->gain_control()->compression_gain_db();
306   config.limiterEnable =
307       _shared->audio_processing()->gain_control()->is_limiter_enabled();
308 
309   return 0;
310 #else
311   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
312                         "GetAgcConfig() EC is not supported");
313   return -1;
314 #endif
315 }
316 
SetRxNsStatus(int channel,bool enable,NsModes mode)317 int VoEAudioProcessingImpl::SetRxNsStatus(int channel,
318                                           bool enable,
319                                           NsModes mode) {
320 #ifdef WEBRTC_VOICE_ENGINE_NR
321   if (!_shared->statistics().Initialized()) {
322     _shared->SetLastError(VE_NOT_INITED, kTraceError);
323     return -1;
324   }
325 
326   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
327   voe::Channel* channelPtr = ch.channel();
328   if (channelPtr == NULL) {
329     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
330                           "SetRxNsStatus() failed to locate channel");
331     return -1;
332   }
333   return channelPtr->SetRxNsStatus(enable, mode);
334 #else
335   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
336                         "SetRxNsStatus() NS is not supported");
337   return -1;
338 #endif
339 }
340 
GetRxNsStatus(int channel,bool & enabled,NsModes & mode)341 int VoEAudioProcessingImpl::GetRxNsStatus(int channel,
342                                           bool& enabled,
343                                           NsModes& mode) {
344 #ifdef WEBRTC_VOICE_ENGINE_NR
345   if (!_shared->statistics().Initialized()) {
346     _shared->SetLastError(VE_NOT_INITED, kTraceError);
347     return -1;
348   }
349 
350   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
351   voe::Channel* channelPtr = ch.channel();
352   if (channelPtr == NULL) {
353     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
354                           "GetRxNsStatus() failed to locate channel");
355     return -1;
356   }
357   return channelPtr->GetRxNsStatus(enabled, mode);
358 #else
359   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
360                         "GetRxNsStatus() NS is not supported");
361   return -1;
362 #endif
363 }
364 
SetRxAgcStatus(int channel,bool enable,AgcModes mode)365 int VoEAudioProcessingImpl::SetRxAgcStatus(int channel,
366                                            bool enable,
367                                            AgcModes mode) {
368   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
369                "SetRxAgcStatus(channel=%d, enable=%d, mode=%d)", channel,
370                (int)enable, (int)mode);
371 #ifdef WEBRTC_VOICE_ENGINE_AGC
372   if (!_shared->statistics().Initialized()) {
373     _shared->SetLastError(VE_NOT_INITED, kTraceError);
374     return -1;
375   }
376 
377   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
378   voe::Channel* channelPtr = ch.channel();
379   if (channelPtr == NULL) {
380     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
381                           "SetRxAgcStatus() failed to locate channel");
382     return -1;
383   }
384   return channelPtr->SetRxAgcStatus(enable, mode);
385 #else
386   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
387                         "SetRxAgcStatus() Agc is not supported");
388   return -1;
389 #endif
390 }
391 
GetRxAgcStatus(int channel,bool & enabled,AgcModes & mode)392 int VoEAudioProcessingImpl::GetRxAgcStatus(int channel,
393                                            bool& enabled,
394                                            AgcModes& mode) {
395 #ifdef WEBRTC_VOICE_ENGINE_AGC
396   if (!_shared->statistics().Initialized()) {
397     _shared->SetLastError(VE_NOT_INITED, kTraceError);
398     return -1;
399   }
400 
401   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
402   voe::Channel* channelPtr = ch.channel();
403   if (channelPtr == NULL) {
404     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
405                           "GetRxAgcStatus() failed to locate channel");
406     return -1;
407   }
408   return channelPtr->GetRxAgcStatus(enabled, mode);
409 #else
410   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
411                         "GetRxAgcStatus() Agc is not supported");
412   return -1;
413 #endif
414 }
415 
SetRxAgcConfig(int channel,AgcConfig config)416 int VoEAudioProcessingImpl::SetRxAgcConfig(int channel, AgcConfig config) {
417   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
418                "SetRxAgcConfig(channel=%d)", channel);
419 #ifdef WEBRTC_VOICE_ENGINE_AGC
420   if (!_shared->statistics().Initialized()) {
421     _shared->SetLastError(VE_NOT_INITED, kTraceError);
422     return -1;
423   }
424 
425   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
426   voe::Channel* channelPtr = ch.channel();
427   if (channelPtr == NULL) {
428     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
429                           "SetRxAgcConfig() failed to locate channel");
430     return -1;
431   }
432   return channelPtr->SetRxAgcConfig(config);
433 #else
434   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
435                         "SetRxAgcConfig() Agc is not supported");
436   return -1;
437 #endif
438 }
439 
GetRxAgcConfig(int channel,AgcConfig & config)440 int VoEAudioProcessingImpl::GetRxAgcConfig(int channel, AgcConfig& config) {
441 #ifdef WEBRTC_VOICE_ENGINE_AGC
442   if (!_shared->statistics().Initialized()) {
443     _shared->SetLastError(VE_NOT_INITED, kTraceError);
444     return -1;
445   }
446 
447   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
448   voe::Channel* channelPtr = ch.channel();
449   if (channelPtr == NULL) {
450     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
451                           "GetRxAgcConfig() failed to locate channel");
452     return -1;
453   }
454   return channelPtr->GetRxAgcConfig(config);
455 #else
456   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
457                         "GetRxAgcConfig() Agc is not supported");
458   return -1;
459 #endif
460 }
461 
DriftCompensationSupported()462 bool VoEAudioProcessing::DriftCompensationSupported() {
463 #if defined(WEBRTC_DRIFT_COMPENSATION_SUPPORTED)
464   return true;
465 #else
466   return false;
467 #endif
468 }
469 
EnableDriftCompensation(bool enable)470 int VoEAudioProcessingImpl::EnableDriftCompensation(bool enable) {
471   WEBRTC_VOICE_INIT_CHECK();
472 
473   if (!DriftCompensationSupported()) {
474     _shared->SetLastError(
475         VE_APM_ERROR, kTraceWarning,
476         "Drift compensation is not supported on this platform.");
477     return -1;
478   }
479 
480   EchoCancellation* aec = _shared->audio_processing()->echo_cancellation();
481   if (aec->enable_drift_compensation(enable) != 0) {
482     _shared->SetLastError(VE_APM_ERROR, kTraceError,
483                           "aec->enable_drift_compensation() failed");
484     return -1;
485   }
486   return 0;
487 }
488 
DriftCompensationEnabled()489 bool VoEAudioProcessingImpl::DriftCompensationEnabled() {
490   WEBRTC_VOICE_INIT_CHECK_BOOL();
491 
492   EchoCancellation* aec = _shared->audio_processing()->echo_cancellation();
493   return aec->is_drift_compensation_enabled();
494 }
495 
SetEcStatus(bool enable,EcModes mode)496 int VoEAudioProcessingImpl::SetEcStatus(bool enable, EcModes mode) {
497   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
498                "SetEcStatus(enable=%d, mode=%d)", enable, mode);
499 #ifdef WEBRTC_VOICE_ENGINE_ECHO
500   if (!_shared->statistics().Initialized()) {
501     _shared->SetLastError(VE_NOT_INITED, kTraceError);
502     return -1;
503   }
504 
505   // AEC mode
506   if ((mode == kEcDefault) || (mode == kEcConference) || (mode == kEcAec) ||
507       ((mode == kEcUnchanged) && (_isAecMode == true))) {
508     if (enable) {
509       // Disable the AECM before enable the AEC
510       if (_shared->audio_processing()->echo_control_mobile()->is_enabled()) {
511         _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
512                               "SetEcStatus() disable AECM before enabling AEC");
513         if (_shared->audio_processing()->echo_control_mobile()->Enable(false) !=
514             0) {
515           _shared->SetLastError(VE_APM_ERROR, kTraceError,
516                                 "SetEcStatus() failed to disable AECM");
517           return -1;
518         }
519       }
520     }
521     if (_shared->audio_processing()->echo_cancellation()->Enable(enable) != 0) {
522       _shared->SetLastError(VE_APM_ERROR, kTraceError,
523                             "SetEcStatus() failed to set AEC state");
524       return -1;
525     }
526     if (mode == kEcConference) {
527       if (_shared->audio_processing()
528               ->echo_cancellation()
529               ->set_suppression_level(EchoCancellation::kHighSuppression) !=
530           0) {
531         _shared->SetLastError(
532             VE_APM_ERROR, kTraceError,
533             "SetEcStatus() failed to set aggressiveness to high");
534         return -1;
535       }
536     } else {
537       if (_shared->audio_processing()
538               ->echo_cancellation()
539               ->set_suppression_level(EchoCancellation::kModerateSuppression) !=
540           0) {
541         _shared->SetLastError(
542             VE_APM_ERROR, kTraceError,
543             "SetEcStatus() failed to set aggressiveness to moderate");
544         return -1;
545       }
546     }
547 
548     _isAecMode = true;
549   } else if ((mode == kEcAecm) ||
550              ((mode == kEcUnchanged) && (_isAecMode == false))) {
551     if (enable) {
552       // Disable the AEC before enable the AECM
553       if (_shared->audio_processing()->echo_cancellation()->is_enabled()) {
554         _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
555                               "SetEcStatus() disable AEC before enabling AECM");
556         if (_shared->audio_processing()->echo_cancellation()->Enable(false) !=
557             0) {
558           _shared->SetLastError(VE_APM_ERROR, kTraceError,
559                                 "SetEcStatus() failed to disable AEC");
560           return -1;
561         }
562       }
563     }
564     if (_shared->audio_processing()->echo_control_mobile()->Enable(enable) !=
565         0) {
566       _shared->SetLastError(VE_APM_ERROR, kTraceError,
567                             "SetEcStatus() failed to set AECM state");
568       return -1;
569     }
570     _isAecMode = false;
571   } else {
572     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
573                           "SetEcStatus() invalid EC mode");
574     return -1;
575   }
576 
577   return 0;
578 #else
579   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
580                         "SetEcStatus() EC is not supported");
581   return -1;
582 #endif
583 }
584 
GetEcStatus(bool & enabled,EcModes & mode)585 int VoEAudioProcessingImpl::GetEcStatus(bool& enabled, EcModes& mode) {
586 #ifdef WEBRTC_VOICE_ENGINE_ECHO
587   if (!_shared->statistics().Initialized()) {
588     _shared->SetLastError(VE_NOT_INITED, kTraceError);
589     return -1;
590   }
591 
592   if (_isAecMode == true) {
593     mode = kEcAec;
594     enabled = _shared->audio_processing()->echo_cancellation()->is_enabled();
595   } else {
596     mode = kEcAecm;
597     enabled = _shared->audio_processing()->echo_control_mobile()->is_enabled();
598   }
599 
600   return 0;
601 #else
602   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
603                         "GetEcStatus() EC is not supported");
604   return -1;
605 #endif
606 }
607 
SetDelayOffsetMs(int offset)608 void VoEAudioProcessingImpl::SetDelayOffsetMs(int offset) {
609   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
610                "SetDelayOffsetMs(offset = %d)", offset);
611   _shared->audio_processing()->set_delay_offset_ms(offset);
612 }
613 
DelayOffsetMs()614 int VoEAudioProcessingImpl::DelayOffsetMs() {
615   return _shared->audio_processing()->delay_offset_ms();
616 }
617 
SetAecmMode(AecmModes mode,bool enableCNG)618 int VoEAudioProcessingImpl::SetAecmMode(AecmModes mode, bool enableCNG) {
619   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
620                "SetAECMMode(mode = %d)", mode);
621 #ifdef WEBRTC_VOICE_ENGINE_ECHO
622   if (!_shared->statistics().Initialized()) {
623     _shared->SetLastError(VE_NOT_INITED, kTraceError);
624     return -1;
625   }
626 
627   EchoControlMobile::RoutingMode aecmMode(
628       EchoControlMobile::kQuietEarpieceOrHeadset);
629 
630   switch (mode) {
631     case kAecmQuietEarpieceOrHeadset:
632       aecmMode = EchoControlMobile::kQuietEarpieceOrHeadset;
633       break;
634     case kAecmEarpiece:
635       aecmMode = EchoControlMobile::kEarpiece;
636       break;
637     case kAecmLoudEarpiece:
638       aecmMode = EchoControlMobile::kLoudEarpiece;
639       break;
640     case kAecmSpeakerphone:
641       aecmMode = EchoControlMobile::kSpeakerphone;
642       break;
643     case kAecmLoudSpeakerphone:
644       aecmMode = EchoControlMobile::kLoudSpeakerphone;
645       break;
646   }
647 
648   if (_shared->audio_processing()->echo_control_mobile()->set_routing_mode(
649           aecmMode) != 0) {
650     _shared->SetLastError(VE_APM_ERROR, kTraceError,
651                           "SetAECMMode() failed to set AECM routing mode");
652     return -1;
653   }
654   if (_shared->audio_processing()->echo_control_mobile()->enable_comfort_noise(
655           enableCNG) != 0) {
656     _shared->SetLastError(
657         VE_APM_ERROR, kTraceError,
658         "SetAECMMode() failed to set comfort noise state for AECM");
659     return -1;
660   }
661 
662   return 0;
663 #else
664   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
665                         "SetAECMMode() EC is not supported");
666   return -1;
667 #endif
668 }
669 
GetAecmMode(AecmModes & mode,bool & enabledCNG)670 int VoEAudioProcessingImpl::GetAecmMode(AecmModes& mode, bool& enabledCNG) {
671 #ifdef WEBRTC_VOICE_ENGINE_ECHO
672   if (!_shared->statistics().Initialized()) {
673     _shared->SetLastError(VE_NOT_INITED, kTraceError);
674     return -1;
675   }
676 
677   enabledCNG = false;
678 
679   EchoControlMobile::RoutingMode aecmMode =
680       _shared->audio_processing()->echo_control_mobile()->routing_mode();
681   enabledCNG = _shared->audio_processing()
682                    ->echo_control_mobile()
683                    ->is_comfort_noise_enabled();
684 
685   switch (aecmMode) {
686     case EchoControlMobile::kQuietEarpieceOrHeadset:
687       mode = kAecmQuietEarpieceOrHeadset;
688       break;
689     case EchoControlMobile::kEarpiece:
690       mode = kAecmEarpiece;
691       break;
692     case EchoControlMobile::kLoudEarpiece:
693       mode = kAecmLoudEarpiece;
694       break;
695     case EchoControlMobile::kSpeakerphone:
696       mode = kAecmSpeakerphone;
697       break;
698     case EchoControlMobile::kLoudSpeakerphone:
699       mode = kAecmLoudSpeakerphone;
700       break;
701   }
702 
703   return 0;
704 #else
705   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
706                         "GetAECMMode() EC is not supported");
707   return -1;
708 #endif
709 }
710 
EnableHighPassFilter(bool enable)711 int VoEAudioProcessingImpl::EnableHighPassFilter(bool enable) {
712   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
713                "EnableHighPassFilter(%d)", enable);
714   if (_shared->audio_processing()->high_pass_filter()->Enable(enable) !=
715       AudioProcessing::kNoError) {
716     _shared->SetLastError(VE_APM_ERROR, kTraceError,
717                           "HighPassFilter::Enable() failed.");
718     return -1;
719   }
720 
721   return 0;
722 }
723 
IsHighPassFilterEnabled()724 bool VoEAudioProcessingImpl::IsHighPassFilterEnabled() {
725   return _shared->audio_processing()->high_pass_filter()->is_enabled();
726 }
727 
RegisterRxVadObserver(int channel,VoERxVadCallback & observer)728 int VoEAudioProcessingImpl::RegisterRxVadObserver(int channel,
729                                                   VoERxVadCallback& observer) {
730   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
731                "RegisterRxVadObserver()");
732   if (!_shared->statistics().Initialized()) {
733     _shared->SetLastError(VE_NOT_INITED, kTraceError);
734     return -1;
735   }
736   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
737   voe::Channel* channelPtr = ch.channel();
738   if (channelPtr == NULL) {
739     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
740                           "RegisterRxVadObserver() failed to locate channel");
741     return -1;
742   }
743   return channelPtr->RegisterRxVadObserver(observer);
744 }
745 
DeRegisterRxVadObserver(int channel)746 int VoEAudioProcessingImpl::DeRegisterRxVadObserver(int channel) {
747   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
748                "DeRegisterRxVadObserver()");
749   if (!_shared->statistics().Initialized()) {
750     _shared->SetLastError(VE_NOT_INITED, kTraceError);
751     return -1;
752   }
753   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
754   voe::Channel* channelPtr = ch.channel();
755   if (channelPtr == NULL) {
756     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
757                           "DeRegisterRxVadObserver() failed to locate channel");
758     return -1;
759   }
760 
761   return channelPtr->DeRegisterRxVadObserver();
762 }
763 
VoiceActivityIndicator(int channel)764 int VoEAudioProcessingImpl::VoiceActivityIndicator(int channel) {
765   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
766                "VoiceActivityIndicator(channel=%d)", channel);
767   if (!_shared->statistics().Initialized()) {
768     _shared->SetLastError(VE_NOT_INITED, kTraceError);
769     return -1;
770   }
771 
772   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
773   voe::Channel* channelPtr = ch.channel();
774   if (channelPtr == NULL) {
775     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
776                           "DeRegisterRxVadObserver() failed to locate channel");
777     return -1;
778   }
779   int activity(-1);
780   channelPtr->VoiceActivityIndicator(activity);
781 
782   return activity;
783 }
784 
SetEcMetricsStatus(bool enable)785 int VoEAudioProcessingImpl::SetEcMetricsStatus(bool enable) {
786   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
787                "SetEcMetricsStatus(enable=%d)", enable);
788 #ifdef WEBRTC_VOICE_ENGINE_ECHO
789   if (!_shared->statistics().Initialized()) {
790     _shared->SetLastError(VE_NOT_INITED, kTraceError);
791     return -1;
792   }
793 
794   if ((_shared->audio_processing()->echo_cancellation()->enable_metrics(
795            enable) != 0) ||
796       (_shared->audio_processing()->echo_cancellation()->enable_delay_logging(
797            enable) != 0)) {
798     _shared->SetLastError(VE_APM_ERROR, kTraceError,
799                           "SetEcMetricsStatus() unable to set EC metrics mode");
800     return -1;
801   }
802   return 0;
803 #else
804   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
805                         "SetEcStatus() EC is not supported");
806   return -1;
807 #endif
808 }
809 
GetEcMetricsStatus(bool & enabled)810 int VoEAudioProcessingImpl::GetEcMetricsStatus(bool& enabled) {
811 #ifdef WEBRTC_VOICE_ENGINE_ECHO
812   if (!_shared->statistics().Initialized()) {
813     _shared->SetLastError(VE_NOT_INITED, kTraceError);
814     return -1;
815   }
816 
817   bool echo_mode =
818       _shared->audio_processing()->echo_cancellation()->are_metrics_enabled();
819   bool delay_mode = _shared->audio_processing()
820                         ->echo_cancellation()
821                         ->is_delay_logging_enabled();
822 
823   if (echo_mode != delay_mode) {
824     _shared->SetLastError(
825         VE_APM_ERROR, kTraceError,
826         "GetEcMetricsStatus() delay logging and echo mode are not the same");
827     return -1;
828   }
829 
830   enabled = echo_mode;
831 
832   return 0;
833 #else
834   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
835                         "SetEcStatus() EC is not supported");
836   return -1;
837 #endif
838 }
839 
GetEchoMetrics(int & ERL,int & ERLE,int & RERL,int & A_NLP)840 int VoEAudioProcessingImpl::GetEchoMetrics(int& ERL,
841                                            int& ERLE,
842                                            int& RERL,
843                                            int& A_NLP) {
844 #ifdef WEBRTC_VOICE_ENGINE_ECHO
845   if (!_shared->statistics().Initialized()) {
846     _shared->SetLastError(VE_NOT_INITED, kTraceError);
847     return -1;
848   }
849   if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) {
850     _shared->SetLastError(
851         VE_APM_ERROR, kTraceWarning,
852         "GetEchoMetrics() AudioProcessingModule AEC is not enabled");
853     return -1;
854   }
855 
856   // Get Echo Metrics from Audio Processing Module.
857   EchoCancellation::Metrics echoMetrics;
858   if (_shared->audio_processing()->echo_cancellation()->GetMetrics(
859           &echoMetrics)) {
860     WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
861                  "GetEchoMetrics(), AudioProcessingModule metrics error");
862     return -1;
863   }
864 
865   // Echo quality metrics.
866   ERL = echoMetrics.echo_return_loss.instant;
867   ERLE = echoMetrics.echo_return_loss_enhancement.instant;
868   RERL = echoMetrics.residual_echo_return_loss.instant;
869   A_NLP = echoMetrics.a_nlp.instant;
870 
871   return 0;
872 #else
873   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
874                         "SetEcStatus() EC is not supported");
875   return -1;
876 #endif
877 }
878 
GetEcDelayMetrics(int & delay_median,int & delay_std,float & fraction_poor_delays)879 int VoEAudioProcessingImpl::GetEcDelayMetrics(int& delay_median,
880                                               int& delay_std,
881                                               float& fraction_poor_delays) {
882 #ifdef WEBRTC_VOICE_ENGINE_ECHO
883   if (!_shared->statistics().Initialized()) {
884     _shared->SetLastError(VE_NOT_INITED, kTraceError);
885     return -1;
886   }
887   if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) {
888     _shared->SetLastError(
889         VE_APM_ERROR, kTraceWarning,
890         "GetEcDelayMetrics() AudioProcessingModule AEC is not enabled");
891     return -1;
892   }
893 
894   int median = 0;
895   int std = 0;
896   float poor_fraction = 0;
897   // Get delay-logging values from Audio Processing Module.
898   if (_shared->audio_processing()->echo_cancellation()->GetDelayMetrics(
899           &median, &std, &poor_fraction)) {
900     WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
901                  "GetEcDelayMetrics(), AudioProcessingModule delay-logging "
902                  "error");
903     return -1;
904   }
905 
906   // EC delay-logging metrics
907   delay_median = median;
908   delay_std = std;
909   fraction_poor_delays = poor_fraction;
910 
911   return 0;
912 #else
913   _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
914                         "SetEcStatus() EC is not supported");
915   return -1;
916 #endif
917 }
918 
StartDebugRecording(const char * fileNameUTF8)919 int VoEAudioProcessingImpl::StartDebugRecording(const char* fileNameUTF8) {
920   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
921                "StartDebugRecording()");
922   if (!_shared->statistics().Initialized()) {
923     _shared->SetLastError(VE_NOT_INITED, kTraceError);
924     return -1;
925   }
926 
927   return _shared->audio_processing()->StartDebugRecording(fileNameUTF8);
928 }
929 
StartDebugRecording(FILE * file_handle)930 int VoEAudioProcessingImpl::StartDebugRecording(FILE* file_handle) {
931   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
932                "StartDebugRecording()");
933   if (!_shared->statistics().Initialized()) {
934     _shared->SetLastError(VE_NOT_INITED, kTraceError);
935     return -1;
936   }
937 
938   return _shared->audio_processing()->StartDebugRecording(file_handle);
939 }
940 
StopDebugRecording()941 int VoEAudioProcessingImpl::StopDebugRecording() {
942   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
943                "StopDebugRecording()");
944   if (!_shared->statistics().Initialized()) {
945     _shared->SetLastError(VE_NOT_INITED, kTraceError);
946     return -1;
947   }
948 
949   return _shared->audio_processing()->StopDebugRecording();
950 }
951 
SetTypingDetectionStatus(bool enable)952 int VoEAudioProcessingImpl::SetTypingDetectionStatus(bool enable) {
953   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
954                "SetTypingDetectionStatus()");
955 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
956   NOT_SUPPORTED(_shared->statistics());
957 #else
958   if (!_shared->statistics().Initialized()) {
959     _shared->SetLastError(VE_NOT_INITED, kTraceError);
960     return -1;
961   }
962 
963   // Just use the VAD state to determine if we should enable typing detection
964   // or not
965 
966   if (_shared->audio_processing()->voice_detection()->Enable(enable)) {
967     _shared->SetLastError(VE_APM_ERROR, kTraceWarning,
968                           "SetTypingDetectionStatus() failed to set VAD state");
969     return -1;
970   }
971   if (_shared->audio_processing()->voice_detection()->set_likelihood(
972           VoiceDetection::kVeryLowLikelihood)) {
973     _shared->SetLastError(
974         VE_APM_ERROR, kTraceWarning,
975         "SetTypingDetectionStatus() failed to set VAD likelihood to low");
976     return -1;
977   }
978 
979   return 0;
980 #endif
981 }
982 
GetTypingDetectionStatus(bool & enabled)983 int VoEAudioProcessingImpl::GetTypingDetectionStatus(bool& enabled) {
984   if (!_shared->statistics().Initialized()) {
985     _shared->SetLastError(VE_NOT_INITED, kTraceError);
986     return -1;
987   }
988   // Just use the VAD state to determine if we should enable typing
989   // detection or not
990 
991   enabled = _shared->audio_processing()->voice_detection()->is_enabled();
992 
993   return 0;
994 }
995 
TimeSinceLastTyping(int & seconds)996 int VoEAudioProcessingImpl::TimeSinceLastTyping(int& seconds) {
997 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
998   NOT_SUPPORTED(_shared->statistics());
999 #else
1000   if (!_shared->statistics().Initialized()) {
1001     _shared->SetLastError(VE_NOT_INITED, kTraceError);
1002     return -1;
1003   }
1004   // Check if typing detection is enabled
1005   bool enabled = _shared->audio_processing()->voice_detection()->is_enabled();
1006   if (enabled) {
1007     _shared->transmit_mixer()->TimeSinceLastTyping(seconds);
1008     return 0;
1009   } else {
1010     _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
1011                           "SetTypingDetectionStatus is not enabled");
1012     return -1;
1013   }
1014 #endif
1015 }
1016 
SetTypingDetectionParameters(int timeWindow,int costPerTyping,int reportingThreshold,int penaltyDecay,int typeEventDelay)1017 int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow,
1018                                                          int costPerTyping,
1019                                                          int reportingThreshold,
1020                                                          int penaltyDecay,
1021                                                          int typeEventDelay) {
1022   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
1023                "SetTypingDetectionParameters()");
1024 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
1025   NOT_SUPPORTED(_shared->statistics());
1026 #else
1027   if (!_shared->statistics().Initialized()) {
1028     _shared->statistics().SetLastError(VE_NOT_INITED, kTraceError);
1029     return -1;
1030   }
1031   return (_shared->transmit_mixer()->SetTypingDetectionParameters(
1032       timeWindow, costPerTyping, reportingThreshold, penaltyDecay,
1033       typeEventDelay));
1034 #endif
1035 }
1036 
EnableStereoChannelSwapping(bool enable)1037 void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) {
1038   _shared->transmit_mixer()->EnableStereoChannelSwapping(enable);
1039 }
1040 
IsStereoChannelSwappingEnabled()1041 bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() {
1042   return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled();
1043 }
1044 
1045 #endif  // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API
1046 
1047 }  // namespace webrtc
1048