Android Audio代码分析21 - 创建AudioEffect对象

今天来看看AudioEffect的构造,以及相关的一些函数。


*****************************************源码*************************************************
//Test case 1.0: test constructor from effect type and get effect ID @LargeTest public void test1_0ConstructorFromType() throws Exception { boolean result = true; String msg = "test1_0ConstructorFromType()"; AudioEffect.Descriptor[] desc = AudioEffect.queryEffects(); assertTrue(msg+": no effects found", (desc.length != 0)); try { AudioEffect effect = new AudioEffect(desc[0].type, AudioEffect.EFFECT_TYPE_NULL, 0, 0); assertNotNull(msg + ": could not create AudioEffect", effect); try { assertTrue(msg +": invalid effect ID", (effect.getId() != 0)); } catch (IllegalStateException e) { msg = msg.concat(": AudioEffect not initialized"); result = false; } finally { effect.release(); } } catch (IllegalArgumentException e) { msg = msg.concat(": Effect not found: "+desc[0].name); result = false; } catch (UnsupportedOperationException e) { msg = msg.concat(": Effect library not loaded"); result = false; } assertTrue(msg, result); }
**********************************************************************************************
源码路径:
frameworks\base\media\tests\mediaframeworktest\src\com\android\mediaframeworktest\functional\MediaAudioEffectTest.java


#######################说明################################
//Test case 1.0: test constructor from effect type and get effect ID @LargeTest public void test1_0ConstructorFromType() throws Exception { boolean result = true; String msg = "test1_0ConstructorFromType()"; AudioEffect.Descriptor[] desc = AudioEffect.queryEffects(); assertTrue(msg+": no effects found", (desc.length != 0)); try { AudioEffect effect = new AudioEffect(desc[0].type, AudioEffect.EFFECT_TYPE_NULL, 0, 0); // +++++++++++++++++++++++++++++++AudioEffect+++++++++++++++++++++++++++++++++ /** * Class constructor. * * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB}, * {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to * built-in effects are defined by AudioEffect class. Other types * can be specified provided they correspond an existing OpenSL * ES interface ID and the corresponsing effect is available on * the platform. If an unspecified effect type is requested, the * constructor with throw the IllegalArgumentException. This * parameter can be set to {@link #EFFECT_TYPE_NULL} in which * case only the uuid will be used to select the effect. * @param uuid unique identifier of a particular effect implementation. * Must be specified if the caller wants to use a particular * implementation of an effect type. This parameter can be set to * {@link #EFFECT_TYPE_NULL} in which case only the type will * be used to select the effect. * @param priority the priority level requested by the application for * controlling the effect engine. As the same effect engine can * be shared by several applications, this parameter indicates * how much the requesting application needs control of effect * parameters. The normal priority is 0, above normal is a * positive number, below normal a negative number. * @param audioSession system wide unique audio session identifier. If audioSession * is not 0, the effect will be attached to the MediaPlayer or * AudioTrack in the same audio session. Otherwise, the effect * will apply to the output mix. * * @throws java.lang.IllegalArgumentException * @throws java.lang.UnsupportedOperationException * @throws java.lang.RuntimeException * @hide */ public AudioEffect(UUID type, UUID uuid, int priority, int audioSession) throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { int[] id = new int[1]; Descriptor[] desc = new Descriptor[1]; // native initialization int initResult = native_setup(new WeakReference<AudioEffect>(this), type.toString(), uuid.toString(), priority, audioSession, id, desc); // +++++++++++++++++++++++++android_media_AudioEffect_native_setup+++++++++++++++++++++++++++++++++++++++ static jint android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc) { LOGV("android_media_AudioEffect_native_setup"); AudioEffectJniStorage* lpJniStorage = NULL; int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY; AudioEffect* lpAudioEffect = NULL; jint* nId = NULL; const char *typeStr = NULL; const char *uuidStr = NULL; effect_descriptor_t desc; jobject jdesc; char str[EFFECT_STRING_LEN_MAX]; jstring jdescType; jstring jdescUuid; jstring jdescConnect; jstring jdescName; jstring jdescImplementor; if (type != NULL) { typeStr = env->GetStringUTFChars(type, NULL); if (typeStr == NULL) { // Out of memory jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); goto setup_failure; } } if (uuid != NULL) { uuidStr = env->GetStringUTFChars(uuid, NULL); if (uuidStr == NULL) { // Out of memory jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); goto setup_failure; } } // type 和 uuid 必须有一个不为空 // 否则,没办法确定用哪个effect lib if (typeStr == NULL && uuidStr == NULL) { lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; goto setup_failure; } lpJniStorage = new AudioEffectJniStorage(); if (lpJniStorage == NULL) { LOGE("setup: Error creating JNI Storage"); goto setup_failure; } // ++++++++++++++++++++++++++++AudioEffectJniStorage++++++++++++++++++++++++++++++++++++ struct effect_callback_cookie { jclass audioEffect_class; // AudioEffect class jobject audioEffect_ref; // AudioEffect object instance }; class AudioEffectJniStorage { public: effect_callback_cookie mCallbackData; AudioEffectJniStorage() { } ~AudioEffectJniStorage() { } }; // ----------------------------AudioEffectJniStorage------------------------------------ lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect); // we use a weak reference so the AudioEffect object can be garbage collected. lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this); LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p", lpJniStorage, lpJniStorage->mCallbackData.audioEffect_ref, lpJniStorage->mCallbackData.audioEffect_class, &lpJniStorage->mCallbackData); if (jId == NULL) { LOGE("setup: NULL java array for id pointer"); lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; goto setup_failure; } // create the native AudioEffect object lpAudioEffect = new AudioEffect(typeStr, uuidStr, priority, effectCallback, &lpJniStorage->mCallbackData, sessionId, 0); if (lpAudioEffect == NULL) { LOGE("Error creating AudioEffect"); goto setup_failure; } // ++++++++++++++++++++++++++++native AudioEffect++++++++++++++++++++++++++++++++++++ AudioEffect::AudioEffect(const char *typeStr, const char *uuidStr, int32_t priority, effect_callback_t cbf, void* user, int sessionId, audio_io_handle_t output ) : mStatus(NO_INIT) { effect_uuid_t type; effect_uuid_t *pType = NULL; effect_uuid_t uuid; effect_uuid_t *pUuid = NULL; LOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr); if (typeStr != NULL) { if (stringToGuid(typeStr, &type) == NO_ERROR) { pType = &type; } } if (uuidStr != NULL) { if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { pUuid = &uuid; } } mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output); // +++++++++++++++++++++++++++++AudioEffect::set+++++++++++++++++++++++++++++++++++ status_t AudioEffect::set(const effect_uuid_t *type, const effect_uuid_t *uuid, int32_t priority, effect_callback_t cbf, void* user, int sessionId, audio_io_handle_t output) { sp<IEffect> iEffect; sp<IMemory> cblk; int enabled; LOGV("set %p mUserData: %p", this, user); // 如果effect 对象已经被创建了,返回无效操作 if (mIEffect != 0) { LOGW("Effect already in use"); return INVALID_OPERATION; } const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { LOGE("set(): Could not get audioflinger"); return NO_INIT; } // 再一次检查type和uuid if (type == NULL && uuid == NULL) { LOGW("Must specify at least type or uuid"); return BAD_VALUE; } mPriority = priority; // cbf其实是函数effectCallback mCbf = cbf; // +++++++++++++++++++++++++++++effectCallback+++++++++++++++++++++++++++++++++++ static void effectCallback(int event, void* user, void *info) { effect_param_t *p; int arg1 = 0; int arg2 = 0; jobject obj = NULL; jbyteArray array = NULL; jbyte *bytes; bool param; size_t size; effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user; JNIEnv *env = AndroidRuntime::getJNIEnv(); LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p", callbackInfo, callbackInfo->audioEffect_ref, callbackInfo->audioEffect_class); if (!user || !env) { LOGW("effectCallback error user %p, env %p", user, env); return; } switch (event) { case AudioEffect::EVENT_CONTROL_STATUS_CHANGED: if (info == 0) { LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL"); goto effectCallback_Exit; } param = *(bool *)info; arg1 = (int)param; LOGV("EVENT_CONTROL_STATUS_CHANGED"); break; case AudioEffect::EVENT_ENABLE_STATUS_CHANGED: if (info == 0) { LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL"); goto effectCallback_Exit; } param = *(bool *)info; arg1 = (int)param; LOGV("EVENT_ENABLE_STATUS_CHANGED"); break; case AudioEffect::EVENT_PARAMETER_CHANGED: if (info == 0) { LOGW("EVENT_PARAMETER_CHANGED info == NULL"); goto effectCallback_Exit; } p = (effect_param_t *)info; if (p->psize == 0 || p->vsize == 0) { goto effectCallback_Exit; } // arg1 contains offset of parameter value from start of byte array arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int); size = arg1 + p->vsize; array = env->NewByteArray(size); if (array == NULL) { LOGE("effectCallback: Couldn't allocate byte array for parameter data"); goto effectCallback_Exit; } bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, p, size); env->ReleaseByteArrayElements(array, bytes, 0); obj = array; LOGV("EVENT_PARAMETER_CHANGED"); break; case AudioEffect::EVENT_ERROR: LOGW("EVENT_ERROR"); break; } env->CallStaticVoidMethod( callbackInfo->audioEffect_class, fields.midPostNativeEvent, callbackInfo->audioEffect_ref, event, arg1, arg2, obj); effectCallback_Exit: if (array) { env->DeleteLocalRef(array); } if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } } // -----------------------------effectCallback----------------------------------- // user其实是AudioEffectJniStorage对象中mCallbackData成员的地址 mUserData = user; mSessionId = sessionId; memset(&mDescriptor, 0, sizeof(effect_descriptor_t)); memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); if (type != NULL) { memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t)); } if (uuid != NULL) { memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t)); } mIEffectClient = new EffectClient(this); // +++++++++++++++++++++++++++++EffectClient+++++++++++++++++++++++++++++++++++ // Implements the IEffectClient interface class EffectClient : public android::BnEffectClient, public android::IBinder::DeathRecipient { public: EffectClient(AudioEffect *effect) : mEffect(effect){} // IEffectClient virtual void controlStatusChanged(bool controlGranted) { mEffect->controlStatusChanged(controlGranted); } virtual void enableStatusChanged(bool enabled) { mEffect->enableStatusChanged(enabled); } virtual void commandExecuted(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t replySize, void *pReplyData) { mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } // IBinder::DeathRecipient virtual void binderDied(const wp<IBinder>& who) {mEffect->binderDied();} private: AudioEffect *mEffect; }; // -----------------------------EffectClient----------------------------------- iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor, mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled); if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus); return mStatus; } // ++++++++++++++++++++++++++AudioFlinger::createEffect++++++++++++++++++++++++++++++++++++++ sp<IEffect> AudioFlinger::createEffect(pid_t pid, effect_descriptor_t *pDesc, const sp<IEffectClient>& effectClient, int32_t priority, int output, int sessionId, status_t *status, int *id, int *enabled) { status_t lStatus = NO_ERROR; sp<EffectHandle> handle; effect_interface_t itfe; effect_descriptor_t desc; sp<Client> client; wp<Client> wclient; LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output); if (pDesc == NULL) { lStatus = BAD_VALUE; goto Exit; } // check audio settings permission for global effects if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) { lStatus = PERMISSION_DENIED; goto Exit; } // +++++++++++++++++++++++++++++++audio_sessions+++++++++++++++++++++++++++++++++ // special audio session values enum audio_sessions { SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream // (value must be less than 0) SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can // be moved by audio policy manager to another output stream // (value must be 0) }; // -------------------------------audio_sessions--------------------------------- // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects // that can only be created by audio policy manager (running in same process) if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) { lStatus = PERMISSION_DENIED; goto Exit; } // check recording permission for visualizer if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 || memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) && !recordingAllowed()) { lStatus = PERMISSION_DENIED; goto Exit; } if (output == 0) { if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) { // output must be specified by AudioPolicyManager when using session // AudioSystem::SESSION_OUTPUT_STAGE // 如果sessionId为AudioSystem::SESSION_OUTPUT_STAGE,effect必须绑定到特定的output lStatus = BAD_VALUE; goto Exit; } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { // if the output returned by getOutputForEffect() is removed before we lock the // mutex below, the call to checkPlaybackThread_l(output) below will detect it // and we will exit safely output = AudioSystem::getOutputForEffect(&desc); // ++++++++++++++++++++++++++++++AudioSystem::getOutputForEffect++++++++++++++++++++++++++++++++++ audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->getOutputForEffect(desc); // +++++++++++++++++++++++++++++AudioPolicyService::getOutputForEffect+++++++++++++++++++++++++++++++++++ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc) { if (mpPolicyManager == NULL) { return NO_INIT; } Mutex::Autolock _l(mLock); return mpPolicyManager->getOutputForEffect(desc); // ++++++++++++++++++++++++++++++AudioPolicyManagerBase::getOutputForEffect++++++++++++++++++++++++++++++++++ audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc) { LOGV("getOutputForEffect()"); // apply simple rule where global effects are attached to the same output as MUSIC streams // 所有的effect都会被绑定到MUSIT stream上,所以,这儿只是简单的将MUSIC stream对应的output返回 return getOutput(AudioSystem::MUSIC); } // ------------------------------AudioPolicyManagerBase::getOutputForEffect---------------------------------- } // -----------------------------AudioPolicyService::getOutputForEffect----------------------------------- } // ------------------------------AudioSystem::getOutputForEffect---------------------------------- } } { Mutex::Autolock _l(mLock); if (!EffectIsNullUuid(&pDesc->uuid)) { // 如果指定了uuid,则根据uuid寻找合适的effect descriptor // if uuid is specified, request effect descriptor lStatus = EffectGetDescriptor(&pDesc->uuid, &desc); if (lStatus < 0) { LOGW("createEffect() error %d from EffectGetDescriptor", lStatus); goto Exit; } // ++++++++++++++++++++++++++++++EffectGetDescriptor++++++++++++++++++++++++++++++++++ 路径:frameworks\base\media\libeffects\factory\EffectsFactory.c int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) { lib_entry_t *l = NULL; effect_descriptor_t *d = NULL; // init 函数我们已经看过 // 如果init已经被调用过,再次进入init函数并不会有真正的动作 // 也就是说,初始化操作只会进行一次 int ret = init(); if (ret < 0) { return ret; } if (pDescriptor == NULL || uuid == NULL) { return -EINVAL; } pthread_mutex_lock(&gLibLock); ret = findEffect(uuid, &l, &d); if (ret == 0) { memcpy(pDescriptor, d, sizeof(effect_descriptor_t)); } // +++++++++++++++++++++++++++++++findEffect+++++++++++++++++++++++++++++++++ int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc) { // gLibraryList是保存所有effect lib的列表 list_elem_t *e = gLibraryList; lib_entry_t *l = NULL; effect_descriptor_t *d = NULL; int found = 0; int ret = 0; while (e && !found) { l = (lib_entry_t *)e->object; list_elem_t *efx = l->effects; while (efx) { d = (effect_descriptor_t *)efx->object; // 比较是否与给定的uuid一致 if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { found = 1; break; } efx = efx->next; } e = e->next; } if (!found) { LOGV("findEffect() effect not found"); ret = -ENOENT; } else { LOGV("findEffect() found effect: %s in lib %s", d->name, l->path); *lib = l; *desc = d; } return ret; } // -------------------------------findEffect--------------------------------- pthread_mutex_unlock(&gLibLock); return ret; } // ------------------------------EffectGetDescriptor---------------------------------- } else { // if uuid is not specified, look for an available implementation // of the required type in effect factory // 如果没指定uuid,则寻找一个相同类型的可用的effect lib if (EffectIsNullUuid(&pDesc->type)) { LOGW("createEffect() no effect type"); lStatus = BAD_VALUE; goto Exit; } uint32_t numEffects = 0; effect_descriptor_t d; bool found = false; lStatus = EffectQueryNumberEffects(&numEffects); if (lStatus < 0) { LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus); goto Exit; } for (uint32_t i = 0; i < numEffects; i++) { lStatus = EffectQueryEffect(i, &desc); if (lStatus < 0) { LOGW("createEffect() error %d from EffectQueryEffect", lStatus); continue; } if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) { // If matching type found save effect descriptor. If the session is // 0 and the effect is not auxiliary, continue enumeration in case // an auxiliary version of this effect type is available // 如果session id为0,即AudioSystem::SESSION_OUTPUT_MIX, // 若找到的effect为auxiliary,则退出,否则的话就继续查找 // 以防止存在可用的该类型的auxiliary的effect。 // 也就是说,对于AudioSystem::SESSION_OUTPUT_MIX的session id来说, // 会优先使用auxiliary的effect。 found = true; memcpy(&d, &desc, sizeof(effect_descriptor_t)); if (sessionId != AudioSystem::SESSION_OUTPUT_MIX || (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { break; } } } if (!found) { lStatus = BAD_VALUE; LOGW("createEffect() effect not found"); goto Exit; } // For same effect type, chose auxiliary version over insert version if // connect to output mix (Compliance to OpenSL ES) // 如果不存在可用的该类型的auxiliary的effect,也只能勉强使用刚才找到的insert的了 if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { memcpy(&desc, &d, sizeof(effect_descriptor_t)); } } // auxiliary的effect只能作用在AudioSystem::SESSION_OUTPUT_MIX的session id上。 // Do not allow auxiliary effects on a session different from 0 (output mix) if (sessionId != AudioSystem::SESSION_OUTPUT_MIX && (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { lStatus = INVALID_OPERATION; goto Exit; } // return effect descriptor memcpy(pDesc, &desc, sizeof(effect_descriptor_t)); // If output is not specified try to find a matching audio session ID in one of the // output threads. // 如果没有指定output,则尝试在output threads中寻找匹配的Session ID。 // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX // because of code checking output when entering the function. // 此时,如果output仍然为0,则说明session ID即不是SESSION_OUTPUT_STAGE,也不是SESSION_OUTPUT_MIX。 // 因为前面我们做过一个检查,如果output为0,若session ID是SESSION_OUTPUT_STAGE,则直接退出; // 若session ID是SESSION_OUTPUT_MIX,则会调用函数AudioSystem::getOutputForEffect来get一个output // (从最终的实现可知,函数AudioSystem::getOutputForEffect最终返回的是music stream对应的output)。 if (output == 0) { // look for the thread where the specified audio session is present for (size_t i = 0; i < mPlaybackThreads.size(); i++) { if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { output = mPlaybackThreads.keyAt(i); break; // ++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::hasAudioSession++++++++++++++++++++++++++++++++++++ uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) { Mutex::Autolock _l(mLock); uint32_t result = 0; if (getEffectChain_l(sessionId) != 0) { result = EFFECT_SESSION; } for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> track = mTracks[i]; // 在创建track的时候,会传入一个session ID if (sessionId == track->sessionId() && !(track->mCblk->flags & CBLK_INVALID_MSK)) { result |= TRACK_SESSION; break; } } return result; } // ----------------------------AudioFlinger::PlaybackThread::hasAudioSession------------------------------------ } } // If no output thread contains the requested session ID, default to // first output. The effect chain will be moved to the correct output // thread when a track with the same session ID is created // 如果找不到output,默认使用第一个。 // 如果相同session ID的trak被创建了,effect链表会被移动到新的track上。 // effect的移动工作在函数AudioFlinger::createTrack中完成见随后代码 if (output == 0 && mPlaybackThreads.size()) { output = mPlaybackThreads.keyAt(0); } // +++++++++++++++++++++++++++++AudioFlinger::createTrack moveEffectChain_l+++++++++++++++++++++++++++++++++++ if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { // prevent same audio session on different output threads uint32_t sessions = t->hasAudioSession(*sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { lStatus = BAD_VALUE; goto Exit; } // check if an effect with same session ID is waiting for a track to be created if (sessions & PlaybackThread::EFFECT_SESSION) { effectThread = t.get(); } } } lSessionId = *sessionId; } else { // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } } LOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, lSessionId, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created if (lStatus == NO_ERROR && effectThread != NULL) { Mutex::Autolock _dl(thread->mLock); Mutex::Autolock _sl(effectThread->mLock); moveEffectChain_l(lSessionId, effectThread, thread, true); // +++++++++++++++++++++++++++++AudioFlinger::moveEffectChain_l+++++++++++++++++++++++++++++++++++ // moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held status_t AudioFlinger::moveEffectChain_l(int session, AudioFlinger::PlaybackThread *srcThread, AudioFlinger::PlaybackThread *dstThread, bool reRegister) { LOGV("moveEffectChain_l() session %d from thread %p to thread %p", session, srcThread, dstThread); sp<EffectChain> chain = srcThread->getEffectChain_l(session); if (chain == 0) { LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p", session, srcThread); return INVALID_OPERATION; } // remove chain first. This is useful only if reconfiguring effect chain on same output thread, // so that a new chain is created with correct parameters when first effect is added. This is // otherwise unecessary as removeEffect_l() will remove the chain when last effect is // removed. srcThread->removeEffectChain_l(chain); // transfer all effects one by one so that new effect chain is created on new thread with // correct buffer sizes and audio parameters and effect engines reconfigured accordingly int dstOutput = dstThread->id(); sp<EffectChain> dstChain; uint32_t strategy; sp<EffectModule> effect = chain->getEffectFromId_l(0); while (effect != 0) { srcThread->removeEffect_l(effect); dstThread->addEffect_l(effect); // if the move request is not received from audio policy manager, the effect must be // re-registered with the new strategy and output if (dstChain == 0) { dstChain = effect->chain().promote(); if (dstChain == 0) { LOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get()); srcThread->addEffect_l(effect); return NO_INIT; } strategy = dstChain->strategy(); } if (reRegister) { AudioSystem::unregisterEffect(effect->id()); AudioSystem::registerEffect(&effect->desc(), dstOutput, strategy, session, effect->id()); // ++++++++++++++++++++++++++++AudioSystem::registerEffect++++++++++++++++++++++++++++++++++++ status_t AudioSystem::registerEffect(effect_descriptor_t *desc, audio_io_handle_t output, uint32_t strategy, int session, int id) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->registerEffect(desc, output, strategy, session, id); // ++++++++++++++++++++++++++++AudioPolicyService::registerEffect++++++++++++++++++++++++++++++++++++ status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, audio_io_handle_t output, uint32_t strategy, int session, int id) { if (mpPolicyManager == NULL) { return NO_INIT; } return mpPolicyManager->registerEffect(desc, output, strategy, session, id); // +++++++++++++++++++++++++++AudioPolicyManagerBase::registerEffect+++++++++++++++++++++++++++++++++++++ status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc, audio_io_handle_t output, uint32_t strategy, int session, int id) { ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("registerEffect() unknown output %d", output); return INVALID_OPERATION; } if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) { LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS", desc->name, (float)desc->cpuLoad/10); return INVALID_OPERATION; } if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", desc->name, desc->memoryUsage); return INVALID_OPERATION; } mTotalEffectsCpuLoad += desc->cpuLoad; mTotalEffectsMemory += desc->memoryUsage; LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d", desc->name, output, strategy, session, id); LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage); LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); EffectDescriptor *pDesc = new EffectDescriptor(); memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t)); pDesc->mOutput = output; pDesc->mStrategy = (routing_strategy)strategy; pDesc->mSession = session; mEffects.add(id, pDesc); return NO_ERROR; } // ---------------------------AudioPolicyManagerBase::registerEffect------------------------------------- } // ----------------------------AudioPolicyService::registerEffect------------------------------------ } // ----------------------------AudioSystem::registerEffect------------------------------------ } effect = chain->getEffectFromId_l(0); } return NO_ERROR; } // -----------------------------AudioFlinger::moveEffectChain_l----------------------------------- } // -----------------------------AudioFlinger::createTrack moveEffectChain_l----------------------------------- } LOGV("createEffect() got output %d for effect %s", output, desc.name); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGE("createEffect() unknown output thread"); lStatus = BAD_VALUE; goto Exit; } // TODO: allow attachment of effect to inputs wclient = mClients.valueFor(pid); if (wclient != NULL) { client = wclient.promote(); } else { client = new Client(this, pid); mClients.add(pid, client); } // create effect on selected output trhead handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus); if (handle != 0 && id != NULL) { *id = handle->id(); } // ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::createEffect_l++++++++++++++++++++++++++++++++++ // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( const sp<AudioFlinger::Client>& client, const sp<IEffectClient>& effectClient, int32_t priority, int sessionId, effect_descriptor_t *desc, int *enabled, status_t *status ) { sp<EffectModule> effect; sp<EffectHandle> handle; status_t lStatus; sp<Track> track; sp<EffectChain> chain; bool chainCreated = false; bool effectCreated = false; bool effectRegistered = false; if (mOutput == 0) { LOGW("createEffect_l() Audio driver not initialized."); lStatus = NO_INIT; goto Exit; } // Do not allow auxiliary effect on session other than 0 if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && sessionId != AudioSystem::SESSION_OUTPUT_MIX) { LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } // Do not allow effects with session ID 0 on direct output or duplicating threads // TODO: add rule for hw accelerated effects on direct outputs with non PCM format if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) { LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); { // scope for mLock Mutex::Autolock _l(mLock); // check for existing effect chain with the requested audio session chain = getEffectChain_l(sessionId); if (chain == 0) { // create a new chain for this session LOGV("createEffect_l() new effect chain for session %d", sessionId); chain = new EffectChain(this, sessionId); addEffectChain_l(chain); // +++++++++++++++++++++++++++AudioFlinger::PlaybackThread::addEffectChain_l+++++++++++++++++++++++++++++++++++++ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain) { int session = chain->sessionId(); int16_t *buffer = mMixBuffer; bool ownsBuffer = false; LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session); if (session > 0) { // Only one effect chain can be present in direct output thread and it uses // the mix buffer as input if (mType != DIRECT) { size_t numSamples = mFrameCount * mChannelCount; buffer = new int16_t[numSamples]; memset(buffer, 0, numSamples * sizeof(int16_t)); LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session); ownsBuffer = true; } // Attach all tracks with same session ID to this chain. for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> track = mTracks[i]; if (session == track->sessionId()) { LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer); track->setMainBuffer(buffer); } } // indicate all active tracks in the chain for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) { sp<Track> track = mActiveTracks[i].promote(); if (track == 0) continue; if (session == track->sessionId()) { LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session); chain->startTrack(); } } } chain->setInBuffer(buffer, ownsBuffer); chain->setOutBuffer(mMixBuffer); // Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect // chains list in order to be processed last as it contains output stage effects // Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before // session AudioSystem::SESSION_OUTPUT_STAGE to be processed // after track specific effects and before output stage // It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and // that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX // Effect chain for other sessions are inserted at beginning of effect // chains list to be processed before output mix effects. Relative order between other // sessions is not important size_t size = mEffectChains.size(); size_t i = 0; for (i = 0; i < size; i++) { if (mEffectChains[i]->sessionId() < session) break; } mEffectChains.insertAt(chain, i); return NO_ERROR; } // ---------------------------AudioFlinger::PlaybackThread::addEffectChain_l------------------------------------- chain->setStrategy(getStrategyForSession_l(sessionId)); chainCreated = true; } else { effect = chain->getEffectFromDesc_l(desc); } LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get()); if (effect == 0) { int id = mAudioFlinger->nextUniqueId(); // Check CPU and memory usage lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id); if (lStatus != NO_ERROR) { goto Exit; } effectRegistered = true; // create a new effect module if none present in the chain effect = new EffectModule(this, chain, desc, id, sessionId); lStatus = effect->status(); if (lStatus != NO_ERROR) { goto Exit; } lStatus = chain->addEffect_l(effect); if (lStatus != NO_ERROR) { goto Exit; } effectCreated = true; // ++++++++++++++++++++++++++++AudioFlinger::EffectModule::EffectModule++++++++++++++++++++++++++++++++++++ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread, const wp<AudioFlinger::EffectChain>& chain, effect_descriptor_t *desc, int id, int sessionId) : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL), mStatus(NO_INIT), mState(IDLE) { LOGV("Constructor %p", this); int lStatus; sp<ThreadBase> thread = mThread.promote(); if (thread == 0) { return; } PlaybackThread *p = (PlaybackThread *)thread.get(); memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t)); // create effect engine from effect factory // 这个函数在看函数queryEffects代码的时候已经接触过 mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface); if (mStatus != NO_ERROR) { return; } lStatus = init(); if (lStatus < 0) { mStatus = lStatus; goto Error; } LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); return; Error: EffectRelease(mEffectInterface); mEffectInterface = NULL; LOGV("Constructor Error %d", mStatus); } // ----------------------------AudioFlinger::EffectModule::EffectModule------------------------------------ effect->setDevice(mDevice); // +++++++++++++++++++++++++++AudioFlinger::EffectModule::setDevice+++++++++++++++++++++++++++++++++++++ status_t AudioFlinger::EffectModule::setDevice(uint32_t device) { Mutex::Autolock _l(mLock); status_t status = NO_ERROR; if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { // convert device bit field from AudioSystem to EffectApi format. device = deviceAudioSystemToEffectApi(device); if (device == 0) { return BAD_VALUE; } status_t cmdStatus; uint32_t size = sizeof(status_t); // 在EffectModule的构造函数中,调用函数EffectCreate对mEffectInterface进行赋值: // mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface); // 此处调用的command函数其实是调用的具体的effect lib中的command 函数 // 如EffectReverb 中的Reverb_Command函数。 status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus); if (status == NO_ERROR) { status = cmdStatus; } } return status; } // ---------------------------AudioFlinger::EffectModule::setDevice------------------------------------- effect->setMode(mAudioFlinger->getMode()); } // create effect handle and connect it to effect module handle = new EffectHandle(effect, client, effectClient, priority); lStatus = effect->addHandle(handle); if (enabled) { *enabled = (int)effect->isEnabled(); } } Exit: if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { Mutex::Autolock _l(mLock); if (effectCreated) { chain->removeEffect_l(effect); } if (effectRegistered) { AudioSystem::unregisterEffect(effect->id()); } if (chainCreated) { removeEffectChain_l(chain); } handle.clear(); } if(status) { *status = lStatus; } return handle; } // ------------------------------AudioFlinger::PlaybackThread::createEffect_l---------------------------------- } Exit: if(status) { *status = lStatus; } return handle; } // --------------------------AudioFlinger::createEffect-------------------------------------- mEnabled = (volatile int32_t)enabled; mIEffect = iEffect; cblk = iEffect->getCblk(); if (cblk == 0) { mStatus = NO_INIT; LOGE("Could not get control block"); return mStatus; } mIEffect = iEffect; mCblkMemory = cblk; mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer()); int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); mCblk->buffer = (uint8_t *)mCblk + bufOffset; iEffect->asBinder()->linkToDeath(mIEffectClient); LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled); return mStatus; } // -----------------------------AudioEffect::set----------------------------------- } // ----------------------------native AudioEffect------------------------------------ lStatus = translateError(lpAudioEffect->initCheck()); if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) { LOGE("AudioEffect initCheck failed %d", lStatus); goto setup_failure; } nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); if (nId == NULL) { LOGE("setup: Error retrieving id pointer"); lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; goto setup_failure; } nId[0] = lpAudioEffect->id(); env->ReleasePrimitiveArrayCritical(jId, nId, 0); nId = NULL; if (typeStr) { env->ReleaseStringUTFChars(type, typeStr); typeStr = NULL; } if (uuidStr) { env->ReleaseStringUTFChars(uuid, uuidStr); uuidStr = NULL; } // get the effect descriptor desc = lpAudioEffect->descriptor(); AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX); jdescType = env->NewStringUTF(str); AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX); jdescUuid = env->NewStringUTF(str); if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { jdescConnect = env->NewStringUTF("Auxiliary"); } else { jdescConnect = env->NewStringUTF("Insert"); } jdescName = env->NewStringUTF(desc.name); jdescImplementor = env->NewStringUTF(desc.implementor); jdesc = env->NewObject(fields.clazzDesc, fields.midDescCstor, jdescType, jdescUuid, jdescConnect, jdescName, jdescImplementor); env->DeleteLocalRef(jdescType); env->DeleteLocalRef(jdescUuid); env->DeleteLocalRef(jdescConnect); env->DeleteLocalRef(jdescName); env->DeleteLocalRef(jdescImplementor); if (jdesc == NULL) { LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); goto setup_failure; } env->SetObjectArrayElement(javadesc, 0, jdesc); env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect); env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage); return AUDIOEFFECT_SUCCESS; // failures: setup_failure: if (nId != NULL) { env->ReleasePrimitiveArrayCritical(jId, nId, 0); } if (lpAudioEffect) { delete lpAudioEffect; } env->SetIntField(thiz, fields.fidNativeAudioEffect, 0); if (lpJniStorage) { delete lpJniStorage; } env->SetIntField(thiz, fields.fidJniData, 0); if (uuidStr != NULL) { env->ReleaseStringUTFChars(uuid, uuidStr); } if (typeStr != NULL) { env->ReleaseStringUTFChars(type, typeStr); } return lStatus; } // -------------------------android_media_AudioEffect_native_setup--------------------------------------- if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { Log.e(TAG, "Error code " + initResult + " when initializing AudioEffect."); switch (initResult) { case ERROR_BAD_VALUE: throw (new IllegalArgumentException("Effect type: " + type + " not supported.")); case ERROR_INVALID_OPERATION: throw (new UnsupportedOperationException( "Effect library not loaded")); default: throw (new RuntimeException( "Cannot initialize effect engine for type: " + type + "Error: " + initResult)); } } mId = id[0]; mDescriptor = desc[0]; synchronized (mStateLock) { mState = STATE_INITIALIZED; } } // --------------------------------AudioEffect-------------------------------- assertNotNull(msg + ": could not create AudioEffect", effect); try { assertTrue(msg +": invalid effect ID", (effect.getId() != 0)); } catch (IllegalStateException e) { msg = msg.concat(": AudioEffect not initialized"); result = false; } finally { effect.release(); } } catch (IllegalArgumentException e) { msg = msg.concat(": Effect not found: "+desc[0].name); result = false; } catch (UnsupportedOperationException e) { msg = msg.concat(": Effect library not loaded"); result = false; } assertTrue(msg, result); }
###########################################################


&&&&&&&&&&&&&&&&&&&&&&&总结&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
在创建AudioEffect的时候:
1、如果指定了uuid,则会根据uuid 寻找匹配的effect lib来创建effect。
2、若没有指定uuid而指定了type,则会寻找相同type中可用的effect lib。
注意,如果session id为SESSION_OUTPUT_MIX,则优先使用auxiliary的effect。
在指定的type中没有可用的auxiliary的effect的情况下,才会使用insert的effect。

effect lib都被注册到一个列表中。
EffectsFactory中的init函数会将build-in的effect lib添加到该列表。
用户可以调用函数EffectLoadLibrary/EffectUnloadLibrary来注册/删除effect lib。


&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值