android释放焦点_Android音频焦点与声音重叠

音视频播放在手机日常使用中非常频繁,当我们听着音乐刷着微博时,看到有趣的视频点击开始播放,音乐自动暂停,退出视频时音乐又自动恢复了播放(如果没有自动恢复的话,比如QQ音乐就会提示是否设置中断后继续播放)。

AAffA0nNPuCLAAAAAElFTkSuQmCC

这一系列流畅自然的操作不是理所应当的吗~当然如果处理不好的话就会出现声音重叠,音频焦点长期被占用的问题,下面我们来看看具体的功能逻辑。

音频焦点相关的讲解参考以下文章

Managing Audio Focus

不同的APP可以同时播放音频,系统会将他们混合在一起,但为了避免同时播放,Android提供了audio focus机制来合理使用音频播放资源。同一时间只能有一个APP获取音频焦点,当需要播放音频时,应该立即请求音频焦点,同样的,在你的APP获取到音频焦点后,其他APP也可以抢占音频焦点,这时你的APP就需要暂停播放或降低声音。音频焦点是合作类型的,APP拥有完全自主的控制权,系统无法阻止,但应用应该遵守音频焦点的指导规则。

好的音频APP在播放时应该遵守以下规则:

开始播放后立即调用requestAudioFocus()方法,并验证返回值为AUDIOFOCUS_REQUEST_GRANTED

当其他app占用音频焦点时,暂停或停止播放,或者降低声音

当播放停止时,放弃音频焦点

在不同的Android版本下,需要使用不同的方法来处理音频焦点:

API level 8以后,使用requestAudioFocus()和abandonAudioFocus()方法,并注册AudioManager.OnAudioFocusChangeListener接收回调。

API level 21以后,需要使用AudioAttributes来描述播放音频的类型。

API level 26以后,需要使用AudioFocusRequest参数,它携带了音频的context和相关功能,系统会根据这些自动管理音频焦点。

具体实现

处理音频焦点问题主要是处理onAudioFocusChange方法:

private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {

@Override

public void onAudioFocusChange(int focusChange) {

switch (focusChange){

case AudioManager.AUDIOFOCUS_GAIN:

//当其他应用申请焦点之后又释放焦点会触发此回调

//可重新播放音乐

Log.d(TAG, "AUDIOFOCUS_GAIN");

start();

break;

case AudioManager.AUDIOFOCUS_LOSS:

//长时间丢失焦点,当其他应用申请的焦点为AUDIOFOCUS_GAIN时,

//会触发此回调事件,例如播放QQ音乐,网易云音乐等

//通常需要暂停音乐播放,若没有暂停播放就会出现和其他音乐同时输出声音

Log.d(TAG, "AUDIOFOCUS_LOSS");

stop();

//释放焦点,该方法可根据需要来决定是否调用

//若焦点释放掉之后,将不会再自动获得

mAudioManager.abandonAudioFocus(mAudioFocusChange);

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:

//短暂性丢失焦点,当其他应用申请AUDIOFOCUS_GAIN_TRANSIENT或AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE时,

//会触发此回调事件,例如播放短视频,拨打电话等。

//通常需要暂停音乐播放

stop();

Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:

//短暂性丢失焦点并作降音处理

Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");

break;

}

}

};

Android8.0以前

参考官方文档获取焦点的方法如下:

// Request audio focus for playback

int result = am.requestAudioFocus(afChangeListener,

// Use the music stream.

AudioManager.STREAM_MUSIC,

// Request permanent focus.

AudioManager.AUDIOFOCUS_GAIN);

但在听音乐的时候播放音频或视频,依旧出现了重叠的声音,实际上有效的做法是这样的

//下面两个常量参数试过很多 都无效,最终反编译了其他app才搞定,汗~

int requestFocusResult = mAudioManager.requestAudioFocus(

mAudioFocusChangeListener,

AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

最后在对应的播放状态下获取和释放音频焦点。

Android8.0之后

在Android8.0中一样使用了requestAudioFocus()来请求音频焦点,不一样的是,使用abandonAudioFocusRequest()释放音频焦点,请求和释放都需要传入同一个AudioFocusRequest实例。使用AudioFocusRequest.Builder来创建,具体实现代码参考官方文档Audio focus in Android 8.0 and later。

mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)

.setAudioAttributes(new AudioAttributes.Builder()

.setUsage(AudioAttributes.USAGE_MEDIA)

.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)

.build())

.setAcceptsDelayedFocusGain(true)

.setOnAudioFocusChangeListener(mAudioFocusChangeListener)

.build();

//请求音频焦点

requestFocusResult = mAudioManager.requestAudioFocus(mAudioFocusRequest);

//释放音频焦点

abandonFocusResult = mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);

注意事项:

Android8.0中其他APP使用AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK参数获取焦点时,将不会回调本APP的onAudioFocusChange()方法。

焦点延迟获取,当焦点被其他APP“锁”住时,requestAudioFocus()会返回AUDIOFOCUS_REQUEST_FAILED,比如正在打电话时,焦点就会被锁住。如果使用了setAcceptsDelayedFocusGain(true)方法,请求将会返回AUDIOFOCUS_REQUEST_DELAYED,在锁解除后,系统会继续处理未完成的焦点请求,并回调onAudioFocusChange()方法。

最后

音频相关的API常常让人疑惑,明明已经根据注释的描述和官方文档中的方法实现了,却达不到预期的效果。还有就是随着Android更新的推广越来越快,高版本API也在随时发生变化,在的适配时需要注意这些细节,以及进行完善的测试。

未完成内容

源码简单分析

在不同机型中进行测试

你可能感兴趣的:(android释放焦点)