Android MediaPlayer 声音渐强渐弱效果实现

Android MediaPlayer 声音渐强渐弱效果实现

1.需求描述

最近公司产品需要提高用户体验:当播放语音消息时,如果当前正在播放其他音频文件,则有一个声音逐渐降低直至暂停的效果;当播放语音消息完成后,则恢复先前的音频,继续播放,且有一个声音逐渐增大到原先音量的效果。

2.解决方案

在网上 Google 了一下,方法都是一样的:创建一个线程,不断循环逐步调节系统音量到最低,然后停止播放,核心代码大概长这样:

final int volume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM);
new Thread(){
    @Override
    public void run() {
        super.run();
        for (int i=1; i<= volume; i++) {
            audioManager.setStreamVolume(AudioManager.STREAM_ALARM, i, 0);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}.start();

我们觉得这套方案不够高效,可以稍微变通一下:不需要调用系统的 setStreamVolume() 方法,是直接调用 MediaPlayer 自带的 setVolume() 方法调节音量,使用系统自带的定时器 CountDownTimer 实现循环调节音量大小。
核心代码大概是这样:

//渐强的时长,单位:毫秒;默认2秒
final long duration = 2000;
//音量调节的时间间隔
long interval = duration / 10;
new CountDownTimer(duration, interval){

    @Override
    public void onTick(long millisUntilFinished) {
        float volume = 1f - millisUntilFinished * 1.0f / duration;
        mediaPlayer.setVolume(volume, volume);
    }

    @Override
    public void onFinish() {
        mediaPlayer.setVolume(1f, 1f);
    }
}.start();

抱歉,最近一直在使用kotlin,即使现在也是半灌水,但 java 也不太习惯了,泪崩啊~~,下面是 kotlin 版本的代码:

/**
 * 声音渐弱
 *
 * @param duration  渐弱的时长,单位:毫秒;默认2秒
 * @param completed 完成回调
 */
fun fadeIn(duration: Long = 2000, completed: () -> Unit = {}) {
    object : CountDownTimer(duration, duration / 10) {
        override fun onFinish() {
            mediaPlayer?.setVolume(0f, 0f)
            mediaPlayer?.pause()
            completed()
        }

        override fun onTick(millisUntilFinished: Long) {
            val volume = millisUntilFinished * 1.0f / duration
            mediaPlayer?.setVolume(volume, volume)
            info("player controller fade in volume = $volume")
        }
    }.start()
}

/**
 * 声音渐强
 *
 * @param duration  渐强的时长,单位:毫秒;默认2秒
 * @param completed 完成回调
 */
fun fadeOut(duration: Long = 2000, completed: () -> Unit = {}) {
    object : CountDownTimer(duration, duration / 10) {
        override fun onFinish() {
            mediaPlayer?.setVolume(1f, 1f)
            completed()
        }

        override fun onTick(millisUntilFinished: Long) {
            val volume = 1f - millisUntilFinished * 1.0f / duration
            mediaPlayer?.setVolume(volume, volume)
        }
    }.start()
    mediaPlayer?.start()
}

这里需要解释一下 MediaPlayer 自带的音量设置方法 setVolume() 中的参数问题:android 系统将音量从 [0~当前音量] 缩放(scale)到 [0f~1f] 的区间,所以设置音量的参数也是从 0 到 1,最大音量为当前系统音量。

3.总结

虽然代码很简单,但是还是很费心思的,希望大家都来围观,从此养成写 blog 的好习惯。

你可能感兴趣的:(Android)