手順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: ウェブプレーヤーを作成するに進みます。