zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    三目运算符
    程序流程结构——if语句
    类型转换
    运算符
    scanf函数与getchar函数
    结构体成员有冒号 位域 位段
    AI作曲的一个点子
    《惯性导航》邓正隆 第一章 惯性导航的基础知识
    《C陷阱与缺陷》 第0章导读 第1章词法陷阱
    类与类之间的关系 18
  • 原文地址:https://www.cnblogs.com/landptf/p/6384112.html
Copyright © 2011-2022 走看看