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/* Automatic Gain Control implementation */
18#include "sles_allinclusive.h"
19
20#include <media/EffectsFactoryApi.h>
21
22#include <audio_effects/effect_agc.h>
23
24/**
25 * returns true if this interface is not associated with an initialized AGC effect
26 */
27static inline bool NO_AUTOGAIN(IAndroidAutomaticGainControl* v) {
28    return (v->mAGCEffect == 0);
29}
30
31SLresult IAndroidAutomaticGainControl_SetEnabled(SLAndroidAutomaticGainControlItf self, SLboolean enabled)
32{
33    SL_ENTER_INTERFACE
34
35    IAndroidAutomaticGainControl *thiz = (IAndroidAutomaticGainControl *) self;
36    interface_lock_exclusive(thiz);
37    thiz->mEnabled = (SLboolean) enabled;
38    if (NO_AUTOGAIN(thiz)) {
39        result = SL_RESULT_CONTROL_LOST;
40    } else {
41        android::status_t status = thiz->mAGCEffect->setEnabled((bool) thiz->mEnabled);
42        result = android_fx_statusToResult(status);
43    }
44    interface_unlock_exclusive(thiz);
45
46    SL_LEAVE_INTERFACE
47}
48
49SLresult IAndroidAutomaticGainControl_IsEnabled(SLAndroidAutomaticGainControlItf self, SLboolean *pEnabled)
50{
51    SL_ENTER_INTERFACE
52
53    if (NULL == pEnabled) {
54        result = SL_RESULT_PARAMETER_INVALID;
55    } else {
56        IAndroidAutomaticGainControl *thiz = (IAndroidAutomaticGainControl *) self;
57        interface_lock_exclusive(thiz);
58        SLboolean enabled = thiz->mEnabled;
59        if (NO_AUTOGAIN(thiz)) {
60            result = SL_RESULT_CONTROL_LOST;
61        } else {
62            *pEnabled = (SLboolean) thiz->mAGCEffect->getEnabled();
63            result = SL_RESULT_SUCCESS;
64        }
65        interface_unlock_exclusive(thiz);
66    }
67    SL_LEAVE_INTERFACE
68}
69
70SLresult IAndroidAutomaticGainControl_IsAvailable(SLAndroidAutomaticGainControlItf self,
71                                                  SLboolean *pEnabled)
72{
73    SL_ENTER_INTERFACE
74
75   *pEnabled = false;
76
77    uint32_t numEffects = 0;
78    int ret = EffectQueryNumberEffects(&numEffects);
79    if (ret != 0) {
80        ALOGE("IAndroidAutomaticGainControl_IsAvailable() error %d querying number of effects",
81              ret);
82        result = SL_RESULT_FEATURE_UNSUPPORTED;
83   } else {
84        ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
85
86        effect_descriptor_t fxDesc;
87        for (uint32_t i = 0 ; i < numEffects ; i++) {
88            if (EffectQueryEffect(i, &fxDesc) == 0) {
89                ALOGV("effect %d is called %s", i, fxDesc.name);
90                if (memcmp(&fxDesc.type, SL_IID_ANDROIDAUTOMATICGAINCONTROL,
91                           sizeof(effect_uuid_t)) == 0) {
92                    ALOGI("found effect \"%s\" from %s", fxDesc.name, fxDesc.implementor);
93                    *pEnabled = true;
94                    break;
95                }
96            }
97        }
98        result = SL_RESULT_SUCCESS;
99    }
100    SL_LEAVE_INTERFACE
101}
102
103static const struct SLAndroidAutomaticGainControlItf_ IAndroidAutomaticGainControl_Itf = {
104    IAndroidAutomaticGainControl_SetEnabled,
105    IAndroidAutomaticGainControl_IsEnabled,
106    IAndroidAutomaticGainControl_IsAvailable
107};
108
109void IAndroidAutomaticGainControl_init(void *self)
110{
111    IAndroidAutomaticGainControl *thiz = (IAndroidAutomaticGainControl *) self;
112    thiz->mItf = &IAndroidAutomaticGainControl_Itf;
113    thiz->mEnabled = SL_BOOLEAN_FALSE;
114    memset(&thiz->mAGCDescriptor, 0, sizeof(effect_descriptor_t));
115    // placement new (explicit constructor)
116    (void) new (&thiz->mAGCEffect) android::sp<android::AudioEffect>();
117}
118
119void IAndroidAutomaticGainControl_deinit(void *self)
120{
121    IAndroidAutomaticGainControl *thiz = (IAndroidAutomaticGainControl *) self;
122    // explicit destructor
123    thiz->mAGCEffect.~sp();
124}
125
126bool IAndroidAutomaticGainControl_Expose(void *self)
127{
128    IAndroidAutomaticGainControl *thiz = (IAndroidAutomaticGainControl *) self;
129    if (!android_fx_initEffectDescriptor(SL_IID_ANDROIDAUTOMATICGAINCONTROL,
130                                         &thiz->mAGCDescriptor)) {
131        SL_LOGE("Automatic Gain Control initialization failed.");
132        return false;
133    }
134    return true;
135}
136