我想实现如下的场景,判断当前Android手机上是否正在播放音乐,如果是,通过某个特定的手势,
或者点击某个按键,将当前我正在听的音乐共享出去。
第一步,就是判断当前是否有音乐正在播放。
最开始我想得有点复杂,以为要深入framework或更下层去做手脚才行,找了一下资料,发现AudioManager对外暴露了接口。
[java]
/** Checks whether any music is active. */
isMusicActive()
通过这个接口就可以判断当前系统是否有音乐在播放了。
还有一个问题,如果我想在音乐一开始就已经播放的时候,就知道这个事件,以便进行特殊的处理。
再进一步看一下 AudioManager 的
源码,发现其中有如下方法:
[java]
/**
* Request audio focus.
* Send a request to obtain the audio focus
* @param l the listener to be notified of audio focus changes
* @param streamType the main audio stream type affected by the focus request
* @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
* is temporary, and focus will be abandonned shortly. Examples of transient requests are
* for the playback of driving directions, or notifications sounds.
* Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
* the previous focus owner to keep playing if it ducks its audio output.
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
* as the playback of a song or a video.
* @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
*/
public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)
从字面意思来看:请求音频焦点,再看这个函数的返回值:
[java]
/**
* 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;
这个函数可能对我有帮助,进一步查一下Google官方的帮助:http://developer.android.com/training/managing-audio/audio-focus.
html
Managing Audio Focus
With multiple apps potentially playing audio it's important to think about how they should interact. To avoid every music app playing at the same time,
Android uses audio focus to moderate audio playback—only apps that hold the audio focus should play audio.
Before your app starts playing audio it should request—and receive—the audio focus. Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that happens.
简单地翻译一下:
管理音频焦点
多个应用都在播放音频的可能性,所以考虑应用间如何交互非常重要。为避免每个音乐应用同时播放,Android使用音频焦点来协调音频的播放----只有获取到音频焦点的应用可以播放音频。
在你的应用开始播放音频之前,它应该先请求--并接收音频焦点。同样,它也应该知道当监听到失去音频焦点后如何合理地进行响应。
沿着这个路应该是对的,写了下面的测试代码进行验证。这个主要是Service的实现,你还需要实现一个Activity去启动Service、结束Service:
[java]
package com.example.servicetest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
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通知,这样更准确一些;
- Android: 判断当前手机品牌(转)
参考资料 Android判断手机ROM 正文 有时候需要判断手机系统的ROM,检测ROM是MIUI.EMUI还是Flyme,可以使用getprop命令,去系统build.prop文件查找是否有对应属性 ...
- javascript判断设备类型-手机(mobile)、安卓(android)、电脑(pc)、其他(ipad/iPod/Windows)等
使用device.js检测设备并实现不同设备展示不同网页 html代码: <!doctype html> <html> <head> <meta charse ...
- [转]Android WebView播放视频(包括全屏播放),androidwebview
Android WebView播放视频(包括全屏播放),androidwebview 最近项目开发中用到了WebView播放视频的功能,总结了开发中犯过的错误,这些错误在开发是及容易遇到的,所以我这里 ...
- android 随手记 videoview循环播放网络视频 和mediaplayer+sufaceview播放网络视频
1:videoview循环播放视频 1>xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res ...
- 使用Vitamio打造自己的Android万能播放器(6)——在线播放(播放列表)
前言 新版本的VPlayer由设计转入开发阶段,预计开发周期为一个月,这也意味着新版本的Vitamio将随之发布,开发者们可以和本系列文章一样,先开发其他功能.本章内容为"在线视频播放列表& ...
- 【Android】Android 代码判断是否获取ROOT权限(二)
[Android]Android 代码判断是否获取ROOT权限 方法比较简单,直接粘贴代码 /** * 判断当前手机是否有ROOT权限 * @return */ public boolean isRo ...
- js判断是否手机自动跳转移动端
写法一: {literal} <script> //判断是否手机自动跳转 var browser={versions:function(){var u=navigator.userAgen ...
- Android中判断网络连接是否可用及监控网络状态
Android中判断网络连接是否可用及监控网络状态 作者: 字体:[增加 减小] 类型:转载 获取网络信息需要在AndroidManifest.xml文件中加入相应的权限,接下来详细介绍Android ...
- ThinkPHP在入口文件中判断是手机还是PC端访问网站
<?php// +----------------------------------------------------------------------// | ThinkPHP [ WE ...
随机推荐
- 错误 1 缺少编译器要求的成员“System.Runtime.CompilerServices.ExtensionAttrib
错误 1 缺少编译器要求的成员“System.Runtime.CompilerServices.ExtensionAttrib 删除Newtonsoft.Json.dll 引用 ,再重新引用即可. 原 ...
- java.nio.charset.UnsupportedCharsetException: cp0
使用jython调用python,提示console: Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0. ...
- [转]JavaScript RegExp 对象参考手册
JavaScript RegExp 对象参考手册 RegExp 对象 RegExp 对象表示正则表达式,它是对字符串执行模式匹配的强大工具. 直接量语法 /pattern/attributes 创建 ...
- [Nlog]使用经验
<?xml version="1.0" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog ...
- 使用JdbcTemplate访问数据库
参考源端:https://blog.csdn.net/liaodehong/article/details/76974827 今天用Spring Boot访问一下数据库,并且把数据返回到页面中,进行增 ...
- 将Hive统计分析结果导入到MySQL数据库表中(一)——Sqoop导入方式
https://blog.csdn.net/niityzu/article/details/45190787 交通流的数据分析,需求是对于海量的城市交通数据,需要使用MapReduce清洗后导入到HB ...
- python之数据驱动ddt
下载ddt并安装 Pip install ddt 或者官网下载安装 http://ddt.readthedocs.io/en/latest/ https://github.com/txels/ddt ...
- 实现PPT在线预览,PPT转图片方案
一.PPT转图片可行方案探索历程 PPT转图片方案 方案具体步骤及分析 已放弃方案 poi(失真度太高):Aspose直接转图片(收费,效果较好,备选):微软Office Online(需要基于Win ...
- 25个必须记住的SSH命令
OpenSSH是SSH连接工具的免费版本.telnet,rlogin和ftp用户可能还没意识到他们在互联网上传输的密码是未加密的,但SSH 是加密的,OpenSSH加密所有通信(包括密码),有效消 ...
- Rhythmk 学习 Hibernate 03 - Hibernate 之 延时加载 以及 ID 生成策略
Hibernate 加载数据 有get,跟Load 1.懒加载: 使用session.load(type,id)获取对象,并不读取数据库,只有在使用返回对象值才正真去查询数据库. @Test publ ...