EffectProxy.cpp revision 9803acb6b2c1b9c01444e0c8c0124adbe9a7157a
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
33// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b
34const effect_descriptor_t gProxyDescriptor = {
35        EFFECT_UUID_INITIALIZER, // type
36        {0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid
37        EFFECT_CONTROL_API_VERSION, //version of effect control API
38        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST |
39         EFFECT_FLAG_VOLUME_CTRL), // effect capability flags
40        0, // CPU load
41        1, // Data memory
42        "Proxy", //effect name
43        "AOSP", //implementor name
44};
45
46
47static const effect_descriptor_t *const gDescriptors[] =
48{
49    &gProxyDescriptor,
50};
51
52
53int EffectProxyCreate(const effect_uuid_t *uuid,
54                            int32_t             sessionId,
55                            int32_t             ioId,
56                           effect_handle_t  *pHandle) {
57
58    effect_descriptor_t* desc;
59    EffectContext* pContext;
60    if (pHandle == NULL || uuid == NULL) {
61        ALOGE("EffectProxyCreate() called with NULL pointer");
62        return -EINVAL;
63    }
64    ALOGV("EffectProxyCreate start..");
65    pContext = new EffectContext;
66    pContext->sessionId = sessionId;
67    pContext->ioId = ioId;
68    pContext->uuid = *uuid;
69    pContext->common_itfe = &gEffectInterface;
70
71    // The sub effects will be created in effect_command when the first command
72    // for the effect is received
73    pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
74
75    // Get the HW and SW sub effect descriptors from the effects factory
76    desc = new effect_descriptor_t[SUB_FX_COUNT];
77    pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
78    int retValue = EffectGetSubEffects(uuid, desc,
79                                sizeof(effect_descriptor_t) * SUB_FX_COUNT);
80    // EffectGetSubEffects returns the number of sub-effects copied.
81    if (retValue != SUB_FX_COUNT) {
82       ALOGE("EffectCreate() could not get the sub effects");
83       delete desc;
84       delete pContext->desc;
85       return -EINVAL;
86    }
87    // Check which is the HW descriptor and copy the descriptors
88    // to the Context desc array
89    // Also check if there is only one HW and one SW descriptor.
90    // HW descriptor alone has the HW_TUNNEL flag.
91    if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
92       !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
93        pContext->desc[SUB_FX_OFFLOAD] = desc[0];
94        pContext->desc[SUB_FX_HOST] = desc[1];
95    }
96    else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
97             !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
98        pContext->desc[SUB_FX_HOST] = desc[0];
99        pContext->desc[SUB_FX_OFFLOAD] = desc[1];
100    }
101    delete desc;
102#if (LOG_NDEBUG == 0)
103    effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
104    ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
105        "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid,
106        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
107        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
108        uuid_print.node[4], uuid_print.node[5]);
109    ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
110        "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid,
111        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
112        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
113        uuid_print.node[4], uuid_print.node[5]);
114#endif
115
116    pContext->replySize = PROXY_REPLY_SIZE_DEFAULT;
117    pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT);
118
119    *pHandle = (effect_handle_t)pContext;
120    ALOGV("EffectCreate end");
121    return 0;
122} //end EffectProxyCreate
123
124int EffectProxyRelease(effect_handle_t handle) {
125    EffectContext * pContext = (EffectContext *)handle;
126    if (pContext == NULL) {
127        ALOGV("ERROR : EffectRelease called with NULL pointer");
128        return -EINVAL;
129    }
130    ALOGV("EffectRelease");
131    delete pContext->desc;
132    free(pContext->replyData);
133
134    if (pContext->eHandle[SUB_FX_HOST])
135       EffectRelease(pContext->eHandle[SUB_FX_HOST]);
136    if (pContext->eHandle[SUB_FX_OFFLOAD])
137       EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]);
138    delete pContext;
139    pContext = NULL;
140    return 0;
141} /*end EffectProxyRelease */
142
143int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
144                                   effect_descriptor_t *pDescriptor) {
145    const effect_descriptor_t *desc = NULL;
146
147    if (pDescriptor == NULL || uuid == NULL) {
148        ALOGV("EffectGetDescriptor() called with NULL pointer");
149        return -EINVAL;
150    }
151    desc = &gProxyDescriptor;
152    *pDescriptor = *desc;
153    return 0;
154} /* end EffectProxyGetDescriptor */
155
156/* Effect Control Interface Implementation: Process */
157int Effect_process(effect_handle_t     self,
158                              audio_buffer_t         *inBuffer,
159                              audio_buffer_t         *outBuffer) {
160
161    EffectContext *pContext = (EffectContext *) self;
162    int ret = 0;
163    if (pContext != NULL) {
164        int index = pContext->index;
165        // if the index refers to HW , do not do anything. Just return.
166        if (index == SUB_FX_HOST) {
167            ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
168                                                       inBuffer, outBuffer);
169        }
170    }
171    return ret;
172}   /* end Effect_process */
173
174/* Effect Control Interface Implementation: Command */
175int Effect_command(effect_handle_t  self,
176                              uint32_t            cmdCode,
177                              uint32_t            cmdSize,
178                              void                *pCmdData,
179                              uint32_t            *replySize,
180                              void                *pReplyData) {
181
182    EffectContext *pContext = (EffectContext *) self;
183    int status = 0;
184    if (pContext == NULL) {
185        ALOGV("Effect_command() Proxy context is NULL");
186        return -EINVAL;
187    }
188    if (pContext->eHandle[SUB_FX_HOST] == NULL) {
189        ALOGV("Effect_command() Calling HOST EffectCreate");
190        status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid,
191                              pContext->sessionId, pContext->ioId,
192                              &(pContext->eHandle[SUB_FX_HOST]));
193        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
194            ALOGV("Effect_command() Error creating SW sub effect");
195            return status;
196        }
197    }
198    if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
199        ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
200        status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid,
201                              pContext->sessionId, pContext->ioId,
202                              &(pContext->eHandle[SUB_FX_OFFLOAD]));
203        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
204            ALOGV("Effect_command() Error creating HW effect");
205            // Do not return error here as SW effect is created
206            // Return error if the CMD_OFFLOAD sends the index as OFFLOAD
207        }
208        pContext->index = SUB_FX_HOST;
209    }
210    // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not
211    // (2) Send the ioHandle of the effectThread when the effect
212    // is moved from one type of thread to another.
213    // pCmdData points to a memory holding effect_offload_param_t structure
214    if (cmdCode == EFFECT_CMD_OFFLOAD) {
215        ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD");
216        if (cmdSize == 0 || pCmdData == NULL) {
217            ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data");
218             *(int*)pReplyData = FAILED_TRANSACTION;
219            return FAILED_TRANSACTION;
220        }
221        effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData;
222        // Assign the effect context index based on isOffload field of the structure
223        pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST;
224        // if the index is HW and the HW effect is unavailable, return error
225        // and reset the index to SW
226        if (pContext->eHandle[pContext->index] == NULL) {
227            ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable");
228            *(int*)pReplyData = FAILED_TRANSACTION;
229            return FAILED_TRANSACTION;
230        }
231        pContext->ioId = offloadParam->ioHandle;
232        ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId);
233        // Update the DSP wrapper with the new ioHandle.
234        // Pass the OFFLOAD command to the wrapper.
235        // The DSP wrapper needs to handle this CMD
236        if (pContext->eHandle[SUB_FX_OFFLOAD])
237            status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
238                             pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
239                             pCmdData, replySize, pReplyData);
240        return status;
241    }
242
243    int index = pContext->index;
244    if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) {
245        ALOGV("Effect_command: effect index is neither offload nor host");
246        return -EINVAL;
247    }
248
249    // Getter commands are only sent to the active sub effect.
250    int *subStatus[SUB_FX_COUNT];
251    uint32_t *subReplySize[SUB_FX_COUNT];
252    void *subReplyData[SUB_FX_COUNT];
253    uint32_t tmpSize;
254    int tmpStatus;
255
256    // grow temp reply buffer if needed
257    if (replySize != NULL) {
258        tmpSize = pContext->replySize;
259        while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) {
260            tmpSize *= 2;
261        }
262        if (tmpSize > pContext->replySize) {
263            ALOGV("Effect_command grow reply buf to %d", tmpSize);
264            pContext->replyData = (char *)realloc(pContext->replyData, tmpSize);
265            pContext->replySize = tmpSize;
266        }
267        if (tmpSize > *replySize) {
268            tmpSize = *replySize;
269        }
270    } else {
271        tmpSize = 0;
272    }
273    // tmpSize is now the actual reply size for the non active sub effect
274
275    // Send command to sub effects. The command is sent to all sub effects so that their internal
276    // state is kept in sync.
277    // Only the reply from the active sub effect is returned to the caller. The reply from the
278    // other sub effect is lost in pContext->replyData
279    for (int i = 0; i < SUB_FX_COUNT; i++) {
280        if (pContext->eHandle[i] == NULL) {
281            continue;
282        }
283        if (i == index) {
284            subStatus[i] = &status;
285            subReplySize[i] = replySize;
286            subReplyData[i] = pReplyData;
287        } else {
288            subStatus[i] = &tmpStatus;
289            subReplySize[i] = replySize == NULL ? NULL : &tmpSize;
290            subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData;
291        }
292        *subStatus[i] = (*pContext->eHandle[i])->command(
293                             pContext->eHandle[i], cmdCode, cmdSize,
294                             pCmdData, subReplySize[i], subReplyData[i]);
295    }
296
297    return status;
298}    /* end Effect_command */
299
300
301/* Effect Control Interface Implementation: get_descriptor */
302int Effect_getDescriptor(effect_handle_t   self,
303                         effect_descriptor_t *pDescriptor) {
304
305    EffectContext * pContext = (EffectContext *) self;
306    const effect_descriptor_t *desc;
307
308    ALOGV("Effect_getDescriptor");
309    if (pContext == NULL || pDescriptor == NULL) {
310        ALOGV("Effect_getDescriptor() invalid param");
311        return -EINVAL;
312    }
313    if (pContext->desc == NULL) {
314        ALOGV("Effect_getDescriptor() could not get descriptor");
315        return -EINVAL;
316    }
317    desc = &pContext->desc[SUB_FX_HOST];
318    *pDescriptor = *desc;
319    pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID
320    // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability
321    if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL)
322        pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
323    else
324        pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED;
325    return 0;
326} /* end Effect_getDescriptor */
327
328} // namespace android
329
330__attribute__ ((visibility ("default")))
331audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
332    .tag = AUDIO_EFFECT_LIBRARY_TAG,
333    .version = EFFECT_LIBRARY_API_VERSION,
334    .name = "Effect Proxy",
335    .implementor = "AOSP",
336    .create_effect = android::EffectProxyCreate,
337    .release_effect = android::EffectProxyRelease,
338    .get_descriptor = android::EffectProxyGetDescriptor,
339};
340