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 功耗状态
相关推荐
Luna-player1 天前
springData
gitee
CRMEB1 天前
电商项目中订单流程可以使用哪些设计模式?如何开发?
java·设计模式·gitee·开源·php·crmeb
常利兵2 天前
一文搞懂双Token、SSO与第三方权限打通,附实战代码
python·gitee·kotlin
fei_sun2 天前
Gitee代码上传
gitee
王家视频教程图书馆2 天前
my projects
gitee
蟑螂恶霸3 天前
Gitee学习指南《一》
gitee
常利兵3 天前
Android “解锁”屏幕方向:APP适配新征程
android·gitee
MR_Colorful3 天前
gitee使用记录
gitee
zhangfeng11333 天前
GitCode gitee 上传超过10m大文件附件的方法
gitee·gitcode