Android16进阶之MediaPlayer.setAudioAttributes调用流程与实战(二百三十六)

简介: 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)逻辑。
  • 应用场景
  1. 区分音频意图 :告诉系统当前播放的是"背景音乐"(USAGE_MEDIA)还是"导航语音"(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)。
  2. 强制路由 :结合 Flags 实现特定硬件需求(如不被系统音效干扰)。
  3. 音频焦点管理 :系统根据 AudioAttributes 自动决定当电话打进来时,是降低当前音乐音量(Ducking)还是直接暂停。

🌻3. 调用流程剖析

3.1 核心步骤
  1. Java 层封装 :应用层通过 AudioAttributes.Builder 构建属性对象。调用 MediaPlayer.setAudioAttributes 后,Java 层会将该对象序列化并通过 JNI 传到底层。
  2. JNI 透传android_media_MediaPlayer_setAudioAttributes 接收请求,将其转换为 Native 层的 audio_attributes_t 结构体。
  3. Client 端存储 :Native 层的 MediaPlayer 实例会将这些属性保存在内存中,并在启动播放引擎(NuPlayer)时传递下去。
  4. AudioPolicy 决策 :当进入 prepare 阶段时,NuPlayer 会创建一个新的 AudioTrack。此时,AudioPolicyManager 会根据设置的 Attributes 查找对应的策略(Strategy)和输出流(Output Stream)。
  5. 硬件路由生效:音频策略服务(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 功耗状态
相关推荐
Railshiqian5 小时前
在android15r17模拟器上实现的一个hal和hal client app示例
android hal
痕忆丶8 小时前
将本地项目文件上传至指定的gitee空仓库
gitee
android_cai_niao10 小时前
给Git项目添加多个远程仓库
git·gitee·github
梦梦代码精2 天前
从工程视角拆解 BuildingAI:一个企业级开源智能体平台的架构设计与实现
人工智能·gitee·开源·github
ganshenml3 天前
Android 存储权限与文件系统演进全解析(Android 10 → 16)
android·gitee
知兀4 天前
【gitee高校】使用模力方舟的大模型;API Error问题
gitee
电化学仪器白超6 天前
小乌龟Git全程图形化操作指南:嵌入式本地版本管理与Gitee私有云备份实战
git·python·单片机·嵌入式硬件·物联网·gitee·自动化
打不了嗝 ᥬ᭄7 天前
Git 原理与使用
git·gitee
longji7 天前
android 01 AOSP android16 aaos 编译及webview升级
android·aaos·aosp·android16
MegaDataFlowers7 天前
基于Gitee帮助中心学习Gitee Go
学习·gitee