Copyright © 2024 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范定义了一个扩展 HTMLMediaElement
的 API,使网页能够控制媒体的远程播放。
本节描述了本文件发布时的状态。当前 W3C 发布的技术报告及其最新修订可在 W3C 技术报告索引(https://www.w3.org/TR/)中找到。
本文件由 Second Screen 工作组 作为 候选推荐标准草案发布,并采用 推荐流程。
本文件基于工作组关于在外部展示型显示设备上呈现网页内容的经验,并在适当情况下复用了 Presentation API 规范中的设计模式和考虑[PRESENTATION-API]。
尽管本文件仍是 进行中的工作 并可能发生变化,工作组认为 API 的接口较为稳定。大部分在 问题跟踪器上的剩余问题目前认为是次要的,除了 第 41号 问题。
第 41号 问题 讨论了远程播放设备有望支持的媒体播放功能集合。工作组将进一步征求开发者反馈和实现经验,以识别这些功能在远程播放时的互操作性问题,并会根据收到的反馈进一步明确规范。
对于其他问题或建议,可以 提交 bug 或 向 邮件列表发送邮件。如有拼写等小编辑错误,欢迎提 pull request。
工作组欢迎所有人审查本文件,并将与 W3C 内相关小组合作,在无障碍、国际化、隐私、安全和技术架构原则等方面进行横向评审。
未有任何特性被标记为风险中。
Second Screen 工作组将在候选推荐周期内为远程播放 API 制定测试套件,并准备实现报告。为使规范升级为提议推荐,每项特性必须有两个独立且可互操作的实现,如候选推荐标准退出标准章节所述。
作为候选推荐标准发布,并不意味着 W3C 及其成员的认可。候选推荐草案整合了工作组计划纳入后续候选推荐快照的所有变更。
本文件为草案,可能随时被其它文件更新、替换或废弃。不应将本文件作为正式引用。
本文件由工作组根据 W3C 专利政策 制定。 W3C 保持一份 与交付物相关的专利公开清单, 该页面还包含专利披露说明。如个人实际知悉其认为包含 必要权利要求的专利,则需按 W3C 专利政策第6节 披露信息。
本文件受 2023年11月3日W3C流程文档 管理。
本规范中,被标记为“非规范性”(non-normative)的部分以及所有编写指南、图示、示例与注释,均非规范性内容。除此之外的内容均为规范性内容。
本文档中的关键字 MAY、MUST、MUST NOT、RECOMMENDED 和 SHOULD,应根据 BCP 14 [RFC2119] [RFC8174] 在且仅在全部为大写字母时,如上述用法那样进行解释。
本规范规定的符合性标准,仅适用于一种产品:实现本规范中相关接口的用户代理(user agent)。
以 ECMAScript 暴露本规范定义 API 的实现,必须依据 Web IDL 规范中 ECMAScript Bindings 的要求实现之 [WEBIDL]。
本节为非规范性内容。
本规范旨在让远程播放设备(如联网电视、投影仪或仅支持音频的扬声器)对网页可用,并兼容通过有线(HDMI、DVI 或类似接口)和无线技术(Miracast、Chromecast、DLNA、AirPlay或类似)连接的播放设备。
屏幕尺寸有限或扬声器不响亮的设备,无法为更多听众(如会议室的同事或家庭聚会的朋友)播放媒体内容。把媒体内容播放到外部更大和/或声音更大的远程播放设备有助于提升感官体验和媒体影响力。
本规范核心在于:允许作为 浏览上下文 的页面,发起并控制选定远程播放设备上的特定媒体元素的远程播放。远程播放的发起和控制方式留给 UA(User Agent)决定,以便兼容多种类型的远程设备。例如,通过 HDMI 或 Miracast 连接远程播放设备时,作为浏览上下文 的同一个 UA 会渲染远程媒体,但它可调用操作系统能力将内容输出至外部远程播放设备,而非本机播放。在这种“媒体镜像”场景下,浏览上下文与媒体播放器都在同一 UA 上运行,输出通过操作系统路由到远程播放设备。本规范对以这种方式连接的设备无特殊要求。
如果远程播放设备能够播放媒体、与浏览上下文通信,但无法自行获取媒体时,浏览上下文需获取媒体数据并传给远程播放设备渲染,这情况常称为媒体远距传输。
如果远程播放设备既可获取又可播放媒体,并能与浏览上下文通信,则浏览上下文无需获取或渲染远程媒体。此时 UA 等同于代理,将必要的数据如媒体源传递给远程播放设备,由其自行播放,通常称为媒体推送。未来可通过定义标准协议强化这种连接方式,便于远程播放设备实现相关消息传递功能。
此处定义的 API,旨在为上述任一路径连接的 远程播放设备 服务。
本节为非规范性内容。
本规范的用例和需求已单独整理,可点击这里查看。
本节展示了突出远程播放 API 主要特性的代码示例。其中 player.html 为播放页、负责控制远程播放,media.ext
为被远程播放的媒体文件。页面和媒体同样来自 https://example.org 域。更多细节请参阅代码示例内注释。
<!-- player.html -->
<!-- 支持远程播放的自定义控制视频元素 -->
<video id="videoElement" src="https://example.org/media.ext" />
<button id="deviceBtn" style="display: none;">选择设备</button>
<script>
// 只要有一个远程播放设备,就显示“选择设备”按钮。
const deviceBtn = document.getElementById("deviceBtn");
const videoElem = document.getElementById("videoElement");
function availabilityCallback(available) {
// 依赖设备可用性,决定是否显示设备选择按钮。
deviceBtn.style.display = available ? "inline" : "none";
}
videoElem.remote.watchAvailability(availabilityCallback).catch(() => {
// 平台不支持设备可用性监控,仅在调用 remote.prompt() 后发现可用远程设备。
// 简单起见,可以直接显示按钮;或者,自行实现按钮的第三种显示状态。
deviceBtn.style.display = "inline";
});
</script>
<!-- player.html -->
<script>
deviceBtn.onclick = () => {
// 请求用户选择远程播放设备。
videoElem.remote.prompt()
// 更新界面,并监听连接状态。
.then(updateRemotePlaybackState);
// 如果未选择设备、取消了 UI 或未找到屏幕,不会触发 then。
};
<script>
<!-- player.html -->
<script>
// 用户代理可能会自行发起远程播放,因此请检查初始状态以同步界面。
if (videoElem.remote.state == "disconnected")
switchToLocalUI();
else
switchToRemoteUI();
videoElem.remote.onconnecting = switchToRemoteUI;
videoElem.remote.onconnect = switchToRemoteUI;
videoElem.remote.ondisconnect = switchToLocalUI;
// 处理连接中/已连接状态。多次调用也没有影响。
function switchToRemoteUI() {
// 用于指示当前为“连接中”或“已连接”状态。通常只需展示播放控制即可,视频元素可隐藏。
videoElem.style.display = "none";
// 停止远程设备可用性监控。
videoElem.remote.cancelWatchAvailability();
};
function switchToLocalUI() {
// 恢复显示视频元素。
videoElem.style.display = "inline";
// 重新开始监控远程设备可用性。
videoElem.remote.watchAvailability(availabilityCallback);
};
<script>
本地播放设备,指的是运行浏览上下文的设备及该设备默认的视频/音频输出。
远程播放设备 指除了本地播放设备以外,浏览上下文可用于播放媒体的任何其他设备。
媒体元素状态,指的是页面和/或用户通过用户代理实现所能观测到的单一 媒体元素 所有属性集合。本规范新引入的属性,为方便起见,不计入媒体元素状态。
paused 属性或媒体元素默认控件上对应的暂停/恢复按钮,反映的都是媒体元素状态。
本地播放状态,指用户代理针对特定 媒体元素状态的实现,用于在本地播放设备上播放。
WebIDL[Exposed=Window]
interface RemotePlayback : EventTarget {
Promise<long> watchAvailability(RemotePlaybackAvailabilityCallback callback);
Promise<undefined> cancelWatchAvailability(optional long id);
readonly attribute RemotePlaybackState state;
attribute EventHandler onconnecting;
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
Promise<undefined> prompt();
};
enum RemotePlaybackState {
"connecting",
"connected",
"disconnected"
};
callback RemotePlaybackAvailabilityCallback = undefined(boolean available);
RemotePlayback 对象允许页面检测
远程播放设备的可用性、连接并控制其播放。
RemotePlaybackState 枚举表示与远程播放设备的可能连接状态。
RemotePlaybackAvailabilityCallback 用于返回当前
远程播放设备可用性。
RemotePlaybackAvailabilityCallback
是页面获取对应媒体元素
远程播放设备可用性的方式。如果用户代理能在后台
监控远程播放设备列表
(无需待处理 prompt() 请求),
则用户代理 必须 实现如下 RemotePlaybackAvailabilityCallback
行为。否则,watchAvailability()
返回的 promise 必须 因
NotSupportedError 被拒绝。
用户代理 必须 记录通过 watchAvailability()
方法注册到每个媒体元素的可用性回调集合。每个
RemotePlayback 对象的可用性回调集合由一组元组
(callbackId, callback) 组成,初始为空。其中:
watchAvailability()
返回的唯一正整数;
RemotePlaybackAvailabilityCallback
对象。
每个媒体元素对应且仅对应一个
RemotePlayback 对象,
因此媒体元素的可用性回调集合
与其remote属性指向的
RemotePlayback对象的可用性回调集合一致。
所有已知 RemotePlayback 对象的
可用性回调集合 合并后,被称为
全局可用性回调集合。
用户代理 必须 维护一个 可用远程播放设备列表。该列表包含 远程播放设备,并基于特定实现的发现机制构建,内容为最近一次 监控远程播放设备列表 算法结果,若该算法未运行过则为空。
用户代理 可以 不支持持续运行 监控远程播放设备列表
算法,比如出于平台或功耗限制。在这种情况下,watchAvailability()
返回的 promise 必须 因
NotSupportedError
被拒绝;
此时全局可用性回调集合为空,监控可用远程设备算法只会作为发起远程播放算法的一部分运行。
当全局可用性回调集合非空时,用户代理 必须 持续监控远程播放设备列表,以便页面通过回调实时获得最新状态,只在有设备时提供远程播放。
用户代理应尽量避免在不必要时监控远程播放设备列表,以满足 节能非功能性需求。例如当全局可用性回调集合为空,或者所有有媒体元素且可用性回调非空的页面均为后台页时,可不运行监控算法。
某些 远程播放设备 由于功能、安全性或硬件限制,仅能播放部分媒体资源,比如只支持某些视频/音频格式的机顶盒、智能电视或网络扬声器。能合理确保某媒体资源远程播放可在该设备上成功播放的设备,称为 兼容远程播放设备。
用户代理用于查找兼容远程播放设备时参考的媒体资源集合,称为 可用性资源集合。
用于在选中远程播放设备上发起远程播放的 媒体资源,称为 远程播放源。远程播放源必须属于媒体元素的可用性资源集合。
从可用性资源集合选择远程播放源的机制取决于实现,但用户代理应该将集合中的每个资源都视为候选远程播放源。
如果用户代理无法确定适合远程播放设备的远程播放源, 建议用户代理把可用性资源集合中所有资源的元信息(如扩展 MIME 类型)发给设备,由其自行运行资源选择算法选定远程播放源。
对于媒体元素,当可用远程播放设备列表为空,
或其中没有与 可用性资源集合中任何源兼容的设备,
则 远程播放不可用。否则称为可用。如果远程播放不可用则布尔值取 false,可用则为
true,称为媒体元素的可用性。
若用户代理停止
监控远程播放设备列表
(如因用户操作或省电需求),应 应该 用 false 调用所有
全局可用性回调集合
里的回调,以便页面及时调整用户体验。同时 应 把全部媒体元素的 可用性 设为
false,这样若将来恢复监控,可正确传播可用性信息。
当调用 watchAvailability()
方法时,用户代理 必须 按如下步骤执行:
Promise。
Promise。
disableRemotePlayback
属性存在于 媒体元素 上,拒绝 promise
并抛出 InvalidStateError
,中止所有剩余步骤。
false 参数调用 callback。
NotSupportedError
异常拒绝 promise。
一个简单的 callbackId 分配算法是在每个 浏览上下文 维护计数器,并在第 6 步递增。
如果 可用性回调集合非空,或存在尚未处理的 发起远程播放请求,则用户代理必须通过以下步骤监控可用远程播放设备列表:
disableRemotePlayback
属性存在于 mediaElement 上,终止本元组所有剩余步骤,转入下一个。
当调用 cancelWatchAvailability() 方法时,用户代理
必须 按如下步骤运行:
Promise。
Promise。
disableRemotePlayback
属性存在于 媒体元素 上,拒绝 promise,抛出
InvalidStateError,中止所有剩余步骤。
undefined,则清空 可用性回调集合。
NotFoundError,中止所有剩余步骤。
当调用 prompt() 方法时,用户代理 必须 执行以下步骤:
Promise。
Promise。
disableRemotePlayback
属性存在于 媒体元素 上,则拒绝
promise,抛出
InvalidStateError,
并终止所有剩余步骤。
prompt()
promise,用户代理可以用 OperationError 拒绝
promise 并终止所有剩余步骤。
prompt()
则无法再弹出新的 UI。
InvalidAccessError
拒绝 promise 并终止这些步骤。
state 或 可用远程播放设备列表),用 NotSupportedError
拒绝 promise 并终止所有剩余步骤。
NotFoundError
拒绝 promise,并终止所有剩余步骤。
state 设为 connecting。
connecting 的事件,事件不冒泡且不可取消,无默认动作。
选择 远程播放设备 即表示用户授权使用该设备。
NotAllowedError
拒绝 promise 并隐藏用户代理展示的 UI。
state 属性表示
RemotePlayback 连接的当前状态。它可以根据连接状态取 RemotePlaybackState
的以下值之一:
当用户代理要 与远程播放设备建立连接 时,必须执行以下步骤:
RemotePlayback 对象。
state 不为 "connecting",中止所有剩余步骤。
disconnected"。
disconnect,对象为 remote。
当 远程播放状态为 "connected" 时,用户代理 应 暂停媒体元素的本地音视频输出。
如果用户代理为媒体元素 暴露了用户界面(如用默认控件),则
应 通过图标或其他方式展示其 远程播放状态为 "connected"。
Accept-Language 头来获取媒体资源。
用户代理可以支持通过浏览器连接到远程播放设备。如可在 暴露给用户的界面 中添加合适控件,或当开启系统级镜像时进行。此功能称为 浏览器发起远程播放。支持此能力的用户代理 应 仅在用户有明确意图(如点击浏览器按钮)时才发起远程播放。
若用户代理支持 浏览器发起远程播放,
state 属性必须反映与
远程播放设备 的当前连接状态。浏览器发起或终止远程播放时,必须按本规范相关算法派发事件。
若 浏览器即将发起媒体元素远程播放,
应先将其 state 初始化为 "connecting",然后启动与远程播放设备的连接流程。
HTMLMediaElement
接口在与 远程播放设备 建立连接后即与远程媒体交互。
当 state 为 "connected" 时,下述规则关联
本地播放状态、媒体元素状态 和
远程播放状态:
HTMLMediaElement
对象的所有媒体命令发送给 远程播放设备 ,以修改其 远程播放状态;
若发送命令失败,用户代理 可以 断开远程播放设备连接。
当用户代理需要断开远程播放设备连接时,必须执行如下操作:
RemotePlayback 对象。
state 为
disconnected,终止后续所有步骤。
state 为
disconnected。
disconnect,目标为 remote。
如果远程播放设备在播放过程中被突然断开(例如断电或网络中断),用户代理应当先运行监控可用远程播放设备列表的步骤,然后再运行
断开远程播放设备连接的步骤。这样可确保在 事件派发前,先唤起 可用性回调集合,便于页面更新提示用户无法恢复播放。
disconnect
disconnected 状态。
下列表格为实现 RemotePlayback
接口的对象必须支持的事件处理器
及其对应的
事件类型,作为
事件处理器
IDL 属性:
| 事件处理器 | 事件类型 |
|---|---|
onconnecting
|
connecting
|
onconnect
|
connect
|
ondisconnect
|
disconnect
|
HTMLMediaElement
的扩展
WebIDLpartial interface HTMLMediaElement {
[SameObject] readonly attribute RemotePlayback remote;
[CEReactions] attribute boolean disableRemotePlayback;
};
remote 属性 必须
返回与
RemotePlayback 的实例,该实例关联此
媒体元素。
某些页面可能希望禁用远程播放
某个媒体元素,例如他们更希望通过 PresentationRequest
在展示屏上展示整个文档。为支持该场景,audio 和 video 元素的内容属性列表增加了一个新的
disableRemotePlayback 属性。
同时,disableRemotePlayback
IDL 属性新增到 HTMLMediaElement 接口,用于反映各元素 disableRemotePlayback
内容属性的取值。
disableRemotePlayback
IDL 属性 必须
反映同名内容属性的值。
如果 disableRemotePlayback
属性存在于 媒体元素
上,则用户代理 不得 远程播放该媒体元素,也不得展示相关的 UI。
当 disableRemotePlayback
属性添加到
媒体元素
时,用户代理必须执行
禁用远程播放的操作:
RemotePlayback 方法返回的
promise,异常类型为 InvalidStateError。
state 不是
disconnected,则为该媒体元素处于连接或连接中状态的 远程播放设备 执行
断开远程播放设备连接 算法。
本节为非规范性内容。
通过 watchAvailability()
方法提供的 callback 机制会暴露有关本地局域网中
远程播放设备
是否存在的一比特信息。这可以与其他信息结合用于指纹识别用户。然而,该信息也与用户本地网络环境有关,因此风险是有限的。此外,设计上页面不会获得
远程播放设备 的可读名称。
该 API 允许监控可用远程播放设备列表。用户代理如何判断 远程播放设备 与 媒体 元素的 资源 的兼容性和可用性属于实现细节。如果用户代理将 媒体资源 与特定类型设备的可用性挂钩,可以被用于探测用户拥有哪些 远程播放设备,无需用户同意。
如果用户通过浏览器设置关闭了后台监控,则用户代理不应监控可用远程播放设备列表。
远程播放 API 抽象了对显示器“本地”含义的界定,也就是说,它会把网络可访问显示器也作为本地显示器暴露。本 API 要求页面获得访问任意显示设备的用户许可,以减轻如在他人可见屏幕上展示不想要内容等问题。
本规范不会强制本地播放设备与 本地播放设备 和 远程播放设备 之间的通信协议,但用户代理应保证双方之间的消息机密性与真实性。
远程播放 API 并不局限于 [SECURE-CONTEXTS],因为 它提供的功能常被用户代理原生支持,无论 浏览上下文 是否安全。用户代理可选择在非安全上下文中始终返回空列表,使本 API 只适用于 [SECURE-CONTEXTS]。
为推进本规范成为建议标准,必须至少有两个独立、可互操作的实现,每项功能均须如此。每项功能可由不同产品实现,不要求所有功能由同一产品支持。此外,实现还必须展示对媒体远距传输和媒体推送场景的支持, 可以在同一产品,也可以在不同产品中实现。
本标准的判断术语定义如下:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: