音频焦点 Android Audio Focus

Android 音频焦点详解

音频焦点(Audio Focus)是 Android 系统用于协调多个应用同时访问音频输出的机制。当多个应用需要播放音频时,音频焦点确保用户听到的内容不会混乱(如多个音乐应用同时播放)。

一、音频焦点的核心概念

  1. 音频焦点的类型

    • 永久性焦点:长时间占用焦点(如音乐播放器)。
    • 短暂性焦点:临时占用焦点(如导航提示音)。
    • Ducking:短暂降低其他应用音量(如通知音)。
  2. 焦点请求类型

    • AUDIOFOCUS_GAIN:请求长期焦点,其他应用需停止播放。 值:1
    • AUDIOFOCUS_GAIN_TRANSIENT:短暂占用焦点,其他应用需暂停。 值:2
    • AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂占用焦点,其他应用降低音量(Ducking)。值:3
    • AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:短暂独占焦点(如语音录制)。值:4
  3. requestAudioFocus 返回值​

    • AUDIOFOCUS_REQUEST_GRANTED:请求成功 值: 1
    • AUDIOFOCUS_REQUEST_FAILED:请求失败 值:0
    • AUDIOFOCUS_REQUEST_DELAYED:焦点延迟授予 值:2(需设置 AUDIOFOCUS_FLAG_DELAY_OK)
  4. 焦点丢失处理
    当其他应用请求焦点时,当前应用需根据情况暂停播放、停止播放或降低音量。

二、代码实现与分析

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 {
   
   
    // 焦点获取失败,处理逻辑
}

在这里插入图片描述

三、实际使用

一、通话打断音乐的流程
  1. 电话应用的优先级
    通话属于高优先级音频场景,系统会强制其他应用让出音频焦点。当来电时,电话应用会请求 AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE 类型的焦点(短暂独占),以确保通话音频的独占性。

  2. 音乐播放器的响应
    音乐播放器在失去焦点时,会通过注册的 OnAudioFocusChangeListener 收到 AUDIOFOCUS_LOSSAUDIOFOCUS_LOSS_TRANSIENT 回调,此时需暂停播放。

  3. 通话结束后的恢复
    当通话结束时,电话应用释放焦点,音乐播放器可能重新获得焦点(需主动重新请求),恢复播放。

四、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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值