Amazon Developer

as

Settings
Sign out
Notifications
Alexa
Amazonアプリストア
Ring
AWS
ドキュメント
Support
Contact Us
My Cases
開発
設計と開発
公開
リファレンス
サポート

Vega Matterキャストの統合

Vega Matterキャストの統合

アプリでMatterキャストを有効にするには、以下を更新する必要があります。

  • クライアント: これはユーザーが使用するAndroidまたはiOSのスマートフォンアプリです。スマートフォンアプリをMatterクライアントにすると、ユーザーがFire TVなどのキャストターゲットを検出できるようになります。さらに、コンテンツをキャストしたり、キャストセッションを制御したりすることもできます。
  • コンテンツアプリ: Vega上で動作するFire TVデバイス上のユーザー向けアプリです。VegaアプリをMatterコンテンツアプリにすると、クライアントがVegaアプリを制御できるようになります。たとえば、クライアントで特定のコンテンツの再生を開始できます。

Matterキャストの概念、用語、および前提条件に関する背景情報については、「Matterキャストの概要」を参照してください。

Vegaを使った開発の背景情報については、「Vega向け開発」を参照してください。

手順1: MatterキャストSDKをクライアントアプリに統合する

VegaでのMatterキャストのクライアント(スマートフォンアプリ)統合は、Fire OSの場合と同じように機能します。AndroidまたはiOSのスマートフォンアプリはMatterキャストSDKを使用して、プレーヤーを検出し、接続を確立し、コマンドを送信します。

VegaデバイスでMatterキャストをサポートするために、スマートフォンアプリを変更する必要はありません。ビルドとセットアップ、コミッショニング、デバイス認証など、MatterキャストSDKをクライアントアプリに統合する方法の詳細については、Fire OS Matterキャスト統合ガイドの手順1を参照してください。

手順2: MatterキャストをVegaアプリに統合する

Vegaにおいて、コンテンツアプリの統合は概念的にFire OSと似ていますが、使用するAPIは異なります。AIDLファイル、Matterエージェントクライアント、BroadcastReceiverなどのMatterプロトコル構成を直接操作する代わりに、VegaアプリはVegaプラットフォームと統合されます。

Vegaプラットフォームは、関連するコマンドと属性のグループであるクラスターにまとめられた、モダリティにとらわれない一連のAPIを提供します。コンテンツアプリはサポートするクラスターのプロバイダーとして登録され、Vega Matterキャストサービスがプロバイダーアプリとクライアントのスマートフォンアプリ間の通信を処理します。

アーキテクチャの概要

Vega OSでは、VegaプラットフォームのMatterキャストサービスがMatterプロトコルレイヤーを処理し、スマートフォンアプリとVegaコンテンツアプリ間の変換を行います。

Vega Matterキャストアーキテクチャ

このアーキテクチャの主な利点は、コンテンツアプリがMatterプロトコルと直接やり取りしないことです。標準のVegaプラットフォームクラスターハンドラーを実装すると、VegaプラットフォームのMatterキャストサービスがすべてのプロトコル変換を処理します。

MatterクラスタからVegaプラットフォームクラスタへのマッピング

Matterキャストはいくつかのクラスターを定義します。Fire OSとVegaアーキテクチャの両方には、システムによって処理され、コンテンツアプリのアクションを必要としないクラスターがいくつかあります。Vegaでは、一部のクラスターは、コンテンツアプリが実装する必要があるVegaプラットフォームクラスターにマップされます。

システム処理クラスター

このコードを実装するためにコンテンツアプリのアクションは必要ありません。

Matterクラスター 説明
アプリランチャー セキュリティとコンテンツアプリの起動、停止、非表示を内部で処理します。
アプリベーシック コンテンツアプリマニフェストからすべてのアプリ情報を自動的に取得します。

コンテンツアプリクラスター

Vegaコンテンツアプリは、プロバイダーとして登録することでこれらのクラスターを実装します。

Matterクラスター Vegaプラットフォームプロバイダー
コンテンツランチャー コンテンツランチャーの概要
メディアの再生 Vegaメディアコントロールの概要
アカウントログイン アカウントログイン統合ガイド

1. アプリのマニフェストを更新する方法

Matterキャストのサポートとアプリが提供するVegaプラットフォームクラスターを宣言するには、Vegaアプリのmanifest.tomlファイルを更新する必要があります。これは、Fire OSにおけるAndroidManifest.xmlの更新に相当するVegaでの作業です。

Matterキャスト構成

[offers.matter-casting]セクションを追加して、アプリのMatterキャストのアイデンティティを宣言してください。ベンダーIDと製品IDは、デバイス認証証明書(DAC)の値と一致する必要があります。詳しくは、「アプリの証明」を参照してください。

開発のためには、次のサンプル値を使用できます。このセクションはマニフェストの[offers]エリアにあります。

クリップボードにコピーしました。

[offers.matter-casting] 
vendor-id = <<CSA によって 付与された アプリ固有  VID 例: 65521>> 
product-id = <<CSA によって 付与された アプリ固有  PID 例: 5678>> 
vendor-name = "あなたのアプリ名" 

マニフェスト全体の例

次の例は、コンテンツランチャー、メディアコントロール、アカウントログイン、およびターゲットナビゲータークラスターと共にMatterキャストをサポートするVegaコンテンツアプリの完全なmanifest.tomlを示しています。com.amazondeveloper.media.sampleは、独自のアプリのパッケージIDに置き換えてください。


クリップボードにコピーしました。

schema-version = 1 
 
[package] 
title = "<アプリタイトル>" 
id = "com.amazondeveloper.media.sample" 
 
# --- コンポーネント --- 
 
[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.group]] 
component-ids = ["com.amazondeveloper.media.sample.main"] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.interface.provider"] 
 
# --- オファー --- 
 
# Matterキャストのアイデンティティ
[offers.matter-casting] 
vendor-id = 65521 
product-id = 5678 
vendor-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"] 
 
# --- メッセージング --- 
 
[[message]] 
uri = "pkg://com.amazondeveloper.media.sample.main" 
sender-privileges = ["*"] 
receiver-privileges = ["self"] 
 
# --- Vegaプラットフォームクラスター宣言 --- 
 
[[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" 
 
# --- 必須モジュール --- 
 
[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.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.group]] 
component-ids = ["com.amazondeveloper.media.sample.main"] 
 
[[processes.group]] 
component-ids = ["com.amazondeveloper.media.sample.interface.provider"] 
 
# --- オファー --- 
 
# Matterキャストのアイデンティティ
[offers.matter-casting] 
vendor-id = 65521 
product-id = 5678 
vendor-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"] 
 
# --- メッセージング --- 
 
[[message]] 
uri = "pkg://com.amazondeveloper.media.sample.main" 
sender-privileges = ["*"] 
receiver-privileges = ["self"] 
 
# --- Vegaプラットフォームクラスター宣言 --- 
 
[[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" 
 
# --- 必須モジュール --- 
 
[needs] 
 
[[needs.module]] 
id = "/com.amazon.kepler.media@IContentLauncher1" 
 
[[needs.module]] 
# この形式で、「media」の後のドット(.)は意図的に追加されています。 
id = "/com.amazon.kepler.media.@IAccountLogin1" 

マニフェストに関する重要なポイント:

  • [offers.matter-casting]セクションは、MatterキャストサービスのためのアプリのMatterアイデンティティ(ベンダーID、プロダクトID、ベンダー名)を宣言します。
  • key = "interface.provider"が付いた[[extras]]セクションは、アプリがサポートするのはどのVegaプラットフォームクラスターかを宣言します。これは、Fire OSにおけるstatic_matter_clusters JSONファイルのようなものです。
  • categoriesフィールドには、プライマリ対話型コンポーネントの「com.amazon.category.kepler.media」が含まれていることが必要です。
  • アカウントログインクラスターはoverride_attribute_componentを使用してステータスクエリをヘッドレスサービスコンポーネントにルーティングするため、システムはアプリのUI全体を起動しなくてもログインステータスをクエリできます。
  • メディアコントロールの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コンテンツランチャークラスターに対応しています。これにより、スマートフォンアプリがVegaアプリ内の特定のコンテンツを起動できるようになります。

スマートフォンアプリがMatterコンテンツランチャーコマンドを送信すると、MatterキャストサービスはそれをVegaプラットフォームのコンテンツランチャー呼び出しに変換します。アプリはIContentLauncherHandlerインターフェイス、具体的にはhandleLaunchContentコールバックを通じてこれを受け取ります。

ハンドラーは以下を受け取ります。

  • contentSearch - エンティティタイプ、値、外部IDを含むパラメーターリストなど、ユーザーが視聴または検索したいコンテンツを記述します。
  • autoPlay - trueの場合、コンテンツを直接再生します(クイック再生)。falseの場合、検索結果を表示します。
  • optionalFields - 追加の任意パラメーター。

詳細なリクエスト例やカタログ統合を含むコンテンツランチャー統合ガイドの全文については、以下を参照してください。

MatterキャストのhandleLaunchContent実装のレスポンスコントラクトは次のとおりです。

クリップボードにコピーしました。

export class ContentLauncherHandler {

  // --- Matter 0x00 LaunchContent(任意、CS機能が必要)と
  // 0x01 LaunchURL(任意、UP機能が必要)---
  //
  // コンテンツ起動は、同じhandleLaunchContentインターフェイスを介してサポートされています。
  // このため、スマートフォンがどちらのコマンド(LaunchURLかLaunchContent)
  // を送信しても、コンテンツアプリは同じように処理します。
  //
  // 重要 - レスポンスコントラクト:
  //   プロバイダーは返されたPromise<ILauncherResponse>を解決する必要があります。Matterキャスト
  //   サービスは25秒のコマンドタイムアウトを強制するため、プロバイダーは
  //   転送と処理のオーバーヘッドを考慮して20秒以内にILauncherResponseを
  //   返す必要があります。25秒以内に応答がない場合
  //   スマートフォンアプリはタイムアウトエラーを受け取ります。
  //
  async handleLaunchContent(
    contentSearch: IContentSearch,
    autoPlay: boolean,
    _optionalFields: ILaunchContentOptionalFields,
  ): Promise<ILauncherResponse> {

    if (autoPlay) {
      console.log('コンテンツランチャー:autoPlay=true、再生を開始します');
    } else {
      console.log('コンテンツランチャー:autoPlay=false、検索結果を表示します');
    }

    // 成功を返す - Matterキャストサービスはこれをステータス
    // SUCCESSのMatter LauncherResponse(0x02)に変換します
    return this.factory
      .makeLauncherResponseBuilder()
      .contentLauncherStatus(ContentLauncherStatusType.SUCCESS)
      .optionalData('起動が正常に処理されました')
      .build();

    // その他のステータスオプション:
    //   ContentLauncherStatusType.AUTH_FAILED      - ユーザーは承認されない
    //   ContentLauncherStatusType.URL_NOT_AVAILABLE - コンテンツが見つからない/その他のエラー
  }
}

4. メディアコントロールクラスターの実装

メディアコントロールクラスターはMatterメディア再生クラスターに対応します。これにより、Vegaアプリでのメディア再生(再生、一時停止、停止、シーク、早送り、早戻し、スキップ送り、スキップ戻しなど)をスマートフォンアプリで制御できます。

スマートフォンアプリがMatterメディア再生コマンドを送信すると、MatterキャストサービスはそれをVegaプラットフォームのメディアコントロール呼び出しに変換します。アプリはIMediaControlHandlerAsyncインターフェイスを介してこれを受け取ります。このインターフェイスにはhandlePlayhandlePausehandleStophandleSeekなどのメソッドが含まれます。

アプリは、現在の再生状態、機能、サポートされている制御などを記述するMediaSessionStateオブジェクトを保持します。再生状態が変化したら、VegaプラットフォームAPIのupdateMediaSessionStates()を通じてアプリから報告します。すると、Matterキャストサービスはこれらの状態更新をMatter属性レポートに変換します。このレポートはスマートフォンアプリがサブスクライブできます。

主要な概念:

  • プロバイダー登録: アプリはそのハンドラーをMediaControlServerComponentAsync.getOrMakeServer()およびsetHandlerForComponent()を使用して登録します。
  • セッション状態: 再生ステータス、位置、速度、機能、およびサポートされているアクションを格納したMediaSessionStateオブジェクトを保持します。
  • 複数セッション: メディアコントロールはピクチャーインピクチャーなどの機能のために複数セッションをサポートします。

メディアコントロール統合ガイドの全文については、以下を参照してください。

MediaPlayStateMediaControlHandlerを実装するには、これらのガイドに従う必要があります。

次に、MediaControlHandlerAsync内に以下を追加して、Matterメディア再生クラスターを追加できます。各ハンドラーはPromise<void>を返します。プロバイダーは、ハンドラー呼び出しのたびに、返されたPromiseを解決するか、または拒否する必要があります。Matterキャストサービスは25秒のコマンドタイムアウトを強制するため、プロバイダーは転送と処理のオーバーヘッドを考慮して20秒以内にPromiseを解決する必要があります。25秒以内に応答がない場合、スマートフォンアプリはタイムアウトエラーを受け取ります。

クリップボードにコピーしました。

export class MediaControlHandlerAsync implements IMediaControlHandlerAsync {

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

  // --- Matter 0x01 一時停止(必須) ---
  async handlePause(
    _sessionId?: IMediaSessionId,
    _context?: ICommandContext,
  ): Promise<void> {
    this.state.playbackStatus = PlaybackStatus.PAUSED;
    this.pushState();
  }

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

  // --- Matter 0x03 スタートオーバー(任意) ---
  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 戻る(任意) ---
  async handlePrevious(): Promise<void> {
    // 前のトラックにスキップするビジネスロジック
  }

  // --- Matter 0x05 次へ(任意) ---
  async handleNext(_sessionId?: IMediaSessionId): Promise<void> {
    // 次のトラックにスキップするビジネスロジック
  }

  // --- Matter 0x06 早戻し(任意、VariableSpeed機能が必要) ---
  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 早送り(任意、VariableSpeed機能が必要) ---
  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 スキップ送り(任意) ---
  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 スキップ戻し(任意) ---
  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 シーク(任意、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アカウントログインクラスターに対応します。Matterキャストのコンテキストでは2つの目的を果たします。

  1. コミッショニングパスコードフロー: 最初のコミッショニングプロセス中に、プレーヤーはコンテンツアプリでGetSetupPINコマンドを呼び出して、コミッショニングパスコードを取得できます。これにより、プレーヤーはユーザーが手動でコードを入力しなくてもクライアントを稼働させることができます。GetSetupPINコマンドには、クライアントからUDCメッセージで渡されるTempAccountIdentifier引数(ローテーションID)があります。コンテンツアプリは通常、独自のクラウドサービスを使用してこのIDを照合し、パスコードを中継します。
  2. ログインステータスレポート: アプリは、認証ステータス(SIGNED_INまたはSIGNED_OUT)をシステムに報告します。Fire TV UIはこの情報を使用して、適切な視聴オプション(「今すぐ観る」や「登録」など)を表示します。Matterキャスト中もクライアントアクセスを判断するために使用されます。

アカウントログインクラスターは、対話型コンポーネントとは別のヘッドレスサービスコンポーネントとして実装されます。システムは、アプリのUI全体を起動しなくてもログインステータスを照会できます。これには以下が必要です。

  • manifest.tomlで宣言されているサービスコンポーネント。
  • ステータスクエリをサービスにルーティングするためのoverride_attribute_component設定。
  • @amazon-devices/headless-task-managerを使用して登録されるヘッドレスエントリーポイント。
  • 対話型コンポーネントとサービスコンポーネントの間でログイン状態を共有するための永続ストレージ(AsyncStorageなど)。

アカウントログイン統合ガイドの全文は、以下を参照してください。

これらのガイドに従って、AccountLoginWrapperservice.jsを実装してください。

次に、AccountLoginWrapper内に以下を追加して、Matterアカウントログインクラスターのサポートを追加できます。各ハンドラーはPromise(handleGetSetupPinの場合Promise<string>handleLoginhandleLogoutの場合Promise<void>)を返します。プロバイダーは、ハンドラー呼び出しのたびに、返されたPromiseを解決するか、または拒否する必要があります。Matterキャストサービスは25秒のコマンドタイムアウトを強制するため、プロバイダーは転送と処理のオーバーヘッドを考慮して20秒以内にPromiseを解決する必要があります。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 ログイン ---
      // コンテンツアプリは、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 ログアウト ---
      // プレーヤーは、ユーザーのセッションを終了するときにこれを送信します。
      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ターゲットナビゲータークラスターに対応します。さまざまな画面、コンテンツカテゴリ、出力エンドポイントなど、アプリ内の再生ターゲット間を移動するためのインターフェイスを提供します。

アプリは、ターゲットナビゲーションリクエストを受け取るハンドラーを登録します。スマートフォンアプリがMatterターゲットナビゲーターコマンドを送信すると、MatterキャストサービスはそれをVegaプラットフォームのターゲットナビゲーター呼び出しに変換します。ハンドラーは、ナビゲート先のターゲットの識別子を含むStandardTargetIdentifier1オブジェクトを受け取ります。

主要な概念:

  • ターゲット検出: アプリは、固有の識別子や人間が読める名前などのメタデータを含む利用可能なターゲットを公開します。
  • ターゲット選択: ハンドラーはナビゲーションリクエストを処理し、要求されたターゲットに切り替えます。

ターゲットナビゲーター統合ガイドは作成中です。

7. レポート属性の変更

Matterキャストの重要な部分は、スマートフォンアプリがコンテンツアプリの現在の状態について常に通知されることです。コンテンツアプリの状態が変化した場合は、VegaプラットフォームAPIを通じてその変化を報告する必要があります。状態変化の例としては、再生の開始、一時停止、ユーザーのログインなどがあります。Vega Matterキャストサービスは、これらの状態変化を、スマートフォンアプリがサブスクリプションを通じて受け取るMatter属性レポートに内部的に変換します。

各クラスターには、属性変更を報告する独自のメカニズムがあります。

Matterクラスター 属性変更を報告するためのVegaプラットフォームクラスタ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アプリストアと照合します。

これはFire TVとまったく同じクライアントの動作です。この機能については、コンテンツアプリから追加で統合する必要はありません。manifest.tomlにあるアプリのパッケージ名が、Vegaアプリストアで公開されているものと一致していることを確認してください。

手順3: プレーヤーを操作する

ビデオプレーヤーのインタラクションには、検出、接続、エンドポイントの選択、コマンドの発行、属性の読み取り、イベントのサブスクライブなどがあります。これらのインタラクションは、MatterキャストSDKを使用してスマートフォンアプリによって処理されます。このインタラクションは、プレーヤーがFire OSとVega OSのどちらを実行していても同じです。

プレーヤーの発見、接続、エンドポイントの選択、スマートフォンからのコンテンツアプリの操作について詳しくは、Fire OS Matterキャスト統合ガイドのステップ3を参照してください。


Last updated: 2026年4月15日