EffectProxy.cpp revision 60c60df7db278d2fa5c90b0fa14f99a61d50272b
1/*
2 * Copyright (C) 2013 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#define LOG_TAG "EffectProxy"
18//#define LOG_NDEBUG 0
19
20#include <cutils/log.h>
21#include <assert.h>
22#include <stdlib.h>
23#include <string.h>
24#include <new>
25#include <EffectProxy.h>
26#include <utils/threads.h>
27#include <media/EffectsFactoryApi.h>
28
29namespace android {
30// This is a dummy proxy descriptor just to return to Factory during the initial
31// GetDescriptor call. Later in the factory, it is replaced with the
32// SW sub effect descriptor
33const effect_descriptor_t gProxyDescriptor = {
34        EFFECT_UUID_INITIALIZER, // type
35        EFFECT_UUID_INITIALIZER, // uuid
36        EFFECT_CONTROL_API_VERSION, //version of effect control API
37        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST |
38         EFFECT_FLAG_VOLUME_CTRL), // effect capability flags
39        0, // CPU load
40        1, // Data memory
41        "Proxy", //effect name
42        "AOSP", //implementor name
43};
44
45
46static const effect_descriptor_t *const gDescriptors[] =
47{
48    &gProxyDescriptor,
49};
50
51int EffectProxyCreate(const effect_uuid_t *uuid,
52                            int32_t             sessionId,
53                            int32_t             ioId,
54                           effect_handle_t  *pHandle) {
55
56    effect_descriptor_t* desc;
57    EffectContext* pContext;
58    if (pHandle == NULL || uuid == NULL) {
59        ALOGE("EffectProxyCreate() called with NULL pointer");
60        return -EINVAL;
61    }
62    ALOGV("EffectProxyCreate start..");
63    pContext = new EffectContext;
64    pContext->sessionId = sessionId;
65    pContext->ioId = ioId;
66    pContext->uuid = *uuid;
67    pContext->common_itfe = &gEffectInterface;
68    // The sub effects will be created in effect_command when the first command
69    // for the effect is received
70    pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
71
72    // Get the HW and SW sub effect descriptors from the effects factory
73    desc = new effect_descriptor_t[SUB_FX_COUNT];
74    pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
75    int retValue = EffectGetSubEffects(uuid, desc,
76                                sizeof(effect_descriptor_t) * SUB_FX_COUNT);
77    // EffectGetSubEffects returns the number of sub-effects copied.
78    if (retValue != SUB_FX_COUNT) {
79       ALOGE("EffectCreate() could not get the sub effects");
80       delete desc;
81       delete pContext->desc;
82       return -EINVAL;
83    }
84    // Check which is the HW descriptor and copy the descriptors
85    // to the Context desc array
86    // Also check if there is only one HW and one SW descriptor.
87    // HW descriptor alone has the HW_TUNNEL flag.
88    if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
89       !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
90        pContext->desc[SUB_FX_OFFLOAD] = desc[0];
91        pContext->desc[SUB_FX_HOST] = desc[1];
92    }
93    else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
94             !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
95        pContext->desc[SUB_FX_HOST] = desc[0];
96        pContext->desc[SUB_FX_OFFLOAD] = desc[1];
97    }
98    delete desc;
99#if (LOG_NDEBUG == 0)
100    effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
101    ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
102        "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid,
103        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
104        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
105        uuid_print.node[4], uuid_print.node[5]);
106    ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
107        "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid,
108        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
109        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
110        uuid_print.node[4], uuid_print.node[5]);
111#endif
112    *pHandle = (effect_handle_t)pContext;
113    ALOGV("EffectCreate end");
114    return 0;
115} //end EffectProxyCreate
116
117int EffectProxyRelease(effect_handle_t handle) {
118    EffectContext * pContext = (EffectContext *)handle;
119    if (pContext == NULL) {
120        ALOGV("ERROR : EffectRelease called with NULL pointer");
121        return -EINVAL;
122    }
123    ALOGV("EffectRelease");
124    delete pContext->desc;
125    if (pContext->eHandle[SUB_FX_HOST])
126       EffectRelease(pContext->eHandle[SUB_FX_HOST]);
127    if (pContext->eHandle[SUB_FX_OFFLOAD])
128       EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]);
129    delete pContext;
130    pContext = NULL;
131    return 0;
132} /*end EffectProxyRelease */
133
134int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
135                                   effect_descriptor_t *pDescriptor) {
136    const effect_descriptor_t *desc = NULL;
137
138    if (pDescriptor == NULL || uuid == NULL) {
139        ALOGV("EffectGetDescriptor() called with NULL pointer");
140        return -EINVAL;
141    }
142    desc = &gProxyDescriptor;
143    *pDescriptor = *desc;
144    return 0;
145} /* end EffectProxyGetDescriptor */
146
147/* Effect Control Interface Implementation: Process */
148int Effect_process(effect_handle_t     self,
149                              audio_buffer_t         *inBuffer,
150                              audio_buffer_t         *outBuffer) {
151
152    EffectContext *pContext = (EffectContext *) self;
153    int ret = 0;
154    if (pContext != NULL) {
155        int index = pContext->index;
156        // if the index refers to HW , do not do anything. Just return.
157        if (index == SUB_FX_HOST) {
158            ALOGV("Calling CoreProcess");
159            ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
160                                                       inBuffer, outBuffer);
161        }
162    }
163    return ret;
164}   /* end Effect_process */
165
166/* Effect Control Interface Implementation: Command */
167int Effect_command(effect_handle_t  self,
168                              uint32_t            cmdCode,
169                              uint32_t            cmdSize,
170                              void                *pCmdData,
171                              uint32_t            *replySize,
172                              void                *pReplyData) {
173
174    EffectContext *pContext = (EffectContext *) self;
175    int status;
176    if (pContext == NULL) {
177        ALOGV("Effect_command() Proxy context is NULL");
178        return -EINVAL;
179    }
180    if (pContext->eHandle[SUB_FX_HOST] == NULL) {
181        ALOGV("Effect_command() Calling HOST EffectCreate");
182        status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid,
183                              pContext->sessionId, pContext->ioId,
184                              &(pContext->eHandle[SUB_FX_HOST]));
185        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
186            ALOGV("Effect_command() Error creating SW sub effect");
187            return status;
188        }
189    }
190    if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
191        ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
192        status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid,
193                              pContext->sessionId, pContext->ioId,
194                              &(pContext->eHandle[SUB_FX_OFFLOAD]));
195        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
196            ALOGV("Effect_command() Error creating HW effect");
197            // Do not return error here as SW effect is created
198            // Return error if the CMD_OFFLOAD sends the index as OFFLOAD
199        }
200        pContext->index = SUB_FX_HOST;
201    }
202    // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not
203    // (2) Send the ioHandle of the effectThread when the effect
204    // is moved from one type of thread to another.
205    // pCmdData points to a memory holding effect_offload_param_t structure
206    if (cmdCode == EFFECT_CMD_OFFLOAD) {
207        ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD");
208        if (cmdSize == 0 || pCmdData == NULL) {
209            ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data");
210             *(int*)pReplyData = FAILED_TRANSACTION;
211            return FAILED_TRANSACTION;
212        }
213        effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData;
214        // Assign the effect context index based on isOffload field of the structure
215        pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST;
216        // if the index is HW and the HW effect is unavailable, return error
217        // and reset the index to SW
218        if (pContext->eHandle[pContext->index] == NULL) {
219            ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable");
220            *(int*)pReplyData = FAILED_TRANSACTION;
221            return FAILED_TRANSACTION;
222        }
223        pContext->ioId = offloadParam->ioHandle;
224        ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId);
225        // Update the DSP wrapper with the new ioHandle.
226        // Pass the OFFLOAD command to the wrapper.
227        // The DSP wrapper needs to handle this CMD
228        if (pContext->eHandle[SUB_FX_OFFLOAD])
229            status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
230                             pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
231                             pCmdData, replySize, pReplyData);
232        return status;
233    }
234
235    int index = pContext->index;
236    if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) {
237        ALOGV("Effect_command: effect index is neither offload nor host");
238        return -EINVAL;
239    }
240    ALOGV("Effect_command: pContext->eHandle[%d]: %p",
241            index, pContext->eHandle[index]);
242    if (pContext->eHandle[SUB_FX_HOST])
243         (*pContext->eHandle[SUB_FX_HOST])->command(
244                             pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize,
245                             pCmdData, replySize, pReplyData);
246    if (pContext->eHandle[SUB_FX_OFFLOAD]) {
247        // In case of SET CMD, when the offload stream is unavailable,
248        // we will store the effect param values in the DSP effect wrapper.
249        // When the offload effects get enabled, we send these values to the
250        // DSP during Effect_config.
251        // So,we send the params to DSP wrapper also
252        (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
253                         pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
254                         pCmdData, replySize, pReplyData);
255    }
256    return 0;
257}    /* end Effect_command */
258
259
260/* Effect Control Interface Implementation: get_descriptor */
261int Effect_getDescriptor(effect_handle_t   self,
262                         effect_descriptor_t *pDescriptor) {
263
264    EffectContext * pContext = (EffectContext *) self;
265    const effect_descriptor_t *desc;
266
267    ALOGV("Effect_getDescriptor");
268    if (pContext == NULL || pDescriptor == NULL) {
269        ALOGV("Effect_getDescriptor() invalid param");
270        return -EINVAL;
271    }
272    if (pContext->desc == NULL) {
273        ALOGV("Effect_getDescriptor() could not get descriptor");
274        return -EINVAL;
275    }
276    desc = &pContext->desc[SUB_FX_HOST];
277    *pDescriptor = *desc;
278    pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID
279    // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability
280    if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL)
281        pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
282    else
283        pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED;
284    return 0;
285} /* end Effect_getDescriptor */
286
287} // namespace android
288
289__attribute__ ((visibility ("default")))
290audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
291    tag : AUDIO_EFFECT_LIBRARY_TAG,
292    version : EFFECT_LIBRARY_API_VERSION,
293    name : "Effect Proxy",
294    implementor : "AOSP",
295    create_effect : android::EffectProxyCreate,
296    release_effect : android::EffectProxyRelease,
297    get_descriptor : android::EffectProxyGetDescriptor,
298};
299