zoukankan      html  css  js  c++  java
  • Android如何判断当前手机是否正在播放音乐,并获取到正在播放的音乐的信息*

    我想实现如下的场景,判断当前Android手机上是否正在播放音乐,如果是,通过某个特定的手势,

    或者点击某个按键,将当前我正在听的音乐共享出去。

    第一步,就是判断当前是否有音乐正在播放。

    最开始我想得有点复杂,以为要深入framework或更下层去做手脚才行,找了一下资料,发现AudioManager对外暴露了接口。

      isMusicActive()  

    通过这个接口就可以判断当前系统是否有音乐在播放了。

    还有一个问题,如果我想在音乐一开始就已经播放的时候,就知道这个事件,以便进行特殊的处理。

    再进一步看一下 AudioManager 的源码,发现其中有如下方法:

      public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)  

    从字面意思来看:请求音频焦点,再看这个函数的返回值:

        /** 
         * A failed focus change request. 
         */  
        public static final int AUDIOFOCUS_REQUEST_FAILED = 0;  
        /** 
         * A successful focus change request. 
         */  
        public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;  

    Managing Audio Focus

    管理音频焦点

    多个应用都在播放音频的可能性,所以考虑应用间如何交互非常重要。为避免每个音乐应用同时播放,Android使用音频焦点来协调音频的播放----只有获取到音频焦点的应用可以播放音频。

    在你的应用开始播放音频之前,它应该先请求--并接收音频焦点。同样,它也应该知道当监听到失去音频焦点后如何合理地进行响应。

    沿着这个路应该是对的,写了下面的测试代码进行验证。这个主要是Service的实现,你还需要实现一个Activity去启动Service、结束Service:

    public class MainService extends Service {
        private static final String TAG = "MainService";
    
        private MediaPlayer player;
    
        private AudioManager mAm;
    
        private MyOnAudioFocusChangeListener mListener;
    
        @Override
        public void onCreate() {
            Log.i(TAG, "onCreate");
    
            player = MediaPlayer.create(this, R.raw.test); // 在res目录下新建raw目录,复制一个test.mp3文件到此目录下。
            player.setLooping(false);
    
            mAm = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
            mListener = new MyOnAudioFocusChangeListener();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onStart(Intent intent, int startid) {
            Toast.makeText(this, "My Service Start", Toast.LENGTH_LONG).show();
            Log.i(TAG, "onStart");
    
            // Request audio focus for playback
            int result = mAm.requestAudioFocus(mListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    
            if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                Log.i(TAG, "requestAudioFocus successfully.");
    
                // Start playback.
                player.start();
            } else {
                Log.e(TAG, "requestAudioFocus failed.");
            }
        }
    
        @Override
        public void onDestroy() {
            Toast.makeText(this, "My Service Stoped", Toast.LENGTH_LONG).show();
            Log.i(TAG, "onDestroy");
            player.stop();
    
            mAm.abandonAudioFocus(mListener);
        }
    
        private class MyOnAudioFocusChangeListener implements OnAudioFocusChangeListener {
            @Override
            public void onAudioFocusChange(int focusChange) {
                Log.i(TAG, "focusChange=" + focusChange);
            }
        }
    }

    和 天天动听 结合起来测试,先打开天天动听播放音乐,再启动这个Service,发现天天动听自动暂停,再停止这个Service,天天动听又开始播放了。
    反过来,我先启动这个Service,再播放、暂停天天动听,“Log.i(TAG, "focusChange=" + focusChange);” 这个确实有输出日志。
    主流的音乐播放器,都遵循此规则的,所以通过使用Android的这个机制,我们就可以监控音乐的播放了。
    还有一个问题,如何知道当前播放的音乐信息呢?两个思路:
    1、通过在后台自动截取音频流的输出,通过服务器进行听歌识曲;
    2、通过在SystemUI中拦截主流音乐播放器的通知;
    第1个思路,从原理上是可行的,但是实现起来难度比较大,而且严重依赖网络;
    还是先来分析一下第2个思路。
    先找主流的Android音乐播放器来做个简单地测试,比如:天天动听、QQ音乐、酷狗音乐、酷我音乐、百度音乐等,在播放过程中,都会向状态栏中发一个Notification消息,其中已经包含歌曲信息。那我只需要做一个特殊的拦截并进行包名匹配,就可以获取正在播放的音乐了。
    具体思路如下:
    1、实现一个服务,这个服务在Android手机启动时,自动运行起来,通过 AudioManager.requestAudioFocus() 获取音频焦点,但什么事都不干,只为有其它音乐播放器开始运行时,得到一个通知消息;
    2、修改SystemUI,当主流音乐播放器发Notification到状态栏时,从中获取到音乐信息;
    3、步骤1的Listener就可以集成到SystemUI中,这样当音乐焦点被其它音乐播放器抢走后,再结合最近收到的Notification通知,这样更准确一些;
    这样,基本上就可以实现我们想要的场景了。

  • 相关阅读:
    JDK1.8源码之HashMap(一)——实现原理、查找及遍历
    JDK1.8源码之ArrayList
    03、Swagger2和Springmvc整合详细记录(爬坑记录)
    02、Java的lambda表达式和JavaScript的箭头函数
    Java-IO流之输入输出流基础示例
    JDBC API 事务的实践
    JDBC API 可滚动可编辑的结果集
    Java虚拟机----垃圾回收与内存分配
    Java数据库连接与查询
    Java虚拟机-对象的创建和访问
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/9637374.html
Copyright © 2011-2022 走看看