手順4: ウェブプレーヤーでメディア再生URLを取得する方法を理解する
GetPlayableItemsMetadataResponseからplaybackContextTokenがウェブプレーヤーに渡されます。ウェブプレーヤーのロジックで、このplaybackContextTokenをメディア再生URLに変換して、ウェブプレーヤーで読み込めるようにすることができます。
- メディア再生URLとメディアプレーヤーの概要
- メディア再生URLのワークフローの詳細
- 使用するハンドラーと関数
- コードの説明
- playbackContextTokenとaccessTokenの違い
- 次のステップ
メディア再生URLとメディアプレーヤーの概要
前のセクション(手順3: AlexaディレクティブとLambdaのレスポンスを理解する)では明らかになっていない点の1つとして、マルチモーダルデバイスが対象メディアの再生URLを取得する方法が挙げられます。これは、この再生URLがLambdaからAlexaに返されていないためです(Fire TV対応アプリでのビデオスキルの実装では、LambdaからADMを介してコンテンツのURLを直接アプリにプッシュしていますが、マルチモーダルデバイスにはアプリがないため、このプロセスに若干の違いがあります)。
基本的なしくみは、次のようになります。GetPlayableItemsMetadataResponseで、LambdaからAlexaにplaybackContextTokenを返します。playbackContextTokenには、メディアを表す指定値が含まれます。playbackContextTokenの値は、Alexa JavaScriptライブラリ(alexa.js)のハンドラーを介してウェブプレーヤーに渡されます。
ウェブプレーヤーのコードで、playbackContextTokenの値をメディア再生用URLに変換できます。この方法では、メディア再生URLをまったく外部に知られることなく使用できます。これ以降のセクションでは、このワークフローとコードについて詳しく説明します。
メディア再生URLのワークフローの詳細
AlexaからGetPlayableItemsディレクティブを受信したら、Lambdaはユーザーのリクエストに応じたメディアを含むGetPlayableItemsResponseをレスポンスとして返します。Alexaでは、メディアタイトルが複数ある場合はユーザーに確認し、あいまいさの問題を解消したうえで、選択されたメディアの詳細情報を取得するためのGetPlayableItemsMetadataディレクティブを送信します。Lambdaからは、メディアの識別子を含むGetPlayableItemsMetadataResponseを返します。この識別子は、playbackContextTokenプロパティで次のように指定されます。
Lambdaのレスポンス: GetPlayableItemsMetadataResponse
{
"event": {
"header": {
"correlationToken": "dFMb0z+PgpgdDmluhJ1LddFvSqZ/jCc8ptlAKulUj90jSqg==",
"messageId": "38ce5b22-eeff-40b8-a84f-979446f9b27e",
"name": "GetPlayableItemsMetadataResponse",
"namespace": "Alexa.VideoContentProvider",
"payloadVersion": "3"
},
"payload": {
"searchResults": [
{
"name": "ブレンダー財団のビッグバックバニー",
"contentType": "ON_DEMAND",
"series": {
"seasonNumber": "1",
"episodeNumber": "1",
"seriesName": "クリエイティブコモンズビデオ",
"episodeName": "パイロット"
},
"playbackContextToken": "{\"streamUrl\": \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\", \"title\": \"ビッグバックバニー\"}",
"parentalControl": {
"pinControl": "REQUIRED"
},
"absoluteViewingPositionMilliseconds": 1232340
}
]
}
}
}
このplaybackContextTokenには、ウェブプレーヤーに送信される識別子が含まれます。この識別子は、コードの開発者が任意に定義します。ウェブプレーヤーでは、この識別子をメディア再生URLに変換します。
前の手順で紹介したサンプルのLambda関数とウェブプレーヤーでは、playbackContextTokenが文字列に変換されたJSONオブジェクトになっています。このウェブプレーヤーのサンプルコードは、playbackContextTokenがstreamUrlとtitleの2つのパラメーターを持つJSONオブジェクトであることを前提としています。ただし、メディアプレーヤーで正しく解析してウェブプレーヤーに渡すことができる値であれば、ここで任意の値を渡すことができます。
マルチモーダルデバイスから(サーバーにある)ウェブプレーヤーが呼び出され、playbackContextTokenが渡されます。この段階で、ウェブプレーヤーのコードでplaybackContextTokenの値を実際のメディア再生URLに変換できます。
このサンプルLambdaコードでは、メディアプレーヤーでメディア再生URLに変換する必要のある識別子をplaybackContextTokenとするのではなく、メディア再生URLをstreamUrlの値として直接設定しています。
使用するハンドラーと関数
独自に作成したウェブプレーヤーでplaybackContextTokenを後からカスタマイズする場合(具体的には手順5: ウェブプレーヤーを作成するを参照)、playbackContextTokenで使用するハンドラーや関数について理解しておくことが重要です。
サンプルウェブプレーヤーには、Alexa JavaScriptライブラリ(alexa.js)が組み込まれています。これは、マルチモーダルデバイスにビデオスキルを統合しているウェブプレーヤーでは常に必要となるライブラリです。Alexa JavaScriptライブラリには、ウェブプレーヤーで実装が必要なイベントハンドラーがいくつか含まれています。これらのハンドラーは、Alexaがウェブプレーヤーに情報を伝達する手段となります。ハンドラーは、alexa.jsのreadyCallback関数で次のように定義されています。
alexa.jsのハンドラー
function readyCallback(controller) {
var Event = AlexaWebPlayerController.Event;
var handlers = {
Event.LOAD_CONTENT: function handleLoad(params) {},
Event.PAUSE: function handlePause() {},
Event.RESUME: function handleResume() {},
Event.SET_SEEK_POSITION: function handleSetPos (positionInMilliseconds) {},
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);
}
ウェブプレーヤーでこれらのハンドラーを実装すると、AlexaからLOAD_CONTENT、PAUSE、RESUMEなどのイベントを送信できるようになります。ウェブプレーヤーでは、これらのハンドラーの情報を処理する必要があります。LOAD_CONTENTは、Alexaがメディア再生URLに関する情報を渡すために使用するハンドラーです。
実装に必要なウェブプレーヤーコンポーネントを所有している必要があることに注意してください。各ビデオスキルでは、ウェブプレーヤーのURIを参照し、そのプレーヤーを呼び出してビデオを再生します。マルチモーダルデバイスには基本的なChromiumウェブブラウザがありますが、Alexaからはその機能の範囲を超えるものは提供できません。そのため、Alexaからの通信を受信するには、ウェブプレーヤーにJavaScriptを組み込む必要があります。
ウェブプレーヤーでAlexa JavaScriptライブラリを初期化すると(AlexaWebPlayerController.initializeを使用します)、AlexaでLOAD_CONTENT: function handleLoad(params) {}イベントを送信して、ユーザーのリクエストに応じてコンテンツを読み込めるようになります。このLOAD_CONTENTの呼び出しでは、イベントハンドラーの登録に記載されているように、4つのパラメーター(params)、つまり、params.contentUri、params.accessToken、params.offsetInMilliseconds、params.autoplayを渡すことができます。params.contentUriパラメーターには、playBackContextTokenが含まれます。
JavaScriptでは、LOAD_CONTENTのこれらのパラメーターを処理し、プレーヤーでコンテンツを再生するために必要なタスクを実行する必要があります。再生URLをplaybackContextTokenに直接含めていない場合は、バックエンドサービスに問い合わせて値を変換することが必要となります(識別子と再生URLのマッピングがバックエンドサービスで行われている場合)。その後、JavaScriptでウェブプレーヤーに再生URLを読み込みます(LambdaからplaybackContextTokenで再生URLを直接渡している場合、この手順は不要になります)。
コードの説明
サンプルウェブプレーヤーのコードで、playbackContextTokenがどのように渡されるかをさらに詳しく見ていきましょう。サンプルウェブプレーヤーでは、srcフォルダにいくつかのJavaScriptファイルがあります。
├── src
│ ├── alexa.js
│ ├── main.js
│ ├── mediaPlayer.js
│ ├── ui.js
│ └── util
│ └── logger.js
alexa.jsファイルには、loadContentHandler関数が含まれています。
function loadContentHandler(playbackParams) {
function loadContent(resolve, reject) {
try {
const content = JSON.parse(playbackParams.contentUri);
mediaPlayer.load(playbackParams);
ui.setVideoTitle(content.title);
resolve();
} catch (err) {
reject(err);
}
}
...
}
この関数では、playbackParams.contentUriを読み込み、contentに設定しています。また、ウェブプレーヤーの関数であるmediaPlayer.loadを呼び出し、playbackParamsを渡しています。mediaPlayer.jsを開いてload関数を探し、playbackParamsがこの関数にどのように渡されているかを見てみましょう。
function load(playbackParams) {
const { video } = self;
const { contentUri, offsetInMilliseconds, autoplay } = playbackParams;
const source = document.createElement('source');
const { streamUrl, title } = JSON.parse(contentUri);
// streamUrlに設定されたcontentUriを基にビデオコンテンツを設定します
source.setAttribute('src', streamUrl);
// URL内を大まかに検索して見つかった拡張子を基にファイルの種類を設定します
if (contentUri.indexOf('.mp4') >= 0) {
source.setAttribute('type', 'video/mp4');
} else if (contentUri.indexOf('.m3u8') >= 0) {
source.setAttribute('type', 'application/x-mpegURL');
} else {
logger.debug(`処理できないビデオの種類がURLで指定されています:${streamUrl}`);
throw new Error({
errorType: alexa.ErrorType.INVALID_CONTENT_URI,
});
}
...
}
const { contentUri, offsetInMilliseconds, autoplay } = playbackParams;という行では、基本的に、playbackParamsという値を展開し、contentUri、offsetInMilliseconds、autoplayという3つの値に変換しています。
const { streamUrl, title } = JSON.parse(contentUri);という行では、contentUriから2つの値(streamUrlとtitle)を取り出しています(このため、サンプルのLambda関数とウェブプレーヤーのコードではplaybackContextTokenがオブジェクトである必要があります)。 ここで、これをプレーヤーに読み込む必要があります。
サンプルLambda関数ではこのようにcontentUriを実装していますが、実装は独自にカスタマイズできます。たとえば、(文字列化したオブジェクトではなく)単純に文字列を使用することもできます。
mediaPlayer.jsでは、video.load関数でメディアを読み込んでいます。
if (autoplay) {
video.play();
} else {
video.load();
}
playメソッドで使用されるsrc属性は、次の行で設定されています。
source.setAttribute('src', streamUrl);
playメソッドでは、sourceパラメーターが読み込まれます。
video.innerHTML = '';
video.appendChild(source);
実際には作成するウェブプレーヤーのコードを使用する可能性が高いため、このサンプルプレーヤーのコードとは異なるはずです。ウェブプレーヤーのコードをカスタマイズする際は、主にalexa.jsで作業を行うことになります。Alexaからのイベントは、すべてここで処理します。
playbackContextTokenとaccessTokenの違い
alexa.jsには、accessTokenというパラメーターを取る別のハンドラーがあります。
Event.ACCESS_TOKEN_CHANGE: function handleAccessToken(accessToken) {}
コンテンツをストリーミングするためにユーザーの認証が必要な場合は、accessTokenも使用します。accessTokenにより、ユーザーが対象のサービスでコンテンツを表示することが許可されます。これに対して、ここで説明してきたplaybackContextToken(およびcontentUri)は、メディア再生URLを伝えるためのものです。playbackContextTokenに、認証情報は一切含まれません。
次のステップ
手順5: ウェブプレーヤーを作成するに進みます。

