AudioEffect.cpp revision a7326b42c42f5014e8dabf18d69a8376b2f3f67d
1/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "AudioEffect"
21
22#include <stdint.h>
23#include <sys/types.h>
24#include <limits.h>
25
26#include <private/media/AudioEffectShared.h>
27#include <media/AudioEffect.h>
28
29#include <utils/Log.h>
30#include <binder/IPCThreadState.h>
31
32
33
34namespace android {
35
36// ---------------------------------------------------------------------------
37
38AudioEffect::AudioEffect()
39    : mStatus(NO_INIT)
40{
41}
42
43
44AudioEffect::AudioEffect(const effect_uuid_t *type,
45                const effect_uuid_t *uuid,
46                int32_t priority,
47                effect_callback_t cbf,
48                void* user,
49                int sessionId,
50                audio_io_handle_t io
51                )
52    : mStatus(NO_INIT)
53{
54    mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
55}
56
57AudioEffect::AudioEffect(const char *typeStr,
58                const char *uuidStr,
59                int32_t priority,
60                effect_callback_t cbf,
61                void* user,
62                int sessionId,
63                audio_io_handle_t io
64                )
65    : mStatus(NO_INIT)
66{
67    effect_uuid_t type;
68    effect_uuid_t *pType = NULL;
69    effect_uuid_t uuid;
70    effect_uuid_t *pUuid = NULL;
71
72    ALOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr);
73
74    if (typeStr != NULL) {
75        if (stringToGuid(typeStr, &type) == NO_ERROR) {
76            pType = &type;
77        }
78    }
79
80    if (uuidStr != NULL) {
81        if (stringToGuid(uuidStr, &uuid) == NO_ERROR) {
82            pUuid = &uuid;
83        }
84    }
85
86    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
87}
88
89status_t AudioEffect::set(const effect_uuid_t *type,
90                const effect_uuid_t *uuid,
91                int32_t priority,
92                effect_callback_t cbf,
93                void* user,
94                int sessionId,
95                audio_io_handle_t io)
96{
97    sp<IEffect> iEffect;
98    sp<IMemory> cblk;
99    int enabled;
100
101    ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
102
103    if (mIEffect != 0) {
104        ALOGW("Effect already in use");
105        return INVALID_OPERATION;
106    }
107
108    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
109    if (audioFlinger == 0) {
110        ALOGE("set(): Could not get audioflinger");
111        return NO_INIT;
112    }
113
114    if (type == NULL && uuid == NULL) {
115        ALOGW("Must specify at least type or uuid");
116        return BAD_VALUE;
117    }
118
119    mPriority = priority;
120    mCbf = cbf;
121    mUserData = user;
122    mSessionId = sessionId;
123
124    memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
125    mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
126    mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
127
128    mIEffectClient = new EffectClient(this);
129
130    iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
131            mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
132
133    if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
134        ALOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
135        return mStatus;
136    }
137
138    mEnabled = (volatile int32_t)enabled;
139
140    mIEffect = iEffect;
141    cblk = iEffect->getCblk();
142    if (cblk == 0) {
143        mStatus = NO_INIT;
144        ALOGE("Could not get control block");
145        return mStatus;
146    }
147
148    mCblkMemory = cblk;
149    mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());
150    int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
151    mCblk->buffer = (uint8_t *)mCblk + bufOffset;
152
153    iEffect->asBinder()->linkToDeath(mIEffectClient);
154    mClientPid = IPCThreadState::self()->getCallingPid();
155    ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
156            mStatus, mEnabled, mClientPid);
157
158    if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
159        AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
160    }
161
162    return mStatus;
163}
164
165
166AudioEffect::~AudioEffect()
167{
168    ALOGV("Destructor %p", this);
169
170    if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
171        if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
172            AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
173        }
174        if (mIEffect != NULL) {
175            mIEffect->disconnect();
176            mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
177        }
178        IPCThreadState::self()->flushCommands();
179    }
180    mIEffect.clear();
181    mIEffectClient.clear();
182    mCblkMemory.clear();
183}
184
185
186status_t AudioEffect::initCheck() const
187{
188    return mStatus;
189}
190
191// -------------------------------------------------------------------------
192
193effect_descriptor_t AudioEffect::descriptor() const
194{
195    return mDescriptor;
196}
197
198bool AudioEffect::getEnabled() const
199{
200    return (mEnabled != 0);
201}
202
203status_t AudioEffect::setEnabled(bool enabled)
204{
205    if (mStatus != NO_ERROR) {
206        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
207    }
208
209    status_t status = NO_ERROR;
210
211    AutoMutex lock(mLock);
212    if (enabled != mEnabled) {
213        if (enabled) {
214            ALOGV("enable %p", this);
215            status = mIEffect->enable();
216        } else {
217            ALOGV("disable %p", this);
218            status = mIEffect->disable();
219        }
220        if (status == NO_ERROR) {
221            mEnabled = enabled;
222        }
223    }
224    return status;
225}
226
227status_t AudioEffect::command(uint32_t cmdCode,
228                              uint32_t cmdSize,
229                              void *cmdData,
230                              uint32_t *replySize,
231                              void *replyData)
232{
233    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
234        ALOGV("command() bad status %d", mStatus);
235        return mStatus;
236    }
237
238    if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
239        if (mEnabled == (cmdCode == EFFECT_CMD_ENABLE)) {
240            return NO_ERROR;
241        }
242        if (replySize == NULL || *replySize != sizeof(status_t) || replyData == NULL) {
243            return BAD_VALUE;
244        }
245        mLock.lock();
246    }
247
248    status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
249
250    if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
251        if (status == NO_ERROR) {
252            status = *(status_t *)replyData;
253        }
254        if (status == NO_ERROR) {
255            mEnabled = (cmdCode == EFFECT_CMD_ENABLE);
256        }
257        mLock.unlock();
258    }
259
260    return status;
261}
262
263
264status_t AudioEffect::setParameter(effect_param_t *param)
265{
266    if (mStatus != NO_ERROR) {
267        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
268    }
269
270    if (param == NULL || param->psize == 0 || param->vsize == 0) {
271        return BAD_VALUE;
272    }
273
274    uint32_t size = sizeof(int);
275    uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
276
277    ALOGV("setParameter: param: %d, param2: %d", *(int *)param->data,
278            (param->psize == 8) ? *((int *)param->data + 1): -1);
279
280    return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size,
281            &param->status);
282}
283
284status_t AudioEffect::setParameterDeferred(effect_param_t *param)
285{
286    if (mStatus != NO_ERROR) {
287        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
288    }
289
290    if (param == NULL || param->psize == 0 || param->vsize == 0) {
291        return BAD_VALUE;
292    }
293
294    Mutex::Autolock _l(mCblk->lock);
295
296    int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
297    int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int);
298
299    if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) {
300        return NO_MEMORY;
301    }
302    int *p = (int *)(mCblk->buffer + mCblk->clientIndex);
303    *p++ = size;
304    memcpy(p, param, sizeof(effect_param_t) + psize);
305    mCblk->clientIndex += size;
306
307    return NO_ERROR;
308}
309
310status_t AudioEffect::setParameterCommit()
311{
312    if (mStatus != NO_ERROR) {
313        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
314    }
315
316    Mutex::Autolock _l(mCblk->lock);
317    if (mCblk->clientIndex == 0) {
318        return INVALID_OPERATION;
319    }
320    uint32_t size = 0;
321    return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL);
322}
323
324status_t AudioEffect::getParameter(effect_param_t *param)
325{
326    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
327        return mStatus;
328    }
329
330    if (param == NULL || param->psize == 0 || param->vsize == 0) {
331        return BAD_VALUE;
332    }
333
334    ALOGV("getParameter: param: %d, param2: %d", *(int *)param->data,
335            (param->psize == 8) ? *((int *)param->data + 1): -1);
336
337    uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
338            param->vsize;
339
340    return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param,
341            &psize, param);
342}
343
344
345// -------------------------------------------------------------------------
346
347void AudioEffect::binderDied()
348{
349    ALOGW("IEffect died");
350    mStatus = DEAD_OBJECT;
351    if (mCbf != NULL) {
352        status_t status = DEAD_OBJECT;
353        mCbf(EVENT_ERROR, mUserData, &status);
354    }
355    mIEffect.clear();
356}
357
358// -------------------------------------------------------------------------
359
360void AudioEffect::controlStatusChanged(bool controlGranted)
361{
362    ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf,
363            mUserData);
364    if (controlGranted) {
365        if (mStatus == ALREADY_EXISTS) {
366            mStatus = NO_ERROR;
367        }
368    } else {
369        if (mStatus == NO_ERROR) {
370            mStatus = ALREADY_EXISTS;
371        }
372    }
373    if (mCbf != NULL) {
374        mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
375    }
376}
377
378void AudioEffect::enableStatusChanged(bool enabled)
379{
380    ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
381    if (mStatus == ALREADY_EXISTS) {
382        mEnabled = enabled;
383        if (mCbf != NULL) {
384            mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
385        }
386    }
387}
388
389void AudioEffect::commandExecuted(uint32_t cmdCode,
390                                  uint32_t cmdSize __unused,
391                                  void *cmdData,
392                                  uint32_t replySize __unused,
393                                  void *replyData)
394{
395    if (cmdData == NULL || replyData == NULL) {
396        return;
397    }
398
399    if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) {
400        effect_param_t *cmd = (effect_param_t *)cmdData;
401        cmd->status = *(int32_t *)replyData;
402        mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
403    }
404}
405
406// -------------------------------------------------------------------------
407
408status_t AudioEffect::queryNumberEffects(uint32_t *numEffects)
409{
410    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
411    if (af == 0) return PERMISSION_DENIED;
412    return af->queryNumberEffects(numEffects);
413}
414
415status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
416{
417    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
418    if (af == 0) return PERMISSION_DENIED;
419    return af->queryEffect(index, descriptor);
420}
421
422status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
423        effect_descriptor_t *descriptor) /*const*/
424{
425    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
426    if (af == 0) return PERMISSION_DENIED;
427    return af->getEffectDescriptor(uuid, descriptor);
428}
429
430
431status_t AudioEffect::queryDefaultPreProcessing(int audioSession,
432                                          effect_descriptor_t *descriptors,
433                                          uint32_t *count)
434{
435    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
436    if (aps == 0) return PERMISSION_DENIED;
437    return aps->queryDefaultPreProcessing(audioSession, descriptors, count);
438}
439// -------------------------------------------------------------------------
440
441status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
442{
443    if (str == NULL || guid == NULL) {
444        return BAD_VALUE;
445    }
446
447    int tmp[10];
448
449    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
450            tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
451        return BAD_VALUE;
452    }
453    guid->timeLow = (uint32_t)tmp[0];
454    guid->timeMid = (uint16_t)tmp[1];
455    guid->timeHiAndVersion = (uint16_t)tmp[2];
456    guid->clockSeq = (uint16_t)tmp[3];
457    guid->node[0] = (uint8_t)tmp[4];
458    guid->node[1] = (uint8_t)tmp[5];
459    guid->node[2] = (uint8_t)tmp[6];
460    guid->node[3] = (uint8_t)tmp[7];
461    guid->node[4] = (uint8_t)tmp[8];
462    guid->node[5] = (uint8_t)tmp[9];
463
464    return NO_ERROR;
465}
466
467status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen)
468{
469    if (guid == NULL || str == NULL) {
470        return BAD_VALUE;
471    }
472
473    snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
474            guid->timeLow,
475            guid->timeMid,
476            guid->timeHiAndVersion,
477            guid->clockSeq,
478            guid->node[0],
479            guid->node[1],
480            guid->node[2],
481            guid->node[3],
482            guid->node[4],
483            guid->node[5]);
484
485    return NO_ERROR;
486}
487
488
489}; // namespace android
490