Android 触摸音的播放

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博客

posted @ 2023-05-23 18:19  xiaowang_lj  阅读(178)  评论(0编辑  收藏  举报