音频焦点 Android Audio Focus

news/2025/3/25 22:27:04/

Android 音频焦点详解

音频焦点(Audio Focus)是 Android 系统用于协调多个应用同时访问音频输出的机制。当多个应用需要播放音频时,音频焦点确保用户听到的内容不会混乱(如多个音乐应用同时播放)。以下从核心概念、使用场景和代码实现三个方面展开说明。

一、音频焦点的核心概念

  1. 音频焦点的类型

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

    • AUDIOFOCUS_GAIN:请求长期焦点,其他应用需停止播放。
    • AUDIOFOCUS_GAIN_TRANSIENT:短暂占用焦点,其他应用需暂停。
    • AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂占用焦点,其他应用降低音量(Ducking)。
    • AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:短暂独占焦点(如语音录制)。
  3. 焦点丢失处理
    当其他应用请求焦点时,当前应用需根据情况暂停播放、停止播放或降低音量。

二、代码实现与分析

1. 请求音频焦点

使用 AudioManager 请求焦点,并监听焦点变化。

// 初始化 AudioManager
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);// 创建焦点变化监听器
AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() {@Overridepublic 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;}}
};// 请求音频焦点(以 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 {// 焦点获取失败,处理逻辑
}
2. 释放音频焦点

在播放结束或应用暂停时释放焦点:

audioManager.abandonAudioFocus(afChangeListener);
3. Android 8.0+ 的 AudioFocusRequest(API 26+)

对于 Android 8.0 及以上设备,使用 AudioFocusRequest 更灵活:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {AudioFocusRequest focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()).setAcceptsDelayedFocusGain(true) // 允许延迟获取焦点.setOnAudioFocusChangeListener(afChangeListener).build();int result = audioManager.requestAudioFocus(focusRequest);
}

三、使用函数

  1. 生命周期管理

    • onPause()onStop() 中释放焦点。
    • onResume() 中重新请求焦点(视场景而定)。
  2. Ducking 实现
    AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 回调中降低音量,而非暂停播放。

  3. 处理延迟焦点
    Android 8.0+ 支持延迟获取焦点,需在 AudioFocusRequest 中配置 setAcceptsDelayedFocusGain(true)

四、实际使用

通话打断音乐

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

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

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

二、代码示例与分析
1. 音乐播放器的焦点处理
// 初始化 AudioManager 和焦点监听器
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
MediaPlayer mediaPlayer = new MediaPlayer();AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() {@Overridepublic void onAudioFocusChange(int focusChange) {switch (focusChange) {case AudioManager.AUDIOFOCUS_LOSS:// 永久丢失焦点(如通话开始)mediaPlayer.pause();audioManager.abandonAudioFocus(this); // 主动释放焦点break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:// 暂时丢失焦点(如短暂通话提示)mediaPlayer.pause();break;case AudioManager.AUDIOFOCUS_GAIN:// 重新获得焦点(如通话结束)if (!mediaPlayer.isPlaying()) {mediaPlayer.start();}break;}}};// 播放音乐前请求焦点
int result = audioManager.requestAudioFocus(afChangeListener,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN
);if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {mediaPlayer.start();
}
2. 电话应用的行为(系统级实现)

电话应用的音频焦点请求由系统自动处理,开发者无需手动实现。其核心逻辑类似:

// 系统电话应用的简化逻辑
audioManager.requestAudioFocus(phoneFocusListener,AudioManager.STREAM_VOICE_CALL,AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
);
三、关键注意事项
  1. 无需手动处理通话打断
    音乐播放器只需正确实现 OnAudioFocusChangeListener,系统会自动触发暂停逻辑。开发者无需监听通话状态。

  2. 恢复播放的策略

    • 如果通话短暂(如未接来电),焦点可能自动恢复(AUDIOFOCUS_GAIN),音乐自动播放。
    • 若通话时间较长(如持续通话),建议在 onResume() 中重新请求焦点。
  3. 与其他高优先级场景的兼容
    除通话外,导航提示、警报声等也会通过音频焦点机制中断音乐,处理逻辑一致。

  4. Android 8.0+ 的适配
    在 Android 8.0 及以上版本,建议使用 AudioFocusRequest 对象(需检查版本):

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {AudioFocusRequest focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build()).setOnAudioFocusChangeListener(afChangeListener).build();audioManager.requestAudioFocus(focusRequest);
    }
    

http://www.ppmy.cn/news/1583067.html

相关文章

鸿蒙app 中 web app和h5的通信

参考的官方文档 主要是 通过web 组件 然后 将h5的 链接 放到 web 中 进行加载h5界面 注意 h5中一切的 操作原生的方法 比如说 返回 拍照 从图库拿取照片 都是调用的 原生的app的方法 大概的代码实现

《鸿蒙原生应用开发:掌控Ability生命周期的艺术》

在鸿蒙原生应用开发的广袤天地中,Ability作为构建应用的基本单元,其生命周期的有效管理宛如基石之于高楼,是打造稳定、高效且用户体验卓越应用的关键所在。随着鸿蒙生态的蓬勃发展,深入理解并巧妙运用Ability生命周期,…

华为OD机试2025A卷 - 工号不够用了怎么办(Java Python JS C++ C )

最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 题目描述 3020年,空间通信集团的员工人数突破20亿人,即将遇到现有工号不够用的窘境。 现在,请你负责调研新工号系统。继承历史传统,新的工号系统由小写英文字母(a-z)和数字(0-9)两部分构…

Karmada v1.13 版本发布!新增应用优先级调度能力

Karmada 是开放的多云多集群容器编排引擎,旨在帮助用户在多云环境下部署和运维业务应用。凭借兼容 Kubernetes 原生 API 的能力,Karmada 可以平滑迁移单集群工作负载,并且仍可保持与 Kubernetes 周边生态工具链协同。 Karmada v1.13 版本[1]现…

ffmpeg+QOpenGLWidget显示视频

​一个基于 ‌FFmpeg 4.x‌ 和 QOpenGLWidget的简单视频播放器代码示例,实现视频解码和渲染到 Qt 窗口的功能。 1)ffmpeg库界面,视频解码支持软解和硬解方式。 硬解后,硬件解码完成需要将数据从GPU复制到CPU。优先采用av_hwf…

[AI]自动化编写代码工具整理

[AI]自动化编写代码工具整理 字节跳动 国内版 Trae - AI 原生 IDE 国际版 Trae - Ship Faster with Trae Cursor Cursor - The AI Code Editor

Leetcode 3493. Properties Graph

Leetcode 3493. Properties Graph 1. 解题思路2. 代码实现 题目链接:3493. Properties Graph 1. 解题思路 这一题的话是要考虑最终聚合的簇的个数,因此很明显就是一个并查集的典型题目。因此,我们只需要创建一个并查集,然后两两…

网络原理之传输层

前文我们了解 应用层 传输层 网络层 数据链路层 物理层 这五层结构,此文我先讨论传输层相关的知识 1. 传输层 负责数据能够从发送端传输到接收端. 1.1 端口号 端⼝号(Port)标识了⼀个主机上进行通信的不同的应用程序 端口号范围划分: 0-1023:知名端口号,HTTP,FTP,SSH等这些…