|  | /* | 
|  | ** | 
|  | ** Copyright 2010, 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_NDEBUG 0 | 
|  | #define LOG_TAG "AudioEffect" | 
|  |  | 
|  | #include <stdint.h> | 
|  | #include <sys/types.h> | 
|  | #include <limits.h> | 
|  |  | 
|  | #include <android/media/IAudioPolicyService.h> | 
|  | #include <binder/IPCThreadState.h> | 
|  | #include <media/AidlConversion.h> | 
|  | #include <media/AudioEffect.h> | 
|  | #include <media/PolicyAidlConversion.h> | 
|  | #include <media/ShmemCompat.h> | 
|  | #include <private/media/AudioEffectShared.h> | 
|  | #include <utils/Log.h> | 
|  |  | 
|  | #define RETURN_STATUS_IF_ERROR(x)    \ | 
|  | {                                \ | 
|  | auto _tmp = (x);             \ | 
|  | if (_tmp != OK) return _tmp; \ | 
|  | } | 
|  |  | 
|  | namespace android { | 
|  | using aidl_utils::statusTFromBinderStatus; | 
|  | using binder::Status; | 
|  | using media::IAudioPolicyService; | 
|  | using media::permission::Identity; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Copy from a raw pointer + size into a vector of bytes. | 
|  | void appendToBuffer(const void* data, | 
|  | size_t size, | 
|  | std::vector<uint8_t>* buffer) { | 
|  | const uint8_t* p = reinterpret_cast<const uint8_t*>(data); | 
|  | buffer->insert(buffer->end(), p, p + size); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | AudioEffect::AudioEffect(const Identity& identity) | 
|  | : mClientIdentity(identity) | 
|  | { | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::set(const effect_uuid_t *type, | 
|  | const effect_uuid_t *uuid, | 
|  | int32_t priority, | 
|  | effect_callback_t cbf, | 
|  | void* user, | 
|  | audio_session_t sessionId, | 
|  | audio_io_handle_t io, | 
|  | const AudioDeviceTypeAddr& device, | 
|  | bool probe) | 
|  | { | 
|  | sp<media::IEffect> iEffect; | 
|  | sp<IMemory> cblk; | 
|  | int enabled; | 
|  |  | 
|  | ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0); | 
|  |  | 
|  | if (mIEffect != 0) { | 
|  | ALOGW("Effect already in use"); | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  |  | 
|  | if (sessionId == AUDIO_SESSION_DEVICE && io != AUDIO_IO_HANDLE_NONE) { | 
|  | ALOGW("IO handle should not be specified for device effect"); | 
|  | return BAD_VALUE; | 
|  | } | 
|  | const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); | 
|  | if (audioFlinger == 0) { | 
|  | ALOGE("set(): Could not get audioflinger"); | 
|  | return NO_INIT; | 
|  | } | 
|  |  | 
|  | if (type == NULL && uuid == NULL) { | 
|  | ALOGW("Must specify at least type or uuid"); | 
|  | return BAD_VALUE; | 
|  | } | 
|  | mProbe = probe; | 
|  | mPriority = priority; | 
|  | mCbf = cbf; | 
|  | mUserData = user; | 
|  | mSessionId = sessionId; | 
|  |  | 
|  | memset(&mDescriptor, 0, sizeof(effect_descriptor_t)); | 
|  | mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL); | 
|  | mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL); | 
|  |  | 
|  | // TODO b/182392769: use identity util | 
|  | mIEffectClient = new EffectClient(this); | 
|  | pid_t pid = IPCThreadState::self()->getCallingPid(); | 
|  | mClientIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid)); | 
|  | pid_t uid = IPCThreadState::self()->getCallingUid(); | 
|  | mClientIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid)); | 
|  |  | 
|  | media::CreateEffectRequest request; | 
|  | request.desc = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_effect_descriptor_t_EffectDescriptor(mDescriptor)); | 
|  | request.client = mIEffectClient; | 
|  | request.priority = priority; | 
|  | request.output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(io)); | 
|  | request.sessionId = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(mSessionId)); | 
|  | request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioDeviceTypeAddress(device)); | 
|  | request.identity = mClientIdentity; | 
|  | request.probe = probe; | 
|  |  | 
|  | media::CreateEffectResponse response; | 
|  |  | 
|  | mStatus = audioFlinger->createEffect(request, &response); | 
|  |  | 
|  | if (mStatus == OK) { | 
|  | mId = response.id; | 
|  | enabled = response.enabled; | 
|  | iEffect = response.effect; | 
|  | mDescriptor = VALUE_OR_RETURN_STATUS( | 
|  | aidl2legacy_EffectDescriptor_effect_descriptor_t(response.desc)); | 
|  | } | 
|  |  | 
|  | // In probe mode, we stop here and return the status: the IEffect interface to | 
|  | // audio flinger will not be retained. initCheck() will return the creation status | 
|  | // but all other APIs will return invalid operation. | 
|  | if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { | 
|  | char typeBuffer[64] = {}, uuidBuffer[64] = {}; | 
|  | guidToString(type, typeBuffer, sizeof(typeBuffer)); | 
|  | guidToString(uuid, uuidBuffer, sizeof(uuidBuffer)); | 
|  | ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d", | 
|  | type != nullptr ? typeBuffer : "NULL", | 
|  | uuid != nullptr ? uuidBuffer : "NULL", | 
|  | mStatus); | 
|  | if (!probe && iEffect == 0) { | 
|  | mStatus = NO_INIT; | 
|  | } | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | mEnabled = (volatile int32_t)enabled; | 
|  |  | 
|  | if (media::SharedFileRegion shmem; | 
|  | !iEffect->getCblk(&shmem).isOk() | 
|  | || !convertSharedFileRegionToIMemory(shmem, &cblk) | 
|  | || cblk == 0) { | 
|  | mStatus = NO_INIT; | 
|  | ALOGE("Could not get control block"); | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | mIEffect = iEffect; | 
|  | mCblkMemory = cblk; | 
|  | // TODO: Using unsecurePointer() has some associated security pitfalls | 
|  | //       (see declaration for details). | 
|  | //       Either document why it is safe in this case or address the | 
|  | //       issue (e.g. by copying). | 
|  | mCblk = static_cast<effect_param_cblk_t*>(cblk->unsecurePointer()); | 
|  | int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); | 
|  | mCblk->buffer = (uint8_t *)mCblk + bufOffset; | 
|  |  | 
|  | IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient); | 
|  | ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId, | 
|  | mStatus, mEnabled, mClientIdentity.pid); | 
|  |  | 
|  | if (!audio_is_global_session(mSessionId)) { | 
|  | AudioSystem::acquireAudioSessionId(mSessionId, pid, uid); | 
|  | } | 
|  |  | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::set(const char *typeStr, | 
|  | const char *uuidStr, | 
|  | int32_t priority, | 
|  | effect_callback_t cbf, | 
|  | void* user, | 
|  | audio_session_t sessionId, | 
|  | audio_io_handle_t io, | 
|  | const AudioDeviceTypeAddr& device, | 
|  | bool probe) | 
|  | { | 
|  | effect_uuid_t type; | 
|  | effect_uuid_t *pType = nullptr; | 
|  | effect_uuid_t uuid; | 
|  | effect_uuid_t *pUuid = nullptr; | 
|  |  | 
|  | ALOGV("AudioEffect::set string\n - type: %s\n - uuid: %s", | 
|  | typeStr ? typeStr : "nullptr", uuidStr ? uuidStr : "nullptr"); | 
|  |  | 
|  | if (stringToGuid(typeStr, &type) == NO_ERROR) { | 
|  | pType = &type; | 
|  | } | 
|  | if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { | 
|  | pUuid = &uuid; | 
|  | } | 
|  |  | 
|  | return set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe); | 
|  | } | 
|  |  | 
|  |  | 
|  | AudioEffect::~AudioEffect() | 
|  | { | 
|  | ALOGV("Destructor %p", this); | 
|  |  | 
|  | if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) { | 
|  | if (!audio_is_global_session(mSessionId)) { | 
|  | AudioSystem::releaseAudioSessionId(mSessionId, | 
|  | VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid))); | 
|  | } | 
|  | if (mIEffect != NULL) { | 
|  | mIEffect->disconnect(); | 
|  | IInterface::asBinder(mIEffect)->unlinkToDeath(mIEffectClient); | 
|  | } | 
|  | mIEffect.clear(); | 
|  | mCblkMemory.clear(); | 
|  | } | 
|  | mIEffectClient.clear(); | 
|  | IPCThreadState::self()->flushCommands(); | 
|  | } | 
|  |  | 
|  |  | 
|  | status_t AudioEffect::initCheck() const | 
|  | { | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | // ------------------------------------------------------------------------- | 
|  |  | 
|  | effect_descriptor_t AudioEffect::descriptor() const | 
|  | { | 
|  | return mDescriptor; | 
|  | } | 
|  |  | 
|  | bool AudioEffect::getEnabled() const | 
|  | { | 
|  | return (mEnabled != 0); | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::setEnabled(bool enabled) | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR) { | 
|  | return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus; | 
|  | } | 
|  |  | 
|  | status_t status = NO_ERROR; | 
|  | AutoMutex lock(mLock); | 
|  | if (enabled != mEnabled) { | 
|  | Status bs; | 
|  |  | 
|  | if (enabled) { | 
|  | ALOGV("enable %p", this); | 
|  | bs = mIEffect->enable(&status); | 
|  | } else { | 
|  | ALOGV("disable %p", this); | 
|  | bs = mIEffect->disable(&status); | 
|  | } | 
|  | if (!bs.isOk()) { | 
|  | status = statusTFromBinderStatus(bs); | 
|  | } | 
|  | if (status == NO_ERROR) { | 
|  | mEnabled = enabled; | 
|  | } | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::command(uint32_t cmdCode, | 
|  | uint32_t cmdSize, | 
|  | void *cmdData, | 
|  | uint32_t *replySize, | 
|  | void *replyData) | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { | 
|  | ALOGV("command() bad status %d", mStatus); | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) { | 
|  | if (mEnabled == (cmdCode == EFFECT_CMD_ENABLE)) { | 
|  | return NO_ERROR; | 
|  | } | 
|  | if (replySize == NULL || *replySize != sizeof(status_t) || replyData == NULL) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  | mLock.lock(); | 
|  | } | 
|  |  | 
|  | std::vector<uint8_t> data; | 
|  | appendToBuffer(cmdData, cmdSize, &data); | 
|  |  | 
|  | status_t status; | 
|  | std::vector<uint8_t> response; | 
|  |  | 
|  | Status bs = mIEffect->command(cmdCode, data, *replySize, &response, &status); | 
|  | if (!bs.isOk()) { | 
|  | status = statusTFromBinderStatus(bs); | 
|  | } | 
|  | if (status == NO_ERROR) { | 
|  | memcpy(replyData, response.data(), response.size()); | 
|  | *replySize = response.size(); | 
|  | } | 
|  |  | 
|  | if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) { | 
|  | if (status == NO_ERROR) { | 
|  | status = *(status_t *)replyData; | 
|  | } | 
|  | if (status == NO_ERROR) { | 
|  | mEnabled = (cmdCode == EFFECT_CMD_ENABLE); | 
|  | } | 
|  | mLock.unlock(); | 
|  | } | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::setParameter(effect_param_t *param) | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR) { | 
|  | return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus; | 
|  | } | 
|  |  | 
|  | if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  |  | 
|  | uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; | 
|  |  | 
|  | ALOGV("setParameter: param: %d, param2: %d", *(int *)param->data, | 
|  | (param->psize == 8) ? *((int *)param->data + 1): -1); | 
|  |  | 
|  | std::vector<uint8_t> cmd; | 
|  | appendToBuffer(param, sizeof(effect_param_t) + psize, &cmd); | 
|  | std::vector<uint8_t> response; | 
|  | status_t status; | 
|  | Status bs = mIEffect->command(EFFECT_CMD_SET_PARAM, | 
|  | cmd, | 
|  | sizeof(int), | 
|  | &response, | 
|  | &status); | 
|  | if (!bs.isOk()) { | 
|  | status = statusTFromBinderStatus(bs); | 
|  | return status; | 
|  | } | 
|  | assert(response.size() == sizeof(int)); | 
|  | memcpy(¶m->status, response.data(), response.size()); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::setParameterDeferred(effect_param_t *param) | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR) { | 
|  | return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus; | 
|  | } | 
|  |  | 
|  | if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  |  | 
|  | Mutex::Autolock _l(mCblk->lock); | 
|  |  | 
|  | int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; | 
|  | int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int); | 
|  |  | 
|  | if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) { | 
|  | return NO_MEMORY; | 
|  | } | 
|  | int *p = (int *)(mCblk->buffer + mCblk->clientIndex); | 
|  | *p++ = size; | 
|  | memcpy(p, param, sizeof(effect_param_t) + psize); | 
|  | mCblk->clientIndex += size; | 
|  |  | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::setParameterCommit() | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR) { | 
|  | return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus; | 
|  | } | 
|  |  | 
|  | Mutex::Autolock _l(mCblk->lock); | 
|  | if (mCblk->clientIndex == 0) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | std::vector<uint8_t> cmd; | 
|  | std::vector<uint8_t> response; | 
|  | status_t status; | 
|  | Status bs = mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, | 
|  | cmd, | 
|  | 0, | 
|  | &response, | 
|  | &status); | 
|  | if (!bs.isOk()) { | 
|  | status = statusTFromBinderStatus(bs); | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::getParameter(effect_param_t *param) | 
|  | { | 
|  | if (mProbe) { | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  | if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { | 
|  | return mStatus; | 
|  | } | 
|  |  | 
|  | if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  |  | 
|  | ALOGV("getParameter: param: %d, param2: %d", *(int *)param->data, | 
|  | (param->psize == 8) ? *((int *)param->data + 1): -1); | 
|  |  | 
|  | uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + | 
|  | param->vsize; | 
|  |  | 
|  | status_t status; | 
|  | std::vector<uint8_t> cmd; | 
|  | std::vector<uint8_t> response; | 
|  | appendToBuffer(param, sizeof(effect_param_t) + param->psize, &cmd); | 
|  |  | 
|  | Status bs = mIEffect->command(EFFECT_CMD_GET_PARAM, cmd, psize, &response, &status); | 
|  | if (!bs.isOk()) { | 
|  | status = statusTFromBinderStatus(bs); | 
|  | return status; | 
|  | } | 
|  | memcpy(param, response.data(), response.size()); | 
|  | return status; | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------------------------------------------- | 
|  |  | 
|  | void AudioEffect::binderDied() | 
|  | { | 
|  | ALOGW("IEffect died"); | 
|  | mStatus = DEAD_OBJECT; | 
|  | if (mCbf != NULL) { | 
|  | status_t status = DEAD_OBJECT; | 
|  | mCbf(EVENT_ERROR, mUserData, &status); | 
|  | } | 
|  | mIEffect.clear(); | 
|  | } | 
|  |  | 
|  | // ------------------------------------------------------------------------- | 
|  |  | 
|  | void AudioEffect::controlStatusChanged(bool controlGranted) | 
|  | { | 
|  | ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, | 
|  | mUserData); | 
|  | if (controlGranted) { | 
|  | if (mStatus == ALREADY_EXISTS) { | 
|  | mStatus = NO_ERROR; | 
|  | } | 
|  | } else { | 
|  | if (mStatus == NO_ERROR) { | 
|  | mStatus = ALREADY_EXISTS; | 
|  | } | 
|  | } | 
|  | if (mCbf != NULL) { | 
|  | mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted); | 
|  | } | 
|  | } | 
|  |  | 
|  | void AudioEffect::enableStatusChanged(bool enabled) | 
|  | { | 
|  | ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf); | 
|  | if (mStatus == ALREADY_EXISTS) { | 
|  | mEnabled = enabled; | 
|  | if (mCbf != NULL) { | 
|  | mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void AudioEffect::commandExecuted(int32_t cmdCode, | 
|  | const std::vector<uint8_t>& cmdData, | 
|  | const std::vector<uint8_t>& replyData) | 
|  | { | 
|  | if (cmdData.empty() || replyData.empty()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) { | 
|  | std::vector<uint8_t> cmdDataCopy(cmdData); | 
|  | effect_param_t* cmd = reinterpret_cast<effect_param_t *>(cmdDataCopy.data()); | 
|  | cmd->status = *reinterpret_cast<const int32_t *>(replyData.data()); | 
|  | mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ------------------------------------------------------------------------- | 
|  |  | 
|  | status_t AudioEffect::queryNumberEffects(uint32_t *numEffects) | 
|  | { | 
|  | const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
|  | if (af == 0) return PERMISSION_DENIED; | 
|  | return af->queryNumberEffects(numEffects); | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor) | 
|  | { | 
|  | const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
|  | if (af == 0) return PERMISSION_DENIED; | 
|  | return af->queryEffect(index, descriptor); | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid, | 
|  | const effect_uuid_t *type, | 
|  | uint32_t preferredTypeFlag, | 
|  | effect_descriptor_t *descriptor) | 
|  | { | 
|  | const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
|  | if (af == 0) return PERMISSION_DENIED; | 
|  | return af->getEffectDescriptor(uuid, type, preferredTypeFlag, descriptor); | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::queryDefaultPreProcessing(audio_session_t audioSession, | 
|  | effect_descriptor_t *descriptors, | 
|  | uint32_t *count) | 
|  | { | 
|  | if (descriptors == nullptr || count == nullptr) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  | const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); | 
|  | if (aps == 0) return PERMISSION_DENIED; | 
|  |  | 
|  | int32_t audioSessionAidl = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_audio_session_t_int32_t(audioSession)); | 
|  | media::Int countAidl; | 
|  | countAidl.value = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*count)); | 
|  | std::vector<media::EffectDescriptor> retAidl; | 
|  | RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( | 
|  | aps->queryDefaultPreProcessing(audioSessionAidl, &countAidl, &retAidl))); | 
|  | *count = VALUE_OR_RETURN_STATUS(convertIntegral<uint32_t>(countAidl.value)); | 
|  | RETURN_STATUS_IF_ERROR(convertRange(retAidl.begin(), retAidl.end(), descriptors, | 
|  | aidl2legacy_EffectDescriptor_effect_descriptor_t)); | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id) | 
|  | { | 
|  | const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
|  | if (af == 0) return PERMISSION_DENIED; | 
|  | *id = af->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::addSourceDefaultEffect(const char *typeStr, | 
|  | const String16& opPackageName, | 
|  | const char *uuidStr, | 
|  | int32_t priority, | 
|  | audio_source_t source, | 
|  | audio_unique_id_t *id) | 
|  | { | 
|  | const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); | 
|  | if (aps == 0) return PERMISSION_DENIED; | 
|  |  | 
|  | if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE; | 
|  |  | 
|  | // Convert type & uuid from string to effect_uuid_t. | 
|  | effect_uuid_t type; | 
|  | if (typeStr != NULL) { | 
|  | status_t res = stringToGuid(typeStr, &type); | 
|  | if (res != OK) return res; | 
|  | } else { | 
|  | type = *EFFECT_UUID_NULL; | 
|  | } | 
|  |  | 
|  | effect_uuid_t uuid; | 
|  | if (uuidStr != NULL) { | 
|  | status_t res = stringToGuid(uuidStr, &uuid); | 
|  | if (res != OK) return res; | 
|  | } else { | 
|  | uuid = *EFFECT_UUID_NULL; | 
|  | } | 
|  |  | 
|  | media::AudioUuid typeAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(type)); | 
|  | media::AudioUuid uuidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(uuid)); | 
|  | std::string opPackageNameAidl = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_String16_string(opPackageName)); | 
|  | media::AudioSourceType sourceAidl = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_audio_source_t_AudioSourceType(source)); | 
|  | int32_t retAidl; | 
|  | RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( | 
|  | aps->addSourceDefaultEffect(typeAidl, opPackageNameAidl, uuidAidl, priority, sourceAidl, | 
|  | &retAidl))); | 
|  | *id = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_unique_id_t(retAidl)); | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::addStreamDefaultEffect(const char *typeStr, | 
|  | const String16& opPackageName, | 
|  | const char *uuidStr, | 
|  | int32_t priority, | 
|  | audio_usage_t usage, | 
|  | audio_unique_id_t *id) | 
|  | { | 
|  | const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); | 
|  | if (aps == 0) return PERMISSION_DENIED; | 
|  |  | 
|  | if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE; | 
|  |  | 
|  | // Convert type & uuid from string to effect_uuid_t. | 
|  | effect_uuid_t type; | 
|  | if (typeStr != NULL) { | 
|  | status_t res = stringToGuid(typeStr, &type); | 
|  | if (res != OK) return res; | 
|  | } else { | 
|  | type = *EFFECT_UUID_NULL; | 
|  | } | 
|  |  | 
|  | effect_uuid_t uuid; | 
|  | if (uuidStr != NULL) { | 
|  | status_t res = stringToGuid(uuidStr, &uuid); | 
|  | if (res != OK) return res; | 
|  | } else { | 
|  | uuid = *EFFECT_UUID_NULL; | 
|  | } | 
|  |  | 
|  | media::AudioUuid typeAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(type)); | 
|  | media::AudioUuid uuidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(uuid)); | 
|  | std::string opPackageNameAidl = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_String16_string(opPackageName)); | 
|  | media::AudioUsage usageAidl = VALUE_OR_RETURN_STATUS( | 
|  | legacy2aidl_audio_usage_t_AudioUsage(usage)); | 
|  | int32_t retAidl; | 
|  | RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( | 
|  | aps->addStreamDefaultEffect(typeAidl, opPackageNameAidl, uuidAidl, priority, usageAidl, | 
|  | &retAidl))); | 
|  | *id = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_unique_id_t(retAidl)); | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::removeSourceDefaultEffect(audio_unique_id_t id) | 
|  | { | 
|  | const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); | 
|  | if (aps == 0) return PERMISSION_DENIED; | 
|  |  | 
|  | int32_t idAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_unique_id_t_int32_t(id)); | 
|  | return statusTFromBinderStatus(aps->removeSourceDefaultEffect(idAidl)); | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id) | 
|  | { | 
|  | const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); | 
|  | if (aps == 0) return PERMISSION_DENIED; | 
|  |  | 
|  | int32_t idAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_unique_id_t_int32_t(id)); | 
|  | return statusTFromBinderStatus(aps->removeStreamDefaultEffect(idAidl)); | 
|  | } | 
|  |  | 
|  | // ------------------------------------------------------------------------- | 
|  |  | 
|  | status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid) | 
|  | { | 
|  | if (str == NULL || guid == NULL) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  |  | 
|  | int tmp[10]; | 
|  |  | 
|  | if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", | 
|  | tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  | guid->timeLow = (uint32_t)tmp[0]; | 
|  | guid->timeMid = (uint16_t)tmp[1]; | 
|  | guid->timeHiAndVersion = (uint16_t)tmp[2]; | 
|  | guid->clockSeq = (uint16_t)tmp[3]; | 
|  | guid->node[0] = (uint8_t)tmp[4]; | 
|  | guid->node[1] = (uint8_t)tmp[5]; | 
|  | guid->node[2] = (uint8_t)tmp[6]; | 
|  | guid->node[3] = (uint8_t)tmp[7]; | 
|  | guid->node[4] = (uint8_t)tmp[8]; | 
|  | guid->node[5] = (uint8_t)tmp[9]; | 
|  |  | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen) | 
|  | { | 
|  | if (guid == NULL || str == NULL) { | 
|  | return BAD_VALUE; | 
|  | } | 
|  |  | 
|  | snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", | 
|  | guid->timeLow, | 
|  | guid->timeMid, | 
|  | guid->timeHiAndVersion, | 
|  | guid->clockSeq, | 
|  | guid->node[0], | 
|  | guid->node[1], | 
|  | guid->node[2], | 
|  | guid->node[3], | 
|  | guid->node[4], | 
|  | guid->node[5]); | 
|  |  | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | } // namespace android |