HarmonyOS AVSession 媒体会话治理:元数据、控制命令与状态同步

媒体应用只在页面内播放还不够,系统控制中心、耳机按键、车机或跨设备控制都需要通过媒体会话理解当前播放状态。AVSession 的难点是把播放器状态、元数据、控制命令和释放时机同步起来。本文用音频路线讲解播放器场景,写一套可维护的媒体会话治理方式。

请添加图片描述

本文先把媒体控制不同步讲清

用户在系统控制中心点暂停,但页面按钮仍显示播放,是媒体会话没有和播放器状态同步。本文把命令入口和状态出口都收口到 MediaSessionBridge。

  • 创建会话后立即写入元数据。
  • 远端命令只调用播放器服务。
  • 播放器状态变化后反向更新会话。
  • 释放时清理会话和监听。

AVSession 资料与声明入口

项目 内容
本地声明 D:/harmonyos/SDK/23/ets/api/@ohos.multimedia.avsession.d.ts
能力范围 媒体会话、播放状态、元数据、远端控制命令。
相关能力 AudioRenderer 负责播放,AVSession 负责系统级媒体会话。
边界 会话状态不等于播放器实现,需要主动同步。

媒体会话的版本边界

项目 内容
SDK HarmonyOS SDK 23。
场景 音乐、播客、音频讲解、系统媒体控制。
状态 播放、暂停、停止、进度和媒体信息。
释放 页面或服务结束时销毁会话,避免系统显示过期媒体。

请添加图片描述

请添加图片描述

先定义播放状态模型

系统会话和播放器都需要读同一份状态。用业务模型承接媒体信息,避免每处都拼 metadata。

export interface PlayingTrack {
  id: string;
  title: string;
  artist: string;
  duration: number;
  coverUri?: string;
}

export interface PlaybackSnapshot {
  track: PlayingTrack;
  position: number;
  playing: boolean;
}

模型层描述业务播放状态。AVSession 和页面都从这里拿数据,减少状态不一致。

创建会话后绑定播放器

会话桥接类负责连接播放器服务和系统会话。页面不直接操作 AVSession。

import avSession from '@ohos.multimedia.avsession';

export class MediaSessionBridge {
  private session?: avSession.AVSession;

  constructor(private player: AudioGuidePlayer) {}

  async open(context: Context): Promise<void> {
    this.session = await avSession.createAVSession(context, 'route_audio_session', 'audio');
    this.bindCommands();
  }
}

桥接类拥有会话生命周期。播放器负责播放,桥接类负责把播放能力暴露给系统。

元数据更新要跟曲目切换绑定

用户切换音频讲解后,系统控制中心必须看到新的标题、作者和时长。

async syncMetadata(track: PlayingTrack): Promise<void> {
  await this.session?.setAVMetadata({
    assetId: track.id,
    title: track.title,
    artist: track.artist,
    duration: track.duration,
    mediaImage: track.coverUri
  });
}

元数据同步只接收 PlayingTrack。它不读取页面字段,避免页面和系统媒体中心显示不同信息。

远端命令只进入播放器服务

耳机按键、系统控制中心和页面按钮都应该调用同一个播放器服务。不要在 AVSession 回调里复制播放逻辑。

private bindCommands(): void {
  this.session?.on('play', async () => this.player.play());
  this.session?.on('pause', async () => this.player.pause());
  this.session?.on('stop', async () => this.player.stop());
  this.session?.on('seek', async (position: number) => this.player.seek(position));
}

命令回调是入口适配层。它只转发到播放器服务,保证所有控制入口行为一致。

播放器变化后反向同步状态

页面点击播放后,如果不更新 AVSession,系统控制中心仍然可能显示暂停。播放器每次状态变化都要推送快照。

async syncPlayback(snapshot: PlaybackSnapshot): Promise<void> {
  await this.syncMetadata(snapshot.track);
  await this.session?.setAVPlaybackState({
    state: snapshot.playing ? avSession.PlaybackState.PLAYBACK_STATE_PLAY : avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
    position: { elapsedTime: snapshot.position, updateTime: Date.now() },
    speed: snapshot.playing ? 1.0 : 0
  });
}

状态同步是出口。播放器内部变化后调用它,系统媒体中心才能展示真实状态。

进度上报要限频

播放进度每秒都变化,但会话更新不需要毫秒级。限频可以降低系统调用和日志噪声。

private lastSyncAt = 0;

async syncProgress(snapshot: PlaybackSnapshot): Promise<void> {
  const now = Date.now();
  if (now - this.lastSyncAt < 1000) {
    return;
  }
  this.lastSyncAt = now;
  await this.syncPlayback(snapshot);
}

限频函数保护状态出口。页面可以高频刷新,系统会话按更稳的节奏更新。

释放会话前先解绑命令

音频页面关闭后,系统控制中心不应继续控制已释放播放器。释放前先 off,再 destroy。

async close(): Promise<void> {
  if (!this.session) {
    return;
  }
  this.session.off('play');
  this.session.off('pause');
  this.session.off('stop');
  this.session.off('seek');
  await this.session.destroy();
  this.session = undefined;
}

关闭函数是资源边界。解绑命令后再销毁会话,避免旧回调访问失效播放器。

媒体会话验证流程:页面、耳机、系统控制中心要一致

AVSession 的验证不能只点页面按钮。建议按顺序测试页面播放、系统控制中心暂停、耳机按键继续、拖动进度、退出页面。每一步都观察页面按钮、系统媒体卡片、播放器真实声音是否一致。只要有一个入口不同步,就回到 MediaSessionBridge 看命令转发和状态同步是否漏掉。多入口控制时要特别注意“谁是事实来源”:播放服务才是真实状态,页面和系统会话都只是状态展示者;如果让每个入口各自维护 playing 字段,迟早会出现一个显示暂停、一个仍在播放的割裂体验。

async function verifySessionSnapshot(bridge: MediaSessionBridge, track: PlayingTrack): Promise<void> {
  await bridge.syncPlayback({
    track,
    position: 0,
    playing: true
  });
  console.info(`[AVSessionVerify] synced track=${track.id}`);
}

这段验证代码直接推送一次播放快照,用来确认系统侧能看到正确元数据和播放状态,并能反查命令入口是否统一。

HarmonyOS AVSession 媒体会话治理排查表

现象 优先查看 处理方式
系统控制中心标题不更新 syncMetadata 是否在切歌后调用 曲目变化立即同步 PlayingTrack。
耳机按键无效 命令监听是否绑定 open 后注册 play/pause/seek。
页面和系统状态相反 播放器变化后是否 syncPlayback 所有状态变化从播放器服务反向同步。
退出后仍显示媒体 close 是否 destroy 会话 页面或服务结束时释放。

HarmonyOS AVSession 媒体会话治理验收清单

上线或交付前建议逐项确认,尤其是生命周期、异常分支和数据一致性。

  • 播放器状态有统一业务模型。
  • AVSession 由桥接类托管。
  • 远端命令只调用播放器服务。
  • 状态和元数据变化后同步到会话。
  • 释放时解绑监听并销毁会话。

小结

AVSession 的工程价值是让系统和外设理解应用正在播放什么、能控制什么。把元数据、命令、状态和释放写成闭环,媒体体验才不会只停留在应用页面内部。

参考资料

以下资料用于核对 API 名称和能力边界,落地时请结合项目目标 API 版本复核。

  • HarmonyOS SDK 23 本地 API 声明:@ohos.multimedia.avsession.d.ts
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐