2 liaoxiang1987 liaoxiang1987 于 2013.05.06 18:35 提问

android 获取其他应用的背景音乐状态

首先,我自己在做一个关于音乐的插件。
其次,该插件的一个需求是在某一个条件下运行,然后弹出一些操作。而这种条件就是当有应用在跑时,如果有背景音乐在播放(play)状态,我不做某些操作。但如果背景音乐在暂停或停止状态(pause or stop),我这边就会做一些操作。

现在的情况是,我找了很多关于android音乐的处理,在底层服务层没有找到能获取到当前音乐播放状态的方式,只能获取到isActive,但这个状态在播放和暂停时都是返回true的。而上层情况是其他应用都是用mediaplay进行播放控制,而我作为另一个应用是获取不到别人应用的类对象的,所以这个问题陷入迷茫状态,希望做过或了解过这块的大神们能给出点方法,意见或思路哦。谢谢了,小弟快苦恼死了,搞了一个星期了

2个回答

liaoxiang1987
liaoxiang1987   2013.05.09 11:59
已采纳

研究两个星期,终于把这个问题进行了曲线救国,下面我来分享下自己的经验:

思路:
首先别人应用使用的播放方法是不同的,有jetPlay,mediaplay,更有牛的人用上了复杂的mediatrack。所以必须得用一个通用的方法进行获取。
其次,对于别人应用来说,无论用那种方法,我们都是获取不到它的播放实例的,比如我研究的是一个Unity3d游戏,底层核心是用mediaplay进行播放控制的,但我们是获取不到它生成的那个实例的。
最后,我们就必须将思路放到底层,比如service,framework,甚至是驱动级

讲一下我自己的研究过程:
首先使用的是liunx下的hook方法,对一些应用调用的库文件进行hook,如果能够直接获取到它自身的函数,比如play,pause等,或者状态参数返回,那这种方法当然是最好的,准确无误,不存在外界干扰。唯一的就是需要root权限,这个我想很简单吧。但有一个很大的缺点,hook函数的调用时frame级别的,如果不做系统是没办法是用的。
但我自己进行了研究,发现在unity3d游戏下,hook方法实用性太差,因为它的封装性太好,而且结构与android正常结构不同,所以我就放弃了。
最后我把思路转向应用级,试试在应用级上能否找到获取状态的函数,但最后不幸的是,除了一个isActive()外,我找不到关于状态的回馈。柳暗花明又一村,就在这里我发现了一个音乐播放器常用的东西----频谱。然后我就试着进行频谱分析来获取状态,而且频谱与播放形式无关,只跟输出数据有关。结果是真让我找到一个歪门邪道。虽然会有延迟还得自己逻辑,但起码是获取到了状态情况。

简约写下流程

{
  private Visualizer visualizer = null;//频谱测试器
  private byte [] mRawVizData;//频谱容器


  //实例化 Visualizer 对象
  visualizer = new Visualizer(0); 
  mRawVizData = new byte[128];

  //对象的初始化
  if(visualizer != null)
  {
    if (visualizer.getEnabled()) {
        visualizer.setEnabled(false);

     }

       visualizer.setCaptureSize(mRawVizData.length);//一定要在频谱false状态使用
       visualizer.setEnabled(true);//开启频谱获取

  }

下面是开一个线程进行循环获取频谱信息,我只把获取给贴出来

int status = Visualizer.ERROR;

  if(visualizer != null)
  {

    //音乐频谱获取
    status = visualizer.getFft(mRawVizData);//获取波形图

    if(status != Visualizer.SUCCESS)
    {
    Log.i("answer", "getWaveFail");
    }
    else
   {                         
    int j = 0;

    for(int i = 0; i < 128; i++)
    {

        if(mRawVizData[i] == 0)
        {
            j++;
        }
    }

        Log.i("answer", "getWave j = " + j);
    }
  }
}

最后我们可以看到j的数量,如果j的数量跟你当时申请数组128相同,说明此时是没有数据流出的,也就是说当前是在pause或stop状态了,其他数据不一样就是有数据进行输出。
关于频谱的使用大家可以参照http://blog.csdn.net/caryee89/article/details/6935237 大牛之作。
本人也就是使用获取一下数据而已,并没多复杂处理,仅供参考。

suannai0314
suannai0314 多谢分享,你可以点答案左侧的√将答案采纳为最佳答案哦
4 年多之前 回复
sasuke38
sasuke38   2013.05.07 15:03

你做这个好像很高级 虽然我不知道他是否正在听歌(你好像说可以检测到) 但是我可以知道他暂停的时机

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_HEADSET_PLUG);
    filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
    filter.addAction(Intent.ACTION_SHUTDOWN);
    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
    registerReceiver(br, filter);

多数播放器会接受这些广播来决定是否暂停音乐播放或者继续播放 当然还有一个重要的广播 那就是线控 那个只能在xml中注册

am2010
am2010 为什么要这么麻烦呢,直接判断music流是否mute应该可以吧。浅见啊,很久没碰audio了。
4 年多之前 回复
sasuke38
sasuke38 是的 别人手动暂停 确实没什么用处 这个太高级了 你去外国网站查查资料吧
4 年多之前 回复
liaoxiang1987
liaoxiang1987 但是你这几个广播消息在扬声器下是接受不到的哦,至少我现在试过了,在别人应用跑的时候,切换了歌曲或暂停了,我这边都没收到这些广播消息哦
4 年多之前 回复
sasuke38
sasuke38 既然如此 也就不存在别人用线控来暂停背景音乐的情况了 所以你只用上面的广播来判断即可满足大多数要求
4 年多之前 回复
liaoxiang1987
liaoxiang1987 你这个是针对耳麦的哦,就是有戴上耳机的消息。我是对应用背景音乐而言,跟外设没关系。只在乎它停止或暂停与否
4 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片