Android 音频焦点详解
音频焦点(Audio Focus)是 Android 系统用于协调多个应用同时访问音频输出的机制。当多个应用需要播放音频时,音频焦点确保用户听到的内容不会混乱(如多个音乐应用同时播放)。
一、音频焦点的核心概念
-
音频焦点的类型
- 永久性焦点:长时间占用焦点(如音乐播放器)。
- 短暂性焦点:临时占用焦点(如导航提示音)。
- Ducking:短暂降低其他应用音量(如通知音)。
-
焦点请求类型
AUDIOFOCUS_GAIN:请求长期焦点,其他应用需停止播放。 值:1AUDIOFOCUS_GAIN_TRANSIENT:短暂占用焦点,其他应用需暂停。 值:2AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂占用焦点,其他应用降低音量(Ducking)。值:3AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:短暂独占焦点(如语音录制)。值:4
-
requestAudioFocus 返回值
- AUDIOFOCUS_REQUEST_GRANTED:请求成功 值: 1
- AUDIOFOCUS_REQUEST_FAILED:请求失败 值:0
- AUDIOFOCUS_REQUEST_DELAYED:焦点延迟授予 值:2(需设置 AUDIOFOCUS_FLAG_DELAY_OK)
-
焦点丢失处理
当其他应用请求焦点时,当前应用需根据情况暂停播放、停止播放或降低音量。
二、代码实现与分析
1. 请求音频焦点
使用 AudioManager 请求焦点,并监听焦点变化。
2. 音频焦点变化返回值
在播放结束或应用暂停时释放焦点:
当焦点状态变化时,系统通过此回调通知应用:
AUDIOFOCUS_LOSS:永久失去焦点(应停止播放并释放资源)。AUDIOFOCUS_LOSS_TRANSIENT:暂时失去焦点(应暂停播放)。AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时失去焦点,但可降低音量继续播放。AUDIOFOCUS_GAIN:重新获得焦点(恢复播放)。
// 初始化 AudioManager
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// 创建焦点变化监听器
AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// 重新获得焦点,恢复播放
mediaPlayer.start();
mediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// 永久丢失焦点,停止播放并释放资源
mediaPlayer.stop();
audioManager.abandonAudioFocus(afChangeListener);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// 暂时丢失焦点,暂停播放
mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// 短暂降低音量
mediaPlayer.setVolume(0.2f, 0.2f);
break;
}
}
};
//requestAudioFocus
//作用:应用通过此方法请求音频焦点,表明它希望播放音频
//参数:
//OnAudioFocusChangeListener:焦点变化时的回调监听器
//streamType:音频流类型(如 STREAM_MUSIC)
//durationHint:焦点持有类型(如 AUDIOFOCUS_GAIN 表示长期占用)
//返回值:
//AUDIOFOCUS_REQUEST_GRANTED:请求成功
//AUDIOFOCUS_REQUEST_FAILED:请求失败
//AUDIOFOCUS_REQUEST_DELAYED:焦点延迟授予(需设置 AUDIOFOCUS_FLAG_DELAY_OK)
// 请求音频焦点(以 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 为例)
int result = audioManager.requestAudioFocus(
afChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// 焦点获取成功,开始播放
mediaPlayer.start();
} else {
// 焦点获取失败,处理逻辑
}

三、实际使用
一、通话打断音乐的流程
-
电话应用的优先级
通话属于高优先级音频场景,系统会强制其他应用让出音频焦点。当来电时,电话应用会请求AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE类型的焦点(短暂独占),以确保通话音频的独占性。 -
音乐播放器的响应
音乐播放器在失去焦点时,会通过注册的OnAudioFocusChangeListener收到AUDIOFOCUS_LOSS或AUDIOFOCUS_LOSS_TRANSIENT回调,此时需暂停播放。 -
通话结束后的恢复
当通话结束时,电话应用释放焦点,音乐播放器可能重新获得焦点(需主动重新请求),恢复播放。
四、framwork 跟 native

1. AudioFocus 机制的关键角色
- AudioManager:
- 应用与 AudioFocus 系统交互的主要入口点。
- 提供
requestAudioFocus()/abandonAudioFocus()/requestAudioFocusRequest()等 API。 - 持有
IAudioService的代理(Binder 对象),用于跨进程调用AudioService。
- AudioService:
- 系统服务 (
com.android.server.audio.AudioService),运行于system_server进程。 - 管理整个系统的音频状态、策略、路由和焦点。
- 通过 Binder (
IAudioService) 接收来自应用的请求。 - 内部核心组件:
MediaFocusControl- 实际管理焦点栈、处理请求和分发焦点变更通知的逻辑中心。
- 系统服务 (
- MediaFocusControl:
AudioService的内部类,是 AudioFocus 机制的“大脑”。- 维护焦点栈 (
mFocusStack): 一个Stack<FocusRequester>,栈顶元素拥有当前音频焦点。栈大小有限制(MAX_STACK_SIZE=100)。 - 处理请求: 接收
requestAudioFocus()和abandonAudioFocus()请求。 - 分发通知: 当焦点状态变化时(如新应用获得焦点、原有应用丢失焦点),通知相应的应用。
- 协调特殊状态: 如电话状态 (
mRingOrCallActive)。
- FocusRequester:
- 表示一个音频焦点请求者。
- 可参考代码
//创建新的焦点请求对象
final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
clientId, afdh, callingPackageName, uid, this, sdk, mEventLogger);
| 参数 | 含义 | 来源 |
|---|---|---|
| aa | 音频属性(如音乐/导航/通话),决定焦点优先级 | 请求方传入 |
| focusChangeHint | 焦点类型(如 AUDIOFOCUS_GAIN 永久占用,AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 短暂降音) | 请求方传入 [citation:6] |
| flags | 标志位(如 AUDIOFOCUS_FLAG_DELAY_OK 允许延迟获取) | 请求方传入 |
| fd | 文件描述符(可能用于音频流控制) | 系统分配 |
| cb | 客户端的 Binder 回调接口(用于焦点变更通知) | 请求方传入 |
| clientId | 客户端唯一标识 | 系统生成 |
| afdh | 死亡回调处理器(监听客户端进程终止) | 前文创建 [citation:6] |
| callingPackageName | 请求方包名 | 系统获取 |
| uid | 请求方用户 ID | 系统获取 |
| this | 指向 MediaFocusControl 的引用(用于回调系统方法) | 当前对象 |
| sdk | 请求方应用的 Target SDK 版本(影响兼容性行为) | 系统获取 |
| mEventLogger | 事件日志器(记录焦点变更事件) | 系统组件 |
- IAudioFocusDispatcher:
- 一个 AIDL 接口 (
android.media.IAudioFocusDispatcher)。 - 客户端实现 (
AudioManager.mAudioFocusDispatcher): 一个Stub对象,运行在应用进程。当MediaFocusControl需要通知应用焦点变化时,通过 Binder 调用它的dispatchAudioFocusChange(int focusChange, String clientId)方法。 - 服务端持有 (
FocusRequester.mFocusDispatcher):MediaFocusControl通过FocusRequ
- 一个 AIDL 接口 (


1619

被折叠的 条评论
为什么被折叠?



