as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

Vega Matter投屏集成

Vega Matter投屏集成

要在您的应用中启用Matter投屏,请更新以下内容:

  • 客户端: 适用于Android或iOS的面向用户的手机应用。通过将您的手机应用设为Matter客户端,用户可以发现诸如Fire TV之类的投屏目标。用户还可以投射内容,以及控制投屏会话。
  • 内容应用: 您的运行于Vega上的Fire TV设备中面向用户的应用程序。通过将您的Vega应用设置为Matter内容应用,客户端可以对其进行控制。例如,客户端可以启动特定内容的播放。

有关Matter Casting技术的相关概念、专业术语与前置条件说明,请查阅Matter Casting概述

若需获取Vega平台的开发相关背景资料,请参考Vega开发指南

步骤1: 将Matter投屏SDK集成到您的客户端应用中

Vega平台上的Matter Casting客户端(手机端应用)集成流程与Fire OS完全一致。你的安卓或iOS手机应用程序需使用Matter Casting SDK来执行发现播放器、建立连接和发送命令等操作。

无需对手机应用程序进行任何更改即可支持Vega设备上的Matter Casting。有关将Matter Casting SDK集成到您的客户端应用程序(包括构建和设置、调试和设备认证)的完整详细信息,请参阅Fire OS Matter Casting集成指南中的第 1 步

步骤2: 将Matter Casting集成到Vega应用程序

在Vega上,内容应用程序集成在概念上与Fire OS类似,但使用不同的API。您的Vega应用程序将与Vega平台集成,无需直接使用AIDL文件、Matter代理客户端和BroadcastReceivers等Matter协议组件。

Vega Platform提供了一套不受模式限制的API,它们划分非不同集群,每个集群都是一组关联的指令与属性的集合。您的内容应用程序注册为其支持的集群的提供商,Vega Matter Casting服务则负责处理您的提供商应用程序和客户端手机应用程序之间的通信。

架构概述

在Vega OS上,Vega平台Matter Casting服务负责处理 Matter 协议层,在手机应用程序和Vega内容应用程序之间完成双向转译。

Vega的Matter Casting架构

这种架构的主要优势在于,您的内容应用程序永远不会直接与Matter协议进行交互。您只需实现标准的Vega平台集群处理程序,Vega平台的Matter Casting服务就会完成所有协议转译工作。

Matter集群与Vega平台集群的映射关系

Matter投屏定义了多个功能集群,Fire OS和Vega架构中都包含部分由系统直接托管的集群,内容应用无需做任何额外开发。在Vega平台中,部分Matter集群会映射为Vega平台集群,需要你的内容应用自行实现。

系统处理的集群

内容应用程序无需执行任何操作,即可实现此类集群的代码。

Matter集群 描述
应用程序启动器 内部处理安全校验,以及内容应用程序的启动、停止、隐藏操作。
应用程序基础 自动从内容应用程序清单中检索所有应用程序信息。

内容应用程序集群

您的Vega内容应用程序通过注册为提供商的方式来实现这些集群。

Matter集群 Vega平台提供商
内容启动器 内容启动器概述
媒体播放 Vega媒体控制概述
账户登录 账户登录集成指南

1.更新您的应用清单

必须更新您的Vega应用程序的manifest.toml文件,以声明对Matter Casting的支持,以及您应用程序所提供的Vega平台集群。Vega中的这一操作相当于Fire OS中的更新AndroidManifest.xml

Matter Casting配置

添加[offers.matter-casting]部分,以声明您应用程序的Matter Casting身份。供应商ID和商品编码必须与您的设备认证证书(DAC)中的对应值相匹配。有关更多信息,请参阅应用认证

在开发阶段,您可以使用以下示例值。此部分位于清单的[offers]区域。

已复制到剪贴板。

[offers.matter-casting] 
vendor-id      = <<CSA授予的应用程序专属VID,例如 65521>> 
product-id  =   <<CSA授予的应用程序专属PID例如
 5678>> 
vendor-name = "Your App Name" 

完整清单示例

以下示例展示了支持内容启动器、媒体控制、账户登录和目标导航集群的Matter Casting的Vega内容应用程序的完整manifest.toml。将com.amazondeveloper.media.sample替换为您应用的程序包ID。


已复制到剪贴板。

schema-version = 1 
 
[package] 
title = "<应用标题>" 
id = "com.amazondeveloper.media.sample" 
 
# --- Components --- 
 
[components] 
 
[[components.interactive]] 
id = "com.amazondeveloper.media.sample.main" 
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0" 
launch-type = "singleton" 
categories = ["com.amazon.category.main", "com.amazon.category.kepler.media"] 
 
# 账户登录的服务组件(无界面,没有 UI)
[[components.service]] 
id = "com.amazondeveloper.media.sample.interface.provider" 
runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0" 
launch-type = "singleton" 
 
# --- Processes --- 
 
[processes] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.main"] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.interface.provider"] 
 
# --- Offers --- 
 
# Matter Casting 身份
[offers.matter-casting] 
vendor-id = 65521 
product-id = 5678 
vendor-name = "Your app name" 
 
[[offers.interaction]] 
id = "com.amazondeveloper.media.sample.main" 
 
[[offers.service]] 
id = "com.amazondeveloper.media.sample.interface.provider" 
required-privileges = ["com.amazon.multimedia.privilege.session.manage"] 
 
[[offers.module]] 
id = "/com.amazondeveloper.media.sample.module@ISomeUri1" 
includes-messages = ["pkg://com.amazondeveloper.media.sample.main"] 
 
# --- Messaging --- 
 
[[message]] 
uri = "pkg://com.amazondeveloper.media.sample.main" 
sender-privileges = ["*"] 
receiver-privileges = ["self"] 
 
# --- Vega platform Cluster Declarations --- 
 
[[extras]] 
key = "interface.provider" 
component-id = "com.amazondeveloper.media.sample.main" 
 
[extras.value.application] 
 
# 内容启动器集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IContentLauncherServer" 
attribute_options = ["partner-id"] 
static-values = { partner-id = "<您的合作伙伴ID>" } 
 
# 媒体控制集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IMediaPlaybackServer" 
command_options = [ 
    "StartOver", 
    "Previous", 
    "Next", 
    "SkipForward", 
    "SkipBackward", 
] 
attribute_options    =   [AudioAdvanceMuted”]  
features = ["AdvancedSeek", "VariableSpeed", "AudioTracks", "TextTracks"] 
 
# 账号登录集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IAccountLoginServer" 
attribute_options = ["Status"] 
# 将账户登录状态读取到服务组件 
override_attribute_component = { Status = "com.amazondeveloper.media.sample.interface.provider" } 
 
# 目标导航集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.ITargetNavigator" 
 
# --- Required Modules --- 
 
[needs] 
 
[[needs.module]] 
id = "/com.amazon.kepler.media@IContentLauncher1" 
 
[[needs.module]] 
# 这种格式故意在“media”后面添加了一个句点 (.)。
id = "/com.amazon.kepler.media.@IAccountLogin1" 

已复制到剪贴板。

schema-version = 1 
 
[package] 
title = "<应用标题>" 
id = "com.amazondeveloper.media.sample" 
 
# --- Components --- 
 
[components] 
 
[[components.interactive]] 
id = "com.amazondeveloper.media.sample.main" 
runtime-module = "/com.amazon.kepler.runtime.react_native_kepler_4@IReactNativeKepler_0" 
launch-type = "singleton" 
categories = ["com.amazon.category.main", "com.amazon.category.kepler.media"] 
 
# 账户登录的服务组件(无界面,没有 UI)
[[components.service]] 
id = "com.amazondeveloper.media.sample.interface.provider" 
runtime-module = "/com.amazon.kepler.runtime.react_native_kepler_headless_4@IReactNativeKeplerHeadless_0" 
launch-type = "singleton" 
 
# --- Processes --- 
 
[processes] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.main"] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.interface.provider"] 
 
# --- Offers --- 
 
# Matter Casting 身份
[offers.matter-casting] 
vendor-id = 65521 
product-id = 5678 
vendor-name = "Your app name" 
 
[[offers.interaction]] 
id = "com.amazondeveloper.media.sample.main" 
 
[[offers.service]] 
id = "com.amazondeveloper.media.sample.interface.provider" 
required-privileges = ["com.amazon.multimedia.privilege.session.manage"] 
 
[[offers.module]] 
id = "/com.amazondeveloper.media.sample.module@ISomeUri1" 
includes-messages = ["pkg://com.amazondeveloper.media.sample.main"] 
 
# --- Messaging --- 
 
[[message]] 
uri = "pkg://com.amazondeveloper.media.sample.main" 
sender-privileges = ["*"] 
receiver-privileges = ["self"] 
 
# --- Vega platform Cluster Declarations --- 
 
[[extras]] 
key = "interface.provider" 
component-id = "com.amazondeveloper.media.sample.main" 
 
[extras.value.application] 
 
# 内容启动器集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IContentLauncherServer" 
attribute_options = ["partner-id"] 
static-values = { partner-id = "<您的合作伙伴ID>" } 
 
# 媒体控制集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IMediaPlaybackServer" 
command_options = [ 
    "StartOver", 
    "Previous", 
    "Next", 
    "SkipForward", 
    "SkipBackward", 
] 
attribute_options    =   [AudioAdvanceMuted”]  
features = ["AdvancedSeek", "VariableSpeed", "AudioTracks", "TextTracks"] 
 
# 账号登录集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.IAccountLoginServer" 
attribute_options = ["Status"] 
# 将账户登录状态读取到服务组件 
override_attribute_component = { Status = "com.amazondeveloper.media.sample.interface.provider" } 
 
# 目标导航集群 
[[extras.value.application.interface]] 
interface_name = "com.amazon.kepler.media.ITargetNavigator" 
 
# --- Required Modules --- 
 
[needs] 
 
[[needs.module]] 
id = "/com.amazon.kepler.media@IContentLauncher1" 
 
[[needs.module]] 
# 这种格式故意在“media”后面添加了一个句点 (.)。
id = "/com.amazon.kepler.media.@IAccountLogin1" 

关于清单的要点:

  • [offers.matter-casting]部分声明了您的应用程序的Matter Casting服务的Matter身份(供应商 ID、产品 ID 和供应商名称)。
  • [[extras]]部分(其key = "interface.provider")说明了您应用支持哪些Vega平台集群。这就像Fire OS中名为static_matter_clusters的JSON文件一样。
  • 在主要交互组件中,categories字段必须包含"com.amazon.category.kepler.media"
  • 账号登录集群利用override_attribute_component 属性将状态查询请求路由至一个无头的服务组件,这使得系统能够在不唤醒整个应用程序用户界面的情况下查询登录状态。
  • 媒体控制集群中的command_options和features字段用于表明应用程序所支持的可选指令与功能特性。请根据您的应用程序的功能,调整这些设置。

2.添加程序包依赖项

将以下依赖项添加到您支持的Vega平台集群的package.json文件中。

已复制到剪贴板。

{ 
  "dependencies": { 
    //内容启动器   
    "@amazon-devices/kepler-media-content-launcher": "^2.0.0", 

    //媒体控件   
    "@amazon-devices/kepler-media-controls": "~1.0.0", 
    "@amazon-devices/kepler-media-types": "~1.0.0", 

    //账号登录  
    "@amazon-devices/kepler-media-account-login": "^1.1.0", 
    "@amazon-devices/headless-task-manager": "^1.1.0", 

    "@amazon-devices/vega-target-navigator-provider": "*" 
  } 
} 

3.实现内容启动器集群

内容启动器集群对应Matter Content Launcher集群,其核心作用是让手机端应用能够直接启动您Vega应用内的指定内容。

当手机应用程序发送Matter Content Launcher命令时,Matter Casting服务会将其转换为Vega平台内容启动器调用。您的应用程序通过IContentLauncherHandler接口接收该请求,具体是通过handleLaunchContent回调来处理。

该回调将接收以下参数:

  • contentSearch — 描述用户想要观看或搜索的内容,包括包含实体类型、值和外部ID的参数列表。
  • autoPlay — 如为true,则直接播放内容(快速播放)。如为false,则显示搜索结果。
  • optionalFields — 其他可选参数。

若需获取完整的内容启动器集成指南(含详细请求示例及目录对接说明),请参阅以下内容。

对于Matter Casting,以下是您在handleLaunchContent实现中的响应规范。

已复制到剪贴板。

export class ContentLauncherHandler {

  // --- Matter 0x00 LaunchContent(可选,需要CS功能)及
  // 0x01 LaunchURL(可选,需要UP功能)---
  //
  //通过相同的handleLaunchContent接口支持内容启动。
  //因此,无论使用哪条命令(LaunchURL或LaunchContent),手机都可以 
  //发送,内容应用程序将以相同的方式处理。
  //
  // 重要 — 响应规范:
  //   提供商必须解析返回的Promise <ILauncherResponse>。Matter Casting
  // 服务强制执行25秒的命令超时,因此提供商 
  //   应在20秒内返回ILauncherResponse,以便
  // 用于传输和处理开销。如果未
  // 在25秒内收到回复,手机应用程序将收到超时错误。
  //
  async handleLaunchContent(
    contentSearch: IContentSearch,
    autoPlay: boolean,
    _optionalFields: ILaunchContentOptionalFields,
  ): Promise<ILauncherResponse> {

    if (autoPlay) {
      console.log('Content Launcher: autoPlay=true, starting playback');
    } else {
      console.log('Content Launcher: autoPlay=false, showing search results');
    }

    //返回SUCCESS — Matter Casting服务将其转译为 
    //状态为SUCCESS的Matter LauncherResponse (0x02) 
    return this.factory
      .makeLauncherResponseBuilder()
      .contentLauncherStatus(ContentLauncherStatusType.SUCCESS)
      .optionalData('启动已成功处理')
      .build();

    // 其他状态选项:
    //   ContentLauncherStatusType.AUTH_FAILED      — 用户未获授权
    //   ContentLauncherStatusType.URL_NOT_AVAILABLE — 未找到内容/其他错误
  }
}

4.实现媒体控制集群

媒体控制集群对应Matter Media Playback集群。它使手机应用能够控制你Vega应用中的媒体播放行为,包括播放、暂停、停止、定位、快进、快退、上一曲、下一曲等操作。

当手机应用程序发送Matter Media Playback命令时,Matter Casting服务会将其转译为Vega平台的Media Controls呼叫。您的应用程序通过IMediaControlHandlerAsync接口接收此信息,包括handlePlayhandlePausehandleStophandleSeek等等。

您的应用程序需维护一个MediaSessionState对象,用于描述当前播放状态、功能和支持的控制选项。当播放状态发生变化时,您可以通过Vega平台API updateMediaSessionStates()予以报回。然后,Matter Casting服务将这些状态更新转换为手机应用程序可以订阅的Matter属性报告。

关键概念:

  • 提供商注册: 您的应用程序使用MediaControlServerComponentAsync.getOrMakeServer()setHandlerForComponent()注册器处理程序。
  • 会话状态: 维护包括播放状态、位置、速度、功能和支持操作的MediaSessionState对象。
  • 多个会话: 媒体控件支持画中画等功能的多个会话。

有关完整的媒体控制集成指南,请参阅以下内容。

应按照这些指南来实现MediaPlayStateMediaControlHandler

接下来,即可在MediaControlHandlerAsync中添加以下内容,以添加Matter Media Playback集群所需的支持。每个处理程序都返回一个Promise<void>。提供商必须解析或拒绝每次处理程序调用的返回Promise。Matter Casting服务强制执行25秒的命令超时,因此提供商必须在20秒内解析承诺,以留出足够开销时间用于传输和处理。如果在25秒内未收到任何响应,则您的手机应用程序将收到超时错误。

已复制到剪贴板。

export class MediaControlHandlerAsync implements IMediaControlHandlerAsync {

  // --- Matter 0x00 Play (mandatory) ---
  async handlePlay(_sessionId?: IMediaSessionId): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PLAYING;
    this.state.playbackSpeed = 1.0;
    this.pushState();
  }

  // --- Matter 0x01 Pause (mandatory) ---
  async handlePause(
    _sessionId?: IMediaSessionId,
    _context?: ICommandContext,
  ): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PAUSED;
    this.pushState();
  }

  // --- Matter 0x02 Stop (mandatory) ---
  async handleStop(_sessionId?: IMediaSessionId): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.NOT_PLAYING;
    this.state.currentPosition = { seconds: 0, nanoseconds: 0 };
    this.pushState();
  }

  // --- Matter 0x03 StartOver (Optional) ---
  async handleStartOver(_sessionId?: IMediaSessionId): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PLAYING;
    this.state.currentPosition = { seconds: 0, nanoseconds: 0 };
    this.state.playbackPosition.position = { seconds: 0, nanoseconds: 0 };
    this.pushState();
  }

  // --- Matter 0x04 Previous (optional) ---
  async handlePrevious(): Promise<void> {
    // 跳到上一曲目的业务逻辑 
  }

  // --- Matter 0x05 Next (optional) ---
  async handleNext(_sessionId?: IMediaSessionId): Promise<void> {
    // 跳到下一曲目的业务逻辑 
  }

  // --- Matter 0x06 Rewind(可选,需用到变速功能)---
  async handleRewind(_sessionId?: IMediaSessionId): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PLAYING;
    if (this.state.playbackSpeed > -5.0) {
      this.state.playbackSpeed =
        this.state.playbackSpeed <= -1.0
          ? this.state.playbackSpeed - 1.0
          : -1.0;
    }
    this.pushState();
  }

  // --- Matter 0x07 FastForward (optional, requires VariableSpeed feature) ---
  async handleFastForward(_sessionId?: IMediaSessionId): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PLAYING;
    if (this.state.playbackSpeed < 5.0) {
      this.state.playbackSpeed =
        this.state.playbackSpeed >= 1.0
          ? this.state.playbackSpeed + 1.0
          : 1.0;
    }
    this.pushState();
  }

  // --- Matter 0x08 SkipForward (optional) ---
  async handleSkipForward(
    delta: ITimeValue,
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    this.state.currentPosition = {
      seconds: this.state.currentPosition.seconds + delta.seconds,
      nanoseconds: this.state.currentPosition.nanoseconds + delta.nanoseconds,
    };
    this.state.playbackPosition.position = this.state.currentPosition;
    this.pushState();
  }

  // --- Matter 0x09 SkipBackward (optional) ---
  async handleSkipBackward(
    delta: ITimeValue,
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    this.state.currentPosition = {
      seconds: Math.max(0, this.state.currentPosition.seconds - delta.seconds),
      nanoseconds: 0,
    };
    this.state.playbackPosition.position = this.state.currentPosition;
    this.pushState();
  }

  // --- Matter 0x0B Seek(可选,需要 AdvancedSeek 功能)---
  async handleSeek(
    position: ITimeValue,
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    this.state.currentPosition = position;
    this.state.playbackPosition.position = position;
    this.pushState();
  }

  // --- Matter 0x0C ActivateAudioTrack(可选,需要 AudioTracks 功能)---
  async handleSetAudioTrack(
    audioTrack: ITrack,
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    // 激活所选音轨的业务逻辑。
  }

  //---Matter 0x0D ActivateTextTrack(可选,需要 TextTracks 功能)---
  async handleEnableTextTrack(
    textTrack: ITrack,
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    // 启用所选文字轨道的业务逻辑 
  }

  // --- Matter 0x0E DeactivateTextTrack(可选,需要 TextTracks 功能)---
  async handleDisableTextTrack(
    _sessionId?: IMediaSessionId,
  ): Promise<void> {
    // 禁用活动文字轨道的业务逻辑。
  }
}

5.部署账户登录集群

账户登录集群对应于 Matter Account Login cluster。在Matter Casting中,该集群有两个用途:

  1. 配对接码流程: 在初始配对接码流程中,播放器可以在您的内容应用程序上调用GetSetupPIN命令来获取配对接码。如此,无需用户手动输入代码,播放器即可完成客户端的配网。GetSetupPIN命令包含一个TempAccountIdentifier参数(即旋转ID),该参数由客户端通过UDC消息传递。内容应用程序通常利用其自有云服务来匹配此配对接码。
  2. 登录状态报告: 您的应用程序需向系统报告其身份验证状态(SIGNED_INSIGNED_OUT)。Fire TV 用户界面根据该状态显示合适的观看选项(例如 “立即观看” 或 “订阅”),以及在Matter Casting期间确定客户端的内容访问权限。

账户登录集群是作为无头服务组件实现的,与交互式组件相互独立。系统可以在不唤醒整个应用程序UI的情况下查询登录状态。为此,需要以下:

  • manifest.toml中声明该无头服务组件。
  • 设置override_attribute_component,将状态查询请求路由至该无头服务组件。
  • 使用@amazon-devices/headless-task-manager注册的无头入口点。
  • 永久存储方案(例如 AsyncStorage),用于在交互组件和服务组件之间共享登录状态。

有关账户登录集成指南的完整内容,请参阅以下内容。

按照这些指南实现AccountLoginWrapperservice.js

接下来,便可在AccountLoginWrapper中添加以下内容,以添加对Matter账户登录集群的支持。每个处理程序都返回一个 Promise(handleGetSetupPinPromise<string>handleLoginhandleLogout则为Promise<void>)。提供商必须解析或拒绝每次处理程序调用的返回promise。Matter Casting服务强制执行25秒的命令超时,因此提供商必须在20秒内解析承诺,以留出足够开销时间用于传输和处理。如果在25秒内未收到任何响应,则手机应用程序将收到超时错误。

已复制到剪贴板。

export class AccountLoginWrapper {

  createAccountLoginHandler(): IAccountLoginHandlerAsync {
    return {

      // --- Matter 0x00 GetSetupPIN ---
      // 内容应用会为指定账户生成设置PIN码。
      handleGetSetupPin: async (accountId: string): Promise<string> => {
        console.log(`[KCP] handleGetSetupPin, accountId=${accountId}`);
        const setupPin = '12345678';
        return setupPin;
      },

      // --- Matter 0x02 Login ---
      // 内容应用会验证PIN码并允许用户登录。
      handleLogin: async (accountId: string, pin: string): Promise<void> => {
        console.log(`[KCP] handleLogin, accountId=${accountId}`);
        await AccountLoginWrapper.saveLoginStatus(true);
        const status = accountLoginServerComponent
          .makeStatusBuilder()
          .status(StatusType.SIGNED_IN)
          .build();
        this.accountLoginServer?.updateStatus(status);
      },

      // --- Matter 0x03 Logout ---
      // 播放器发送此消息以结束用户的会话。
      handleLogout: async (): Promise<void> => {
        console.log('[KCP] handleLogout');
        await AccountLoginWrapper.saveLoginStatus(false);
        const status = accountLoginServerComponent
          .makeStatusBuilder()
          .status(StatusType.SIGNED_OUT)
          .build();
        this.accountLoginServer?.updateStatus(status);
      },
    };
  }
}

6.实现目标导航集群

目标导航集群对应于Matter Target Navigator集群。它提供了一个接口,用于在应用程序中不同播放目标之间导航,例如切换不同屏幕界面、内容分类或输出端点。

应用程序需注册一个处理程序来接收目标导航请求。当手机应用程序发送Matter Target Navigator命令时,Matter Casting服务会将其转移为Vega平台的Target Navigator调用。处理程序会收到一个StandardTargetIdentifier1对象,其中包含要导航至的目标标识符。

关键概念:

  • 目标发现: 您的应用程序需对外公开可用的导航目标及其元数据,包括唯一的标识符和人类可读的名称。
  • 目标选择: 您的处理程序负责接收并处理导航请求,随后切换至指定的目标界面或端点。

Target Navigator集成指南正在编写之中。

7.报告属性变化

Matter Casting的一个关键环节,是确保手机应用程序可以随时了解内容应用程序的当前状态。当内容应用程序的状态发生变化时,您必须通过Vega Platform API将这些更改上报。状态变化示例包括:播放开始、暂停或用户登录。Vega Matter Casting Service在内部将这些状态变化转译为Matter属性报告,由手机应用程序通过订阅接收。

每个集群都有自己的报告属性变更的机制。

Matter集群 用于报告属性变更的Vega Platform cluster API
内容启动器 不支持
媒体播放 MediaControlServerAsync.updateMediaSessionStates()
账户登录 IAccountLoginServerAsync.updateStatus()
媒体播放 开发中

媒体控制

已复制到剪贴板。

const server: IMediaControlServerAsync =
  MediaControlServerComponentAsync.getOrMakeServer();

// 任何播放状态更改后,重建并推送会话状态。
const mediaPlayerState = new MediaPlayerState(); // 来自您的MediaPlayerState类

//示例:用户按下播放键。
mediaPlayerState.playbackStatus = PlaybackStatus.PLAYING;
mediaPlayerState.playbackSpeed = 1.0;
server.updateMediaSessionStates([mediaPlayerState.getServerState()]);

//示例:用户想要定位至 5 分钟处。
mediaPlayerState.currentPosition = { seconds: 300, nanoseconds: 0 };
mediaPlayerState.playbackPosition.position = { seconds: 300, nanoseconds: 0 };
server.updateMediaSessionStates([mediaPlayerState.getServerState()]);

// 示例:用户按下暂停键。
mediaPlayerState.playbackStatus = PlaybackStatus.PAUSED;
server.updateMediaSessionStates([mediaPlayerState.getServerState()]);

// 示例:内容发生更改(例如已开始下一集或内容启动器启动了
// 一部新电影)。
mediaPlayerState.mediaId = {
  contentId: 'episode-002',
  catalogName: 'my-catalog-v1',
};
mediaPlayerState.playbackStatus = PlaybackStatus.PLAYING;
mediaPlayerState.currentPosition = { seconds: 0, nanoseconds: 0 };
mediaPlayerState.playbackPosition.position = { seconds: 0, nanoseconds: 0 };
server.updateMediaSessionStates([mediaPlayerState.getServerState()]);

账户登录

已复制到剪贴板。

const server: IAccountLoginServerAsync =
  new AccountLoginServerComponent().getOrMakeServer();

// 示例:用户登录。
const signedInStatus = new AccountLoginServerComponent()
  .makeStatusBuilder()
  .status(StatusType.SIGNED_IN)
  .build();
server.updateStatus(signedInStatus);

// 示例:用户注销。
const signedOutStatus = new AccountLoginServerComponent()
  .makeStatusBuilder()
  .status(StatusType.SIGNED_OUT)
  .build();
server.updateStatus(signedOutStatus);

8.按需安装您的Vega应用程序

如果用户尚未安装您的内容应用程序,但尝试投屏至该应用程序,则系统应提示用户安装该应用程序。此操作利用应用程序启动器集群在系统层面进行处理。手机应用程序在启动应用程序集群有效载荷的ApplicationID中提供软件包名称,系统会将名称与Vega App Store进行匹配,从而引导完成安装。

此客户端行为与Fire TV中完全相同,您的内容应用程序无需为这一功能进行额外的集成。这一确保manifest.toml中的应用程序包名称与Vega App Store中发布的包名称相匹配。

步骤3: 与播放器交互

视频播放器的交互行为可能是发现设备、建立连接、选择端点、发出命令、读取属性或订阅事件等。这些交互均由手机应用程序使用Matter Casting SDK完成处理。无论播放器运行的是Fire OS还是Vega OS,该交互过程都是一样的。

有关发现、连接至播放器,以及选择终端和通过手机与内容应用程序进行交互的完整详细信息,请参阅Fire OS Matter Casting集成指南中的第3步


Last updated: 2026年4月15日