1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* Acoustic Echo Cancellation implementation */
18 #include "sles_allinclusive.h"
19 
20 #include <media/EffectsFactoryApi.h>
21 
22 #include <audio_effects/effect_aec.h>
23 
24 /**
25  * returns true if this interface is not associated with an initialized AEC effect
26  */
NO_ECHOCANCEL(IAndroidAcousticEchoCancellation * v)27 static inline bool NO_ECHOCANCEL(IAndroidAcousticEchoCancellation* v) {
28     return (v->mAECEffect == 0);
29 }
30 
IAndroidAcousticEchoCancellation_SetEnabled(SLAndroidAcousticEchoCancellationItf self,SLboolean enabled)31 static SLresult IAndroidAcousticEchoCancellation_SetEnabled(SLAndroidAcousticEchoCancellationItf self,
32                                                      SLboolean enabled)
33 {
34     SL_ENTER_INTERFACE
35 
36     IAndroidAcousticEchoCancellation *thiz = (IAndroidAcousticEchoCancellation *) self;
37     interface_lock_exclusive(thiz);
38     thiz->mEnabled = (SLboolean) enabled;
39     if (NO_ECHOCANCEL(thiz)) {
40         result = SL_RESULT_CONTROL_LOST;
41     } else {
42         android::status_t status = thiz->mAECEffect->setEnabled((bool) thiz->mEnabled);
43         result = android_fx_statusToResult(status);
44     }
45     interface_unlock_exclusive(thiz);
46 
47     SL_LEAVE_INTERFACE
48 }
49 
IAndroidAcousticEchoCancellation_IsEnabled(SLAndroidAcousticEchoCancellationItf self,SLboolean * pEnabled)50 static SLresult IAndroidAcousticEchoCancellation_IsEnabled(SLAndroidAcousticEchoCancellationItf self,
51                                                     SLboolean *pEnabled)
52 {
53     SL_ENTER_INTERFACE
54 
55     if (NULL == pEnabled) {
56         result = SL_RESULT_PARAMETER_INVALID;
57     } else {
58         IAndroidAcousticEchoCancellation *thiz = (IAndroidAcousticEchoCancellation *) self;
59         interface_lock_exclusive(thiz);
60         SLboolean enabled = thiz->mEnabled;
61         if (NO_ECHOCANCEL(thiz)) {
62             result = SL_RESULT_CONTROL_LOST;
63         } else {
64             *pEnabled = (SLboolean) thiz->mAECEffect->getEnabled();
65             result = SL_RESULT_SUCCESS;
66         }
67         interface_unlock_exclusive(thiz);
68     }
69 
70     SL_LEAVE_INTERFACE
71 }
72 
IAndroidAcousticEchoCancellation_IsAvailable(SLAndroidAcousticEchoCancellationItf self,SLboolean * pEnabled)73 SLresult IAndroidAcousticEchoCancellation_IsAvailable(SLAndroidAcousticEchoCancellationItf self,
74                                                       SLboolean *pEnabled)
75 {
76     SL_ENTER_INTERFACE
77 
78     *pEnabled = false;
79 
80     uint32_t numEffects = 0;
81     int ret = EffectQueryNumberEffects(&numEffects);
82     if (ret != 0) {
83         ALOGE("IAndroidAcousticEchoCancellation_IsAvailable() error %d querying number of effects",
84               ret);
85         result = SL_RESULT_FEATURE_UNSUPPORTED;
86    } else {
87         ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
88 
89         effect_descriptor_t fxDesc;
90         for (uint32_t i = 0 ; i < numEffects ; i++) {
91             if (EffectQueryEffect(i, &fxDesc) == 0) {
92                 ALOGV("effect %d is called %s", i, fxDesc.name);
93                 if (memcmp(&fxDesc.type, SL_IID_ANDROIDACOUSTICECHOCANCELLATION,
94                            sizeof(effect_uuid_t)) == 0) {
95                     ALOGI("found effect \"%s\" from %s", fxDesc.name, fxDesc.implementor);
96                     *pEnabled = true;
97                     break;
98                 }
99             }
100         }
101         result = SL_RESULT_SUCCESS;
102     }
103     SL_LEAVE_INTERFACE
104 }
105 
106 static const struct SLAndroidAcousticEchoCancellationItf_ IAndroidAcousticEchoCancellation_Itf = {
107     IAndroidAcousticEchoCancellation_SetEnabled,
108     IAndroidAcousticEchoCancellation_IsEnabled,
109     IAndroidAcousticEchoCancellation_IsAvailable
110 };
111 
IAndroidAcousticEchoCancellation_init(void * self)112 void IAndroidAcousticEchoCancellation_init(void *self)
113 {
114     IAndroidAcousticEchoCancellation *thiz = (IAndroidAcousticEchoCancellation *) self;
115     thiz->mItf = &IAndroidAcousticEchoCancellation_Itf;
116     thiz->mEnabled = SL_BOOLEAN_FALSE;
117     memset(&thiz->mAECDescriptor, 0, sizeof(effect_descriptor_t));
118     // placement new (explicit constructor)
119     (void) new (&thiz->mAECEffect) android::sp<android::AudioEffect>();
120 }
121 
IAndroidAcousticEchoCancellation_deinit(void * self)122 void IAndroidAcousticEchoCancellation_deinit(void *self)
123 {
124     IAndroidAcousticEchoCancellation *thiz = (IAndroidAcousticEchoCancellation *) self;
125     // explicit destructor
126     thiz->mAECEffect.~sp();
127 }
128 
IAndroidAcousticEchoCancellation_Expose(void * self)129 bool IAndroidAcousticEchoCancellation_Expose(void *self)
130 {
131     IAndroidAcousticEchoCancellation *thiz = (IAndroidAcousticEchoCancellation *) self;
132     if (!android_fx_initEffectDescriptor(SL_IID_ANDROIDACOUSTICECHOCANCELLATION,
133                                          &thiz->mAECDescriptor)) {
134         SL_LOGE("Acoustic Echo Cancellation initialization failed.");
135         return false;
136     }
137     return true;
138 }
139