步骤4: 了解您的网页播放器如何获取媒体播放URL (VSK Echo Show)
亚马逊通过您的GetPlayableItemsMetadataResponse,将playbackContextToken传递给您的网页播放器。您的网页播放器中的逻辑可以将此playbackContextToken转换为网页播放器加载的媒体播放URL。
媒体播放URL和媒体播放器概览
在上一部分(步骤3: 了解Alexa指令和Lambda响应)中可能看不到的一个细节,即多模式设备获取媒体播放URL的方式,因为这个播放URL不是您的Lambda传回给Alexa的内容。(借助视频技能的Fire TV应用实现,您的Lambda可通过ADM将内容URL直接推送到您的应用。但是,由于多模式设备没有应用,因此这里的过程略有不同。)
大体而言,它的工作原理如下。在您的Lambda的GetPlayableItemsMetadataResponse中,您的Lambda将playbackContextToken传回给Alexa。playbackContextToken包含您选择的用于描述媒体的值。亚马逊通过Alexa JavaScript库 (alexa.js) 中的处理程序将playbackContextToken值传递给您的网页播放器。
然后,您的网页播放器的代码可以将playbackContextToken值转换为媒体播放URL。这样,您可以将媒体播放URL完全保密,从而只有您自己知道。以下部分将更详细地介绍此工作流程和代码。
媒体播放URL的工作流程详情
在您的Lambda收到来自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": "来自Blender Foundation的Big Buck Bunny",
"contentType": "ON_DEMAND",
"series": {
"seasonNumber": "1",
"episodeNumber": "1",
"seriesName": "知识共享视频",
"episodeName": "Pilot"
},
"playbackContextToken": "{\"streamUrl\": \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\", \"title\": \"Big Buck Bunny\"}",
"parentalControl": {
"pinControl": "REQUIRED"
},
"absoluteViewingPositionMilliseconds": 1232340
}
]
}
}
}
此playbackContextToken包含一个完全由您定义的标识符,您希望亚马逊将其发送给您的网页播放器。您的网页播放器会将此标识符转换为媒体播放URL。
在前面步骤中提供的示例Lambda和网页播放器中,playbackContextToken是一个转换为字符串的JSON对象。示例网页播放器代码期望playbackContextToken是一个带有streamUrl和title参数的JSON对象。但是,您可以在这里传递任何您需要的值,只要您的媒体播放器能正确解析这个值并将这个值传递给您的网页播放器。
多模式设备调用您的网页播放器(位于您的服务器上),并将playbackContextToken传递给它。此时,您的网页播放器代码可以将playbackContextToken的值转换为您的实际媒体播放URL。
在示例Lambda代码中,示例Lambda没有让playbackContextToken成为需要媒体播放器转换为媒体播放URL的标识符,而是直接将媒体播放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调用中,Alexa可以传递Register Event Handlers中定义的四个参数 (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);
// 基于将contentUri作为直播URL来设置视频内容
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(三个不同的值)。
行const { streamUrl, title } = JSON.parse(contentUri);从contentUri中提取两个值(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: 构建您的网页播放器。

