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コンテンツアプリ間の変換を行います。

このアーキテクチャの主な利点は、コンテンツアプリが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インターフェイスを介してこれを受け取ります。このインターフェイスにはhandlePlay、handlePause、handleStop、handleSeekなどのメソッドが含まれます。
アプリは、現在の再生状態、機能、サポートされている制御などを記述するMediaSessionStateオブジェクトを保持します。再生状態が変化したら、VegaプラットフォームAPIのupdateMediaSessionStates()を通じてアプリから報告します。すると、Matterキャストサービスはこれらの状態更新をMatter属性レポートに変換します。このレポートはスマートフォンアプリがサブスクライブできます。
主要な概念:
- プロバイダー登録: アプリはそのハンドラーを
MediaControlServerComponentAsync.getOrMakeServer()およびsetHandlerForComponent()を使用して登録します。 - セッション状態: 再生ステータス、位置、速度、機能、およびサポートされているアクションを格納した
MediaSessionStateオブジェクトを保持します。 - 複数セッション: メディアコントロールはピクチャーインピクチャーなどの機能のために複数セッションをサポートします。
メディアコントロール統合ガイドの全文については、以下を参照してください。
MediaPlayStateとMediaControlHandlerを実装するには、これらのガイドに従う必要があります。
次に、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つの目的を果たします。
- コミッショニングパスコードフロー: 最初のコミッショニングプロセス中に、プレーヤーはコンテンツアプリで
GetSetupPINコマンドを呼び出して、コミッショニングパスコードを取得できます。これにより、プレーヤーはユーザーが手動でコードを入力しなくてもクライアントを稼働させることができます。GetSetupPINコマンドには、クライアントからUDCメッセージで渡されるTempAccountIdentifier引数(ローテーションID)があります。コンテンツアプリは通常、独自のクラウドサービスを使用してこのIDを照合し、パスコードを中継します。 - ログインステータスレポート: アプリは、認証ステータス(
SIGNED_INまたはSIGNED_OUT)をシステムに報告します。Fire TV UIはこの情報を使用して、適切な視聴オプション(「今すぐ観る」や「登録」など)を表示します。Matterキャスト中もクライアントアクセスを判断するために使用されます。
アカウントログインクラスターは、対話型コンポーネントとは別のヘッドレスサービスコンポーネントとして実装されます。システムは、アプリのUI全体を起動しなくてもログインステータスを照会できます。これには以下が必要です。
- manifest.tomlで宣言されているサービスコンポーネント。
- ステータスクエリをサービスにルーティングするための
override_attribute_component設定。 @amazon-devices/headless-task-managerを使用して登録されるヘッドレスエントリーポイント。- 対話型コンポーネントとサービスコンポーネントの間でログイン状態を共有するための永続ストレージ(
AsyncStorageなど)。
アカウントログイン統合ガイドの全文は、以下を参照してください。
これらのガイドに従って、AccountLoginWrapperとservice.jsを実装してください。
次に、AccountLoginWrapper内に以下を追加して、Matterアカウントログインクラスターのサポートを追加できます。各ハンドラーはPromise(handleGetSetupPinの場合Promise<string>、handleLoginとhandleLogoutの場合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を参照してください。
関連トピック
- Matterキャストの概要(Fire OS)
- Matterキャストの統合(Fire OS)
- アプリの照明(Fire OS)
- Vega向けの開発
- Vegaアプリのマニフェストファイルの概要
- コンテンツランチャー統合ガイド
- Vegaメディアコントロールを始める
- アカウントログイン統合ガイド
- コンテンツランチャーとアカウントログインのテスト
Last updated: 2026年4月15日

