ヘッドレスアプローチを使用したクライアント側広告挿入の実装
このチュートリアルでは、ヘッドレスアプローチを使用してVegaアプリにクライアント側広告挿入(CSAI)を実装します。このアプローチでは、クライアント/サーバーアーキテクチャを使用し、JavaScript Interface(JSI)ベースのプロセス間通信(IPC)を介して、UIレイヤーのIPlayerClientインスタンスから、独立したサービスレイヤーのVideoPlayerインスタンスと通信します。コンテンツ用のメインプレーヤークライアントと、広告ブレーク中に共有ビデオサーフェスを置き換える広告プレーヤークライアントで構成される、デュアルプレーヤーアーキテクチャをセットアップします。
このチュートリアルの例は、シームレスな広告遷移のために広告を事前バッファリングする方法を示しています。CSAIの概念、テクニック、同期戦略に関する基本的な知識については、Vegaでのクライアント側広告挿入を参照してください。
このチュートリアルでは、次の方法を学習します。
- プレーヤークライアントの参照とインポートを設定する
- 広告マーカーを検出し、広告プレーヤークライアントを事前に初期化する
- 広告がバッファリングされるまで待機した後、メインコンテンツを一時停止する
- ビデオサーフェスを切り替えて広告を再生する
- 広告の終了後にメインコンテンツに戻る
前提条件
- Vega開発環境がセットアップされていること
- Vega SDK v0.22以降
@amazon-devices/kepler-player-clientと@amazon-devices/kepler-player-serverの各パッケージがインストールされていること- メインコンテンツプレーヤークライアントが既に初期化され、サービスに接続されていること
- React NativeとTypeScriptに関する基本的な知識
プレーヤークライアントの参照の設定
必要なパッケージをインポートし、メインプレーヤークライアント、広告プレーヤークライアント、セッションIDの参照を作成します。
import {
PlayerClientFactory,
IPlayerClient,
IPlayerSessionPositionListener,
} from '@amazon-devices/kepler-player-client';
import {
IPlayerSessionId,
IPlayerSessionMediaInfo,
IPlayerSessionStatus,
IPlayerSessionState,
} from '@amazon-devices/kepler-player-server';
// プレーヤークライアントの参照
const playerClient = useRef<IPlayerClient | undefined>(undefined); // メインコンテンツプレーヤークライアント(既に初期化済み)
const adPlayerClient = useRef<IPlayerClient | undefined>(undefined); // 広告プレーヤークライアント
const playerSessionId = useRef<IPlayerSessionId | undefined>(undefined); // メインセッションID
const adPlayerSessionId = useRef<IPlayerSessionId | undefined>(undefined); // 広告セッションID
const sessionIdCounter = useRef(1);
広告マーカーの検出と広告プレーヤークライアントの事前初期化
位置リスナーで広告ブレークが近づいていることを検出したら、広告プレーヤークライアントをautoPlay=falseとして事前に初期化します。さらに、広告のバッファリング完了と終了を検出するためのリスナーを登録します。
- 位置リスナーを設定して、次に来る広告ブレークを検出します。
const positionListener: IPlayerSessionPositionListener = {
onPositionUpdated: (updatedPosition) => {
const currentTime = updatedPosition[0]?.position || 0;
// アプリ固有のロジックで広告ブレークが近づいているかどうかを判断します。
if (adBreakApproaching(currentTime)) {
initializeAdPlayer(adMediaInfo);
}
},
};
- 広告プレーヤークライアントの初期化関数を作成します。ステータスリスナーを登録して、READYとENDEDの状態を検出します。
IPlayerSessionState.READYを利用できないプラットフォームでは、サービスはフォールバックとしてplayerReadyメッセージを送信します。
const initializeAdPlayer = async (adMediaInfo: IPlayerSessionMediaInfo) => {
const factory = new PlayerClientFactory();
adPlayerClient.current = factory.getOrMakeClient(serviceComponentId);
adPlayerSessionId.current = { id: sessionIdCounter.current++ };
// ENDED状態(および利用可能な場合はREADY)を検出するステータスリスナーを登録します。
await adPlayerClient.current?.registerStatusListener({
onSessionStatusChanged: (updatedStatus: Array<IPlayerSessionStatus>) => {
const adStatus = updatedStatus.find(
s => s.sessionId?.id === adPlayerSessionId.current?.id
);
if (
IPlayerSessionState.READY !== undefined &&
adStatus?.playbackState === IPlayerSessionState.READY
) {
onAdReady();
} else if (adStatus?.playbackState === IPlayerSessionState.ENDED) {
onAdEnded();
}
}
}, adPlayerSessionId.current);
// フォールバック: IPlayerSessionState.READYを利用できないプラットフォームでは、
// 代わりにplayerReadyメッセージがサービスから送信されます。
if (IPlayerSessionState.READY === undefined) {
await adPlayerClient.current?.registerMessageListener(
{
onMessageReceived: (message: any) => {
if (message.type === 'playerReady') {
onAdReady();
}
},
},
adPlayerSessionId.current,
);
}
// 手動で制御するためにautoPlay=falseを指定して広告を読み込みます。
await adPlayerClient.current?.load(
adMediaInfo,
{ startPosition: 0, autoPlay: false },
adPlayerSessionId.current,
);
};
広告のバッファリングの待機とメインコンテンツの一時停止
広告プレーヤーからREADY(バッファリング完了)が通知され、位置リスナーで広告の開始時間になったことが検出されたら、メインコンテンツを一時停止します。
let adReady = false;
const onAdReady = () => {
adReady = true;
// 位置リスナーが広告の開始時間を検出するまで待ちます。
};
// 広告の準備が整い、位置リスナーで広告の開始時間になったことが検出されたら、次の処理を実行します。
if (adReady && currentTime >= adStartTime) {
playerClient.current?.pause(playerSessionId.current);
}
サーフェスの切り替えと広告の再生
メインコンテンツのステータスがPAUSEDに変わったら、メインサーフェスを消去して広告プレーヤーに引き渡します。
await playerClient.current?.registerStatusListener({
onSessionStatusChanged: (updatedStatus: Array<IPlayerSessionStatus>) => {
const mainStatus = updatedStatus.find(
s => s.sessionId?.id === playerSessionId.current?.id
);
if (mainStatus?.playbackState === IPlayerSessionState.PAUSED && adPlayerClient.current) {
clearMainSurfaceHandle();
setAdSurfaceHandle();
adPlayerClient.current?.play(adPlayerSessionId.current);
}
}
}, playerSessionId.current);
メインコンテンツへの復帰
広告が終了したら、広告サーフェスを消去し、広告プレーヤークライアントをクリーンアップして、メインコンテンツを再開します。
const onAdEnded = async () => {
await clearAdSurfaceHandle();
cleanupAdPlayer();
await setMainSurfaceHandle();
await playerClient.current?.play(playerSessionId.current);
};
const cleanupAdPlayer = () => {
if (!adPlayerClient.current) return;
adPlayerClient.current.unloadSync(1000, adPlayerSessionId.current);
adPlayerClient.current = undefined;
adReady = false;
};
リソースのクリーンアップ
コンポーネントのマウントが解除されるかプレーヤーセッションが終了したら、広告プレーヤーの読み込みを解除し、リソースを解放します。
const cleanup = () => {
if (adPlayerClient.current) {
adPlayerClient.current.unloadSync(1000, adPlayerSessionId.current);
adPlayerClient.current = undefined;
}
// メインプレーヤークライアントのクリーンアップはアプリの既存のティアダウンロジックによって処理します。
};
関連コンテンツ
Last updated: 2026年3月13日

