简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
-
-
- [🌻1. 前言](#🌻1. 前言)
- [🌻2. 用法与应用场景](#🌻2. 用法与应用场景)
- [🌻3. 调用流程剖析](#🌻3. 调用流程剖析)
-
- [3.1 核心步骤](#3.1 核心步骤)
- [3.2 涉及核心时序图](#3.2 涉及核心时序图)
- [🌻4. 实战应用案例](#🌻4. 实战应用案例)
- [🌻5. 用法总结](#🌻5. 用法总结)
-
🌻1. 前言
本篇目的:Android16音频深度解析之MediaPlayer.setAudioAttributes调用流程与实战。
在 Android 早期版本中,开发者通过 setAudioStreamType 来指定音频流类型(如 STREAM_MUSIC)。然而,从 Android 5.0 开始,官方引入了 AudioAttributes 来取代单一的流类型。在 Android 16 中,setAudioAttributes 已经成为定义音频意图(如:这是闹钟、音乐还是电话回声)的标准方式,它直接影响系统的音频路由、焦点调度以及混音策略。
🌻2. 用法与应用场景
MediaPlayer.setAudioAttributes 用于在播放前配置音频的属性信息,包括用途(Usage)、内容类型(ContentType)和标志位(Flags)。
- 用法说明 :必须在
setDataSource之后、prepare()之前调用。如果在准备完成后再设置,属性可能无法立即生效。 - 运行结果:系统根据属性自动选择最优的物理输出设备(如扬声器、蓝牙耳机)并执行相应的音频焦点(Audio Focus)逻辑。
- 应用场景:
- 区分音频意图 :告诉系统当前播放的是"背景音乐"(
USAGE_MEDIA)还是"导航语音"(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)。 - 强制路由 :结合
Flags实现特定硬件需求(如不被系统音效干扰)。 - 音频焦点管理 :系统根据
AudioAttributes自动决定当电话打进来时,是降低当前音乐音量(Ducking)还是直接暂停。
🌻3. 调用流程剖析
3.1 核心步骤
- Java 层封装 :应用层通过
AudioAttributes.Builder构建属性对象。调用MediaPlayer.setAudioAttributes后,Java 层会将该对象序列化并通过 JNI 传到底层。 - JNI 透传 :
android_media_MediaPlayer_setAudioAttributes接收请求,将其转换为 Native 层的audio_attributes_t结构体。 - Client 端存储 :Native 层的
MediaPlayer实例会将这些属性保存在内存中,并在启动播放引擎(NuPlayer)时传递下去。 - AudioPolicy 决策 :当进入
prepare阶段时,NuPlayer会创建一个新的AudioTrack。此时,AudioPolicyManager会根据设置的Attributes查找对应的策略(Strategy)和输出流(Output Stream)。 - 硬件路由生效:音频策略服务(AudioPolicyService)根据当前的属性和策略,动态切换物理链路(如切到扬声器或 A2DP 蓝牙)。
3.2 涉及核心时序图
AudioTrack AudioPolicyService NuPlayer Engine MediaPlayer Native MediaPlayer Java 应用代码层 AudioTrack AudioPolicyService NuPlayer Engine MediaPlayer Native MediaPlayer Java 应用代码层 调用 setAudioAttributes(attr) 执行 native_setAudioAttributes 更新本地属性缓存 调用 prepareAsync() 引擎启动并透传属性 请求根据属性获取最佳 Output 返回对应的 IO Handle 和策略 创建 AudioTrack 并注入 Attributes 音频链路按属性要求就绪
🌻4. 实战应用案例
本案例演示了如何正确构建 AudioAttributes 并将其应用到 MediaPlayer 中,以实现一个符合规范的音乐播放配置。
java
public class AudioAttributeManager {
private MediaPlayer mediaPlayer;
public void playMusicWithAttributes(Context context, Uri uri) {
mediaPlayer = new MediaPlayer();
try {
// 1. 设置数据源
mediaPlayer.setDataSource(context, uri);
// 2. 构建音频属性
// USAGE_MEDIA: 表示这是媒体音乐
// CONTENT_TYPE_MUSIC: 内容是音乐,通常会经过均衡器优化
AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
// 3. 在 Prepare 之前设置属性
mediaPlayer.setAudioAttributes(attributes);
mediaPlayer.setOnPreparedListener(mp -> {
System.out.println("属性设置成功,开始播放...");
mp.start();
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
public void playAlarmWithAttributes(Context context, Uri uri) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(context, uri);
// 针对闹钟场景的配置:即使手机静音,闹钟也可能通过特定路由输出
AudioAttributes alarmAttr = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ALARM)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
mediaPlayer.setAudioAttributes(alarmAttr);
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
}
🌻5. 用法总结
| 调用层级 | 核心职责 | 关键特性/影响 |
|---|---|---|
| 应用框架层 | 提供 Builder 模式构建属性 | 逻辑上取代了旧的 StreamType |
| 系统服务层 | 管理音频路由决策 (AudioPolicy) | 决定音频从哪个扬声器/耳机出声 |
| 引擎处理层 | 将属性参数注入 AudioTrack 实例 |
确保 NuPlayer 渲染时具备正确的 Metadata |
| 音频渲染层 | 负责音量缩减(Ducking)逻辑 | 决定当有通知时,当前音乐是变小还是暂停 |
| 硬件抽象层 | 匹配物理端口的低功耗模式 | 根据 Usage 调整 DSP 功耗状态 |