summaryrefslogtreecommitdiffstats
path: root/media/libeffects/proxy/EffectProxy.cpp
blob: 62d3fd3da716a2f90813fcb2bf0878cc2fb5e7f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "EffectProxy"
//#define LOG_NDEBUG 0

#include <cutils/log.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include <EffectProxy.h>
#include <utils/threads.h>
#include <media/EffectsFactoryApi.h>

namespace android {
// This is a dummy proxy descriptor just to return to Factory during the initial
// GetDescriptor call. Later in the factory, it is replaced with the
// SW sub effect descriptor
// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b
const effect_descriptor_t gProxyDescriptor = {
        EFFECT_UUID_INITIALIZER, // type
        {0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid
        EFFECT_CONTROL_API_VERSION, //version of effect control API
        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST |
         EFFECT_FLAG_VOLUME_CTRL), // effect capability flags
        0, // CPU load
        1, // Data memory
        "Proxy", //effect name
        "AOSP", //implementor name
};


static const effect_descriptor_t *const gDescriptors[] =
{
    &gProxyDescriptor,
};


int EffectProxyCreate(const effect_uuid_t *uuid,
                            int32_t             sessionId,
                            int32_t             ioId,
                           effect_handle_t  *pHandle) {

    effect_descriptor_t* desc;
    audio_effect_library_t** aeli;
    sub_effect_entry_t** sube;
    EffectContext* pContext;
    if (pHandle == NULL || uuid == NULL) {
        ALOGE("EffectProxyCreate() called with NULL pointer");
        return -EINVAL;
    }
    ALOGV("EffectProxyCreate start..");
    pContext = new EffectContext;
    pContext->sessionId = sessionId;
    pContext->ioId = ioId;
    pContext->uuid = *uuid;
    pContext->common_itfe = &gEffectInterface;

    // The sub effects will be created in effect_command when the first command
    // for the effect is received
    pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL;

    // Get the HW and SW sub effect descriptors from the effects factory
    desc = new effect_descriptor_t[SUB_FX_COUNT];
    aeli = new audio_effect_library_t*[SUB_FX_COUNT];
    sube = new sub_effect_entry_t*[SUB_FX_COUNT];
    pContext->sube = new sub_effect_entry_t*[SUB_FX_COUNT];
    pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
    pContext->aeli = new audio_effect_library_t*[SUB_FX_COUNT];
    int retValue = EffectGetSubEffects(uuid, sube, SUB_FX_COUNT);
    // EffectGetSubEffects returns the number of sub-effects copied.
    if (retValue != SUB_FX_COUNT) {
       ALOGE("EffectCreate() could not get the sub effects");
       delete[] sube;
       delete[] desc;
       delete[] aeli;
       delete[] pContext->sube;
       delete[] pContext->desc;
       delete[] pContext->aeli;
       return -EINVAL;
    }
    // Check which is the HW descriptor and copy the descriptors
    // to the Context desc array
    // Also check if there is only one HW and one SW descriptor.
    // HW descriptor alone has the HW_TUNNEL flag.
    desc[0] = *(effect_descriptor_t*)(sube[0])->object;
    desc[1] = *(effect_descriptor_t*)(sube[1])->object;
    aeli[0] = sube[0]->lib->desc;
    aeli[1] = sube[1]->lib->desc;
    if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
       !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
        pContext->sube[SUB_FX_OFFLOAD] = sube[0];
        pContext->desc[SUB_FX_OFFLOAD] = desc[0];
        pContext->aeli[SUB_FX_OFFLOAD] = aeli[0];
        pContext->sube[SUB_FX_HOST] = sube[1];
        pContext->desc[SUB_FX_HOST] = desc[1];
        pContext->aeli[SUB_FX_HOST] = aeli[1];
    }
    else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
             !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
        pContext->sube[SUB_FX_HOST] = sube[0];
        pContext->desc[SUB_FX_HOST] = desc[0];
        pContext->aeli[SUB_FX_HOST] = aeli[0];
        pContext->sube[SUB_FX_OFFLOAD] = sube[1];
        pContext->desc[SUB_FX_OFFLOAD] = desc[1];
        pContext->aeli[SUB_FX_OFFLOAD] = aeli[1];
    }
    delete[] desc;
    delete[] aeli;
    delete[] sube;
#if (LOG_NDEBUG == 0)
    effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
    ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
        "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid,
        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
        uuid_print.node[4], uuid_print.node[5]);
    ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
        "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid,
        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
        uuid_print.node[4], uuid_print.node[5]);
#endif

    pContext->replySize = PROXY_REPLY_SIZE_DEFAULT;
    pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT);

    *pHandle = (effect_handle_t)pContext;
    ALOGV("EffectCreate end");
    return 0;
} //end EffectProxyCreate

int EffectProxyRelease(effect_handle_t handle) {
    EffectContext * pContext = (EffectContext *)handle;
    if (pContext == NULL) {
        ALOGV("ERROR : EffectRelease called with NULL pointer");
        return -EINVAL;
    }
    ALOGV("EffectRelease");
    delete[] pContext->desc;
    free(pContext->replyData);

    if (pContext->eHandle[SUB_FX_HOST])
       pContext->aeli[SUB_FX_HOST]->release_effect(pContext->eHandle[SUB_FX_HOST]);
    if (pContext->eHandle[SUB_FX_OFFLOAD])
       pContext->aeli[SUB_FX_OFFLOAD]->release_effect(pContext->eHandle[SUB_FX_OFFLOAD]);
    delete[] pContext->aeli;
    delete[] pContext->sube;
    delete pContext;
    pContext = NULL;
    return 0;
} /*end EffectProxyRelease */

int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
                                   effect_descriptor_t *pDescriptor) {
    const effect_descriptor_t *desc = NULL;

    if (pDescriptor == NULL || uuid == NULL) {
        ALOGV("EffectGetDescriptor() called with NULL pointer");
        return -EINVAL;
    }
    desc = &gProxyDescriptor;
    *pDescriptor = *desc;
    return 0;
} /* end EffectProxyGetDescriptor */

/* Effect Control Interface Implementation: Process */
int Effect_process(effect_handle_t     self,
                              audio_buffer_t         *inBuffer,
                              audio_buffer_t         *outBuffer) {

    EffectContext *pContext = (EffectContext *) self;
    int ret = 0;
    if (pContext != NULL) {
        int index = pContext->index;
        // if the index refers to HW , do not do anything. Just return.
        if (index == SUB_FX_HOST) {
            ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
                                                       inBuffer, outBuffer);
        }
    }
    return ret;
}   /* end Effect_process */

/* Effect Control Interface Implementation: Command */
int Effect_command(effect_handle_t  self,
                              uint32_t            cmdCode,
                              uint32_t            cmdSize,
                              void                *pCmdData,
                              uint32_t            *replySize,
                              void                *pReplyData) {

    EffectContext *pContext = (EffectContext *) self;
    int status = 0;
    if (pContext == NULL) {
        ALOGV("Effect_command() Proxy context is NULL");
        return -EINVAL;
    }
    if (pContext->eHandle[SUB_FX_HOST] == NULL) {
        ALOGV("Effect_command() Calling HOST EffectCreate");
        status = pContext->aeli[SUB_FX_HOST]->create_effect(
                              &pContext->desc[SUB_FX_HOST].uuid,
                              pContext->sessionId, pContext->ioId,
                              &(pContext->eHandle[SUB_FX_HOST]));
        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
            ALOGV("Effect_command() Error creating SW sub effect");
            return status;
        }
    }
    if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
        ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
        status = pContext->aeli[SUB_FX_OFFLOAD]->create_effect(
                              &pContext->desc[SUB_FX_OFFLOAD].uuid,
                              pContext->sessionId, pContext->ioId,
                              &(pContext->eHandle[SUB_FX_OFFLOAD]));
        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
            ALOGV("Effect_command() Error creating HW effect");
            pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
            // Do not return error here as SW effect is created
            // Return error if the CMD_OFFLOAD sends the index as OFFLOAD
        }
        pContext->index = SUB_FX_HOST;
    }
    // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not
    // (2) Send the ioHandle of the effectThread when the effect
    // is moved from one type of thread to another.
    // pCmdData points to a memory holding effect_offload_param_t structure
    if (cmdCode == EFFECT_CMD_OFFLOAD) {
        ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD");
        if (cmdSize == 0 || pCmdData == NULL) {
            ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data");
             *(int*)pReplyData = FAILED_TRANSACTION;
            return FAILED_TRANSACTION;
        }
        effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData;
        // Assign the effect context index based on isOffload field of the structure
        pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST;
        // if the index is HW and the HW effect is unavailable, return error
        // and reset the index to SW
        if (pContext->eHandle[pContext->index] == NULL) {
            ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable");
            *(int*)pReplyData = FAILED_TRANSACTION;
            return FAILED_TRANSACTION;
        }
        pContext->ioId = offloadParam->ioHandle;
        ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId);
        // Update the DSP wrapper with the new ioHandle.
        // Pass the OFFLOAD command to the wrapper.
        // The DSP wrapper needs to handle this CMD
        if (pContext->eHandle[SUB_FX_OFFLOAD]) {
            ALOGV("Effect_command: Calling OFFLOAD command");
            return (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
                           pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
                           pCmdData, replySize, pReplyData);
        }
        *(int*)pReplyData = NO_ERROR;
        ALOGV("Effect_command OFFLOAD return 0, replyData %d",
                                                *(int*)pReplyData);

        return NO_ERROR;
    }

    int index = pContext->index;
    if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) {
        ALOGV("Effect_command: effect index is neither offload nor host");
        return -EINVAL;
    }

    // Getter commands are only sent to the active sub effect.
    int *subStatus[SUB_FX_COUNT];
    uint32_t *subReplySize[SUB_FX_COUNT];
    void *subReplyData[SUB_FX_COUNT];
    uint32_t tmpSize;
    int tmpStatus;

    // grow temp reply buffer if needed
    if (replySize != NULL) {
        tmpSize = pContext->replySize;
        while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) {
            tmpSize *= 2;
        }
        if (tmpSize > pContext->replySize) {
            ALOGV("Effect_command grow reply buf to %d", tmpSize);
            pContext->replyData = (char *)realloc(pContext->replyData, tmpSize);
            pContext->replySize = tmpSize;
        }
        if (tmpSize > *replySize) {
            tmpSize = *replySize;
        }
    } else {
        tmpSize = 0;
    }
    // tmpSize is now the actual reply size for the non active sub effect

    // Send command to sub effects. The command is sent to all sub effects so that their internal
    // state is kept in sync.
    // Only the reply from the active sub effect is returned to the caller. The reply from the
    // other sub effect is lost in pContext->replyData
    for (int i = 0; i < SUB_FX_COUNT; i++) {
        if (pContext->eHandle[i] == NULL) {
            continue;
        }
        if (i == index) {
            subStatus[i] = &status;
            subReplySize[i] = replySize;
            subReplyData[i] = pReplyData;
        } else {
            subStatus[i] = &tmpStatus;
            subReplySize[i] = replySize == NULL ? NULL : &tmpSize;
            subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData;
        }
        *subStatus[i] = (*pContext->eHandle[i])->command(
                             pContext->eHandle[i], cmdCode, cmdSize,
                             pCmdData, subReplySize[i], subReplyData[i]);
    }

    return status;
}    /* end Effect_command */


/* Effect Control Interface Implementation: get_descriptor */
int Effect_getDescriptor(effect_handle_t   self,
                         effect_descriptor_t *pDescriptor) {

    EffectContext * pContext = (EffectContext *) self;
    const effect_descriptor_t *desc;

    ALOGV("Effect_getDescriptor");
    if (pContext == NULL || pDescriptor == NULL) {
        ALOGV("Effect_getDescriptor() invalid param");
        return -EINVAL;
    }
    if (pContext->desc == NULL) {
        ALOGV("Effect_getDescriptor() could not get descriptor");
        return -EINVAL;
    }
    desc = &pContext->desc[SUB_FX_HOST];
    *pDescriptor = *desc;
    pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID
    // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability
    if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL)
        pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
    else
        pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED;
    return 0;
} /* end Effect_getDescriptor */

} // namespace android

__attribute__ ((visibility ("default")))
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
    .tag = AUDIO_EFFECT_LIBRARY_TAG,
    .version = EFFECT_LIBRARY_API_VERSION,
    .name = "Effect Proxy",
    .implementor = "AOSP",
    .create_effect = android::EffectProxyCreate,
    .release_effect = android::EffectProxyRelease,
    .get_descriptor = android::EffectProxyGetDescriptor,
};