Android 音频焦点(Audio Focus)
原址
CONTENTS
- 引子
- 音频焦点
- 一个简单的示例
- 注意:
引子
说 Audio Focus 前先说个很简单需求:来电时暂停正在播放的音乐,电话结束时恢复播放。
看到这个需求,第一反应肯定是:监听用户来电状态,作相应操作。这里不多做介绍,这样做有个不好的地方就是需要隐私权限!这样做一点也不优雅。
后来搜索时看到一篇分析文章:Android来电时停止音乐播放的流程(顺便说一嘴,这篇转载居然不注明出处!!)。文章里的分析很明确的指出,系统在框架层就很好的帮我们处理了这个需求,问题是如何将音乐交给系统框架来处理呢?
音频焦点
问题的解决方法就是:请求系统的音频焦点(Request the Audio Focus)。
如果英文还行,强烈建议请看官方的原文:Managing Audio Playback,里面介绍的很清楚。以下为简单概述。
官方文档指出Android 在处理音频播放是分了多个“音频流”的,如音乐流、音效流、电话声音流等,使控制音量时可以互不干涉。多数情况下我们播放音乐都是使用 STREAM_MUSIC 音频流。
另外,系统中可能会有多个应用程序会播放音频,所以需要考虑他们之间该如何协调,为了避免同时播放音乐,Android 系统使用音频焦点来进行统一管理,即只有获得了音频焦点的应用程序才可以播放音乐。
那么,播放音频应该这样来做:
- 获取音频焦点 requestAudioFocus
- 获取成功后,开始播放音频
- 处理音频焦点的丢失和“DUCK”
- 播放完毕后取消焦点
如此便可以完美的解决引子里的需求。
一个简单的示例
MusicService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
public class MusicService extends Service {
private AudioManager mAm;
private boolean isPlaymusic;
private String url;
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
mAm = (AudioManager) getSystemService(AUDIO_SERVICE);
}
@Override
public void onStart(Intent intent, int startId) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
isPlaymusic = bundle.getBoolean("isPlay", true);
url = bundle.getString("url");
if (isPlaymusic)
play();
else
stop();
}
}
}
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
pause();
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
resume();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
// mAm.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
mAm.abandonAudioFocus(afChangeListener);
// Stop playback
stop();
}
}
};
private boolean requestFocus() {
// Request audio focus for playback
int result = mAm.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
private void resume() {
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
private void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
OnCompletionListener completionListener = new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer player) {
if(!player.isLooping()){
mAm.abandonAudioFocus(afChangeListener);
}
}
};
private void play() {
if (requestFocus()) {
if (mediaPlayer == null) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(completionListener);
} catch (IOException e) {
e.printStackTrace();
}
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null)
mediaPlayer.release();
}
private void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
|
经模拟器测试,当来电时音频焦点会给到铃声流,并打出日志:
I/AudioService(1235): AudioFocus requestAudioFocus() from AudioFocus_For_Phone_Ring_And_Calls
此时MusicService
中的afChangeListener
会得到AUDIOFOCUS_LOSS_TRANSIENT
,于是会暂停播放音频。
当通话结束或者挂掉电话,afChangeListener
会得到AUDIOFOCUS_GAIN
,于是恢复播放音频。
注意:
- 播放完毕一定要禁止掉请求的音频焦点
abandonAudioFocus(afChangeListener)
,否则,如果播放完毕后的某个时段刚好有个通话结束,并且此时没有其他的应用占用了焦点,系统会重新通知服务里的afChangeListener
,导致音频再次的播放。 - 如果丢失的短暂音频焦点允许DUCK状态
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
,在这种情况下,应用程序降低音量继续播放,不需要暂停。再次获取后,恢复原来的音量。
Android 音频焦点(Audio Focus)相关推荐
- android音频焦点Audio Focus
为了便于理解,我们以android的8.0以前的版本为例,8.0以后有一定改动,但是基本思路一样. 关于管理音频焦点(8.0以前和更高版本)的官方文档:https://developer.androi ...
- Android音频焦点处理
概要 Android系统允许多个应用同时播放音频,这种特性有利有弊.例如当我们正在听音乐的时候突然点开了一个视频,如果我们发现音乐的声音和视频的的声音混合了在一起,这显然让我们非常不爽.而如果我们在播 ...
- Android音频焦点申请处理
为了便于理解,我们以android的8.0以前的版本为例,8.0以后有一定改动,但是基本思路一样. 关于管理音频焦点(8.0以前和更高版本)的官方文档:https://developer.androi ...
- Android音频焦点
因为系统中可能会有多个应用程序会播放音频,所以需要考虑他们之间该如何交互,为了避免多个应用程序同时播放 音乐,Android 系统使用音频焦点来进行统一管理,即只有获得了音频焦点的应用程序才可以播放音 ...
- Android音频焦点及混音策略
1.前言 1.1 音频焦点官方解读 两个或两个以上的 Android 应用可同时向同一输出流播放音频.系统会将所有音频流混合在一起.虽然这是一项出色的技术,但却会给用户带来很大的困扰.为了避免所有音乐 ...
- Android音频焦点AudioFocus使用
Android开发中免不了需要播放视频,音频文件,但是手机上可能有其他的一些软件,在后台播放音频的时候,这个时候另外的软件也需要播放音频,这个时候就会出现俩个音频同时播放的问题,在Android2.2 ...
- Android 音频焦点处理
刚开始的时候,认为在智能机中,每个 APP 都是各自管各自的,媒体播放也是这样子的:然而对比同类产品,发现同类产品可以放到播放自如,体验很好,通过对比研究,根源就在于音频焦点处理上. 一.引言 在功能 ...
- 【安卓R 源码】获取音频焦点和释放音频焦点
一. 获取焦点流程 1. 电话焦点只有系统可以申请,如果是电话焦点,系统会把所有多媒体和游戏的音频流实例全部mute.同理电话焦点释放会解除mute操作 2. 系统管理的焦点栈有大小限制限制为100. ...
- Android 9.0失去音频焦点后不能再获取到焦点
问题 在9.0版本上,A先申请音频焦点,B先申请再释放音频焦点后,A也不能收到onAudioFocusChange回调,导致不能继续播放. 但是在7.1版本,这种情况是会正常播放的. 分析过程 查看源 ...
最新文章
- 2018, 自动驾驶异常艰难的一年
- C/C++ sizeof函数解析——解决sizeof求结构体大小的问题
- QTableWidget控件总结
- python mac读取 文件属性_从Python获取和设置mac文件和文件夹查找器标签
- linux操作系统之线程同步及互斥量
- CF248E Piglet's Birthday(概率dp)
- 站点信息 统计 内容 概况
- HTML5_增强可访问性和解决IE兼容性问题
- 小小一款代码编辑器竟然也可以有程序运行之功能——Sublime Text3运行各种语言程序的总结
- maya藤蔓插件_用maya制作藤蔓蔓延的效果
- win11怎么隐藏任务栏图标?
- Dllmain的作用
- html超链接访问前颜色,html超链接颜色设置
- 青少年CTF-Web-CheckMe01
- springboot启动时报错 错误:找不到或无法加载主类 xxx.SpringDemoApplication
- 人人都在谈的 “数据驱动” 到底是什么?你确认自己做的是数据驱动吗?
- python如何模拟微信扫码登录_python 微信扫码登录故障解决
- Python框架django路由管理
- 计算机网络实验连接云,云计算机网络实验室, 多媒体数字语音设备
- ArcGIS Maps SDK for Unreal Engine通过UI方式显示地图教程