16、车载媒体应用:MediaSession与MediaBrowserService;CarMediaService与媒体源管理;本地与在线音乐播放;视频播放与投屏

车载娱乐系统里,媒体应用是用户最常打交道的模块。开车时听歌、等人时看视频,这些场景我们每天都在面对。今天我就把这块的核心知识点拆开揉碎了讲给你听。

核心知识点一览

  • MediaSession 与 MediaBrowserService 的配对使用
  • CarMediaService 如何管理多个媒体源
  • 本地音乐 vs 在线音乐的播放差异
  • 视频播放与投屏的技术选型
车载媒体应用核心架构 CarMediaService MediaSession MediaBrowserService 媒体源管理 播放策略 本地音乐 在线音乐 视频播放 投屏 基于 Android Automotive 的媒体架构

16.1 MediaSession 与 MediaBrowserService

这两个东西是 Android 媒体框架的基石。说白了,MediaSession 是「播放器对外暴露的控制接口」,MediaBrowserService 是「媒体内容目录的提供者」。

我刚开始做车载媒体时,犯过一个低级错误——直接把 MediaPlayer 实例暴露给 UI 层。结果呢?UI 和播放逻辑耦合得死死的,换个播放器就得改一堆代码。后来老老实实用 MediaSession,真香。

MediaSession 的核心职责

  • 接收外部控制命令(播放、暂停、下一曲、快进等)
  • 向系统广播当前播放状态(正在播放哪首歌、进度多少)
  • 配合锁屏、通知栏、语音助手等系统组件
// 创建 MediaSession 的典型写法
MediaSessionCompat mediaSession = new MediaSessionCompat(context, TAG);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
    @Override
    public void onPlay() {
        // 我习惯在这里先检查当前是否有待播放的媒体项
        if (currentMediaId != null) {
            player.play();
        }
    }

    @Override
    public void onPause() {
        player.pause();
    }

    @Override
    public void onSkipToNext() {
        loadMedia(nextMediaId);
    }
});
mediaSession.setActive(true);

个人经验:MediaSession 的 Callback 是在 binder 线程回调的,不要在里边直接操作 UI。我曾经在这踩过坑,导致界面刷新延迟。建议用 Handler 切回主线程。

MediaBrowserService 的作用

它负责向系统提供媒体库的层级结构。比如你的音乐 App 里有「本地音乐」「在线音乐」「我的收藏」这些分类,MediaBrowserService 就是把这些目录暴露出去的桥梁。

public class MusicBrowserService extends MediaBrowserServiceCompat {
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化媒体源管理器
        mediaSourceManager = new MediaSourceManager(this);
    }

    @Override
    public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
                                 Bundle rootHints) {
        // 这里可以做权限校验
        return new BrowserRoot("root", null);
    }

    @Override
    public void onLoadChildren(String parentMediaId,
                               Result<List<MediaBrowserCompat.MediaItem>> result) {
        // 根据 parentMediaId 返回子媒体项
        result.sendResult(mediaSourceManager.getChildren(parentMediaId));
    }
}

你想想看,如果没有 MediaBrowserService,每个 App 都得自己实现一套媒体目录管理逻辑,系统也没法统一调度。Google 设计这套框架,说白了就是为了标准化。

16.2 CarMediaService 与媒体源管理

车载系统和手机不一样。手机上一个音乐 App 只管自己的数据,但车载上可能有多个媒体源:USB 音乐、蓝牙音乐、在线音乐、收音机……这些源需要统一管理。

CarMediaService 就是 Android Automotive 专门干这事的。它负责注册、切换、优先级管理多个媒体源。

媒体源类型 优先级 典型场景
紧急广播 最高 安全预警、交通信息
导航提示 导航语音播报
电话 蓝牙通话
媒体播放 普通 音乐、视频
系统音效 按键音、提示音

注意:媒体源切换时一定要做淡入淡出处理。我曾经见过一个项目,切换源时直接咔一声切过去,用户体验极差。后来加了 200ms 的交叉淡入淡出,效果好了很多。

16.3 本地与在线音乐播放

本地音乐和在线音乐,技术实现上差别不小。我分别说说。

本地音乐播放

核心是 MediaPlayer 或 ExoPlayer。本地文件路径清晰,不需要处理网络波动。但要注意几个点:

  • 文件格式兼容性:MP3、FLAC、WAV、AAC 都得支持
  • 元数据读取:用 MediaMetadataRetriever 提取专辑封面、歌手、时长
  • 存储权限:Android 10 以后要用 MediaStore API
// 读取本地音乐元数据
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
    retriever.setDataSource(context, uri);
    String title = retriever.extractMetadata(
        MediaMetadataRetriever.METADATA_KEY_TITLE);
    String artist = retriever.extractMetadata(
        MediaMetadataRetriever.METADATA_KEY_ARTIST);
    // 获取专辑封面
    byte[] cover = retriever.getEmbeddedPicture();
} finally {
    retriever.release();
}

在线音乐播放

在线播放的核心挑战是网络。我建议用 ExoPlayer,它对自适应码率(HLS、DASH)支持很好。

  • 缓存策略:边播边缓存,断网时还能听
  • 预加载:用户切歌时提前缓冲下一首
  • 错误重试:网络波动时自动重试,别直接崩掉

避坑指南:在线音乐播放时,别忘了处理音频焦点。我曾经遇到过导航语音播报时音乐没暂停,两个声音混在一起,用户差点把车机砸了。用 AudioManager.requestAudioFocus() 就能解决。

16.4 视频播放与投屏

车载视频播放比音乐复杂得多。原因很简单——开车时不能看视频,但停车时可以。所以视频播放要跟车辆状态绑定。

视频播放的技术选型

  • ExoPlayer:首选,支持硬解码,性能好
  • VideoView:简单场景可以用,但定制能力弱
  • 自定义 SurfaceView + MediaCodec:需要极致性能时用
// 车辆状态监听,控制视频播放
VehiclePropertyManager propertyManager = 
    new VehiclePropertyManager(context);
propertyManager.getProperty(
    VehicleProperty.PARKING_BRAKE_ON, 
    new VehiclePropertyManager.VehiclePropertyListener() {
        @Override
        public void onPropertyChange(VehiclePropValue value) {
            boolean isParked = value.getValue() == 1;
            if (isParked) {
                videoPlayer.start();
            } else {
                videoPlayer.pause();
                // 我习惯在这里显示一个提示:"行驶中已暂停视频"
                showDrivingNotice();
            }
        }
    });

投屏功能

投屏分两种:手机投屏到车机(如 Android Auto、CarPlay),以及车机投屏到后排屏幕。

  • Android Auto:走 MediaSession 协议,车机作为客户端
  • Miracast / DLNA:无线投屏,延迟较高
  • 有线投屏:USB-C 转 HDMI,延迟低,适合视频

核心原则:无论哪种投屏方式,都要保证驾驶安全。视频内容只能在驻车时显示,投屏时也要遵守这个规则。这是法规要求,不是技术选择。

嗯,关于车载媒体应用的核心内容就这些。MediaSession 和 MediaBrowserService 是基础,CarMediaService 是车载特有的管理机制,本地和在线播放各有侧重,视频播放要跟车辆状态联动。把这些理清楚了,车载媒体应用的骨架就有了。

公众号:蓝海资料掘金营,微信 deep3321