android 媒体之 MediaSession

一、框架

1. MediaSession (媒体会话)

• 角色: 核心枢纽和状态机。它是整个媒体播放控制的核心。

• 作用:

bash 复制代码
封装播放状态: 持有当前播放状态(如播放/暂停、当前播放位置、播放速度、播放队列、当前媒体项元数据等)。

暴露控制接口: 通过 setCallback() 设置一个 MediaSession.Callback。这个回调定义了如何处理来自外部的控制命令(如 onPlay(), onPause(),
onSkipToNext(), onSeekTo() 等)。应用的后台播放逻辑主要实现在这里。

分发状态更新: 当播放状态发生变化(如开始播放、暂停、切歌、进度更新)时,MediaSession 会主动通知所有连接到它的 MediaController。

提供令牌 (Token): 生成一个 MediaSession.Token。这个 Token 是 MediaSession的唯一标识符和安全凭证,用于前台组件(通过 MediaBrowser)连接到后台服务并获取 MediaController。

• 位置: 通常由后台服务(MediaBrowserService)创建并持有。

• 关键点: 它不直接处理媒体播放,而是定义接口和保存状态,具体的播放动作由 MediaSession.Callback 的实现者(你的播放逻辑)完成。

2. MediaBrowserService (媒体浏览器服务)

• 角色: 后台服务的基类。它是长期运行在后台(通常在一个独立的进程)的服务,负责管理媒体内容库、播放逻辑以及与前台 UI 的连接。

• 作用:

bash 复制代码
生命周期管理: 作为 Android Service,它可以在 UI 不可见时(如应用退到后台、锁屏)继续运行,保证播放不中断。

托管 MediaSession: 创建并持有 MediaSession 实例,实现其 Callback 中的播放控制逻辑。

管理内容库: 实现 onLoadChildren() 等方法,向连接的客户端(MediaBrowser)提供媒体内容的结构(如专辑列表、歌曲列表)。

连接点: 提供 onGetRoot() 方法,验证请求连接的客户端(MediaBrowser)是否有权限,并返回一个 BrowserRoot 对象(通常包含 MediaSession 的 Token)。这是前台连接后台的入口。

管理客户端连接: 维护连接到它的 MediaBrowser 客户端列表。

• 位置: 后台服务,继承自 Service。

• 关键点: 它是后台播放逻辑的容器和连接桥梁。它创建 MediaSession 并实现其核心播放逻辑。

3. MediaBrowser (媒体浏览器)

• 角色: 前台 UI 的连接器。由前台组件(如 Activity、Fragment)创建和使用。

• 作用:

bash 复制代码
连接到 MediaBrowserService: 使用 MediaBrowserService 的组件名(或通过 MediaSession.Token)发起连接请求。

获取会话令牌: 连接成功后,通过 getSessionToken() 方法获取到 MediaBrowserService 所持有的 MediaSession 的 Token。

浏览媒体内容: 使用 subscribe() 方法订阅媒体内容树(如"所有歌曲"、"按艺术家")的更新,并通过 MediaBrowser.SubscriptionCallback 接收内容(MediaItem 列表)。使用 unsubscribe() 取消订阅。

断开连接: 在 UI 销毁时断开与服务的连接。

• 位置: 前台 UI 组件(Activity/Fragment)。

• 关键点: 它主要负责建立连接和获取内容结构。它本身不直接控制播放。获取到 MediaSession.Token 后,它的主要任务就完成了(用于创建 MediaController)。

4. MediaController (媒体控制器)

• 角色: 前台 UI 的控制代理和状态接收器。

• 作用:

bash 复制代码
创建: 前台 UI 组件使用 MediaBrowser 连接成功后获取到的 MediaSession.Token,通过 MediaControllerCompat.getMediaController() 或 MediaControllerCompat 的构造函数创建 MediaController。

发送控制命令: 提供方法(如 getTransportControls().play(), pause(), skipToNext(), seekTo())让 UI 发送播放控制命令。这些命令最终会被路由到后台 MediaSession 的 Callback 中执行。

获取当前状态: 提供方法(如 getPlaybackState(), getMetadata())让 UI 查询当前的播放状态和媒体元数据。

接收状态更新: 通过注册 MediaController.Callback,UI 可以监听 MediaSession 的状态变化(如播放状态改变、元数据更新、队列变化)。当后台状态变化时,MediaSession 会通知所有关联的 MediaController,这些 MediaController 再回调其注册的 Callback 通知 UI 更新。

与 MediaSession 交互: 它是前台 UI 与后台 MediaSession 交互的主要通道。

• 位置: 前台 UI 组件(Activity/Fragment),通常与 MediaBrowser 在同一组件中使用。

• 关键点: 它是 UI 控制播放和获取状态更新的主要工具。它通过 MediaSession.Token 与后台的 MediaSession 建立联系。

5.关系和工作流程

  1. 后台启动: 你的应用启动后台服务(继承自 MediaBrowserService)。该服务在 onCreate() 中创建 MediaSession,设置其 Callback(实现播放逻辑),并可能开始准备播放。
  2. 前台启动: 用户打开应用 UI(Activity/Fragment)。
  3. 连接: UI 创建 MediaBrowser 对象,使用 MediaBrowserService 的组件名调用 connect() 尝试连接。
  4. 验证与连接: MediaBrowserService 的 onGetRoot() 被调用,验证客户端权限并返回 BrowserRoot(包含 MediaSession.Token)。连接成功。
  5. 获取控制器: UI 的 MediaBrowser.ConnectionCallback.onConnected() 被调用。在这里,UI 通过 MediaBrowser.getSessionToken() 获取 MediaSession.Token,并用它创建 MediaController。
  6. 浏览内容 (可选): UI 可以使用 MediaBrowser.subscribe() 请求媒体内容结构(如显示歌曲列表)。
  7. 控制播放: 当用户点击 UI 上的播放按钮时,UI 调用 MediaController.getTransportControls().play()。
  8. 命令路由: MediaController 将 play() 命令发送给后台的 MediaSession。
  9. 执行命令: MediaSession 调用其 Callback.onPlay() 方法。你在这里实现的后台播放逻辑开始执行(例如,开始播放音乐)。
  10. 状态更新: 播放开始后,后台逻辑(在 Callback.onPlay() 中)更新 MediaSession 的状态(例如,设置播放状态为 PlaybackState.STATE_PLAYING)。
  11. 状态分发: MediaSession 自动将新的播放状态广播给所有连接的 MediaController。
  12. UI 更新: UI 的 MediaController 收到状态更新,触发其注册的 MediaController.Callback.onPlaybackStateChanged()。UI 在这里更新界面(如将按钮图标改为暂停图标,更新进度条)。
  13. 断开: 当 UI 销毁时,它调用 MediaController.unregisterCallback() 和 MediaBrowser.disconnect() 进行清理。

注意点

• MediaSession: 核心状态和控制接口。定义"能做什么"(Callback)和"当前状态是什么"。

• MediaBrowserService: 后台服务的基类。托管 MediaSession,实现播放逻辑,管理内容库,处理客户端连接。

• MediaBrowser: 前台连接器。负责连接到 MediaBrowserService 并获取 MediaSession.Token(用于创建 MediaController)和浏览内容。

• MediaController: 前台代理。利用 MediaSession.Token 与后台 MediaSession 通信,发送控制命令并接收状态更新,驱动 UI 变化。

相关推荐
峥嵘life16 小时前
Android蓝牙停用绝对音量原理
android
czlczl2002092517 小时前
IN和BETWEEN在索引效能的区别
android·adb
Volunteer Technology17 小时前
ES高级搜索功能
android·大数据·elasticsearch
北京自在科技18 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
lbb 小魔仙18 小时前
2026远程办公软件夏季深度横测:ToDesk、向日葵、网易UU远程全面对比,远控白皮书
android·服务器·网络协议·tcp/ip·postgresql
coding_fei18 小时前
AudioServer初始化过程
android
brucelee18619 小时前
Docker 运行 Android 模拟器
android·docker·容器
私人珍藏库19 小时前
[Android] 小柚市场app v2.3.0.8安卓版TV版
android
HackTorjan19 小时前
MySQL高可用架构设计与最佳实践
android·人工智能·mysql·adb·自动化
Gary Studio19 小时前
自定义 Android 系统服务与 HAL 交互全流程指南
android·交互