前面我们对AcousticEchoCanceler进行了相关的分析,在http://androidxref.com/7.1.2_r36/ 与目前学习的项目中均未实现AcousticEchoCanceler功能,因此我们接下来的分析需要假设该类库存在的情况下进行分析。我们快速的定位到AcousticEchoCanceler.setEnabled(Boolean);
进行分析。依据
/frameworks/base/media/java/android/media/audiofx/AcousticEchoCanceler.java
中,setEnabled
具体实现需要阅读AudioEffect
类。构造函数AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
中对构造函数示意如下:
#type 音效引擎类型,这里传过来的是EFFECT_TYPE_AEC
#uuid 特定效果实现的唯一标识符,这里传递过来的是EFFECT_TYPE_NULL
#priority 应用程序请求的优先级控制效果引擎。同样的效果引擎可以由多个应用程序共享,此参数表示请求的应用程序需要多少效果控制参数。正常优先级为0,高于正常优先级为a正数,低于正常值为负数,这里传递过来的是0
我们粗略的看一下构造方法,其中比较核心的流程如下
{
...
//将一些参数传递给jni层
int initResult = native_setup(new WeakReference<AudioEffect>(this), type.toString(), uuid.toString(), priority, audioSession, id,desc, ActivityThread.currentOpPackageName());
...
}
此时再来查看一下我们比较关心的setEnabled
方法。
public int setEnabled(boolean enabled) throws IllegalStateException {
checkState("setEnabled()");
return native_setEnabled(enabled);
}
依据JNI相关规则我们定位到
/frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
源码中通过显式注册native_setup
对应到了android_media_AudioEffect_native_setup
函数,native_setEnabled
对应到了android_media_AudioEffect_native_setEnabled
。我们来快速过一遍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, jstring opPackageName)
{
AudioEffectJniStorage* lpJniStorage = NULL;
int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
sp<AudioEffect> lpAudioEffect;
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;
ScopedUtfChars opPackageNameStr(env, opPackageName);
setAudioEffect(env, thiz, 0);
typeStr = env->GetStringUTFChars(type, NULL);
uuidStr = env->GetStringUTFChars(uuid, NULL);
lpJniStorage = new AudioEffectJniStorage();
lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
//弱引用,对象摧毁时进行垃圾回收
lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
//创建native AudioEffect 对象
lpAudioEffect = new AudioEffect(typeStr,
String16(opPackageNameStr.c_str()),
uuidStr,
priority,
effectCallback,
&lpJniStorage->mCallbackData,
(audio_session_t) sessionId,
0);
//检查AudioEffect初始化状态
lStatus = translateError(lpAudioEffect->initCheck());
nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
nId[0] = lpAudioEffect->id();
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
//获取描述信息
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 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
jdescConnect = env->NewStringUTF("Pre Processing");
} 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->SetObjectArrayElement(javadesc, 0, jdesc);
setAudioEffect(env, thiz, lpAudioEffect);
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
return (jint) AUDIOEFFECT_SUCCESS;
}
因此我们可以确定核心代码是AudioEffectJniStorage
和AudioEffect
对象的创建。我们来看一下这几个对象的描述:
#AudioEffectJniStorage 一个辅助类,用于共享内存的访问,将调用者传递给了AudioEffect对象
#AudioEffect 音效对象
其中其主要目的是对AudioEffect对象初始化,并且调用了AudioEffect的initCheck方法获取状态。
在AudioEffect构造函数中
/frameworks/av/media/libmedia/AudioEffect.cpp
AudioEffect::AudioEffect(const char *typeStr,const String16& opPackageName,const char *uuidStr,int32_t priority,
effect_callback_t cbf,
void* user,
audio_session_t sessionId,
audio_io_handle_t io
): mStatus(NO_INIT), mOpPackageName(opPackageName)
{
....
mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
....
}
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)
{
...
mIEffectClient = new EffectClient(this);
iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,mIEffectClient, priority, io, mSessionId, mOpPackageName, &mStatus, &mId, &enabled);
...
return mStatus;
}
status_t AudioEffect::initCheck() const
{
return mStatus;
}
因此创建"Effect"的任务交给了audioFlinger,initCheck只是检查了创建"Effect"的状态码。
/frameworks/av/services/audioflinger/AudioFlinger.cpp
sp<IEffect> AudioFlinger::createEffect(
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
audio_io_handle_t io,
audio_session_t sessionId,
const String16& opPackageName,
status_t *status,
int *id,
int *enabled)
{
....
sp<EffectHandle> handle;
ThreadBase *thread = checkRecordThread_l(io);
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
&desc, enabled, &lStatus, pinned);
...
return handle;
}
接着我们来跟踪createEffect_l
代码
/frameworks/av/services/audioflinger/Threads.cpp
精简后代码如下
sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority,
audio_session_t sessionId,
effect_descriptor_t *desc,
int *enabled,
status_t *status,
bool pinned)
{
sp<EffectModule> effect;
sp<EffectHandle> handle;
status_t lStatus;
sp<EffectChain> chain;
{ // scope for 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
ALOGV("createEffect_l() new effect chain for session %d", sessionId);
chain = new EffectChain(this, sessionId);
addEffectChain_l(chain);
chain->setStrategy(getStrategyForSession_l(sessionId));
} else {
effect = chain->getEffectFromDesc_l(desc);
}
if (effect == 0) {
audio_unique_id_t id = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
// Check CPU and memory usage
lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
// create a new effect module if none present in the chain
lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);
effect->setDevice(mOutDevice);
effect->setDevice(mInDevice);
effect->setMode(mAudioFlinger->getMode());
effect->setAudioSource(mAudioSource);
}
// create effect handle and connect it to effect module
handle = new EffectHandle(effect, client, effectClient, priority);
lStatus = handle->initCheck();
if (lStatus == OK) {
lStatus = effect->addHandle(handle.get());
}
if (enabled != NULL) {
*enabled = (int)effect->isEnabled();
}
}
*status = lStatus;
return handle;
}
参阅网上相关资料我们需要跟踪chain->createEffect_l
函数
/frameworks/av/services/audioflinger/Effects.cpp
status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect,
ThreadBase *thread,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
{
...
effect = new EffectModule(thread, this, desc, id, sessionId, pinned);
status_t lStatus = effect->status();
...
return lStatus;
}
跟踪new EffectModule
frameworks/av/services/audioflinger/Effects.cpp
AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
const wp<AudioFlinger::EffectChain>& chain,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
: mPinned(pinned),
mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
mDescriptor(*desc),
// mConfig is set by configure() and not used before then
mEffectInterface(NULL),
mStatus(NO_INIT), mState(IDLE),
// mMaxDisableWaitCnt is set by configure() and not used before then
// mDisableWaitCnt is set by process() and updateState() and not used before then
mSuspended(false),
mAudioFlinger(thread->mAudioFlinger)
{
..
mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
...
}
EffectCreate
函数由工厂类EffectsFactory.c
提供
frameworks/av/media/libeffects/factory/EffectsFactory.c
int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
{
list_elem_t *e = gLibraryList;
lib_entry_t *l = NULL;
effect_descriptor_t *d = NULL;
effect_handle_t itfe;
effect_entry_t *fx;
int found = 0;
int ret;
ret = init();
//再配置文件中进行匹配
ret = findEffect(NULL, uuid, &l, &d);
if (ret < 0){
// Sub effects are not associated with the library->effects,
// so, findEffect will fail. Search for the effect in gSubEffectList.
ret = findSubEffect(uuid, &l, &d);
if (ret < 0 ) {
goto exit;
}
}
// create effect in library
ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
...
return ret;
}
这里的xxx->create_effect
,在后面提到的AUDIO_EFFECT_LIBRARY_INFO_SYM
结构体中进行配置。