1.源码路径 frameworks\base\services\core\java\com\android\server\audio\AudioService.java.
AudioService
//========================================================================================== // Sound Effects //========================================================================================== private static final class LoadSoundEffectReply implements SoundEffectsHelper.OnEffectsLoadCompleteHandler { private static final int SOUND_EFFECTS_LOADING = 1; private static final int SOUND_EFFECTS_LOADED = 0; private static final int SOUND_EFFECTS_ERROR = -1; private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000; private int mStatus = SOUND_EFFECTS_LOADING; @Override public synchronized void run(boolean success) { mStatus = success ? SOUND_EFFECTS_LOADED : SOUND_EFFECTS_ERROR; notify(); } public synchronized boolean waitForLoaded(int attempts) { while ((mStatus == SOUND_EFFECTS_LOADING) && (attempts-- > 0)) { try { wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS); } catch (InterruptedException e) { Log.w(TAG, "Interrupted while waiting sound pool loaded."); } } return mStatus == SOUND_EFFECTS_LOADED; } } /** @see AudioManager#playSoundEffect(int) */ public void playSoundEffect(int effectType) { playSoundEffectVolume(effectType, -1.0f); } /** @see AudioManager#playSoundEffect(int, float) */ public void playSoundEffectVolume(int effectType, float volume) { // do not try to play the sound effect if the system stream is muted if (isStreamMute(STREAM_SYSTEM)) { return; } if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) { Log.w(TAG, "AudioService effectType value " + effectType + " out of range"); return; } sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE, effectType, (int) (volume * 1000), null, 0); }
发送msg交给handler处理
case MSG_PLAY_SOUND_EFFECT: mSfxHelper.playSoundEffect(msg.arg1, msg.arg2); break; mSfxHelper是SoundEffectsHelper 的实例 @NonNull private SoundEffectsHelper mSfxHelper; frameworks\base\services\core\java\com\android\server\audio\SoundEffectsHelper.java /*package*/ void playSoundEffect(int effect, int volume) { sendMsg(MSG_PLAY_EFFECT, effect, volume, null, 0); }
private class SfxHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_LOAD_EFFECTS: onLoadSoundEffects((OnEffectsLoadCompleteHandler) msg.obj); break; case MSG_UNLOAD_EFFECTS: onUnloadSoundEffects(); break; case MSG_PLAY_EFFECT: final int effect = msg.arg1, volume = msg.arg2; onLoadSoundEffects(new OnEffectsLoadCompleteHandler() { @Override public void run(boolean success) { if (success) { onPlaySoundEffect(effect, volume); } } }); break; case MSG_LOAD_EFFECTS_TIMEOUT: if (mSoundPoolLoader != null) { mSoundPoolLoader.onTimeout(); } break; } } }
播放策略
void onPlaySoundEffect(int effect, int volume) { float volFloat; // use default if volume is not specified by caller if (volume < 0) { volFloat = (float) Math.pow(10, (float) mSfxAttenuationDb / 20); } else { volFloat = volume / 1000.0f; } Resource res = mResources.get(mEffects[effect]); if (mSoundPool != null && res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && res.mLoaded) { mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f); } else { MediaPlayer mediaPlayer = new MediaPlayer(); try { String filePath = getResourceFilePath(res); mediaPlayer.setDataSource(filePath); mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); mediaPlayer.prepare(); mediaPlayer.setVolume(volFloat); mediaPlayer.setOnCompletionListener(new OnCompletionListener() { public void onCompletion(MediaPlayer mp) { cleanupPlayer(mp); } }); mediaPlayer.setOnErrorListener(new OnErrorListener() { public boolean onError(MediaPlayer mp, int what, int extra) { cleanupPlayer(mp); return true; } }); mediaPlayer.start(); } catch (IOException ex) { Log.w(TAG, "MediaPlayer IOException: " + ex); } catch (IllegalArgumentException ex) { Log.w(TAG, "MediaPlayer IllegalArgumentException: " + ex); } catch (IllegalStateException ex) { Log.w(TAG, "MediaPlayer IllegalStateException: " + ex); } } }
SoundEffectsHelper(Context context) { mContext = context; mSfxAttenuationDb = mContext.getResources().getInteger( com.android.internal.R.integer.config_soundEffectVolumeDb); startWorker(); }
frameworks\base\core\res\res\values\config.xml <!-- The attenuation in dB applied to the sound effects played through AudioManager.playSoundEffect() when no volume is specified. --> <integer name="config_soundEffectVolumeDb">-6</integer>
通常调用SoundPool.load来加载某个音频文件,获得一个音效id,然后就可以用play方法来播放。
SoundPool的play方法原型如下:
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate);
play方法第二、三个参数用于指定左右声道的音量,取值范围是0.0~1.0。这里要说的就是这个音量值与系统音量的关系。
(356条消息) Android SoundPool.play方法的音量与系统音量的关系_foruok的博客-CSDN博客