Android音频焦点详解(上)

转载请注明出处:http://www.cnblogs.com/landptf/p/6384112.html



2017年开年第一篇博客,很早就想总结一下Android音频的相关知识。
今天我们先来看一下音频焦点的相关内容,分为上下篇,上篇主要介绍音频焦点在媒体类应用中的使用,下篇进行源码分析,我们学习源码不仅仅是为了更深入的了解,更主要的目的是学习Android的设计架构,为我们在平时开发过程中提供一些优秀的设计思想。
一 焦点在Android应用中的作用
我们的手机里经常会安装一些媒体类的应用,例如网易云音乐,QQ音乐,爱奇艺视频,优酷视频等等,你有没有想过,当我们听QQ音乐的歌曲时,切换到网易云音乐播放歌曲,或者打开爱奇艺观看视频时,QQ音乐播放的歌曲就会暂停,这是为什么呢?又是如何实现的呢?如果不暂停会是什么效果呢?
以上这些疑问都可以用音频焦点来解释,在下面的内容中你将找到答案。
二 焦点讲解
众所周知Android是一个开放的系统,为了协调各媒体应用之间的关系,Android增加了音频焦点管理机制,各应用开发者应尽量遵循该机制进行开发。
我们通过一个例子来讲解Android的焦点机制。
新建一个Activity,在其中增加一个播放暂停按钮,来控制音乐播放。
看一下部分关键代码,全部代码在文末会给出

private void initData() {
        //1 初始化AudioManager对象
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        //2 申请焦点
        mAudioManager.requestAudioFocus(mAudioFocusChange, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        AssetFileDescriptor fileDescriptor;
        try {
            //3 获取音频文件,我从网上下载的歌曲,放到了assets目录下
            fileDescriptor = this.getAssets().openFd("littlelucky.mp3");
            //4 实例化MediaPlayer对象
            mMediaPlayer = new MediaPlayer();
            //5 设置播放流类型
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            //6 设置播放源,有多个参数可以选择,具体参考相关文档,本文旨在介绍音频焦点
            mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
                    fileDescriptor.getStartOffset(),
                    fileDescriptor.getLength());
            //7 设置循环播放
            mMediaPlayer.setLooping(true);
            //8 准备监听
            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    //9 准备完成后自动播放
                    mMediaPlayer.start();
                }
            });
            //10 异步准备
            mMediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

涉及到的MediaPlayer播放音乐流程请自行查询相关文档,不在本文介绍范围
我们重点看一下第2步 申请焦点
通过AudioManager对象调用requestAudioFocus方法,有三个参数
OnAudioFocusChangeListener l,int streamType,int durationHint
1 焦点变化的监听器

private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange){
                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;
                case AudioManager.AUDIOFOCUS_GAIN:
                    //当其他应用申请焦点之后又释放焦点会触发此回调
                    //可重新播放音乐
                    Log.d(TAG, "AUDIOFOCUS_GAIN");
                    start();
                    break;
            }
        }
    };

 2 streamType音源类型,在AudioManager中定义

/** 通话 */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** 系统声音 */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
/** 铃声 */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
/** 音乐 */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
/** 闹铃声 */
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
/** 通知音 */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide 蓝牙电话 */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** @hide 强制的系统声音 */
public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
/** DTMF拨号音 */
public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
/** @hide 文本识别音 */
public static final int STREAM_TTS = AudioSystem.STREAM_TTS;

3 durationHint 获得焦点的时间长短
在AudioManager中定义了四种类型

AUDIOFOCUS_GAIN //长时间获得焦点
AUDIOFOCUS_GAIN_TRANSIENT //短暂性获得焦点,用完应立即释放
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK //短暂性获得焦点并降音,可混音播放
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE //短暂性获得焦点,录音或者语音识别

我们可根据自己的应用的使用场景来合理的配置每个参数,并在焦点变化监听器来做相应的处理。
调试代码已上传github:https://github.com/landptf/BlogDemo

原文地址:https://www.cnblogs.com/landptf/p/6384112.html