手順5: ウェブプレーヤーを作成する
この手順では、独自のウェブプレーヤーを作成します。このウェブプレーヤーでは、Alexa JavaScriptライブラリを参照および初期化し、その他の機能を提供します。
ウェブプレーヤーの要件
ウェブプレーヤーを作成する際は、コーデック、フォーマット、標準に関する以下の要件に留意してください。
ビデオの要件:
- HLS/MPEG-DASH
- MP4 H.264
- Widevine DRMレベル1
- Encrypted Media Extensions(EME)
- Media Source Extensions(MSE)
オーディオの要件:
- MP4(AAC)
- WebM(Vorbis)
- WebM(Opus)
- AAC-LCはサポートされていますが、AAC-SBRはサポートされていません。適切かつ確実に再生されるようにするため、メディアは「Chromium」向けに定義されたオーディオ仕様を遵守する必要があります。Chromiumの詳細については、Chromium ProjectsサイトのAudio/Video(英語のみ)を参照してください。
画面解像度の要件
Amazonデバイスに送信されるビデオコンテンツは、ディスプレイの解像度よりも高い解像度にすることはできません。ウェブアプリでディスプレイの解像度を確認するには、以下のようにします。
var displayHeight = window.screen.height * window.devicePixelRatio;
var displayWidth = window.screen.width * window.devicePixelRatio;
ウェブプレーヤーでは、上記で計算された高さおよび幅と同じかそれ未満のビデオ解像度を選択する必要があります。ビデオ解像度がディスプレイの解像度よりも高い場合、デバイスでドロップフレームや遅延が発生したり、ビデオコンテンツがまったく再生されなかったりすることがあります。
ユーザーエージェント文字列(window.navigator.userAgent)は、常に先頭がAlexaWebMediaPlayerという文字列になります。
- ユーザーエージェント文字列の例: AlexaWebMediaPlayer/1.0 (Linux; Android 7.1.2)
上記のいずれかの要件が既存のストリーム選択ロジックと異なる場合は、このユーザーエージェント文字列を使用して、Echo Showデバイス上で実行されているかどうかを判別します。Echo Showデバイスで実行されている場合は、上記のガイダンスに従うようにしてください。
ウェブプレーヤーの作成
ウェブプレーヤーを作成するには、大まかな流れとして、以下の各セクションで説明するタスクを完了する必要があります。
ウェブプレーヤーの移行または作成
コンテンツを配信するウェブアセットが既にある場合は、ウェブプレーヤーコンポーネントとサポート機能を分離します。サポート機能には、指標レポートや広告ロジック、その他の依存関係などがあります。ビデオはフルスクリーンモードで排他的に再生する必要があり、ほかのウェブサイトへのリンクは制限されます。
ウェブプレーヤーのスタイルの設定
ウェブプレーヤーのスタイルを設定して、プレーヤーのビジュアルコントロールやビデオ以外の要素を適用します。ビデオのエクスペリエンスに関する認定のガイドラインについては、認定に向けたテストを行うを参照してください。
Alexa Video JavaScriptライブラリのインクルード
alexa-web-player-controller JavaScriptライブラリにより、Alexaとウェブプレーヤーとの間のやり取りが可能になります。HTMLで次のスクリプトタグを使用して、JavaScriptライブラリを読み込みます。
<script type="text/javascript" src="https://dmx0zb087qvjm.cloudfront.net/alexa-web-player-controller.0.1.min.js"></script>
Alexa Video JavaScriptライブラリの初期化
ウェブアプリの初期化コードで、Alexaオブジェクトの準備ができるまで待ってから、readyCallbackとerrorCallbackでalexa-web-player-controllerライブラリを初期化します。readyCallbackは、ライブラリを実行する準備が整ったときに呼び出されます。
readyCallbackでは、ライブラリとやり取りするためのコントローラーオブジェクトを受け取ります。ここに、制御メソッドが含まれています。エラーが発生してウェブプレーヤーが終了する場合は、errorCallbackが呼び出され、人が判読できる形式のエラーメッセージがユーザーに表示されます。
エラーメッセージの送信後、alexa-web-player-controllerライブラリによりウェブコンテナが閉じられます。ライブラリを初期化する際に、イベントハンドラーを登録することもできます。その場合は、イベント名をキーとするコールバック関数のマップを含む引数を追加します。それ以外の場合は、controller.on(handlers)メソッドまたはcontroller.on(event, handler)メソッドを使用してハンドラーを登録できます(次のセクションで説明します)。必要となるのは、再生、一時停止、再開のハンドラーです。
プレーヤーでクローズドキャプションがサポートされている場合は、初期化時にgetClosedCaptionsStateメソッドを呼び出します。状態がIDLEのsetPlayerStateメソッドが呼び出されると、初期化のシーケンスは完了したと見なされます。getClosedCaptionsStateおよびsetPlayerStateメソッドの詳細については、以降のセクションで説明します。
// このスクリプトの前にAlexa Video JavaScriptライブラリを読み込みます。
AlexaWebPlayerController.initialize(readyCallback, errorCallback);
または
AlexaWebPlayerController.initialize(readyCallback, errorCallback, handlers);
イベントハンドラーの登録
controller.on(handlers)メソッドまたはcontroller.on(event, handler)メソッドを使用してハンドラーを登録します。必要となるのは、再生、一時停止、再開のハンドラーです。
function readyCallback(controller) {
    var Event = AlexaWebPlayerController.Event;
    var handlers = {
        Event.LOAD_CONTENT: function handleLoad(params) {},
        Event.PAUSE: function handlePause() {},
        Event.RESUME: function handleResume() {},
        Event.ADJUST_SEEK_POSITION: function handleAdjustPos(offsetInMilliseconds) {},
        Event.NEXT: function handleNext() {},
        Event.PREVIOUS: function handlePrevious() {},
        Event.CLOSED_CAPTIONS_STATE_CHANGE: function handleCCState(state) {},
        Event.PREPARE_FOR_CLOSE: function handlePrepareForClose() {},
        Event.ACCESS_TOKEN_CHANGE: function handleAccessToken(accessToken) {}
    };
    controller.on(handlers);
}
次の表は、さまざまなハンドラーとそのパラメーターをまとめたものです。
| キー | キーの説明 | ハンドラーのパラメーター | 型 | パラメーターの説明 | 
|---|---|---|---|---|
| LOAD_CONTENT | 指定されたコンテンツを読み込みます。 | params.contentUri | 文字列 | ビデオスキルAPIのレスポンスで提供されたコンテンツのURI。 | 
| params.accessToken | 文字列 | ユーザーの認証情報。 | ||
| params.offsetInMilliseconds | 整数 | 再生の開始位置を示す、コンテンツの先頭からのオフセット。 | ||
| params.autoplay | ブール型 | 読み込み後に自動的にコンテンツを再生するかどうかを示すフラグ。autoplay=trueの場合はプレーヤーで再生が開始され、 autoplay=falseの場合は読み込み後にPAUSED(一時停止)の状態になります。 | ||
| PAUSE | 再生を一時停止します。 | (なし) | — | — | 
| RESUME | 再生を再開します。 | (なし) | — | — | 
| ADJUST_SEEK_POSITION | 現在位置からのオフセットを指定して再生位置を変更します。 | offsetInMilliseconds | 整数 | 正の値の場合、再生位置を先頭からオフセット分だけ後ろにずらします。負の値の場合、再生位置を末尾からオフセット分だけ前にずらします。 | 
| NEXT | 次のビデオがある場合は、そのビデオに進みます。 | (なし) | — | — | 
| PREVIOUS | 前のビデオがある場合は、そのビデオに戻ります。 | (なし) | — | — | 
| CLOSED_CAPTIONS_STATE_CHANGE | クローズドキャプションの状態を更新します。 | state | オブジェクト | クローズドキャプションの状態(enabled、text、background、windowBackgroundなど)。 | 
| PREPARE_FOR_CLOSE | 250ミリ秒でデバイスがウェブコンテナを閉じるのに備え、残りのアクションを処理します。 | (なし) | — | — | 
| ACCESS_TOKEN_CHANGE | アクセストークンを更新します。 | accessToken | 文字列 | ユーザーの認証情報。 | 
ハンドラーの実装
コマンドの処理方法は、プレーヤーの実装によって異なります。ハンドラーはすべてPromiseオブジェクトを返す必要があります。このオブジェクトは、コマンドが正常に処理された場合には解決され、エラーが発生した場合には拒否されます(errorTypeとメッセージを含むエラーオブジェクトが返されます)。PLAY、PAUSE、RESUMEでエラーが発生した場合は、デバイスでPREPARE_FOR_CLOSEが呼び出され、ウェブプレーヤーの終了が試行されます。
LOAD_CONTENTの処理では、ハンドラーが受け取るパラメーターに、AWS Lambda関数のレスポンスで送信されたcontentUriが含まれます。これは、再生するコンテンツを示すものです。コンテンツをストリーミングするためにユーザーの認証が必要な場合は、accessTokenも使用します。ユーザーがコンテンツの途中から視聴を再開する場合にはoffsetInMilliseconds、コンテンツの読み込み後に自動再生する必要がある場合にはautoplayなどの追加情報を含めることもできます。ハンドラーはPromiseオブジェクトを返します。このオブジェクトは、再生コマンドが正常に処理されたときに解決され、エラーが発生した場合は拒否されます(errorTypeとメッセージを含むエラーオブジェクトが返されます)。
ローディングオーバーレイの非表示
プレーヤーは、controller.showLoadingOverlayに値falseを指定して呼び出すまで表示されません。呼び出しは、アセットの読み込みが完了し、表示の準備が整ってから行います。コンテンツが読み込まれ、UIが表示可能になったら、このメソッドを呼び出して、オーバーレイを無効にする必要があります。ローディングオーバーレイは、初期化中には必ず表示されます。
それ以降のコンテンツ読み込みの呼び出し(関連のない新しいコンテンツを読み込むための呼び出しなど)では、ローディングオーバーレイを有効にし、適宜無効にすることができます。ただし、これは必須ではありません。読み込み中の画面をカスタマイズする場合は、コンテンツの準備ができるまでローディングオーバーレイを無効にしておき、独自の画面を表示することができます。この呼び出しは、コンテンツの再生中は行わないようにしてください。
controller.showLoadingOverlay(false);
Alexaへの再生ライフサイクルイベントの送信
プレーヤーで状態が変更になった場合は、controller.setPlayerState(playerState)メソッドを使用して、ライフサイクルイベントをAlexaに渡します。playerStateには、StateとpositionInMillisecondsの2つのプロパティがあります。
プレーヤーの状態が変わるたびに、controller.setPlayerState(playerState)メソッドを呼び出します。
playerStateは、現在のコンテンツ再生動作と一致している必要があります。これは、再生中にAlexaによってウェブコンテナが閉じられたり、再生が一時停止または停止されたコンテナが長時間そのままになったりすることを避けるためです。
controller.setPlayerState({
    state: AlexaWebPlayerController.State.IDLE,
    positionInMilliseconds: 0
});
次の表は、プレーヤーの状態の一覧です。
| 状態 | 説明 | 
|---|---|
| IDLE | プレーヤーはアイドル状態です。読み込まれたコンテンツや再生中のコンテンツはありません。プレーヤーはコンテンツをストリーミングする準備ができています。 | 
| BUFFERING | コンテンツをバッファリングしているため、再生が停止されています。 | 
| PLAYING | プレーヤーはコンテンツをアクティブにストリーミングしています。 | 
| PAUSED | コンテンツの途中で再生が停止されています。 | 
許可する操作の構成
Alexaで許可される操作が変更された場合は、JavaScriptライブラリを介してcontroller.setAllowedOperations(allowedOperatons)を使用して、許可する操作を設定します。操作を許可するにはハンドラーが必要ですが、このハンドラーは事前に実装されていません。デフォルトでは、操作は許可されていません。許可するには、ハンドラーを実装し、allowedOperationsで操作の設定をtrueにする必要があります。
controller.setAllowedOperations({
    adjustRelativeSeekPositionForward: true,
    adjustRelativeSeekPositionBackwards: true,
    setAbsoluteSeekPositionForward: true,
    setAbsoluteSeekPositionBackwards: true,
    next: true,
    previous: true,
});
| 名前 | 型 | 必要なハンドラー | 説明 | 
|---|---|---|---|
| allowedOperations | オブジェクト | なし | コンテンツに対して現在プレーヤーで許可される操作。 | 
| adjustRelativeSeekPositionForward | ブール型 | adjustSeekPosition | trueの場合、ユーザーは現在の位置から早送りのシークができます。 | 
| adjustRelativeSeekPositionBackwards | ブール型 | adjustSeekPosition | trueの場合、ユーザーは現在の位置から早戻しのシークができます。 | 
| setAbsoluteSeekPositionForward | ブール型 | setSeekPosition | trueの場合、ユーザーは絶対位置を指定して早送りのシークができます。 | 
| setAbsoluteSeekPositionBackwards | ブール型 | setSeekPosition | trueの場合、ユーザーは絶対位置を指定して早戻しのシークができます。 | 
| next | ブール型 | next | trueの場合、ユーザーは再生キューにある次のコンテンツをリクエストできます。 | 
| previous | ブール型 | previous | trueの場合、ユーザーは再生キューにある1つ前のコンテンツをリクエストできます。 | 
Alexaへのコンテンツメタデータの送信
controller.setMetadata(metadata)メソッドを使用して、現在のコンテンツのメタデータを渡します。この処理は、最初のコンテンツでも、それ以降に再生される新しいコンテンツでも行います。
controller.setMetadata({
    type: AlexaWebPlayerController.ContentType.TV_SERIES_EPISODE,
    value: {
        name: "name",
        closedCaptions: {
            available: true
        },
        durationInMilliseconds: 1000,
        series: {
            name: "name",
            seasonNumber: 1
        },
        episode: {
            number: 1,
            name: "name"
        }
    }
});
ほかのビデオのメタデータ:
controller.setMetadata({
    type: AlexaWebPlayerController.ContentType.VIDEO,
    value: {
        name: "",
        closedCaptions: {
             available: true
        },
        durationInMilliseconds: 1000,
    }
});
| 名前 | 説明 | 必須/任意 | 型 | 値 | 
|---|---|---|---|---|
| type | メタデータのコンテンツタイプ。 | 必須 | 文字列 | AlexaWebPlayerController.ContentType | 
| value | メタデータの値。タイプによって値は異なる場合があります。 | 必須 | オブジェクト | JSONオブジェクト | 
| name | ビデオの名前。 | 必須 | 文字列 | 例: インターステラー | 
| closedCaptions | ビデオのクローズドキャプション。 | 必須 | オブジェクト | JSONオブジェクト | 
| available | クローズドキャプションを使用できるかどうか。 | 必須 | ブール型 | true、false | 
| durationInMilliseconds | ビデオの再生時間(ミリ秒)。 | 任意 | 数値 | 例: 3141343 | 
| series | シリーズのメタデータ。 | 任意 | オブジェクト | JSONオブジェクト | 
| name | シリーズの名前。 | 任意 | 文字列 | 例: サバイバー: ボルネオ編 | 
| seasonNumber | シーズン番号。 | 任意 | 文字列 | 例: 1 | 
| episode | エピソードのメタデータ。 | 任意 | オブジェクト | JSONオブジェクト | 
| name | エピソードの名前。 | 任意 | 文字列 | 例: 無人島 | 
| number | エピソード番号。 | 任意 | 文字列 | 例: 1 | 
| AlexaWebPlayerController .ContentType | 値(文字列) | 説明 | 
|---|---|---|
| TV_SERIES_EPISODE | TV_SERIES_EPISODE | TVシリーズのエピソードのコンテンツタイプ。 | 
| VIDEO | VIDEO | ビデオのコンテンツタイプ。 | 
クローズドキャプションの状態の取得/設定
controller.getClosedCaptionsState()メソッドを使用して、再生開始時にデバイスレベルのクローズドキャプション設定を取得します。クローズドキャプションのオンとオフを切り替えるには、controller.setClosedCaptionsStateEnabled(enabled)メソッドを使用します。
controller.getClosedCaptionsState();
controller.setClosedCaptionsStateEnabled(isEnabled: boolean);
クローズドキャプションの状態:
{
    enabled: ,
    text: {
        size: ,
        color: ,
        opacity: ,
        font: ,
        edge: ,
    },
    background: {
        color: ,
        opacity: ,
    },
    windowBackground: {
        color: ,
        opacity: ,
    }
}
| 名前 | 説明 | 型 | 値 | 
|---|---|---|---|
| enabled | クローズドキャプションが有効かどうか。 | ブール型 | true、false | 
| text | テキストの設定。 | オブジェクト | なし | 
| size | テキストのサイズ。 | 数値 | テキストのサイズ(ピクセル単位) 例: 10 | 
| color | テキストの色。 | 文字列 | テキストの色(16進数コードでのRGB値) 例: #ff0000 | 
| opacity | テキストの色の透明度。 | 数値 | テキストの色の透明度(0~1.0のアルファ値) 例: 1.0 | 
| font | テキストのフォント。 | 文字列 | フォント(Google Fonts) 
 | 
| edge | 文字の縁取りのスタイル。 | 数値 | 縁取りのスタイル: 
 | 
| background | テキストの背景の設定。 | オブジェクト | なし | 
| color | テキストの背景の色。 | 文字列 | テキストの背景色(色のRGB値) 例: #ff0000 | 
| opacity | テキストの背景の透明度。 | 数値 | テキストの背景の透明度×パーセンテージ(テキストの背景色がデフォルトに設定されている場合は無効。0~1.0のアルファ値) 例: 1.0 | 
| windowBackground | ウィンドウの背景の設定。 | オブジェクト | なし | 
| color | クローズドキャプションウィンドウの背景の色。 | 文字列 | ウィンドウの背景色(RGB値) 例: #ff0000 | 
| opacity | クローズドキャプションウィンドウの背景の透明度。 | 数値 | ウィンドウの背景の透明度(ウィンドウの背景色がデフォルトに設定されている場合は無効。0~1.0のアルファ値) 例: 1.0 | 
致命的なエラーの報告
プレーヤーでエラーが発生し、コンテンツを再生できない場合、controller.sendError(error)メソッドを使用して致命的なエラーをAlexaに送信します。Alexaはウェブアプリを非表示にし、PREPARE_FOR_CLOSEハンドラーを呼び出して、ウェブプレーヤーを終了します。致命的でないエラーの場合、Alexaに送信する必要はありません。
controller.sendError({
    type: AlexaWebPlayerController.ErrorType.PLAYER_ERROR,
    message: '文字列型のエラーメッセージ'
});
| エラータイプ | 説明 | 
|---|---|
| PLAYER_ERROR | メディアプレーヤーに関して回復不可能なエラーが発生した場合は、 PLAYER_ERRORイベントを送信します。 | 
| CLIENT_ERROR | プレーヤーに関係しないクライアント側のエラーについては、 CLIENT_ERRORを送信します。 | 
| SERVER_ERROR | SERVER_ERRORは、サーバー側でエラーが発生したことを示します。これには、リクエストの失敗、コンテンツのバッファリングの失敗、アセットへのアクセスの失敗、接続の問題などが含まれます。 | 
エクスペリエンスの終了処理
再生のセッションが終了したら、controller.close()メソッドを呼び出してAlexaに通知します。Alexaはウェブアプリを非表示にし、PREPARE_FOR_CLOSEハンドラーを呼び出して、エクスペリエンスを終了します。
controller.close();
一般からアクセス可能なURLでのウェブプレーヤーのホスト
最後に、パブリックURLでプレーヤーにアクセスできるようにします。Alexaデバイスでは安全な接続が必要であるため、HTTPSを使用してウェブプレーヤーにアクセスできるようにします。
この段階で、ウェブプレーヤーはマルチモーダルデバイスでのテストを行う準備がほぼできています。ただし、その前に、必要なビデオスキルAPIをスキルのLambda関数に実装する必要があります。その方法については、次のセクションの手順6: Lambdaに送信されたAlexaディレクティブに応答するを参照してください。

