今天來看看如何將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對象中。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
摘自:江風的專欄