您的位置:首页 > 移动开发 > Android开发

Android Audio代码分析23 - attachAuxEffect函数

2011-10-20 21:43 513 查看
今天来看看如何将AudioEffect与AudioTrack关联起来。

*****************************************源码*************************************************
//Test case 1.7: test auxiliary effect attachement on AudioTrack
@LargeTest
public void test1_7AuxiliaryOnAudioTrack() throws Exception {
boolean result = false;
String msg = "test1_7AuxiliaryOnAudioTrack()";

try {
AudioTrack track = new AudioTrack(
AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT),
AudioTrack.MODE_STREAM);
assertNotNull(msg + ": could not create AudioTrack", track);
AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
AudioEffect.EFFECT_TYPE_NULL,
0,
0);

track.attachAuxEffect(effect.getId());
track.setAuxEffectSendLevel(1.0f);
result = true;
effect.release();
track.release();
} catch (IllegalArgumentException e) {
msg = msg.concat(": Equalizer not found");
loge(msg, ": Equalizer not found");
} catch (UnsupportedOperationException e) {
msg = msg.concat(": Effect library not loaded");
loge(msg, ": Effect library not loaded");
}
assertTrue(msg, result);
}


**********************************************************************************************

源码路径:

frameworks\base\media\tests\mediaframeworktest\src\com\android\mediaframeworktest\functional\MediaAudioEffectTest.java

#######################说明################################
//Test case 1.7: test auxiliary effect attachement on AudioTrack
@LargeTest
public void test1_7AuxiliaryOnAudioTrack() throws Exception {
boolean result = false;
String msg = "test1_7AuxiliaryOnAudioTrack()";

try {
AudioTrack track = new AudioTrack(
AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT),
AudioTrack.MODE_STREAM);
assertNotNull(msg + ": could not create AudioTrack", track);
AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
AudioEffect.EFFECT_TYPE_NULL,
0,
0);

// 此处getId获取的是调用JNI接口native_setup时得到的
track.attachAuxEffect(effect.getId());
// +++++++++++++++++++++++++++++attachAuxEffect+++++++++++++++++++++++++++++++++++
/**
* Attaches an auxiliary effect to the audio track. A typical auxiliary
* effect is a reverberation effect which can be applied on any sound source
* that directs a certain amount of its energy to this effect. This amount
* is defined by setAuxEffectSendLevel().
* {@see #setAuxEffectSendLevel(float)}.
* <p>After creating an auxiliary effect (e.g.
* {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
* {@link android.media.audiofx.AudioEffect#getId()} and use it when calling
* this method to attach the audio track to the effect.
* <p>To detach the effect from the audio track, call this method with a
* null effect id.
*
* @param effectId system wide unique id of the effect to attach
* @return error code or success, see {@link #SUCCESS},
*    {@link #ERROR_INVALID_OPERATION}, {@link #ERROR_BAD_VALUE}
*/
public int attachAuxEffect(int effectId) {
if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
return native_attachAuxEffect(effectId);
// ++++++++++++++++++++++++++++android_media_AudioTrack_attachAuxEffect++++++++++++++++++++++++++++++++++++
static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env,  jobject thiz,
jint effectId) {

AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
thiz, javaAudioTrackFields.nativeTrackInJavaObj);

if (lpTrack) {
return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
// ++++++++++++++++++++++++++++++AudioTrack::attachAuxEffect++++++++++++++++++++++++++++++++++
status_t AudioTrack::attachAuxEffect(int effectId)
{
LOGV("attachAuxEffect(%d)", effectId);
// mAudioTrack在函数AudioTrack::createTrack中被赋值,其最终指向的其实是一个TrackHandle对象
status_t status = mAudioTrack->attachAuxEffect(effectId);
// ++++++++++++++++++++++++++++++AudioFlinger::TrackHandle::attachAuxEffect++++++++++++++++++++++++++++++++++
status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)
{
return mTrack->attachAuxEffect(EffectId);
// ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::attachAuxEffect++++++++++++++++++++++++++++++++++
status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
{
status_t status = DEAD_OBJECT;
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
status = playbackThread->attachAuxEffect(this, EffectId);
// ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::attachAuxEffect++++++++++++++++++++++++++++++++++
status_t AudioFlinger::PlaybackThread::attachAuxEffect(
const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
{
Mutex::Autolock _l(mLock);
return attachAuxEffect_l(track, EffectId);
// +++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::attachAuxEffect_l+++++++++++++++++++++++++++++++++++
status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(
const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
{
status_t status = NO_ERROR;

// 如果EffectId为0,其实是清楚effect
if (EffectId == 0) {
track->setAuxBuffer(0, NULL);
// +++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::setAuxBuffer+++++++++++++++++++++++++++++++++++
void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer)
{
// 函数AudioFlinger::PlaybackThread::detachAuxEffect_l中调用了函数AudioFlinger::PlaybackThread::Track::auxEffectId来得到mAuxEffectId
mAuxEffectId = EffectId;
// 函数AudioFlinger::MixerThread::prepareTracks_l中会调用函数AudioFlinger::PlaybackThread::Track::auxBuffer获取mAuxBuffer
//            mAudioMixer->setParameter(
//                AudioMixer::TRACK,
//                AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());
mAuxBuffer = buffer;
}
// -----------------------------AudioFlinger::PlaybackThread::Track::setAuxBuffer-----------------------------------
} else {
// Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX
sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId);
// +++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::getEffect_l+++++++++++++++++++++++++++++++++++
sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
{
sp<EffectModule> effect;

// 先得到chain
sp<EffectChain> chain = getEffectChain_l(sessionId);
// ++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::getEffectChain_l++++++++++++++++++++++++++++++++++++
sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)
{
sp<EffectChain> chain;

size_t size = mEffectChains.size();
for (size_t i = 0; i < size; i++) {
if (mEffectChains[i]->sessionId() == sessionId) {
// 函数AudioFlinger::PlaybackThread::addEffectChain_l会向mEffectChains添加成员
// 函数AudioFlinger::PlaybackThread::createEffect_l和AudioFlinger::PlaybackThread::addEffect_l中,
// 会判断指定session Id对应的effect chain是否存在,若不存在,创建一个,并调用mEffectChains添加到mEffectChains中
chain = mEffectChains[i];
break;
}
}
return chain;
}
// ----------------------------AudioFlinger::PlaybackThread::getEffectChain_l------------------------------------
if (chain != 0) {
// 再根据effect Id从chain上得到effect
effect = chain->getEffectFromId_l(effectId);
// +++++++++++++++++++++++++++AudioFlinger::EffectChain::getEffectFromId_l+++++++++++++++++++++++++++++++++++++
// getEffectFromId_l() must be called with PlaybackThread::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)
{
sp<EffectModule> effect;
size_t size = mEffects.size();

for (size_t i = 0; i < size; i++) {
// by convention, return first effect if id provided is 0 (0 is never a valid id)
if (id == 0 || mEffects[i]->id() == id) {
// 函数AudioFlinger::EffectChain::addEffect_l会向mEffects中添加effect
// 函数AudioFlinger::PlaybackThread::createEffect_l和AudioFlinger::PlaybackThread::addEffect_l中,
// 会调用函数AudioFlinger::EffectChain::addEffect_l
effect = mEffects[i];
break;
}
}
return effect;
}
// ---------------------------AudioFlinger::EffectChain::getEffectFromId_l-------------------------------------
}
return effect;
}
// -----------------------------AudioFlinger::PlaybackThread::getEffect_l-----------------------------------
if (effect != 0) {
if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());
} else {
status = INVALID_OPERATION;
}
} else {
status = BAD_VALUE;
}
}
return status;
}
// -----------------------------AudioFlinger::PlaybackThread::attachAuxEffect_l-----------------------------------
}
// ------------------------------AudioFlinger::PlaybackThread::attachAuxEffect----------------------------------
}
return status;
}
// ------------------------------AudioFlinger::PlaybackThread::Track::attachAuxEffect----------------------------------
}
// ------------------------------AudioFlinger::TrackHandle::attachAuxEffect----------------------------------
if (status == NO_ERROR) {
mAuxEffectId = effectId;
}
return status;
}
// ------------------------------AudioTrack::attachAuxEffect----------------------------------
} else {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for attachAuxEffect()");
return AUDIOTRACK_ERROR;
}
}
// ----------------------------android_media_AudioTrack_attachAuxEffect------------------------------------
}
// -----------------------------attachAuxEffect-----------------------------------
track.setAuxEffectSendLevel(1.0f);
// +++++++++++++++++++++++++++++++setAuxEffectSendLevel+++++++++++++++++++++++++++++++++
/**
* Sets the send level of the audio track to the attached auxiliary effect
* {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
* <p>By default the send level is 0, so even if an effect is attached to the player
* this method must be called for the effect to be applied.
* <p>Note that the passed level value is a raw scalar. UI controls should be scaled
* logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
* so an appropriate conversion from linear UI input x to level is:
* x == 0 -> level = 0
* 0 < x <= R -> level = 10^(72*(x-R)/20/R)
*
* @param level send level scalar
* @return error code or success, see {@link #SUCCESS},
*    {@link #ERROR_INVALID_OPERATION}
*/
public int setAuxEffectSendLevel(float level) {
if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
// clamp the level
if (level < getMinVolume()) {
level = getMinVolume();
}
if (level > getMaxVolume()) {
level = getMaxVolume();
}
native_setAuxEffectSendLevel(level);
// ++++++++++++++++++++++++++++++android_media_AudioTrack_setAuxEffectSendLevel++++++++++++++++++++++++++++++++++
static void
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
{
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
if (lpTrack == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
return;
}

lpTrack->setAuxEffectSendLevel(level);
// +++++++++++++++++++++++++++++AudioTrack::setAuxEffectSendLevel+++++++++++++++++++++++++++++++++++
status_t AudioTrack::setAuxEffectSendLevel(float level)
{
LOGV("setAuxEffectSendLevel(%f)", level);
if (level > 1.0f) {
return BAD_VALUE;
}

mSendLevel = level;

// 函数AudioFlinger::MixerThread::prepareTracks_l中有使用mCblk->sendLevel
// va = (uint32_t)(v * cblk->sendLevel);
// aux = int16_t(va);
// mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux);
mCblk->sendLevel = uint16_t(level * 0x1000);

return NO_ERROR;
}
// -----------------------------AudioTrack::setAuxEffectSendLevel-----------------------------------
}
// ------------------------------android_media_AudioTrack_setAuxEffectSendLevel----------------------------------
return SUCCESS;
}
// -------------------------------setAuxEffectSendLevel---------------------------------
result = true;
effect.release();
track.release();
} catch (IllegalArgumentException e) {
msg = msg.concat(": Equalizer not found");
loge(msg, ": Equalizer not found");
} catch (UnsupportedOperationException e) {
msg = msg.concat(": Effect library not loaded");
loge(msg, ": Effect library not loaded");
}
assertTrue(msg, result);
}


###########################################################

&&&&&&&&&&&&&&&&&&&&&&&总结&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

attachAuxEffect最终会将effect 的in buffer赋值给track对象的auxBuffer。

setAuxEffectSendLevel会将send level保存到audio_track_cblk_t对象中。

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息