触摸按键音流程
前面简要的流程我们就不分析了,画了一下简要的流程图,由于我分析的源码具有特殊性,分为两条线路来看
第一部分
客制化实现按键音部分,也就是意味着加载资源和播放按键音是单独实现的。实际上是走外部音源调音的这条线路
第二部分
原生的按键音流程,后面会挑一些比较关键的流程分析记录一下
AudioService.java
我们看主要看下AudioService.java中的的流程
/** @see AudioManager#playSoundEffect(int, float) */
public void playSoundEffectVolume(int effectType, float volume) {
if (mUseDspEffect) {
final IAudioPolicyCallback extVolCtlr;
synchronized (mExtVolumeControllerLock) {
extVolCtlr = mExtVolumeController;
}
if(extVolCtlr != null) {
//MSG_NOTIFY_VOL_EVENT会发送到外部路由策略端(该部分实际是用于调节音量的流程)
sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
AudioManager.ADJUST_PLAY_EFFECT + effectType, 0 /*ignored*/,
extVolCtlr, 0 /*delay*/);
}else{d
Log.e(TAG, "AudioService playSoundEffectVolume failed for no ext Volume Controller found!");
}
return;
}
// do not try to play the sound effect if the system stream is muted
if (isStreamMutedByRingerOrZenMode(STREAM_SYSTEM)) {
return;
}
if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
return;
}
//Android原生的按键音流程
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
effectType, (int) (volume * 1000), null, 0);
}
我们主要看Android原生的按键音流程
private void onPlaySoundEffect(int effectType, int volume) {
synchronized (mSoundEffectsLock) {
onLoadSoundEffects(); //初始化资源文件、构造SoundPool
if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
volFloat, volFloat, 0, 0, 1.0f);
//使用soundpool实现按键音
} else {
//使用mediaPlayer播放按键音资源文件
}
}
}
简单的看下onLoadSoundEffects方法
private boolean onLoadSoundEffects() {
int status;
loadTouchSoundAssets(); //1、从framework/res 下的audio_assets.xml中,将id和按键音资源文件名解析后保存到SOUND_EFFECT_FILES_MAP 数组中。资源文件名保存到SOUND_EFFECT_FILES list中
//构造soundpool
mSoundPool = new SoundPool.Builder()
.setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
.build();
mSoundPoolCallBack = null;
mSoundPoolListenerThread = new SoundPoolListenerThread();
mSoundPoolListenerThread.start(); //启动一个soundpool load资源文件的线程
/*
* poolId table: The value -1 in this table indicates that corresponding
* file (same index in SOUND_EFFECT_FILES[] has not been loaded.
* Once loaded, the value in poolId is the sample ID and the same
* sample can be reused for another effect using the same file.
*/
//将poolId的每一位都设置为-1
int[] poolId = new int[SOUND_EFFECT_FILES.size()];
for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
poolId[fileIdx] = -1;
}
/*
* Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
* If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
* this indicates we have a valid sample loaded for this effect.
*/
//通过soundpool load system/media/audio/ui/下的每一个文件,load成功后,将poolId的每一位重新赋值。
int numSamples = 0;
for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
// Do not load sample if this effect uses the MediaPlayer
if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
continue;
}
if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
String filePath = getSoundEffectFilePath(effect);
int sampleId = mSoundPool.load(filePath, 0);
if (sampleId <= 0) {
Log.w(TAG, "Soundpool could not load file: "+filePath);
} else {
SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
numSamples++;
}
} else {
SOUND_EFFECT_FILES_MAP[effect][1] =
poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
}
}
// wait for all samples to be loaded
//所有的资源文件都成功的load完成,最后将soundpool release
if (numSamples > 0) {
mSoundPoolCallBack.setSamples(poolId);
attempts = 3;
status = 1;
while ((status == 1) && (attempts-- > 0)) {
try {
mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
status = mSoundPoolCallBack.status();
} catch (InterruptedException e) {
Log.w(TAG, "Interrupted while waiting sound pool callback.");
}
}
} else {
status = -1;
}
if (mSoundPoolLooper != null) {
mSoundPoolLooper.quit();
mSoundPoolLooper = null;
}
mSoundPoolListenerThread = null;
if (status != 0) {
Log.w(TAG,
"onLoadSoundEffects(), Error "+status+ " while loading samples");
for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
SOUND_EFFECT_FILES_MAP[effect][1] = -1;
}
}
mSoundPool.release();
mSoundPool = null;
}
}
return (status == 0);
}
onLoadSoundEffects load资源完成后,就可以通过soundpool play实现按键音了。
如果有兴趣了解SoundPool的同学可以点击这里