//总结一下effect和track的关联:
//1、全局类型的effect和track的创建无关,可以根据固定的规则查找线程,然后构造effect
// 当需要使用时,可以根据全局sessionId进行查找,然后将其移到track所在的线程
//2、非全局类型的effect
// 2.1、先有effect时,如果没有找到sessionId对应的track或者effect所在的线程,
// 表示该track没有建立,默认在第一个线程中创建effect,当创建track之后,
// 将根据sessionId查找到该effect所在的Chain,然后将其移到track所在的线程
// 2.2、已有track时,再创建effec比较简单,会根据track的sessionId找到track所在的线程,
// 然后在该线程中创建effect
//补充:根据采样率、流类型等参数可以确定track所在的线程,而根据track生成的sessionId
// 可以确定effect所在的线程,由此可以看出一般来说都是先有track,对应的effect
// 当然全局性的effect除外
// 支持的effect类型
#define EFFECT_FLAG_TYPE_INSERT (0 << EFFECT_FLAG_TYPE_SHIFT)
#define EFFECT_FLAG_TYPE_AUXILIARY (1 << EFFECT_FLAG_TYPE_SHIFT)
#define EFFECT_FLAG_TYPE_REPLACE (2 << EFFECT_FLAG_TYPE_SHIFT)
#define EFFECT_FLAG_TYPE_PRE_PROC (3 << EFFECT_FLAG_TYPE_SHIFT)
#define EFFECT_FLAG_TYPE_POST_PROC (4 << EFFECT_FLAG_TYPE_SHIFT)
/*参数type是要创建的effect的类型。标准的类型已经在AudioEffect类中定义了,可以直接使用
若要使用其他的类型,需要提供OpenSLES interface ID,并且在平台中存在该类型
若指定的类型不存在,则会抛出IllegalArgumentException异常
若type为EFFECT_TYPE_NULL,则只会根据uuid来选择effect
参数uuid用于指定一个特定effect的实现。
若uuid为EFFECT_TYPE_NULL,则只会根据type来选择effect
参数priority是优先级,会根据优先级来判断effect engine的控制权
参数audioSession,相同audioSession ID的AudioTrack和MediaPlayer共享Audio Effect
*/
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);
....
mId = id[0];
mDescriptor = desc[0];
synchronized (mStateLock) {
mState = STATE_INITIALIZED;
}
}
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)
{
ALOGV("android_media_AudioEffect_native_setup");
....
// create the native AudioEffect object
// 在index为0的线程中创建effect对象
lpAudioEffect = new AudioEffect(typeStr,
uuidStr,
priority,
effectCallback,
&lpJniStorage->mCallbackData,
sessionId,
0);
lStatus = translateError(lpAudioEffect->initCheck());
if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
ALOGE("AudioEffect initCheck failed %d", lStatus);
goto setup_failure;
}
....
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");
}
....
return AUDIOEFFECT_SUCCESS;
setup_failure:
return lStatus;
}
AudioEffect::AudioEffect(const char *typeStr,
const char *uuidStr,
int32_t priority,
effect_callback_t cbf,
void* user,
int sessionId,
audio_io_handle_t io
)
: mStatus(NO_INIT)
{
....
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,
int sessionId,
audio_io_handle_t io)
{
sp<IEffect> iEffect;
sp<IMemory> cblk;
int enabled;
.....
mPriority = priority;
mCbf = cbf;
mUserData = user;
mSessionId = sessionId;
// 构造effect的描述对象,UUID和TYPE的默认值为EFFECT_UUID_NULL
// 如果都是默认值,则构造effect对象失败
memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
mIEffectClient = new EffectClient(this);
//构造Effect之后返回EffectHandle
iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
ALOGE("set(): AudioFlinger could no
Audio笔记之AudioEffect
最新推荐文章于 2022-05-16 21:13:53 发布
本文详细介绍了Android中AudioEffect的使用,包括全局和非全局类型的效果与音轨的关联,以及创建和查找效果的过程。重点讲解了如何根据sessionId和effect的类型确定其所在线程,以及如何在正确的位置创建和移动效果。
摘要由CSDN通过智能技术生成