步骤5: 构建您的网页播放器 (VSK Echo Show)
在此步骤中,您将构建自己的网页播放器。网页播放器将引用和初始化Alexa JavaScript库并提供其他功能。
网页播放器要求
在构建自己的网页播放器时,请记住有关编解码器、格式和标准的以下要求:
视频要求:
- HLS/MPEG-DASH
- MP4 H.264
- Widevine DRM级别1
- 加密媒体扩展 (EME)
- 媒体源扩展 (MSE)
音频要求:
- 采用AAC的MP4
- 采用Vorbis的WebM
- 采用Opus的WebM
- 支持AAC-LC,但不支持AAC-SBR。媒体应遵循为“Chromium”定义的音频规范,以确保正常播放。有关Chromium的更多信息,可以参见Chromium项目站点的音频/视频(仅提供英文版)。
屏幕分辨率要求
发送到亚马逊设备的视频内容的分辨率不能高于显示器的分辨率。使用以下命令在网页应用中检查显示器的分辨率:
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设备上运行。如果是这样,请参照之前的指南。
构建自己的网页播放器
要构建自己的网页播放器,请完成以下各部分中描述的高级别任务。
迁移或构建网页播放器
如果您现有的网页资产可以提供您的内容,请隔离网页播放器组件和支持功能,例如指标报告、广告逻辑和其他依赖关系。您的视频必须是仅能在全屏模式下播放的视频。指向任何其他网站的链接会受到限制。
设定网页播放器样式
设定网页播放器样式以应用播放器的视觉控件和非视频元素。有关视频体验的认证指南,请参阅认证测试。
纳入Alexa视频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视频JavaScript库
在网页应用的初始化代码中,等待Alexa对象准备就绪,然后使用readyCallback和errorCallback初始化alexa-web-player-controller库。当准备好执行库时,将调用readyCallback。
在readyCallback中,您将收到一个用于与库通信的控制器对象,其中包括控制方法。如果出现导致网页播放器关闭的错误,则会调用errorCallback。用户收到一条人类可阅读的错误消息。
alexa-web-player-controller库在发送错误消息后会关闭网页容器。在库初始化期间,您还可以选择通过添加一个参数,其中包含以事件名称为键的回调函数映射,由此注册事件处理程序。否则,您可以使用下一部分中介绍的controller.on(handlers) / controller.on(event, handler) 方法来注册处理程序。需要处理程序play、pause和resume。
如果您的播放器支持隐藏式字幕,请在初始化期间调用getClosedCaptionsState方法。当在状态为IDLE的情况下调用setPlayerState方法时,初始化序列被视为已完成。以下各部分提供了有关getClosedCaptionsState和setPlayerState方法的更多信息。
// 在此脚本之前加载Alexa视频JavaScript库。
AlexaWebPlayerController.initialize(readyCallback, errorCallback);
或
AlexaWebPlayerController.initialize(readyCallback, errorCallback, handlers);
注册事件处理程序
使用controller.on(handlers) /controller.on(event, handler) 方法注册处理程序。需要处理程序play、pause和resume。
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 |
字符串 | Video Skill 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 | 对象 | 隐藏式字幕状态包括启用、文本、背景、窗口背景。 |
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和消息的错误对象拒绝。
隐藏加载叠加层
在以值false调用controller.showLoadingOverlay之前,您的播放器不可见。在资产加载完毕并且体验准备好展示后进行调用。当内容加载完毕且用户界面可呈现时,必须调用此方法来禁用叠加层。加载叠加层在初始化期间始终显示。
如果后续调用加载内容(例如调用新的无关内容),您就可以打开加载叠加层并适当地将其关闭,但这并非必需。如果您需要自定义的加载屏幕,可以在内容准备就绪之前将其禁用并提供自己的可视化。播放内容时不得调用此项。
controller.showLoadingOverlay(false);
向Alexa发送播放生命周期事件
当您的播放器更改状态时,使用controller.setPlayerState(playerState) 方法将生命周期事件传递给Alexa。playerState包含两个属性,即State和positionInMilliseconds。
每当播放器状态发生变化时,都调用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,则允许用户请求播放队列中的上一个内容。 |
向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 |
视频的名称。 | 是 | 字符串 | 示例: Interstellar |
closedCaptions |
视频的隐藏式字幕。 | 是 | 对象 | JSON对象 |
available |
隐藏式字幕的可用性。 | 是 | 布尔值 | true、false |
durationInMilliseconds |
以毫秒为单位的视频持续时间。 | 否 | 数量 | 示例: 3141343 |
series |
连续剧的元数据。 | 否 | 对象 | JSON对象 |
name |
连续剧的名称。 | 否 | 字符串 | 示例: Survivor: Borneo |
seasonNumber |
季的编号。 | 否 | 字符串 | 示例: 1 |
episode |
剧集的元数据。 | 否 | 对象 | JSON对象 |
name |
剧集的名称。 | 否 | 字符串 | 示例: The Marooning |
number |
剧集的编号。 | 否 | 字符串 | 示例: 1 |
| AlexaWebPlayerController .ContentType |
Value (string) | 描述 |
|---|---|---|
TV_SERIES_EPISODE |
TV_SERIES_EPISODE |
电视连续剧集的内容类型 |
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 |
文本的颜色 | 字符串 |
文本颜色(采用十六进制代码的RGB值) 示例: #ff0000
|
opacity |
文本的颜色不透明度 | 数量 |
文本颜色不透明度(alpha值介于0 - 1.0之间) 示例: 1.0
|
font |
文本的字体。 | 字符串 |
字体(来自Google字体(仅提供英文版))
|
edge |
文本的边缘样式。 | 数量 |
边缘样式:
|
后台 |
文本背景首选项。 | 对象 | 不适用 |
color |
文本背景的颜色。 | 字符串 |
文本背景颜色(这是颜色的RGB值) 示例: #ff0000
|
opacity |
文本背景的不透明度 | 数量 |
文本背景不透明度*百分比(当文本背景颜色设置为默认值时禁用;alpha值介于0 - 1.0之间) 示例: 1.0
|
windowBackground |
窗口背景首选项 | 对象 | 不适用 |
color |
隐藏式字幕窗口背景的颜色。 | 字符串 |
窗口背景颜色(RGB值) 示例: #ff0000
|
opacity |
隐藏式字幕窗口背景的不透明度。 | 数量 |
窗口背景不透明度(当窗口背景颜色设置为默认值时禁用;alpha值介于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访问。确保可以通过使用HTTPS访问您的网页播放器,因为Alexa设备需要安全的连接。
此时,您的网页播放器几乎已经准备好在多模式设备上进行测试。但首先,您必须在技能的Lambda函数中实现所需的Video Skill API,如下一部分中所述:步骤6: 对传送至Lambda的Alexa指令做出响应。
后续步骤
继续执行步骤6: 对传送至Lambda的Alexa指令做出响应。
Last updated: 2023年1月4日

