Initial Author of this Specification was Ian Hickson, Google Inc., with the following
copyright statement:
© Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software
ASA. You are granted a license to use, reproduce and create derivative works of this document.
All subsequent changes since 26 July 2011 done by the W3C WebRTC Working Group (and previously the Device APIs Working Group) are under the following Copyright © 2011-2023 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本文档定义了一组 JavaScript API,可用于从平台请求本地媒体,包括音频和视频。
本节描述了本文档在发布时的状态。当前 W3C 出版物和本技术报告的最新修订版可在 W3C 标准与草案索引 https://www.w3.org/TR/ 上找到。
本文档尚未完成。API 基于 WHATWG 的初步工作。
在本文档进入“建议推荐”阶段之前,WebRTC 工作组计划解决广泛审查中出现的问题。
本文档由 Web 实时通信工作组以 推荐路径 的方式发布为候选推荐草案。
作为候选推荐发布,不代表 W3C 及其成员的认可。候选推荐草案整合了工作组计划在后续快照中纳入的前一个候选推荐中的变更。
这是一个草案文件,可能随时被更新、替换或废弃为其他文件。不应将本文档作为除“进行中的工作”之外的引用。
本文档由 W3C 专利政策 约束下的工作组制作。 W3C 维护着 与本组成果相关的专利公开名单 ,该页面还包含专利披露的说明。任何实际知晓专利且认为该专利包含 必要声明 的个人,必须按照 《W3C 专利政策》第6节进行信息披露。
本文档受 2023年11月3日 W3C 流程文档 管辖。
本节为非规范性内容。
本文档定义了用于请求访问本地多媒体设备(如麦克风或摄像头)的 API。
本文档还定义了 MediaStream API,它提供了控制多媒体流数据消费位置的手段,并对产生媒体的设备提供部分控制。它还暴露了能够采集和呈现媒体的设备信息。
除明确标注为非规范性部分外,所有创作指南、图示、示例和注释均为非规范性内容。除此之外,规范的其他内容均为规范性。
本文档中的关键字 MAY、MUST、MUST NOT、NOT REQUIRED 和 SHOULD 按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,仅当这些关键字以全部大写形式出现时,如此处所示。
本规范定义了仅适用于单一产品的符合性标准:实现本规范中接口的用户代理(User Agent)。
以算法或具体步骤表达的符合性要求可以以任何方式实现,只要最终结果是等效的。(特别是,本规范定义的算法旨在便于理解,而非高性能。)
使用 ECMAScript [ECMA-262] 实现本规范中 API 的实现,必须与 Web IDL 规范中定义的 ECMAScript 绑定一致 [WEBIDL],因本规范采用该规范及术语。
源是提供媒体流轨道源的“事物”。源是媒体本身的广播者。源可以是物理摄像头、麦克风、用户硬盘上的本地视频或音频文件、网络资源或静态图片。请注意,本文档仅描述麦克风和摄像头类型源的使用,其他类型源的使用在其他文档中说明。
应用如果没有事先获得关于源的授权,则只能获得可用源的数量、类型及其与其他设备的关系。应用被授权使用某个源时,关于该源的更多信息才可能可用(见9.2.1 访问控制模型)。
源没有约束——轨道有约束。当源连接到轨道时,必须为该轨道产生符合其约束的媒体。多个轨道可以连接到同一个源。用户代理 处理(如降采样)可以用于确保所有轨道都拥有合适的媒体。
源具有可约束属性,这些属性的能力(capabilities)和设置(settings) 通过轨道被暴露。虽然可约束属性“归属”源,但源可以同时满足不同需求。因此,能力对于使用同一个源的所有(多个)轨道是通用的,而设置可以因轨道不同而不同(例如,两个绑定到同一源的不同轨道对象查询能力和设置信息时,会得到相同的能力,但可能得到不同的设置,以满足各自的约束)。
设置指的是源的可约束属性的即时、当前值。设置始终为只读。
源的状态可能会动态变化,例如摄像头因低光环境而切换到较低帧率。在这些情况下,与受影响源相关的轨道可能不再满足设置的约束。平台应当尽量减少此类偏离,但即使无法满足约束,也会继续传递媒体,无论是暂时还是永久条件。
尽管设置是源的属性,但只通过连接到该源的轨道向应用暴露。通过ConstrainablePattern
接口暴露。
每个可约束属性都有一个能力,用于描述该属性是否被源支持,以及支持值的范围。与设置一样,能力通过ConstrainablePattern
接口向应用暴露。
支持的能力值必须标准化为本规范中定义的范围和枚举类型。
在轨道上调用getCapabilities
()
会返回所有连接到该源的轨道的相同底层源能力。
本 API 有意简化。能力无法描述不同值之间的交互。例如,无法准确描述一个摄像头在低帧率下能产生高分辨率视频流,在高帧率下只能产生低分辨率流。能力仅描述每个值的完整范围。约束之间的交互通过尝试应用约束来暴露。
约束为应用提供了通用控制面板,既可用于为轨道选择合适的源,也可在选定后影响源的操作方式。
约束限制了源在为轨道提供媒体时可用的运行模式范围。如未指定轨道约束,实现在选择源设置时可在其支持能力的完整范围内自由选择。实现也可在所应用全部约束的范围内随时调整源设置。
getUserMedia
()
使用约束帮助为轨道选择合适的源并进行配置。此外,轨道上的ConstrainablePattern
接口包含用于动态更改轨道约束的
API。
如果轨道的初始约束无法满足,则不会通过getUserMedia
()
连接到源。不过,满足轨道约束的能力可能会随时间变化,约束也可更改。如果情况变化导致无法满足约束,ConstrainablePattern
接口会定义合适的错误,通知应用。5. 模型:源、接收端、约束和设置详细解释了约束的交互方式。
每个可约束属性都有一个约束,其名称与相关源设置名和能力名对应。
根据约束在约束结构中的位置,约束分为三类:
MediaStream API 的两个主要组件是
MediaStreamTrack
和 MediaStream
接口。
MediaStreamTrack
对象表示来自
用户代理中的一个媒体源的单一类型媒体,例如由网络摄像头产生的视频。
MediaStream
用于将多个
MediaStreamTrack
对象分组为一个单元,可以被录制或在媒体元素中呈现。
每个MediaStream
可以包含零个或多个
MediaStreamTrack
对象。一个
MediaStream
中的所有轨道在呈现时应当同步。这不是硬性要求,因为来自不同时钟源的轨道可能无法同步。不同的
MediaStream
对象之间不需要同步。
虽然目的是同步轨道,但在某些情况下允许轨道失去同步可能更好。特别是当轨道为远程来源且为实时[WEBRTC]时,允许不同步可能比积累延迟或出现故障和其他问题更好。实现应理解关于播放同步选择的影响,以及这些对用户感知的影响。
单个 MediaStreamTrack
可表示多通道内容,如立体声或 5.1
音频或立体视频,其中各通道之间有明确定义的关系。关于通道的信息可能通过其他 API(如 [WEBAUDIO])暴露,但本规范不直接访问通道。
MediaStream
对象具有输入和输出,代表对象所有轨道的合并输入和输出。
MediaStream
的输出控制对象的呈现方式,例如录制到文件时保存的内容或用于
video
元素时显示的内容。
单个 MediaStream
对象可以同时附加到多个不同输出。
可以使用
MediaStream
()
构造函数从已有的媒体流或轨道创建新的
MediaStream
对象。构造函数参数可以是现有的
MediaStream
对象,此时其所有轨道会加入新的
MediaStream
对象,或是一个
MediaStreamTrack
对象数组。后者可实现从不同源流合成一个流。
MediaStream
和
MediaStreamTrack
对象都可被克隆。克隆的
MediaStream
包含原流中所有成员轨道的克隆。克隆的
MediaStreamTrack
拥有独立于被克隆实例的约束集合,允许来自同一源的媒体在不同
消费者中应用不同约束。MediaStream
对象也用于
getUserMedia
之外的场景,如 [WEBRTC]。
MediaStream
MediaStream constructor
用于根据已有轨道组装一个新的流。它可选接收一个类型为
MediaStream
或 MediaStreamTrack
对象数组的参数。构造函数被调用时,用户代理必须按如下步骤执行:
令 stream 为新构造的
MediaStream
对象。
初始化 stream.id
属性为新生成的值。
如果构造函数参数存在,执行以下步骤:
根据参数类型构造轨道集合 tracks:
一个 MediaStream
对象:
令 tracks 为包含该 MediaStreamTrack
对象的集合,来自 MediaStream
的 轨道集合。
一组 MediaStreamTrack
对象:
令 tracks 为包含所有提供序列中 MediaStreamTrack
的集合。
对于 tracks 中的每个 MediaStreamTrack
,
track ,执行以下步骤:
返回 stream。
MediaStream
的轨道存储在
轨道集合中。轨道集合必须包含与流的轨道对应的 MediaStreamTrack
对象。集合中的轨道顺序由用户代理定义,API不会对顺序有任何要求。查找集合中特定 MediaStreamTrack
的正确方式是通过其 id
查找。
从 MediaStream
输出读取数据的对象称为
MediaStream
消费者。当前 MediaStream
消费者包括媒体元素(如
video
和
audio
)
[HTML],Web实时通信(WebRTC;RTCPeerConnection
)
[WEBRTC],媒体录制
(MediaRecorder
) [mediastream-recording],图像采集
(ImageCapture
) [image-capture],以及 Web 音频
(MediaStreamAudioSourceNode
)
[WEBAUDIO]。
MediaStream
的消费者必须能够处理轨道的添加和移除。具体行为由各消费者定义。
MediaStream
对象在拥有至少一个尚未 结束 的 MediaStreamTrack
时被称为活动。如果没有轨道或仅有已 结束 的轨道,则为非活动。
MediaStream
对象在拥有至少一个 MediaStreamTrack
,其 [[Kind]]
为 "audio"
且未 结束 时被称为可听。如果没有音频轨道或仅有已 结束 的音频轨道,则为不可听。
用户代理可以在响应外部事件时更新 MediaStream
的 轨道集合。本规范未规定具体情况,但其他使用
MediaStream API 的规范可能会规定。例如 WebRTC 1.0 [WEBRTC]
规范中,从其他 Peer 接收到的 MediaStream
的 轨道集合可因媒体会话变化而更新。
要将 轨道添加 track 到 MediaStream
stream,用户代理必须
执行以下步骤:
要将 轨道移除
track 从 MediaStream
stream,用户代理必须
执行以下步骤:
如果 track 不在 stream 的 轨道集合中,则终止这些步骤。
触发轨道事件,事件名为 removetrack
,事件内容为
track,目标为 stream。
WebIDL[Exposed=Window]
interface MediaStream
: EventTarget {
constructor
();
constructor
(MediaStream
stream);
constructor
(sequence<MediaStreamTrack
> tracks);
readonly attribute DOMString id
;
sequence<MediaStreamTrack
> getAudioTracks
();
sequence<MediaStreamTrack
> getVideoTracks
();
sequence<MediaStreamTrack
> getTracks
();
MediaStreamTrack
? getTrackById
(DOMString trackId);
undefined addTrack
(MediaStreamTrack
track);
undefined removeTrack
(MediaStreamTrack
track);
MediaStream
clone
();
readonly attribute boolean active
;
attribute EventHandler onaddtrack
;
attribute EventHandler onremovetrack
;
};
id
类型为 DOMString
,
只读id
属性必须返回对象创建时初始化的值。
创建 MediaStream
时,
用户代理必须生成一个标识符字符串,并必须将对象的 id
属性初始化为该字符串,除非对象是作为特殊算法的一部分创建,该算法指定了流 id 的初始化方式。推荐做法是使用 UUID [rfc4122],其规范形式为36位字符。为避免指纹识别,实现应当在生成UUID时使用RFC 4122的4.4或4.5节中的格式。
指定流 id 初始化方式的算法示例如,将传入网络组件与 MediaStream
对象关联的算法。[WEBRTC]
active
类型为 boolean
,只读
active
属性必须在此 MediaStream
为
活动时返回 true
,否则返回 false
。
onaddtrack
类型为 EventHandler
该事件处理器的事件类型为 addtrack
。
onremovetrack
类型为 EventHandler
该事件处理器的事件类型为 removetrack
。
getAudioTracks()
返回表示此流中音频轨道的 MediaStreamTrack
对象序列。
getAudioTracks
方法必须返回一个序列,表示此流的 轨道集合中所有
MediaStreamTrack
对象的快照,其 [[Kind]]
等于
"audio"
。由 轨道集合转换为序列的过程由 用户代理定义,且多次调用时序列顺序不需保持稳定。
getVideoTracks()
返回表示此流中视频轨道的 MediaStreamTrack
对象序列。
getVideoTracks
方法必须返回一个序列,表示此流的 轨道集合中所有
MediaStreamTrack
对象的快照,其 [[Kind]]
等于
"video"
。由 轨道集合转换为序列的过程由 用户代理定义,且多次调用时序列顺序不需保持稳定。
getTracks()
返回表示此流中所有轨道的 MediaStreamTrack
对象序列。
getTracks
方法必须返回此流的 轨道集合中所有
MediaStreamTrack
对象的快照,无论 [[Kind]]
类型。由 轨道集合转换为序列的过程由用户代理定义,且多次调用时序列顺序不需保持稳定。
getTrackById()
getTrackById
方法必须返回此流 轨道集合中 MediaStreamTrack
对象,其 [[Id]]
等于 trackId,不存在则返回
null
。
addTrack()
将给定的 MediaStreamTrack
添加到此
MediaStream
。
令 track 为方法参数,stream 为调用该方法的 MediaStream
对象。
如果 track 已在 stream 的 轨道集合中,则终止这些步骤。
removeTrack()
从此 MediaStream
移除给定的 MediaStreamTrack
对象。
调用 removeTrack
方法时,用户代理必须执行如下步骤:
令 track 为方法参数,stream 为调用该方法的 MediaStream
对象。
如果 track 不在 stream 的 轨道集合中,则终止这些步骤。
clone()
克隆给定的 MediaStream
及其所有轨道。
调用 clone
()
方法时,用户代理必须执行如下步骤:
令 streamClone 为新构造的
MediaStream
对象。
初始化 streamClone.MediaStream
.id
为新生成的值。
克隆每个轨道到此
MediaStream
对象,并将结果添加到
streamClone 的 轨道集合中。
期望触发 addtrack 或 removetrack 事件的用户代理代码应通过其他对象引用保持目标 MediaStream
对象存活。垃圾回收 MediaStream
对象时无需考虑 addtrack 或 removetrack
事件监听器的存在。
MediaStreamTrack
MediaStreamTrack
对象表示 用户代理中的一个媒体源。示例源是连接到 用户代理的设备。其他规范可能定义用于 MediaStreamTrack
的源以覆盖此处规定的行为。多个 MediaStreamTrack
对象可以表示同一个媒体源,例如用户在两次调用 getUserMedia
()
时选择了相同的摄像头。
MediaStreamTrack
源定义如下属性:
MediaStreamTrack
或 MediaStreamTrack
的子类型。默认设置为 MediaStreamTrack
。MediaStreamTrack
时执行。步骤以新创建的 MediaStreamTrack
作为输入。默认步骤为空。MediaStreamTrack
时执行。步骤以源和目标的 MediaStreamTrack
作为输入。默认步骤为空。MediaStreamTrack
对象中的数据不一定有规范的二进制形式;例如它可能只是“用户摄像头当前的视频”。这样允许 用户代理以最适合用户平台的方式处理媒体。
脚本可通过 stop
()
方法指示 MediaStreamTrack
对象不再需要其源。当所有使用某源的轨道被 stop
或以其他方式结束,该源进入 已停止 状态。如果源是 getUserMedia
()
暴露的设备,则源停止时,用户代理 必须执行如下步骤:
令 mediaDevices 为相关的 MediaDevices
对象。
令 deviceId 为源设备的 deviceId
。
设置 mediaDevices.[[devicesLiveMap]]
[deviceId]
为
false
。
如果与设备类型和 deviceId 相关权限的 权限状态
对 mediaDevices 的 相关设置对象
不是 "granted
",
则设置 mediaDevices.[[devicesAccessibleMap]]
[deviceId]
为
false
。
要创建 MediaStreamTrack,给定底层 source 和 mediaDevicesToTieSourceTo,运行以下步骤:
令 track 为一个新对象,类型为 source 的 MediaStreamTrack 源类型。
初始化 track 的以下内部槽:
[[Source]], 初始化为 source。
[[Id]],
初始化为新生成的唯一标识符字符串。生成方式参见 MediaStream
.id
属性。
[[Kind]],
若 source 是音频源,则初始化为 "audio"
,若 source 是视频源,则初始化为 "video"
。
[[Label]],
初始化为 source 的 label(如果用户代理提供),否则为 ""
。用户代理 可以为音频和视频源打标签(如“内置麦克风”或“外部USB摄像头”)。
[[ReadyState]],
初始化为 "live
"。
[[Enabled]],
初始化为 true
。
[[Muted]],
若 source已静音则为true
,否则为false
。
ConstrainablePattern
规定初始化。
[[Restrictable]],初始化为 false
。
如果 mediaDevicesToTieSourceTo 不为 null
,
使用 将 track 源绑定到
MediaDevices
,参数为 source 和 mediaDevicesToTieSourceTo。
用 track 为参数,运行 source 的 MediaStreamTrack 源特定构造步骤。
返回 track。
要初始化 track 的底层源为 source,请执行以下步骤:
初始化 track.[[Source]]
为
source。
按 ConstrainablePattern
规定初始化
track 的 [[Capabilities]],
[[Constraints]] 和
[[Settings]]。
要将 track 源绑定到 MediaDevices
,
给定 source 和 mediaDevices,请执行以下步骤:
将 source 添加到
mediaDevices.[[mediaStreamTrackSources]]
。
要停止所有源,对于 全局对象 globalObject, 用户代理 必须执行如下步骤:
对于 MediaStreamTrack
对象 track
,其 相关全局对象为
globalObject,
设置 track 的 [[ReadyState]]
为
"ended
"。
如果 globalObject 是 Window
,
则对于 globalObject 的 关联的 MediaDevices
.[[mediaStreamTrackSources]]
中的每个
source,
停止 source。
用户代理 必须在以下条件下对 globalObject 执行停止所有源:
如果 globalObject 是 WorkerGlobalScope
对象且其 关闭
标志被设置为 true。
实现可以使用每个源的引用计数来跟踪源的使用,但具体细节超出本规范范围。
要克隆轨道,用户代理 必须执行以下步骤:
令 track 为待克隆的 MediaStreamTrack
对象。
令 source 为 track 的
[[Source]]
。
令 trackClone 为用 source 和 null
创建 MediaStreamTrack 的结果。
设置 trackClone 的 [[ReadyState]]
为
track 的 [[ReadyState]]
的值。
设置 trackClone 的 [[Capabilities]] 为 track 的 [[Capabilities]] 的克隆。
设置 trackClone 的 [[Constraints]] 为 track 的 [[Constraints]] 的克隆。
设置 trackClone 的 [[Settings]] 为 track 的 [[Settings]] 的克隆。
用 track 和 trackClone 为参数,运行 source 的 MediaStreamTrack 源特定克隆步骤。
返回 trackClone。
对于"live
" MediaStreamTrack
,媒体流动有两个维度:静音/未静音 和 启用/禁用。
静音(Muted)指的是输入到 MediaStreamTrack
。当其源 静音(即暂时无法为轨道提供数据)时,MediaStreamTrack
处于 静音状态。
在静音时,不得向 MediaStreamTrack
提供实时采样。
静音状态无法被网页应用控制,但可通过读取 muted
属性并监听相关事件 mute
和 unmute
进行观察。
MediaStreamTrack
被静音的原因由其 源定义。
对于摄像头和麦克风源,静音 的原因是 由实现定义。 这允许用户代理在如下场景下实现隐私保护: 用户按下麦克风物理静音按钮,用户关闭内嵌摄像头的笔记本电脑盖,用户在操作系统中切换控制,用户在 用户代理界面点击静音按钮,用户代理(代替用户)进行静音等。
在某些操作系统上,当其他具有更高音频优先级的应用获得麦克风访问权限(如移动操作系统上来电时),麦克风访问可能会被从 用户代理“窃取”。
用户代理 应当通过 muted
及相关事件向网页应用提供此类信息。
每当 用户代理针对摄像头或麦克风源启动此类 由实现定义 的变更时,必须使用用户交互任务源,排队一个任务,设置轨道静音状态为用户期望的状态。
要将轨道静音状态设置为 newState,用户代理 必须执行以下步骤:
令 track 为相关的 MediaStreamTrack
。
如果 track.[[Muted]]
已为
newState,则终止这些步骤。
设置 track.[[Muted]]
为
newState。
触发事件,事件名为 eventName,目标为 track。
启用/禁用(Enabled/disabled)则可由应用控制(并观察),通过 enabled
属性实现。
对于消费者而言,无论 MediaStreamTrack
处于静音还是禁用(或两者均有),消费者得到的信息都是零内容,即音频为静音,视频为黑帧。换句话说,仅当 MediaStreamTrack
对象既未静音又已启用时,源媒体才流动。例如,视频元素仅含静音或禁用的音视频轨道时,播放的是黑帧和无声。
对于新创建的 MediaStreamTrack
对象,默认始终启用(除非另有说明,如克隆时),静音状态反映源在轨道创建时的状态。
MediaStreamTrack
在生命周期中有两个状态:live(活动)和 ended(结束)。新创建的 MediaStreamTrack
可以处于任一状态,取决于创建方式。例如,克隆已结束轨道会得到新的已结束轨道。当前状态由对象的 readyState
属性反映。
在活动状态下,轨道处于激活,媒体(或零内容,如果 MediaStreamTrack
被 静音 或 禁用)可以被消费者使用。
如果源是 navigator.mediaDevices.
getUserMedia
()
暴露的设备,则当某轨道变为静音或禁用,并且该设备所有已连接轨道均为静音、禁用或已停止时,UA 可以使用设备的 deviceId
deviceId
,设置 navigator.mediaDevices.
[[devicesLiveMap]]
[deviceId] 为
false
,但应在任何未停止轨道重新变为未静音或启用时,及时恢复为 true
。
当由设备暴露的活动、未静音且已启用的轨道变为静音或禁用,并且该设备所有轨道(在所有 UA 管理的 navigable 中)均为静音、禁用或已停止时,UA 应当在3秒内释放设备,同时给用户合理时间察觉状态变化。UA 应当在任何由该设备产生的活动轨道重新变为既未静音又启用时尝试重新获取设备,前提是该轨道的 相关全局对象 的 关联文档 此时在视图中。如果文档当时不在视图中,UA 应当排队任务静音轨道,并在文档重新进入视图后,才排队任务取消静音。 如果重新获取设备失败,UA 必须结束轨道(UA 可以在检测到设备问题(如设备被物理移除)时更早终止)。
目的是让用户通过物理摄像头(和麦克风)指示灯熄灭获得隐私保证,即物理和逻辑“隐私指示器”对齐,至少在当前文档是设备唯一使用者时。
虽然其他同时使用设备的应用和文档有时会干扰这一目标,但不会影响本规范的规则。
当轨道的源断开连接或耗尽时,MediaStreamTrack
对象被认为结束。
如果所有使用同一源的 MediaStreamTrack
都已 结束,则源会被
停止。
应用调用 stop
()
方法后,或当 源永久不再为轨道生产实时采样(以先到者为准),MediaStreamTrack
被认为结束(ended)。
对于摄像头和麦克风源,除 stop
()
外,源结束的原因是
由实现定义
(如用户撤销页面使用本地摄像头权限,或用户代理因任何原因指示轨道结束)。
当 MediaStreamTrack
track
因除 stop()
方法外的其他原因结束时,用户代理 必须排队任务,执行以下步骤:
如果 track 的 [[ReadyState]]
已为 "ended
",则终止这些步骤。
设置 track 的 [[ReadyState]]
为 "ended
"。
通知 track 的 [[Source]]
,track 已 结束,以便源可被 停止,除非仍有其他 MediaStreamTrack
对象依赖该源。
如果轨道因用户请求而结束,则该事件的事件源为用户交互事件源。
要执行设备权限撤销算法,参数为 permissionName,请执行以下步骤:
令 tracks 为所有当前
"live
"
MediaStreamTrack
,其权限与该类轨道("camera"
或 "microphone"
)
匹配 permissionName。
对 tracks 中的每个 track, 结束该轨道。
MediaStreamTrack
是 可约束对象,定义见 可约束模式部分。
约束是针对轨道设置的,并可能影响源。
无论
是在轨道初始化时提供,还是需要在运行时建立,
Constraints
ConstrainablePattern
接口定义的 API
允许检索和操作当前在轨道上建立的约束。
轨道结束后,仍会暴露
固有可约束轨道属性列表。
该列表包含 deviceId
、
facingMode
和
groupId
。
WebIDL[Exposed=Window]
interface MediaStreamTrack
: EventTarget {
readonly attribute DOMString kind
;
readonly attribute DOMString id
;
readonly attribute DOMString label
;
attribute boolean enabled
;
readonly attribute boolean muted
;
attribute EventHandler onmute
;
attribute EventHandler onunmute
;
readonly attribute MediaStreamTrackState
readyState
;
attribute EventHandler onended
;
MediaStreamTrack
clone
();
undefined stop
();
MediaTrackCapabilities
getCapabilities
();
MediaTrackConstraints
getConstraints
();
MediaTrackSettings
getSettings
();
Promise<undefined> applyConstraints
(optional MediaTrackConstraints
constraints = {});
};
kind
类型为 DOMString
,
只读id
类型为 DOMString
,
只读label
类型为 DOMString
,
只读enabled
类型为 boolean
enabled
属性控制对象的 启用状态。
获取时,
this.[[Enabled]]
必须返回。
设置时,
this.[[Enabled]]
必须设为新值。
因此,当 MediaStreamTrack
结束 后,其 enabled
属性
仍可更改取值;只是新值不会产生任何作用。
muted
类型为 boolean
,
只读onmute
类型为 EventHandler
该事件处理器的事件类型为 mute。
onunmute
类型为 EventHandler
该事件处理器的事件类型为 unmute。
readyState
类型为
MediaStreamTrackState
,
只读
获取时,readyState
属性必须返回
this.[[ReadyState]]
。
onended
类型为 EventHandler
该事件处理器的事件类型为 ended。
clone
stop
调用 MediaStreamTrack
对象的
stop
()
方法时,用户代理必须执行以下步骤:
令 track 为当前
MediaStreamTrack
对象。
如果 track 的 [[ReadyState]]
为 "ended
",
则终止这些步骤。
通知 track 的源,track 已 结束。
源收到轨道结束通知后,除非仍有其他
MediaStreamTrack
对象依赖该源,否则会被
停止。
设置 track 的 [[ReadyState]]
为 "ended
"。
getCapabilities
返回该 MediaStreamTrack
所表示的源的能力,可约束对象。
定义见 可约束模式接口。
由于此方法提供可能长期存在的、跨域的底层设备信息,会增加设备指纹识别面。
getConstraints
定义见 可约束模式接口。
getSettings
调用 MediaStreamTrack
对象的
MediaStreamTrack
.getSettings
()
方法时,
用户代理 必须执行以下步骤:
令 track 为当前 MediaStreamTrack
对象。
如果 track 的 [[ReadyState]]
为 "ended
",
执行以下子步骤:
令 settings 为新的 MediaTrackSettings
字典。
对于 固有可约束轨道属性列表中的每个 property, 如果 track 在结束时拥有此属性,则添加对应属性到 settings,值为轨道结束时的值。
返回 settings。
返回轨道的当前设置,定义见 可约束模式接口。
applyConstraints
调用 MediaStreamTrack
对象的
applyConstraints
()
方法时,用户代理必须执行以下步骤:
令 track 为当前
MediaStreamTrack
对象。
如果 track 的 [[ReadyState]]
为 "ended
",
执行以下子步骤:
令 p 为新建的 Promise。
resolve
p,值为 undefined
。
返回 p。
调用并返回 applyConstraints 模板方法的结果,参数如下:
MediaStreamTrack
,
settings
dictionary 指的是可能的 MediaTrackSettings
字典实例。用户代理
不得包含固有不可更改设备属性,除非这些属性在 固有可约束轨道属性列表中,或包含
不得暴露 的设备属性。
其他规范可定义有时不得暴露的可约束属性。
对于每个 settings dictionary,其中 resizeMode 为 "none", 用户代理 必须再包含一个只有 resizeMode 为 "crop-and-scale" 的 otherwise identical settings dictionary。不支持围绕非原生模式的约束。
实际效果是 crop-and-scale 是 none 的超集。
WebIDLenum MediaStreamTrackState
{
"live
",
"ended
"
};
枚举值 | 说明 |
---|---|
live |
轨道处于活动状态(轨道的底层媒体源正在尽最大努力实时提供数据)。 |
ended |
轨道已结束(轨道的底层媒体源不再提供数据,并且不会再为此轨道提供更多数据)。轨道进入此状态后,永不离开此状态。 例如,当用户拔掉作为轨道媒体源的 USB 摄像头时, |
MediaTrackSupportedConstraints
表示 用户代理 用于控制 能力 的 MediaStreamTrack
对象的约束列表。
此字典仅用于作为函数返回值,而不会作为操作参数。
未来的规范可以通过定义带有 boolean
类型字典成员的 partial
dictionary 来扩展 MediaTrackSupportedConstraints
字典。
本规范中指定的约束仅适用于由 MediaStreamTrack
生成的实例,
这些实例来自 MediaDevices
.getUserMedia
()
,
除非其他规范另有说明。
WebIDLdictionary MediaTrackSupportedConstraints
{
boolean width
= true;
boolean height
= true;
boolean aspectRatio
= true;
boolean frameRate
= true;
boolean facingMode
= true;
boolean resizeMode
= true;
boolean sampleRate
= true;
boolean sampleSize
= true;
boolean echoCancellation
= true;
boolean autoGainControl
= true;
boolean noiseSuppression
= true;
boolean latency
= true;
boolean channelCount
= true;
boolean deviceId
= true;
boolean groupId
= true;
boolean backgroundBlur
= true;
};
width
类型为 boolean
,
默认值为
true
height
类型为 boolean
,
默认值为
true
aspectRatio
类型为 boolean
,
默认值为
true
frameRate
类型为 boolean
,
默认值为
true
facingMode
类型为 boolean
,
默认值为
true
resizeMode
类型为 boolean
,
默认值为
true
sampleRate
类型为 boolean
,
默认值为
true
sampleSize
类型为 boolean
,
默认值为
true
echoCancellation
类型为 boolean
,
默认值为
true
autoGainControl
类型为 boolean
,
默认值为
true
noiseSuppression
类型为 boolean
,
默认值为
true
latency
类型为 boolean
,
默认值为
true
channelCount
类型为 boolean
,
默认值为
true
deviceId
类型为 boolean
,
默认值为
true
groupId
类型为 boolean
,
默认值为
true
backgroundBlur
类型为 boolean
,
默认值为
true
MediaTrackCapabilities
表示 能力的 MediaStreamTrack
对象。
未来的规范可以通过定义带有适当类型字典成员的 partial dictionary 来扩展 MediaTrackCapabilities 字典。
WebIDLdictionary MediaTrackCapabilities
{
ULongRange
width
;
ULongRange
height
;
DoubleRange
aspectRatio
;
DoubleRange
frameRate
;
sequence<DOMString> facingMode
;
sequence<DOMString> resizeMode
;
ULongRange
sampleRate
;
ULongRange
sampleSize
;
sequence<(boolean or DOMString)> echoCancellation
;
sequence<boolean> autoGainControl
;
sequence<boolean> noiseSuppression
;
DoubleRange
latency
;
ULongRange
channelCount
;
DOMString deviceId
;
DOMString groupId
;
sequence<boolean> backgroundBlur
;
};
由于历史原因,deviceId
和
groupId
是 DOMString
类型,而不是 sequence<DOMString>
,这与 Capabilities
在
中的预期类型不同。
ConstrainablePattern
MediaTrackCapabilities
成员width
类型为 ULongRange
height
类型为 ULongRange
aspectRatio
类型为 DoubleRange
frameRate
类型为 DoubleRange
facingMode
类型为
sequence<DOMString
>
一个摄像头可以报告多个朝向模式。例如,在高端远程会议系统中,有多个摄像头面向用户,用户左侧的摄像头可以同时报告 "left
"
和 "user
"。具体见 facingMode。
resizeMode
类型为
sequence<DOMString
>
用户代理 可以使用裁剪和降采样为摄像头提供比其原生分辨率更多的分辨率选择。
报告的序列必须列出 UA 可用于该摄像头的所有分辨率派生方式。值 "none
" 必须存在,表示可以限制 UA 不进行裁剪和降采样。具体见 resizeMode。
sampleRate
类型为 ULongRange
sampleSize
类型为 ULongRange
echoCancellation
类型为
sequence<boolean
>
如果源无法进行回声消除,则列表中仅包含一个 false
。如果源能进行回声消除,则列表中必须包含
true
。如果脚本可控该功能,则列表必须至少同时包含 true
和
false
。此外,如果源允许控制取消哪些音源,则必须包含 EchoCancellationModeEnum
枚举的所有支持值。如果列表中包含 true
或 false
,则它们必须出现在所有 EchoCancellationModeEnum
值之前。具体见 echoCancellation。
autoGainControl
类型为
sequence<boolean
>
如果源无法进行自动增益控制,则只报告 false
。如果自动增益控制无法关闭,则只报告
true
。如果脚本可控该功能,则报告 true
和 false
两种可能值。具体见 autoGainControl。
noiseSuppression
类型为
sequence<boolean
>
如果源无法进行降噪,则只报告 false
。如果降噪功能无法关闭,则只报告 true
。如果脚本可控该功能,则报告
true
和 false
两种可能值。具体见 noiseSuppression。
latency
类型为 DoubleRange
channelCount
类型为 ULongRange
deviceId
类型为 DOMString
groupId
类型为 DOMString
backgroundBlur
类型为
sequence<boolean
>
false
。如果背景虚化功能无法关闭,则只报告 true
。如果脚本可控该功能,则报告
true 和 false 两种可能值。具体见 backgroundBlur。WebIDLdictionary MediaTrackConstraints
: MediaTrackConstraintSet
{
sequence<MediaTrackConstraintSet
> advanced
;
};
MediaTrackConstraints
成员advanced
类型为
sequence<MediaTrackConstraintSet
>
定义见 约束与约束集。
未来的规范可以通过定义带有适当类型字典成员的 partial dictionary 来扩展
MediaTrackConstraintSet
字典。
WebIDLdictionary MediaTrackConstraintSet
{
ConstrainULong
width
;
ConstrainULong
height
;
ConstrainDouble
aspectRatio
;
ConstrainDouble
frameRate
;
ConstrainDOMString
facingMode
;
ConstrainDOMString
resizeMode
;
ConstrainULong
sampleRate
;
ConstrainULong
sampleSize
;
ConstrainBooleanOrDOMString
echoCancellation
;
ConstrainBoolean
autoGainControl
;
ConstrainBoolean
noiseSuppression
;
ConstrainDouble
latency
;
ConstrainULong
channelCount
;
ConstrainDOMString
deviceId
;
ConstrainDOMString
groupId
;
ConstrainBoolean
backgroundBlur
;
};
MediaTrackConstraintSet
成员width
类型为 ConstrainULong
height
类型为 ConstrainULong
aspectRatio
类型为 ConstrainDouble
frameRate
类型为 ConstrainDouble
facingMode
类型为 ConstrainDOMString
resizeMode
类型为 ConstrainDOMString
sampleRate
类型为 ConstrainULong
sampleSize
类型为 ConstrainULong
echoCancellation
类型为 ConstrainBooleanOrDOMString
autoGainControl
类型为 ConstrainBoolean
noiseSuppression
类型为 ConstrainBoolean
latency
类型为 ConstrainDouble
channelCount
类型为 ConstrainULong
deviceId
类型为 ConstrainDOMString
groupId
类型为 ConstrainDOMString
backgroundBlur
类型为 ConstrainBoolean
MediaTrackSettings
表示 设置的 MediaStreamTrack
对象。
未来规范可以通过定义带有适当类型字典成员的 partial dictionary 来扩展 MediaTrackSettings 字典。
WebIDLdictionary MediaTrackSettings
{
unsigned long width
;
unsigned long height
;
double aspectRatio
;
double frameRate
;
DOMString facingMode
;
DOMString resizeMode
;
unsigned long sampleRate
;
unsigned long sampleSize
;
(boolean or DOMString) echoCancellation
;
boolean autoGainControl
;
boolean noiseSuppression
;
double latency
;
unsigned long channelCount
;
DOMString deviceId
;
DOMString groupId
;
boolean backgroundBlur
;
};
MediaTrackSettings
成员width
类型为 unsigned long
height
类型为 unsigned long
aspectRatio
类型为 double
frameRate
类型为 double
facingMode
类型为 DOMString
resizeMode
类型为 DOMString
sampleRate
类型为 unsigned long
sampleSize
类型为 unsigned long
echoCancellation
类型为 boolean
或 DOMString
autoGainControl
类型为 boolean
noiseSuppression
类型为 boolean
latency
类型为
double
channelCount
类型为 unsigned long
deviceId
类型为 DOMString
groupId
类型为 DOMString
backgroundBlur
类型为 boolean
,
默认值为
true
MediaStreamTrack 的初始可约束属性名称如下定义。
以下可约束属性适用于视频和音频 MediaStreamTrack
对象:
属性名 | 类型 | 说明 |
---|---|---|
deviceId | DOMString |
生成 MediaStreamTrack 内容的设备标识符。符合
MediaDeviceInfo .deviceId 的定义。
注意此属性的设置值是由附加到 MediaStreamTrack 的源唯一决定的。尤其是
getCapabilities ()
只会返回 deviceId 的一个值。因此此属性可用于 getUserMedia ()
初始媒体选择。
但对于 applyConstraints ()
后续媒体控制无效,
因为试图设置不同值会导致 ConstraintSet 无法满足。
若使用长度为0的字符串作为 deviceId 约束值配合 getUserMedia () ,
可以视为未指定约束。
|
groupId | DOMString |
生成 MediaStreamTrack 内容的设备的
文档唯一组标识符。
符合 MediaDeviceInfo .groupId 的定义。
注意此属性的设置值由附加到 MediaStreamTrack 的源唯一决定。尤其是 getCapabilities ()
只会返回 groupId 的一个值。由于该属性在会话间不稳定,用于 getUserMedia ()
初始媒体选择时作用有限。
对于 applyConstraints ()
后续媒体控制无效,
因为试图设置不同值会导致 ConstraintSet 无法满足。
|
以下可约束属性仅适用于视频 MediaStreamTrack
对象:
属性名 | 类型 | 说明 |
---|---|---|
width | unsigned long
|
宽度,单位为像素。作为能力,其有效范围应覆盖视频源预设宽度值,最小值为1,最大值为最大宽度。 用户代理 必须支持对最小宽度至原生分辨率宽度区间内任意值的降采样。 |
height | unsigned long
|
高度,单位为像素。作为能力,其有效范围应覆盖视频源预设高度值,最小值为1,最大值为最大高度。 用户代理 必须支持对最小高度至原生分辨率高度区间内任意值的降采样。 |
frameRate | double |
帧率(每秒帧数)。 如果视频源预设能决定帧率,则作为能力,其有效范围应覆盖视频源预设帧率值,最小值为0,最大值为最大帧率。 用户代理 必须 支持通过对原生分辨率帧率做整数降采样获得的帧率。 如果无法确定帧率(如源不原生提供帧率,或无法从流中确定),则能力值 必须参考 用户代理 的 vsync 显示帧率。 作为设置,此值表示配置的帧率。
如降采样,则为该值而非原生帧率。例如设置为25帧/秒,摄像头原生为30帧/秒,但因光照实际只有20帧/秒,则 |
aspectRatio | double |
精确的宽高比(像素宽度/像素高度,双精度小数点后十位)或宽高比范围。 |
facingMode | DOMString |
该字符串为 VideoFacingModeEnum
成员之一,描述摄像头可面向的方向(用户视角)。
注意
不属于此枚举的字符串可能不会被原样返回,保留了未来使用WebIDL枚举的可能性。
|
resizeMode | DOMString |
此字符串为 VideoResizeModeEnum 成员之一。
描述 UA 派生分辨率的方式,即是否允许对摄像头输出进行裁剪和降采样。
UA 可以通过降采样、升采样和/或裁剪伪装并发使用摄像头,仅在摄像头被其他应用占用时对 "none" 使用。
不属于此枚举的字符串可能不会被原样返回,保留了未来使用WebIDL枚举的可能性。
|
backgroundBlur | boolean |
某些平台或用户代理可能为视频帧(尤其是摄像头视频流)提供内建背景虚化。Web应用可能希望控制或至少感知源级虚化,以便更新UI或避免重复虚化。 |
在某些系统上,可能需要根据环境因素自动翻转捕获视频的X/Y轴,width
、height
和 aspectRatio
约束与能力在所有算法中必须保持不变,并仅按 主方向考虑,除非 getSettings
()
算法,需要在任何时刻根据捕获视频实际尺寸翻转这些属性。
主方向是支持自动翻转视频X/Y轴系统由用户代理定义的方向。
WebIDLenum VideoFacingModeEnum
{
"user
",
"environment
",
"left
",
"right
"
};
枚举值 | 说明 |
---|---|
user |
源面向用户(自拍摄像头)。 |
environment |
源背向用户(面对环境)。 |
left |
源面向用户左侧。 |
right |
源面向用户右侧。 |
下图展示了视频面向模式与用户的关系。
WebIDLenum VideoResizeModeEnum
{
"none
",
"crop-and-scale
"
};
枚举值 | 说明 |
---|---|
none |
该分辨率和帧率由摄像头、驱动或操作系统提供。 注意:UA 可以报告该值以伪装并发使用,仅在摄像头被其他 navigable
占用时。 |
crop-and-scale |
该分辨率由 用户代理 从更高摄像头分辨率降采样和/或裁剪获得,或由 用户代理 对帧率降采样获得。媒体不得被升采样、拉伸或伪造非输入源数据,除下述情况外。 注意:UA 可以升采样以伪装并发使用,仅在摄像头被其他应用占用时。 |
以下可约束属性仅适用于音频 MediaStreamTrack
对象:
属性名 | 值类型 | 说明 |
---|---|---|
sampleRate | unsigned long
|
音频数据的每秒采样率。 |
sampleSize | unsigned long
|
线性采样位数。作为约束,仅对能产生线性采样的音频设备适用。 |
echoCancellation | boolean 或 DOMString |
当多个麦克风同时播放音频流时,通常希望尝试从麦克风输入信号中去除正在播放的声音,这被称为回声消除。 某些场景下无需此功能,关闭可避免音频伪影。应用可控制此行为。 |
autoGainControl | boolean |
通常对麦克风输入信号希望自动增益控制。有些情况下不需要,关闭可避免音频被更改。应用可控制此行为。 |
noiseSuppression | boolean |
通常对麦克风输入信号希望进行降噪。有些情况下不需要,关闭可避免音频被更改。应用可控制此行为。 |
latency | double |
延迟或延迟范围,单位秒。指从处理开始(如真实世界发生声音)到数据可用于下一步的时间。部分应用对低延迟有强需求,部分可接受高延迟以节省能耗。该数值为配置目标延迟,实际延迟可能有偏差。 |
channelCount | unsigned long
|
音频数据的独立声道数,即每个采样帧的音频样本数。 |
WebIDLenum EchoCancellationModeEnum
{
"all
",
"remote-only
"
};
枚举值 | 说明 |
---|---|
"all " |
系统必须尝试从麦克风输入信号中去除系统播放的所有声音。 该选项用于最大化隐私,防止本地音频如通知或屏幕阅读器被传输。 |
"remote-only "
|
系统必须尝试去除来自 WebRTC UA 决定取消哪些 |
EchoCancellationModeEnum
枚举值外,
echoCancellation
可约束属性也接受 true
和 false
。false
表示不进行回声消除,
true
表示由UA决定去除哪些音频。true
必须至少像
"remote-only" 一样消除回声,
建议尽可能像 "all" 一样消除回声。
如果 MediaStreamTrack
对象尚未 结束,且注册了 mute、
unmute
或 ended 事件的事件监听器,
不得被垃圾回收。
每种源类型可进一步细化垃圾回收规则,因为某些源可能永远不会触发某些事件。
MediaStreamTrack
的
stop() 方法,
尤其是采集轨道,因为底层资源代价高昂,并且会影响呈现给用户的隐私指示器。
addtrack
和 removetrack
事件
使用
MediaStreamTrackEvent
接口。
addtrack
和 removetrack
事件通知
脚本 轨道集合 已被
MediaStream
的 用户代理 更新。
触发名为
e 的轨道事件,并关联一个 MediaStreamTrack
track,表示创建并在指定目标分发一个事件,其名称为 e,该事件不会冒泡(除非另有规定),也不可取消(除非另有规定),并使用
MediaStreamTrackEvent
接口,track
属性设置为 track,必须这样处理。
WebIDL[Exposed=Window]
interface MediaStreamTrackEvent
: Event {
constructor
(DOMString type, MediaStreamTrackEventInit
eventInitDict);
[SameObject] readonly attribute MediaStreamTrack
track
;
};
constructor()
构造一个新的
MediaStreamTrackEvent
。
track
类型为 MediaStreamTrack
,只读track
属性表示与事件关联的 MediaStreamTrack
对象。
WebIDLdictionary MediaStreamTrackEventInit
: EventInit {
required MediaStreamTrack
track
;
};
track
类型为 MediaStreamTrack
,必需本节为非规范性内容。
用户代理提供了从源到汇的媒体管道。在用户代理中,
汇指的是
<img
>、
<video
>、
以及
<audio
>
标签。
传统源包括流式内容、文件和网络资源。这些源产生的媒体通常不会随时间改变——这些源可以视为静态的。
向用户展示这些源的汇(就是实际标签本身)有多种控制方式可以操作源内容。例如,
<img
>
标签会将一个1600x1200像素的大图缩放至由width="400"
和height="300"
定义的矩形内。
源有生命周期。默认情况下,源的生命周期与创建它的上下文绑定。例如,由
MediaDevices
.getUserMedia
()
创建的源,视为由其 navigator.mediaDevices
上下文创建。同理,
RTCRtpReceiver
对象的源与
RTCPeerConnection
实体绑定,而该实体又与其创建上下文绑定。
除非某些源的定义中明确说明,否则当创建上下文消失时,源总是停止。需要注意的是,来自不同上下文的两个源可以同时使用同一个采集设备,
一个源可以独立于另一个源停止。
getUserMedia API 增加了麦克风和摄像头等动态源——这些源的特性可根据应用需求变化。这些源本质上是动态的。
一个
<video
>
元素展示动态源的媒体时,
可以对内容进行缩放,也可以沿着媒体管道反馈信息,使源产生更适合展示的内容。
注意:这种反馈回路显然只是实现了一种“优化”,但收益并不微小。这种优化可以节省电池、减少网络拥堵等……
需要注意的是,
MediaStream
汇(如
<video
>、
<audio
>,
甚至
RTCPeerConnection
)仍可以对源流进行进一步转换,
超出本规范所述的设置、
能力以及约束
的范围。(汇的转换选项,包括
RTCPeerConnection
的相关选项,
不在本规范范围之内。)
对轨道约束的变更或应用可能会影响所有共享该源的轨道的
设置,
从而影响所有使用该源的下游汇。许多汇能够适应这些变化,如
<
元素或video
>RTCPeerConnection
。
但如 Recorder API 之类的汇,可能会因源设置变化而失败。
RTCPeerConnection
是一个有趣的对象,因为它同时作为汇和源处理网络流。作为汇,它可以对源进行转换(如降低码率、缩放分辨率、调整帧率),作为源,它也可能被轨道源改变自己的设置。
为了说明对某个源的变更如何影响不同的汇,来看以下示例。该示例只用到宽度和高度,但同理也适用于本规范所暴露的所有设置。如图所示,家庭客户端从本地摄像头获取了一个视频源。该源的宽高设置分别为800x600像素。该家庭客户端上的三个
MediaStream
对象包含使用同一个
<deviceId
的轨道。这三个媒体流连接到三个不同的汇:一个
<
元素(A)、另一个
video
><
元素(B),以及一个 peer connection(C)。该 peer connection 将源视频流传到远程客户端。远程客户端有两个媒体流,其轨道以 peer connection
为源。两个媒体流分别连接到两个
video
><
元素(Y 和 Z)。
video
>
此时,家庭客户端上的所有汇都必须对原始源尺寸进行变换。B 将视频缩小,A 将视频放大(导致画质损失),而 C 也略微放大视频以便网络传输。远程客户端上,汇 Y 大幅缩小视频,汇 Z 不做缩放。
在调用 applyConstraints
()
后,其中一个轨道希望家庭客户端的视频源分辨率提升至1920x1200像素。
需要注意的是,源的改变会立刻影响家庭客户端上的所有轨道和汇,但不会影响远程客户端上的任何汇(或源)。随着家庭客户端的视频源尺寸增大,汇 A 无需再进行缩放,汇 B 需要比以前更多地缩小视频。汇 C(peer connection)则需将视频缩小,以保持向远程客户端的传输不变。
虽然未展示,远程客户端侧也可以提出同样有效的设置变更请求。该变更会像之前影响 A、B、C 一样影响 Y 和 Z,还可能导致与家庭客户端上的 peer connection 重新协商,调整其对家庭客户端视频源的转换。此类变更不要求对汇 A、B 或家庭客户端的视频源产生任何变化。
需注意,本规范未定义远程客户端视频源变化自动触发家庭客户端视频源变化的机制。只要不超出应用设定的约束,具体实现可以在源到汇间进行优化,如下例所示。
很明显,对某个源的变更会影响消费该源的汇。但在某些场景下,对某个汇的变更也可能导致实现调整源的设置。下图对此进行了说明。下图中,家庭客户端的视频源发送尺寸为1920x1200像素的视频流。该视频源未受约束,即其实际尺寸对应用而言是灵活的。两个
MediaStream
对象包含同一个
deviceId
,这些MediaStream
分别连接到两个不同的
<
汇A和B。汇A尺寸为video
>width="1920"
和height="1200"
,直接展示源视频内容不做变换。汇B尺寸较小,因此将视频缩放至320x200像素适配其矩形区域。
当应用将汇A尺寸缩小(宽从1920变为1024,高从1200变为768)时,用户代理的媒体管道可能意识到没有任何汇需要更高的源分辨率,源和汇A做了不必要的工作。此时,若没有其他约束强制源继续输出高分辨率视频,媒体管道可以改变源分辨率:
如上图,家庭客户端的视频源分辨率被改为汇A和B所需尺寸中的较大值,以优化播放。虽然图中未展示,peer connection 等其他汇也可能采用同样行为。
可能会对某个轨道应用约束,而源无法满足这些约束,无论是因为源本身无法满足,还是已经满足了与之冲突的约束。当这种情况发生时,
applyConstraints
()
返回的 promise 会被拒绝,不会应用任何新约束。因为约束未发生变化,源本身也无需做任何变更。下面是该行为的示例。
本例中,两个媒体流各有一个共享同一源的视频轨道。第一个轨道初始未应用约束,连接到汇N。汇N分辨率为800x600像素,将源分辨率1024x768缩放适配。另一个轨道有一个必需约束,强制关闭源的补光灯,连接到汇P。汇P宽高与源一致。
此时,第一个轨道添加了一个 必需约束,要求补光灯必须开启。此时,两个必需约束无法同时满足(补光灯无法同时开和关)。由于该状态是第一个轨道试图应用冲突约束造成的,约束应用失败,源设置和两个轨道的约束都不会发生变化。
MediaStream
可以分配给媒体元素。MediaStream
不支持预加载和寻址,表示一个简单的、可能是无限的线性
媒体时间轴。时间轴从0开始,只要媒体元素处于
可能播放状态,时间轴就会按实际时间线性递增。当MediaStream
暂停播放时,时间轴不会递增。
支持本规范的用户代理 必须支持 srcObject
属性(定义在HTMLMediaElement
接口中,参见
[HTML]),
其中包括对MediaStream
对象的播放支持。
[HTML]文档概述了HTMLMediaElement
如何与媒体提供者对象协作。当媒体提供者对象为MediaStream
时,适用以下内容:
每当创建AudioTrack
或VideoTrack
时,
id
和label
属性必须初始化为相应MediaStreamTrack
的属性,
kind
属性初始化为"main"
,language
属性为空字符串。
MediaStream
的当前数据,不得缓冲。
由于MediaStream
的轨道集合顺序未定义,因此不要求AudioTrackList
和VideoTrackList
的顺序。
如果元素是HTMLVideoElement
,
则当其视频播放结束时,称为播放结束,具体如下:
元素的
readyState
至少为HAVE_METADATA
,并且
MediaStream
状态从active变为inactive,或
MediaStream
状态在最后一次调用play
()
后,
从active变为inactive,
又回到active,且
autoplay
为false
。
播放结束后,如果有新的MediaStreamTrack
加入MediaStream
,
除非autoplay
为true
或元素被重新启动(例如Web应用调用play
()
),
否则不会恢复播放。
如果元素是HTMLAudioElement
,
则当其音频播放结束时,称为播放结束,具体如下:
元素的
readyState
至少为HAVE_METADATA
,
并且
MediaStream
状态从audible变为inaudible,或
MediaStream
状态在最后一次调用play
()
后,
从audible变为inaudible,
又回到audible,且
autoplay
为false
。
播放结束后,若有新的音频MediaStreamTrack
加入MediaStream
,
除非autoplay
为true
或元素被重启(如Web应用调用play
()
),
否则不会恢复播放。
对HTMLMediaElement
调用fastSeek
()
方法应被忽略。
MediaStream
的特性对相关HTMLMediaElement
的属性行为和可执行操作有限制,具体如下:
属性名 | 属性类型 | 当提供者为MediaStream时的设置/获取行为 | 补充说明 |
---|---|---|---|
preload
|
DOMString |
获取时:none 。设置时:忽略。 |
MediaStream 无法预加载。 |
buffered
|
TimeRanges
|
buffered.length 必须返回0 。 |
MediaStream 无法预加载,因此缓冲区始终为空时间范围。 |
currentTime
|
double |
任何非负整数。初始值为0 ,只要元素处于可能播放状态,值线性递增。
|
该值为 官方播放位置,单位为秒。尝试更改该值必须被忽略。 |
seeking
|
boolean |
false |
MediaStream 不可寻址,因此该属性必须始终返回false 。 |
defaultPlaybackRate
|
double |
获取时:1.0 。设置时:忽略。 |
MediaStream 不可寻址,因此该属性必须始终返回1.0 ,尝试更改必须被忽略。注意这也意味着ratechange 事件不会触发。
|
playbackRate
|
double |
获取时:1.0 。设置时:忽略。 |
MediaStream 不可寻址,因此该属性必须始终返回1.0 ,尝试更改必须被忽略。注意这也意味着ratechange 事件不会触发。
|
played
|
TimeRanges
|
played.length 必须返回1 。played.start(0) 必须返回0 。played.end(0) 必须返回最新的currentTime 。
|
MediaStream 的时间轴始终只有一个区间,从0到当前currentTime。
|
seekable
|
TimeRanges
|
seekable.length 必须返回0 。 |
MediaStream 不可寻址。 |
loop
|
boolean |
true , false |
设置loop
属性无效,因为MediaStream 没有定义结束,因此无法循环。
|
由于上述所有setter均不改变HTMLMediaElement
内部状态,
一旦MediaStream
不再是元素的已分配媒体提供者对象,
列出的属性会恢复到分配流之前的值。
MediaStream
在已分配媒体提供者对象中不再被分配,
当srcObject
被赋值为null
或非流对象,
发生在媒体元素加载算法之前。
因此,如果playbackRate
和defaultPlaybackRate
与分配流之前不同,
ratechange
事件可能会被触发(第7步)。
某些操作会抛出或触发 OverconstrainedError
。这是 DOMException
的扩展,包含与约束失败相关的附加信息。
WebIDL[Exposed=Window]
interface OverconstrainedError
: DOMException {
constructor
(DOMString constraint, optional DOMString message = "");
readonly attribute DOMString constraint
;
};
OverconstrainedError
运行以下步骤:
令 constraint 为构造函数的第一个参数。
令 message 为构造函数的第二个参数。
令 e 为一个新的
OverconstrainedError
对象。
调用 DOMException
的构造函数,
传入 message
参数为 message,name
参数为
"OverconstrainedError"
。
该名称没有映射到旧代码,因此 e 的 code
属性将返回 0。
设置 e.constraint 为 constraint。
返回 e。
constraint
类型为 DOMString
,
只读与此错误相关的约束名,如果没有特定约束名则为 ""
。
本节为非规范性内容。
以下事件会在 MediaStream
对象上触发:
事件名 | 接口 | 触发时机... |
---|---|---|
addtrack | MediaStreamTrackEvent |
有新的 MediaStreamTrack
被添加到该流。注意,当脚本直接修改 MediaStream
的轨道时不会触发此事件。 |
removetrack | MediaStreamTrackEvent |
有 MediaStreamTrack
被从该流移除。注意,当脚本直接修改 MediaStream
的轨道时不会触发此事件。 |
以下事件会在 MediaStreamTrack
对象上触发:
事件名 | 接口 | 触发时机... |
---|---|---|
mute | Event |
MediaStreamTrack
的源暂时无法提供数据时。 |
unmute | Event |
MediaStreamTrack
的源在暂时无法提供数据后重新变为活动状态时。 |
ended | Event |
|
以下事件会在 MediaDevices
对象上触发:
事件名 | 接口 | 触发时机... |
---|---|---|
devicechange | DeviceChangeEvent
|
可用给 用户代理 的媒体设备集合发生改变。当前设备列表可通过
devices 属性获取。
|
本节描述了脚本可用于查询用户代理连接的媒体输入和输出设备(例如网络摄像头或耳机)的API。
MediaDevices
MediaDevices
对象是用于检查和访问用户代理可用媒体设备的API入口。
要 创建 MediaDevices 对象,给定 realm,执行以下步骤:
令 mediaDevices 为 MediaDevices
对象(在 realm
中),初始化以下内部槽:
令 settings 为 mediaDevices 的 相关设置对象。
对于 MediaDevices
.getUserMedia
()
暴露的每种设备类型 kind,执行:
设 mediaDevices.[[kindsAccessibleMap]]
[kind]
为 true
,
如果与 kind 关联的权限(如 "camera"
、
"microphone"
)的
permission state
为 "granted
",
否则为 false
。
对于 MediaDevices
.getUserMedia
()
暴露的每个具体设备,使用设备的 deviceId deviceId,执行:
设 mediaDevices.[[devicesLiveMap]]
[deviceId]
为 false
,
且设 mediaDevices.[[devicesAccessibleMap]]
[deviceId]
为 true
,
如果与该设备类型及 deviceId 关联的权限(针对 settings)的 permission state
为 "granted
",
否则为 false
。
返回 mediaDevices。
对于 getUserMedia
()
暴露的每种设备类型
kind,
每当与 kind 相关的权限的 权限状态发生变化时,
针对 mediaDevices 的 相关设置对象,
执行以下步骤:
如果状态从其他值变为 "granted
",
则将
mediaDevices.[[kindsAccessibleMap]]
[kind]
设为 true
。
如果状态从 "granted
"
变为其他值,
则将
mediaDevices.[[kindsAccessibleMap]]
[kind]
设为 false
。
对于 getUserMedia
()
暴露的每个具体设备,
每当与该设备类型和 deviceId 相关的权限的 权限状态发生变化时,
针对 mediaDevices 的 相关设置对象,
执行以下步骤:
如果状态从其他值变为 "granted
",
则将
mediaDevices.[[devicesAccessibleMap]]
[deviceId]
设为 true
(如果尚未为 true
)。
如果状态从 "granted
"
变为其他值,
且设备当前已 停止,
则将
mediaDevices.[[devicesAccessibleMap]]
[deviceId]
设为 false
。
当有新的媒体输入/输出设备可用,或已有设备变得不可用,或某种媒体设备类型的系统默认设备发生变化时,
用户代理 必须为每个 MediaDevices
对象 mediaDevices(满足 device enumeration can proceed
条件为 true
,其他 MediaDevices
对象不处理)执行以下
设备变更通知步骤:
令 lastExposedDevices 为
创建设备信息对象列表(参数为
mediaDevices 和
mediaDevices.[[storedDeviceList]]
)。
令 deviceList 为用户代理可用的所有媒体输入/输出设备的列表。
令 newExposedDevices 为 创建设备信息对象列表(参数为 mediaDevices 和 deviceList)。
如果 newExposedDevices 的 MediaDeviceInfo
对象与 lastExposedDevices 相同且顺序一致,则终止这些步骤。
由于 enumerateDevices
算法,上述步骤只会对允许使用 enumerateDevices
枚举特定 MediaDeviceKind
的文档触发
devicechange 事件。
设 mediaDevices.[[storedDeviceList]]
为
deviceList。
加入一个任务,触发事件,事件名为 devicechange
,
使用 DeviceChangeEvent
构造器,devices
初始化为
newExposedDevices,
在 mediaDevices 处触发。
用户代理 可以合并多个事件为一个事件(例如同时添加/移除多个设备,如带麦克风的摄像头)。
此外,如果曾遍历的某 MediaDevices
对象
后续满足 device enumeration can proceed 条件(如
进入可视区域),
用户代理 必须
在该 MediaDevices
对象上执行
设备变更通知步骤。
这些事件可能会在不同来源的文档上同时触发。用户代理
可以通过对事件时间点进行扰动,避免跨域活动相关性。
WebIDL[Exposed=Window, SecureContext]
interface MediaDevices
: EventTarget {
attribute EventHandler ondevicechange
;
Promise<sequence<MediaDeviceInfo
>> enumerateDevices
();
};
ondevicechange
类型为 EventHandler
该事件处理器的事件类型为 devicechange。
enumerateDevices
收集 用户代理 可用的媒体输入和输出设备信息。
该方法返回一个 promise。promise 将在
成功时携带一个
MediaDeviceInfo
对象序列,
表示 用户代理 可用的媒体输入和输出设备(枚举成功时)。
该序列中表示输入设备的元素将为 InputDeviceInfo
类型,继承自
MediaDeviceInfo
。
摄像头和麦克风源 应当 可枚举。增加其他源类型的规范会给出该源类型是否可枚举的建议。
当调用 enumerateDevices
()
方法时,用户代理必须执行以下步骤:
令 p 为一个新 promise。
令 mediaDevices 为 this。
并行执行以下步骤:
当 proceed 为 false
时,
用户代理
必须等待,直到队列任务将 proceed 设置为
设备枚举可进行 的结果(参数为
mediaDevices),使 proceed 变为 true
。
令 resultList 为
创建设备信息对象列表
的结果,参数为 mediaDevices 和
mediaDevices.[[storedDeviceList]]
。
resolve p,值为 resultList。
返回 p。
要执行 创建设备信息对象列表,给定 mediaDevices 和 deviceList, 执行以下步骤:
令 resultList 为一个空列表。
令 microphoneList、cameraList 和 otherDeviceList 为空列表。
令 document 为 mediaDevices 的
相关全局对象
的 关联
Document
。
对 deviceList 中每个已发现的设备 device,执行如下子步骤:
如果 device 不是麦克风,或 document 不允许使用 "microphone"
功能,
跳过本设备,继续下一个设备(如有)。
令 deviceInfo 为 创建设备信息对象 的结果(表示 device,参数为 mediaDevices)。
如果 device 是系统默认麦克风, 则将 deviceInfo 前置到 microphoneList。 否则,将 deviceInfo 添加到 microphoneList。
对 deviceList 中每个已发现的设备 device,执行如下子步骤:
如果 麦克风信息可暴露 在
mediaDevices 上为 false
,
则将 microphoneList 截断为仅保留第一个。
如果 摄像头信息可暴露 在
mediaDevices 上为
false
,
则将 cameraList 截断为仅保留第一个。
对 deviceList 中每个已发现的设备 device,执行如下子步骤:
如果 device 是麦克风或摄像头,跳过本设备,继续下一个设备(如有)。
执行 除摄像头和麦克风外的设备暴露决策算法,
参数为 device、microphoneList、cameraList 和
mediaDevices。
若结果为 false
,跳过本设备,继续下一个设备(如有)。
令 deviceInfo 为 创建设备信息对象 的结果(表示 device,参数为 mediaDevices)。
如果 device 是系统默认音频输出, 则将 deviceInfo 前置到 otherDeviceList。 否则,将 deviceInfo 添加到 otherDeviceList。
按顺序将 microphoneList 中的所有设备追加到 resultList。
按顺序将 cameraList 中的所有设备追加到 resultList。
按顺序将 otherDeviceList 中的所有设备追加到 resultList。
返回 resultList。
由于该方法会跨会话和来源返回可用媒体采集设备的持久信息,
它增加了 用户代理 暴露的指纹信息面。
只要 相关全局对象
的
关联
Document
未进行采集,则该方法只会暴露两位信息:是否有摄像头和是否有麦克风。
用户代理 可通过假装系统有摄像头和麦克风来进行缓解,
直到 相关全局对象
的 关联
Document
调用
getUserMedia
()
并传入合理约束。
当 相关全局对象
的 关联
Document
开始采集后,会通过所有媒体采集设备列表(包括分组和设备标签)向跨域共享更多持久信息,进一步增加指纹信息面。
用户代理 可通过清理设备标签来限制暴露。例如移除标签中的用户名,但保留设备制造商或型号信息。
重要的是,清理后的标签仍要让用户能识别对应设备。
上述算法意味着,访问媒体设备信息取决于相关全局对象的
关联
Document
是否进行了采集。
对于摄像头和麦克风设备,如果相关全局对象的
关联
Document
未进行采集
(即getUserMedia
()
未被调用或未成功解析),
MediaDeviceInfo
对象将包含
kind
的有效值,但
deviceId
、
label
和
groupId
都为空字符串。
另外,kind
每种类型最多只会在
enumerateDevices
()
结果中列出一个设备。
否则,
MediaDeviceInfo
对象将包含有意义的
deviceId
、
kind
、
label
和
groupId
值。所有可用设备都会在
enumerateDevices
()
结果中列出。
要执行 创建设备信息对象(用于表示已发现的设备 device,给定 mediaDevices),请执行以下步骤:
令 deviceInfo 为一个新的 MediaDeviceInfo
对象,用于表示
device。
初始化 deviceInfo.kind
为
device的类型。
如果 deviceInfo.kind
等于"videoinput",且 摄像头信息可暴露在
mediaDevices上为 false
,则返回 deviceInfo。
如果 deviceInfo.kind
等于"audioinput",且 麦克风信息可暴露
在 mediaDevices上为false
,则返回 deviceInfo。
初始化 deviceInfo.label
为 device的标签。
如果已存在用于 device 的 deviceId
,则初始化
deviceInfo.deviceId
为该值;
否则令 deviceInfo.deviceId
为
按deviceId
描述新生成的唯一标识符。
如果 device 属于与 document 已表示的设备相同的物理设备,
则初始化 deviceInfo.groupId
为现有
groupId
值;
否则令 deviceInfo.groupId
为
按groupId
描述新生成的唯一标识符。
返回 deviceInfo
要进行 设备枚举可进行 检查, 给定 mediaDevices, 执行以下步骤:
返回 is in view 的结果,参数为 mediaDevices。
要进行 设备信息可暴露 检查,给定 mediaDevices,执行以下步骤:
要进行 摄像头信息可暴露 检查,给定 mediaDevices,执行以下步骤:
如果任何本地 "videoinput" 类型设备已绑定到 mediaDevices 的 相关全局对象
的
关联
Document
下的活动 MediaStreamTrack
上,返回
true
。
返回 mediaDevices.[[canExposeCameraInfo]]
。
要进行 麦克风信息可暴露 检查,给定 mediaDevices,执行以下步骤:
如果任何本地 "audioinput" 类型设备已绑定到 mediaDevices 的 相关全局对象
的
关联
Document
下的活动 MediaStreamTrack
上,返回
true
。
返回 mediaDevices.[[canExposeMicrophoneInfo]]
。
要进行 is in view 检查, 给定 mediaDevices,执行以下步骤:
如果 mediaDevices 的 相关全局对象
的
关联
Document
是完全激活
且其可见性状态
为 "visible"
,则返回 true
;否则返回 false
。
要进行 有系统焦点 检查,给定 mediaDevices,执行以下步骤:
要进行 设备暴露可扩展 检查,给定 deviceType,执行以下步骤:
要在 mediaDevices 上设置设备信息暴露,给定 requestedTypes 集合 和一个布尔值 value,执行以下步骤:
如果 "video"
在 requestedTypes
中,则执行以下子步骤:
将 mediaDevices.[[canExposeCameraInfo]]
设为 value。
如果 value 为 true
且 设备暴露可扩展(类型为
"microphone"),
则将 mediaDevices.[[canExposeMicrophoneInfo]]
设为 true
。
如果 "audio"
在 requestedTypes
中,则执行以下子步骤:
将 mediaDevices.[[canExposeMicrophoneInfo]]
设为 value。
如果 value 为 true
且 设备暴露可扩展(类型为 "camera"),
则将 mediaDevices.[[canExposeCameraInfo]]
设为 true
。
除摄像头和麦克风外设备的暴露决策算法 以 device、microphoneList、cameraList 和 mediaDevices 作为输入,并返回一个布尔值,以决定是否向网页暴露 device 的信息。
默认返回 false
。
其他规范可以为特定设备类型定义该算法。
要对 globalObject 执行 上下文正在采集 检查, 请执行以下步骤:
如果 globalObject 不是 Window
,
则返回 false。
令 mediaDevices 为 globalObject 的 关联 MediaDevices
。
对 mediaDevices.[[mediaStreamTrackSources]]
中的每个 source,执行以下子步骤:
令 deviceId 为 source 设备的 deviceId。
如果 mediaDevices.[[devicesLiveMap]]
[deviceId]
为 true
,则返回 true
。
返回 false
。
该算法覆盖所有采集轨道,包括麦克风、摄像头和屏幕。
WebIDL[Exposed=Window, SecureContext]
interface MediaDeviceInfo
{
readonly attribute DOMString deviceId
;
readonly attribute MediaDeviceKind
kind
;
readonly attribute DOMString label
;
readonly attribute DOMString groupId
;
[Default] object toJSON
();
};
deviceId
类型为 DOMString
,只读所表示设备的标识符。设备 必须通过其标识符和 kind
唯一标识。
为确保存储的标识符可被识别,标识符 必须在 Document
的
同源
顶级可遍历对象中保持一致。
在 子可导航对象中,
标识符是否跨文档一致,必须遵循 用户代理的存储分区规则
(如 localStorage
),
以避免影响跨站相关性防护措施。如果标识符可以唯一识别用户,则必须在其他来源的文档中不可猜测,以防止跨来源相关性。只要标识符与用户无关且可通过其他方式(如 User-Agent
字符串)猜测,则可在不同来源间复用。
如果任何本地设备已绑定到本来源页面的活动
MediaStreamTrack
,
或本来源已获得访问本地设备的 存储权限,
则该标识符必须被持久保存,除非下述特殊情况。唯一且稳定的标识符允许应用跨多次访问保存、识别设备可用性并直接请求特定源。
但只要没有本地设备被绑定到本来源页面的活动 MediaStreamTrack,且本来源没有获得本地设备的 存储权限,则用户代理 可以 在本来源最后一个浏览会话关闭后清除该标识符。如果用户代理选择不清除, 则必须允许用户可见地检查并删除该标识符,如同 cookie。
由于 deviceId
可能跨会话持久化,
且为减少其作为指纹机制的潜力,deviceId
应当如 cookie
[COOKIES] 一样对待,
即用户代理 不得为被禁止使用 cookie
的站点持久化设备标识符,
且用户代理 必须在清除其他持久化存储时,旋转每个来源的设备标识符。
kind
类型为
MediaDeviceKind
,只读
所表示设备的类型。
label
类型为 DOMString
,只读描述该设备的标签(例如“外部USB摄像头”)。该标签用于让终端用户区分设备。应用不能假定标签包含任何特定信息,比如设备类型或型号。 如果设备没有标签,则此属性必须返回空字符串。
groupId
类型为 DOMString
,只读所表示设备的分组标识符。如果两个设备属于同一物理设备,则具有相同的分组标识。例如,代表同一耳机的扬声器和麦克风的音频输入输出设备 groupId 相同。
分组标识符必须为每个document唯一生成。
toJSON
WebIDLenum MediaDeviceKind
{
"audioinput
",
"audiooutput
",
"videoinput
"
};
MediaDeviceKind 枚举描述 |
|
---|---|
audioinput |
表示音频输入设备,例如麦克风。 |
audiooutput |
表示音频输出设备,例如耳机。 |
videoinput |
表示视频输入设备,例如摄像头。 |
InputDeviceInfo
接口用于访问其所代表输入设备的能力。
WebIDL[Exposed=Window, SecureContext]
interface InputDeviceInfo
: MediaDeviceInfo
{
MediaTrackCapabilities
getCapabilities
();
};
getCapabilities
返回一个 MediaTrackCapabilities
对象,
描述该设备主音频或视频轨道的能力(根据其 kind
值),在没有用户提供约束的情况下。
这些能力必须与调用
getCapabilities
()
于 MediaStream
返回的第一个同类 MediaStreamTrack
的结果一致,
其中 getUserMedia({deviceId: id})
,id为本对象的
deviceId
属性值。
如果尚未获得任何本地设备的访问权限,并且本 InputDeviceInfo
已针对唯一识别信息进行过滤(详见
enumerateDevices
()
结果说明),则该方法返回一个空字典。
devicechange
事件使用 DeviceChangeEvent
接口。
WebIDL[Exposed=Window]
interface DeviceChangeEvent
: Event {
constructor
(DOMString type, optional DeviceChangeEventInit
eventInitDict = {});
[SameObject] readonly attribute FrozenArray<MediaDeviceInfo
> devices
;
[SameObject] readonly attribute FrozenArray<MediaDeviceInfo
> userInsertedDevices
;
};
devices
类型为 FrozenArray<MediaDeviceInfo
>,
只读
devices
属性返回当前可用设备列表的
MediaDeviceInfo
对象数组。
userInsertedDevices
类型为 FrozenArray<MediaDeviceInfo
>,
只读
userInsertedDevices
属性返回仅包含用户最近新插入或激活并随本事件首次暴露的 MediaDeviceInfo
对象的数组。
否则返回空列表。
用户代理 可以包含在调用 getUserMedia
()
前用户插入或激活的设备,只要本事件首次暴露它们且用户未在 getUserMedia
()
中选取设备。
这些 MediaDeviceInfo
对象(如有)必须也存在于 devices
中。
用户在通话过程中(或通话前后立即)插入设备是希望立即使用该设备的强烈信号。
鼓励应用根据该属性来区分此信号与设备信息暴露变化带来的设备差异。
WebIDLdictionary DeviceChangeEventInit
: EventInit {
sequence<MediaDeviceInfo
> devices
= [];
};
devices
类型为 sequence<MediaDeviceInfo
>,
默认值为 []
devices
成员是一个 MediaDeviceInfo
对象数组,表示可用设备。
本节扩展了 Navigator
以及
MediaDevices
,提供用于请求访问用户代理可用媒体输入设备权限的 API。
另外,可以通过某些类型的 DOM 元素(如 video 元素)捕获本地 MediaStream
。
这对于自动化测试非常有用。
[mediacapture-fromelement]
MediaDevices
接口扩展getUserMedia
()
的定义相较于过去在
Navigator
下的方法有两个主要变化。
首先,getUserMedia
()
方法的官方定义(也是推荐开发者使用的)现在在本节 MediaDevices
下。
之所以这样决定,是因为原 API 仍然可用于 Navigator.getUserMedia
(为兼容旧代码),工作组也承认早期用户曾被鼓励写成 "var getUserMedia =
navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;" 以兼容不同浏览器版本。因此,为了功能等价,Navigator
下的 getUserMedia()
方法以本节定义为准。
第二,这里定义的方法基于 Promise,而 Navigator
下的方法仍基于回调。希望在 Navigator 下查找 getUserMedia() 的开发者请阅读那里的详细说明。
getSupportedConstraints
方法用于让应用判断 用户代理
支持哪些约束属性。应用可能需要这些信息以可靠地使用
必需约束或在
高级约束中获得可预期结果。
WebIDLpartial interface MediaDevices
{
MediaTrackSupportedConstraints
getSupportedConstraints
();
Promise<MediaStream
> getUserMedia
(optional MediaStreamConstraints
constraints = {});
};
getSupportedConstraints
返回一个字典,其成员是用户代理已知的可约束属性。受支持的属性必须被列出,用户代理不得在返回的字典中出现不支持的属性。返回值表示用户代理实际实现的内容,并且在一次浏览会话期间不会变化。
弹窗请求用户允许使用其摄像头或其他视频、音频输入。
constraints 参数是 MediaStreamConstraints
类型的字典。
该方法返回一个 promise。promise 在
成功时会返回合适的 MediaStream
对象,如果用户接受有效轨道(如下描述)。
如果找不到有效轨道或用户拒绝授权,promise会 拒绝,具体情况如下。
当调用 getUserMedia()
方法时,用户代理 必须执行以下步骤:
令 constraints 为方法的第一个参数。
令 requestedMediaTypes 为 constraints 中值为字典或
true
的媒体类型集合。
如果 requestedMediaTypes 为空,则返回一个 拒绝的 promise,异常类型为 TypeError
。
WebIDL 虽然参数是 optional,但调用必须传参才能成功。
令 document 为 相关全局对象的
关联
Document
。
如果 document 不是
完全激活,则返回一个
拒绝的
promise,异常类型为 DOMException
,
name
属性为 "InvalidStateError
"。
如果 requestedMediaTypes 包含 "audio",且 document 不允许使用 "microphone" 权限名的功能, 跳到 权限失败 步骤。
如果 requestedMediaTypes 包含 "video",且 document 不允许使用 "camera" 权限名的功能, 跳到 权限失败 步骤。
令 mediaDevices 为 this。
令 isInView 为 is in view 算法的结果。
令 p 为一个新的 promise。
并行执行以下步骤:
当 isInView 为 false
时,
用户代理
必须等待,直到队列任务将 isInView 设为 is in view
算法结果为 true
。
令 finalSet 为一个(初始为空的)集合。
对 requestedMediaTypes 中的每种媒体类型 kind,执行:
对每种 kind 类型的每个可能源设备的每种可能配置,构造一个 候选项,作为最终 MediaStreamTrack
的占位符,包含源设备及其设置字典。
称该候选集合为 candidateSet。
如果 candidateSet 为空,跳到 未找到失败 步骤。
true
,则
CS 为空约束集;否则用 constraints 的 kind 项值。
MediaStreamTrack
定义的约束属性。即在 "video"
内的音频约束和 "audio"
内的视频约束会被忽略,而不会导致 OverconstrainedError。如果 CS 中有某个 必需约束,其名字不在 设备选择允许的必需约束列表里,
则 拒绝
p,异常类型为 TypeError
,终止这些步骤。
对 candidateSet 中每个候选项,使用 SelectSettings 算法及
CS。若结果为 undefined
,移除该候选项。这样可排除不满足约束的设备。
如果 candidateSet 为空,令 failedConstraint
为所有设置字典中 fitness distance 为无穷大的任何 必需约束,如没有则为
""
,跳到 约束失败 步骤。
此错误可透露底层设备无法提供哪些能力,用户尚未授权就能用于指纹识别。
读取所有 candidateSet 中未绑定到当前 Document
活动 MediaStreamTrack
的设备的权限状态。移除权限状态为 "denied
"
的候选项。
如果 candidateSet 为空,说明该类型设备都处于 "denied
"
状态,跳到 权限失败 步骤。
可选地(如基于用户偏好、安全原因或平台限制),跳到 权限失败 步骤。
将 candidateSet 中所有候选项加入 finalSet。
令 stream 为一个新的空 MediaStream
对象。
对 requestedMediaTypes 中每种媒体类型 kind,并行执行以下子步骤:
用户代理鼓励将不同类型媒体的并发请求合并为一个用户权限弹窗。
请求权限使用
PermissionDescriptor
,
name
设置为 kind 关联的权限名(如 "camera"
对应 "video"
,
"microphone"
对应
"audio"
),
同时考虑所有绑定到当前 Document
活动并具有 同权限的 MediaStreamTrack
,
权限状态为 "granted
",最终获得一组媒体。
同权限指获取权限时要求和当前请求相同级别(如非隔离)的 MediaStreamTrack
。
请求用户权限时,用户代理 必须披露权限是仅授予所选设备还是同类所有设备。
如果用户未响应,算法会在此步骤停滞。
如果请求结果为 "denied
",跳到
权限失败 步骤。
令 hasSystemFocus 为 false
。
当 hasSystemFocus 为 false
时,
用户代理
必须等待,直到队列任务根据 has system
focus
算法将 hasSystemFocus 设为 true
。
设置设备信息暴露,参数为
mediaDevices、requestedMediaTypes
和true
。
对 requestedMediaTypes 中每种媒体类型 kind,执行:
令 finalCandidate 为所提供媒体,该媒体 必须是 finalSet 中精确的一个 kind 类型候选项。具体选择由 用户代理决定,可询问用户。
用户代理 应当根据 SelectSettings 算法计算的 fitness distance 作为选择依据,也可用其他内部信息(如用户偏好)。
请求结果为 "granted
"。
如果硬件错误(如系统/程序/网页锁定)导致无法访问,则移除 finalSet 中对应候选项。
若 finalSet 中无该类型候选项,则 拒绝
p,异常类型为
DOMException
,
name
属性值为
"NotReadableError
",终止这些步骤。否则,更新
finalSet 后重试。
若设备访问因其他原因失败,则移除对应候选项。若 finalSet 无该类型候选项,则 拒绝
p,异常类型为 DOMException
,
name
属性值为 "AbortError
",终止这些步骤。否则,更新
finalSet 后重试。
令 grantedDevice 为 finalCandidate 的源设备。
用 grantedDevice 的 deviceId deviceId,
将 mediaDevices.[[devicesLiveMap]]
[deviceId]
设为 true
(如尚未为 true),
且 mediaDevices.[[devicesAccessibleMap]]
[deviceId]
也设为 true
(如尚未为 true)。
令 track 为 创建
MediaStreamTrack 的结果,参数为 grantedDevice 和
mediaDevices。
MediaStreamTrack
的源 不得改变。
将 track 加入 stream 的轨道集合。
对 stream 中所有轨道,运行 ApplyConstraints
算法,并传入适当约束。若返回非 undefined
,令
failedConstraint 为该结果,跳到 约束失败 步骤。
对 stream 中每个 track,
将轨道源与
MediaDevices
绑定,参数为 track.[[Source]]
和
mediaDevices。
resolve p,值为 stream,终止这些步骤。
未找到失败:
如果 允许
getUserMedia 特定失败,
参数为 requestedMediaTypes,结果为 false
,跳到
权限失败 步骤。
拒绝
p,异常类型为
DOMException
,
name
属性值为 "NotFoundError
"。
约束失败:
如果 允许
getUserMedia 特定失败,
参数为 requestedMediaTypes,结果为 false
,跳到
权限失败 步骤。
令 message 为 undefined
或信息性人类可读消息,
constraint 为 failedConstraint(若 设备信息可暴露为
true
),否则为 ""
。
拒绝
p,异常类型为 OverconstrainedError
,通过 OverconstrainedError(constraint,
message)
构造。
权限失败:拒绝
p,异常类型为 DOMException
,
name
属性值为 "NotAllowedError
"。
返回 p。
要检查 允许 getUserMedia 特定失败, 给定 requestedMediaTypes,执行以下步骤:
在上述算法中,约束会检查两次——设备选择时和批准访问后。两次检查之间可能有时间间隔,选中的设备或许已不适用,这种情况会导致 NotReadableError。
设备选择允许的必需约束 包含以下约束名: width, height, aspectRatio, frameRate, facingMode, resizeMode, sampleRate, sampleSize, echoCancellation, autoGainControl, noiseSuppression, latency, channelCount, deviceId, groupId。
MediaStreamConstraints
字典用于指示
用户代理在
MediaStreamTrack
中应包含哪些类型的轨道,
并通过 MediaStream
返回给
getUserMedia
()
。
WebIDLdictionary MediaStreamConstraints
{
(boolean 或 MediaTrackConstraints
) video
= false;
(boolean 或 MediaTrackConstraints
) audio
= false;
};
MediaStreamConstraints
成员video
类型为
(boolean
或 MediaTrackConstraints
)
,
默认值为 false
如果为 true
,则请求返回的
MediaStream
包含一个视频轨道。
如果提供了 Constraints
结构,则进一步指定视频轨道的类型和设置。如果为 false
,则
MediaStream
不得包含视频轨道。
audio
类型为
(boolean
或 MediaTrackConstraints
)
,
默认值为 false
如果为 true
,则请求返回的
MediaStream
包含一个音频轨道。
如果提供了
Constraints
结构,
则进一步指定音频轨道的类型和设置。如果为
false
,则 MediaStream
不得包含音频轨道。
本节为非规范性内容。
本节中的 getUserMedia() 定义反映了最初提出的调用格式,仅为希望保留向后兼容性的浏览器记录。它与推荐接口有两个重要区别。
首先,getUserMedia() 方法的官方定义(也是推荐开发者使用的)现在在 MediaDevices
下。由于原始 API 仍可在 Navigator
对象下使用(为兼容旧代码),工作组承认早期用户常定义 getUserMedia 为 "var getUserMedia =
navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;",以兼容不同浏览器版本。因此,为了功能等价,本节的方法以 MediaDevices 下的方法为准。
第二,规范中所有其他基于回调的方法都改为基于 Promise,因此 navigator.getUserMedia() 也需通过 navigator.mediaDevices.getUserMedia() 实现。由于 navigator.getUserMedia() 现在是规范中唯一剩余的回调方法,关于它是否应继续保留、是否应语法也改为 Promise,仍在讨论中,特别欢迎仍在使用该功能的开发者参与讨论。
其他从回调迁移到 Promise 的方法,因未被广泛实现,无需考虑遗留用法。
实现不需要实现该接口即可视为合规。
WebIDL
getUserMedia
弹窗请求用户允许使用其摄像头或其他视频、音频输入。
constraints 参数是 MediaStreamConstraints
类型的字典。
如果用户接受有效轨道(参见 getUserMedia
()
和
MediaDevices
),
successCallback 会被调用并传入合适的 MediaStream
对象。
如果查找有效轨道失败或用户拒绝授权(参见 getUserMedia
()
和
MediaDevices
),
errorCallback 会被调用。
当调用 getUserMedia
()
方法时,
用户代理 必须运行以下步骤:
令 constraints 为方法的第一个参数。
令 successCallback 为第二个参数指定的回调。
令 errorCallback 为第三个参数指定的回调。
按 getUserMedia() 算法 的步骤运行,参数为 constraints,并令 p 为得到的 promise。
当 p 成功且值为 stream时,执行:
用 stream 调用 successCallback。
当 p 失败且原因为 r时,执行:
用 r 调用 errorCallback。
本节为非规范性内容。
用户代理建议在确定 getUserMedia
()
调用会成功时预留资源。最佳做法是在 promise 解析之前预留资源。后续页面或其他应用再次调用 getUserMedia
()
时,应将已分配的资源及其他应用占用的资源视为“忙碌”。这些被标记为“忙碌”的资源不应提供给当前网页使用,除非用户明确指定。可选地,用户代理可选择仅向同一源页面(即保持该资源忙碌的原始流对应的页面)提供来自忙碌源的流。
本规范建议在授权弹窗或设备选择界面(如果有)时,允许用户选择任何可用硬件作为页面请求的流源(前提是该资源能满足所有 必需约束)。虽然不是强制推荐,但有些 用户代理可能支持用本地文件或其他媒体替换视频或音频源。文件选择器可用于此功能。
本规范还建议将因先前调用 getUserMedia()(无论是本页还是其他仍存活的页面)而忙碌的所有资源展示给用户,并允许用户终止流并将资源用于当前页面。如果操作环境允许,还建议同样展示并处理其他应用当前占用的资源。如果用户选择此选项,必须移除受影响页面流中对应资源的轨道。
请求设备权限时,用户代理可以选择为同一来源存储该权限,避免用户后续再次授权。是否为每个设备单独存储、为同类设备存储,还是为所有设备存储权限,由 用户代理决定,但必须让用户明确知晓,并且存储权限时必须获得该集合全部设备的授权,例如存储所有摄像头的权限时,必须全部摄像头都授权而不仅是其中一个。
如上所述,本规范不强制授权后是否存储权限。若权限未存储,则权限仅在所有由该设备产生的 MediaStreamTrack 停止之前有效。
MediaStream
可以包含多个视频和音频轨道。例如,可将两个或更多摄像头的视频合并到一个流对象中。但当前 API 不允许页面表达需要多个独立视频源的需求。
建议允许同一页面多次调用 getUserMedia(),以便页面请求多个独立的视频和/或音频流。
注意,如果页面多次调用 getUserMedia(),它们请求和分配资源的顺序不受本规范约束。
一次 getUserMedia() 调用总是返回一个最多包含一个音频轨道和一个视频轨道的流。如果脚本在页面稳定前多次调用 getUserMedia(),本规范建议 UI 设计者合并弹窗,让用户一次授权多个摄像头或媒体源。每次调用的约束可用于决定哪些流分配哪些源。
生成 deviceId
的高效做法是:用私钥 +(origin 或 origin+顶级 origin,视用户代理分区规则而定)+ salt + 驱动层设备底层硬件 id 生成加密哈希,并以字母数字串呈现。建议哈希长度不超过
32 位,但也不宜更短,以避免冲突风险。
另一种低熵方案是以存储空间换安全:为每个 origin 或 origin+顶级 origin(按 用户代理分区规则)每遇到一个新设备,随机分配 0~255 号,若号用尽则淘汰最久未使用的设备。
可约束模式允许应用检查和调整实现该模式的对象(可约束对象)的属性。它被拆分为一组独立定义,以便其他规范引用。核心概念是“能力”,即对象的可约束属性及其可能值集合,这些值可以是范围或枚举。例如,摄像头可能支持帧率(属性)在每秒20到50帧之间(范围),也可能可以设置(属性)朝向用户、远离用户或向左/向右(枚举)。应用可通过
getCapabilities()
访问器检查可约束属性的支持能力。
应用可通过基本和/或高级约束集(ConstraintSet)及 applyConstraints()
方法选择对象能力的(范围)值。约束集包含对象的一个或多个属性名,以及每个属性的期望值(或期望值范围)。每对属性/值都可视为一个约束。例如,应用设置一个包含两个约束的约束集,第一个要求摄像头帧率在每秒30到40帧之间(范围),第二个要求摄像头朝向用户(具体值)。这些约束的交互方式取决于它们是在基本约束结构(即带有额外
'advanced' 属性的约束集)中,还是在高级列表中的约束集。行为如下:基本约束结构中的所有 'min'、'max'、'exact' 约束共同视为必需约束,如无法同时满足这些属性名的所有约束,用户代理必须拒绝返回的promise。否则,必须应用必需约束。接下来,将按顺序处理
advanced
列表中的每个约束集(即一起满足所有约束),若无法全部满足,则跳过该约束集。然后,用户代理必须分别尝试应用所有 'ideal'
约束或作为属性的裸值(称为可选基本约束)。对于这些属性,必须最大可能地满足它们,顺序不限。最后,用户代理必须resolve返回的promise。
以下示例有助于理解约束的工作方式。第一个是基本约束结构,给出了三个约束,用户代理会分别尝试满足。根据摄像头可用分辨率,可能无法同时满足三个约束。如果如此,用户代理会尽量满足两个,或只满足一个。如无法同时满足三个约束,可能有多个能满足两个约束的组合,此时由用户代理选择。
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 1280,
height: 720,
aspectRatio: 3/2
}
});
下一个示例略微复杂。width 和 height 仍给出理想值,但同时对它们和 frameRate 设定了最小要求。如果无法满足 frameRate、width 或 height 的最小值,则拒绝promise。否则,会尝试满足 width、height 和 aspectRatio 目标值,然后resolvepromise。
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: {min: 640, ideal: 1280},
height: {min: 480, ideal: 720},
aspectRatio: 3/2,
frameRate: {min: 20}
}
});
} catch (error) {
if (error.name != "OverconstrainedError") {
throw error;
}
// 约束失败。 请尝试其他组合(未弹出授权框)
}
本例展示了通过 'advanced' 属性实现的约束结构的完全控制。此时,用户代理对必需约束的处理方式不变,但在尝试满足理想值前会处理 'advanced' 列表。此例的 'advanced' 列表包含两个约束集,第一个指定 width 和 height,第二个指定 aspectRatio。注意在 advanced 列表里,裸值视为 'exact' 值。本例表示:“我需要视频宽至少640、高至少480。优选精确1920x1280,但如果不行,优选4x3的宽高比,如果还不行,给我最接近1280x720的分辨率。”
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: {min: 640, ideal: 1280},
height: {min: 480, ideal: 720},
frameRate: {min: 30},
advanced: [
{width: 1920, height: 1280},
{aspectRatio: 4/3},
{frameRate: {min: 50}},
{frameRate: {min: 40}}
]
}
});
} catch (error) {
if (error.name != "OverconstrainedError") {
throw error;
}
// 约束失败。 请尝试其他组合(未弹出授权框)
}
高级约束集的顺序很重要。在上例中,无法同时满足1920x1280和4x3约束集。由于1920x1280在列表前,用户代理会先尝试满足它。应用作者可通过为同一属性指定多个高级约束集实现回退策略。应用还指定了两个高级约束集,分别要求帧率大于50和大于40。如果用户代理能设置帧率大于50,则会设置,后续约束集会被自动满足。如果用户代理不能设置大于50,则会跳过该约束集,尝试设置大于40。如果用户代理都无法满足,则基本约束集的 'min' 值要求至少为30。也就是说,用户代理如果拿不到大于30的值就会完全失败,但会优先选大于50的,次选大于40的。
注意,与基本约束不同,高级列表中的约束集必须整体满足或整体跳过。因此,{width: 1920, height: 1280}
是请求该分辨率,而不是单独请求宽或高。可将基本约束视为“或”请求(非互斥),而高级约束集则是“与”请求。应用可通过 getConstraints()
访问器检查当前生效的完整约束集。
用户代理为可约束属性选择的具体值称为“设置”。例如,应用指定帧率必须至少30、最多40,则设置可以是32、35或37。应用可通过 getSettings
()
访问器查询对象可约束属性的当前设置。
虽然本规范正式将
ConstrainablePattern
定义为一个 WebIDL
接口,但实际上它是其他接口的模板或模式,不能直接继承,
因为方法的返回值需要被扩展,而 WebIDL 无法做到这一点。因此,每个希望使用此处定义功能的接口都必须提供其自身的
WebIDL 函数和接口副本。但它可以引用此处定义的语义,这些语义不会改变。示例请参见 MediaStreamTrack 接口定义。
该模式依赖 constrainable object 定义三个内部槽:
一个 [[Capabilities]] 内部槽,初始化为一个
Capabilities
字典,描述所暴露的每个可约束属性的聚合允许值,如
Capabilities 所述,如果没有则为空字典。
一个 [[Constraints]] 内部槽,初始化为一个
为空的 Constraints
字典。
一个 [[Settings]] 内部槽,初始化为一个
Settings
字典,描述所暴露的每个可约束属性当前激活的设置值,如
Settings 所述,如果没有则为空字典。
WebIDL[Exposed=Window]
interface ConstrainablePattern
{
Capabilities
getCapabilities
();
Constraints
getConstraints
();
Settings
getSettings
();
Promise<undefined> applyConstraints
(optional Constraints
constraints = {});
};
getCapabilities()
方法返回对象所支持的可约束属性名称的字典。当被调用时,用户代理
必须返回 [[Capabilities]] 内部槽的值。
底层硬件可能无法完全映射到所定义的可约束属性的范围。当出现这种情况时,条目
应当定义如何将硬件的设置转换并缩放到属性定义的值。例如,假设一个假设的
fluxCapacitance 属性范围是 -10(最小)到 10(最大),但常见硬件设备只支持 "off"、"medium" 和 "full" 三个值。
可约束属性定义可能会指定,对于这种硬件,用户代理
应该将范围值 -10 映射到 "off",10 映射到 "full",0 映射到 "medium"。也可能指明,如果 ConstraintSet 设置为严格值
3,用户代理
应尝试将硬件设置为 "medium",而 getSettings
()
应返回 fluxCapacitance 为 0,因为这是与 "medium" 对应的值。
getConstraints
getConstraints()
方法
返回最近一次成功调用 ApplyConstraints
算法
时的 Constraints 参数,并保持指定顺序。注意,返回的一些高级 ConstraintSets 可能当前未满足。要检查哪些 ConstraintSets 当前有效,
应用应使用 getSettings
。
用户代理 可返回效果完全相同的约束集,而不是精确的约束。当被调用时,
用户代理
必须返回 [[Constraints]] 内部槽的值。
getSettings()
方法
返回对象所有可约束属性的当前设置,无论是平台默认值还是通过
ApplyConstraints 算法
设置。注意,设置是符合约束的目标值,
因此有时可能与测量性能不同。当被调用时,用户代理 必须返回
[[Settings]]
内部槽的值。
当 applyConstraints 模板方法 被调用时, 用户代理 必须执行以下步骤:
令 object 为调用此方法的对象。
令 newConstraints 为此方法的参数。
令 p 为一个新的 promise。
并行运行以下步骤,如果此方法多次调用则保持调用顺序:
令 failedConstraint 为运行 ApplyConstraints 算法, 参数为 newConstraints 的结果。
令 successfulSettings 为上述步骤算法执行后 object 的当前设置。
队列一个任务,运行以下步骤:
如果 failedConstraint 不为
undefined
,令 message 为
undefined
或有信息的人类可读消息,reject
p,并以
OverconstrainedError
新建对象调用
OverconstrainedError(failedConstraint,
message)
,然后终止这些步骤。此时原有约束保留。
将 object 的 [[Constraints]]
内部槽设置为 newConstraints 或一个与
newConstraints 在所有情况下效果相同的
Constraints
字典。
将 object 的 [[Settings]] 内部槽设置为 successfulSettings。
resolve
p,值为 undefined
。
返回 p。
ApplyConstraints 算法 说明如下。以下是算法中用到的预备定义:
我们用术语 settings dictionary 表示可能应用为对象设置值的集合。
对于字符串值约束,下文定义 “==” 为真,当序列中的某一值与被比较的值完全相同。
我们定义 fitness distance, 即一个 settings dictionary 与约束集 CS 之间的距离, 对每个成员(由 constraintName 和 constraintValue 组成)在 CS 中 存在 时,其值如下:
如果 constraintName 不被 用户代理 支持,则距离为 0。
如果约束 必需 (constraintValue 包含一个或多个 'min'、'max' 或 'exact' 成员, 或本身为裸值且裸值视为 'exact'),且 settings dictionary 的 constraintName 成员值不满足约束或不存在,则距离为正无穷。
如果约束不适用于该类型对象,则距离为 0(即此约束不影响距离)。
如果 constraintValue 是布尔型,但可约束属性不是,则距离取决于 settings dictionary 的 constraintName 是否 存在,公式如下:
(constraintValue == exists) ? 0 : 1
如果 settings dictionary 的 constraintName 成员 不存在,距离为 1。
(actual == ideal) ? 0 : |actual - ideal| / max(|actual|, |ideal|)
(actual == ideal) ? 0 : 1
更多定义:
我们定义 SelectSettings 算法如下:
注意,未知属性会被 WebIDL 丢弃,这意味着未知/不支持的必需约束会被悄悄忽略。为避免意外,建议应用作者先使用 getSupportedConstraints
()
方法,如下方示例所示。
ConstrainablePattern
对象。令 copy 为 object 的不受约束副本(即 copy 应如同所有
ConstraintSet 都被移除的 object)。
对 copy 的所有可能的 settings dictionary,计算其 fitness distance,将属性的裸值视为理想值。令 candidates 为所有 fitness distance 有限的 settings dictionary 集合。
如果 candidates 为空,则返回 undefined
作为 SelectSettings 算法的结果。
计算每个 candidates settings dictionary 与该 ConstraintSet 的 fitness distance,将属性的裸值视为精确值。
如果某些 candidates settings dictionary 的距离有限,则保留这些 settings dictionary,丢弃其他的。
如果所有 candidates 的距离均为无穷,则忽略此 ConstraintSet。
从 candidates 中选择一个 settings dictionary,作为 SelectSettings 算法的结果。用户代理 必须 使用距离最小的 settings dictionary(见第 3 步计算)。如果有多个最小距离,用户代理 根据系统默认属性值和 用户代理 默认属性值选择一个。
对于所选设备有系统默认值的属性,如果与上述算法兼容,则 应当 使用系统默认值。通常如 sampleRate 或 sampleSize。其他属性如 echoCancellation 或 resizeMode 通常没有系统默认值。用户代理 为这些属性定义自己的默认值。实现者需注意选择合适的默认值,因为它们常常影响媒体内容的生成。
建议参考已有实现以选择有意义的默认值。注意,默认值可能因系统不同而异,例如桌面与移动设备。撰写本文时,用户代理实现通常采用如下默认值,这些值便于 RTCPeerConnection 作为 sink 使用:
width 设为 640。
height 设为 480。
frameRate 设为 30。
echoCancellation 设为
true
。
要对 object 应用 ApplyConstraints algorithm,给定参数 newConstraints,用户代理 必须 执行以下步骤:
令 successfulSettings 为以 newConstraints 为约束集运行 SelectSettings 算法的结果。
如果 successfulSettings 为 undefined
,令
failedConstraint 为在执行 SelectSettings 算法时所有 settings
dictionary 的距离为无穷的任一 必需约束,若没有则为 ""
,然后返回
failedConstraint 并终止这些步骤。
undefined
。任何与上述算法结果一致的实现都是允许的。例如,实现可以只跟踪约束下设置的最大最小值,而不是所有可能值。
在选择 settings dictionary 时,UA 可以使用任何可用信息。例如,是否作为 getUserMedia 设备选择的一部分进行选择、摄像头的能耗是否因 settings dictionary 不同而变化,或者使用某个 settings dictionary 会导致设备驱动使用重采样等。
用户代理 可以 在任何时候为对象的可约束属性选择新设置。此时 必须 按上述算法尝试满足所有当前约束,令 successfulSettings 为所得新设置,并队列一个任务执行以下步骤:
令 object 为一个或多个可约束属性的新设置已被更改的
对象。
ConstrainablePattern
将 object 的 [[Settings]] 内部槽设置为 successfulSettings。
下面是一个可以传递给
applyConstraints
()
或作为
constraints
返回值的 Constraints 示例。
它使用了为摄像头来源的 可约束属性 定义的约束,
适用于 MediaStreamTrack
。
在此示例中,所有约束均为理想值,意味着结果是基于用户具体摄像头的“尽力而为”:
await track.applyConstraints({
width: 1920,
height: 1080,
frameRate: 30,
});
const {width, height, frameRate} = track.getSettings();
console.log(`${width}x${height}x${frameRate}`); // 1920x1080x30,或者可能是例如
// 1280x720x30,属于尽力而为
为了更细致的控制,应用可以强制要求精确匹配,只要能够处理失败:
try {
await track.applyConstraints({
width: {exact: 1920},
height: {exact: 1080},
frameRate: {min: 25, ideal: 30, max: 30},
});
const {width, height, frameRate} = track.getSettings();
console.log(`${width}x${height}x${frameRate}`); // 1920x1080x25-30!
} catch (error) {
if (error.name != "OverconstrainedError") {
throw error;
}
console.log(`此摄像头无法满足请求的 ${error.constraint}。`);
}
约束也可以传递给 getUserMedia
,不仅仅是初始化方便,还可以影响设备选择。
在这种情况下,
固有约束
也是可用的。
下面是一个示例,展示如何用约束优先选择上次访问时的特定摄像头和麦克风,并对分辨率和立体声有要求; 一旦授权,将应用这些约束,并在请求设备不再可用时(或在某些用户代理中被用户覆盖时)帮助寻找合适的替代设备:
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId: localStorage.camId,
width: {min: 800, ideal: 1024, max: 1280},
height: {min: 600}
},
audio: {
deviceId: localStorage.micId,
channelCount: 2
}
});
// 已授权。 存储设备ID以便下次使用
localStorage.camId = stream.getVideoTracks()[0].getSettings().deviceId;
localStorage.micId = stream.getAudioTracks()[0].getSettings().deviceId;
} catch (error) {
if (error.name != "OverconstrainedError") {
throw error;
}
// 约束不满足。 未找到 合适替代设备
}
上述示例避免使用 {exact: deviceId}
,这样如果首选设备不可用,浏览器可以立即提供其他摄像头选择。
示例也会在每次授权时存储 deviceId
,以便表示新的选择。
相对地,下面是一个用约束实现内容内摄像头选择器的示例。
此时我们使用 exact
,并仅依赖于来自用户选择列表的 deviceId
:
async function switchCameraTrack(freshlyChosenDeviceId, oldTrack) {
if (isMobile) {
oldTrack.stop(); // 某些平台一次只能打开一个摄像头。
}
const stream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId: {exact: freshlyChosenDeviceId}
}
});
const [track] = stream.getVideoTracks();
localStorage.camId = track.getSettings().deviceId;
return track;
}
下面是一个申请手机后置摄像头的示例,理想情况下为720p,但也接受接近这个分辨率的值。 注意对分辨率约束是以横屏模式指定的:
async function getBackCamera() {
return await navigator.mediaDevices.getUserMedia({
video: {
facingMode: {exact: 'environment'},
width: 1280,
height: 720
}
});
}
下面是一个“我想要接近720p的原生16:9分辨率,但即使没有原生支持,也要求精确帧率为10”的示例。 这需要分两步进行:先获取原生模式,再应用自定义帧率。 这也演示了如何从当前设置推导约束,注意可能发生旋转:
async function nativeResolutionButDecimatedFrameRate() {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
resizeMode: 'none', // 表示原生分辨率和帧率
width: 1280,
height: 720,
aspectRatio: 16 / 9 // 宽高比可能不是完全精确
}
});
const [track] = stream.getVideoTracks();
const {width, height, aspectRatio} = track.getSettings();
// 约束为横屏,设置可能被旋转(竖屏)
if (width < height) {
[width, height] = [height, width];
aspectRatio = 1 / aspectRatio;
}
await track.applyConstraints({
resizeMode: 'crop-and-scale',
width: {exact: width},
height: {exact: height},
frameRate: {exact: 10},
aspectRatio,
});
return stream;
}
下面是一个展示如何使用
getSupportedConstraints
的示例,
用于应用无法容忍约束因用户代理不支持而被忽略的情形:
async function getFrontCameraRes() {
const supports = navigator.mediaDevices.getSupportedConstraints();
for (const constraint of ["facingMode", "aspectRatio", "resizeMode"]) {
if (!(constraint in supports) {
throw new OverconstrainedError(constraint, "Not supported");
}
}
return await navigator.mediaDevices.getUserMedia({
video: {
facingMode: {exact: 'user'},
advanced: [
{aspectRatio: 16/9, height: 1080, resizeMode: "none"},
{aspectRatio: 4/3, width: 1280, resizeMode: "none"}
]
}
});
}
有效输入集的规范语法取决于值的类型。除了标准原子类型(boolean、long、double、DOMString)以外,有效值还包括任意原子类型的列表,以及如下定义的最小-最大范围。
列表值必须被解释为“或”关系。例如,如果相机属性 'facingMode' 被定义为有效值 ["left", "right", "user",
"environment"],这意味着 'facingMode' 可以取 "left"、"right"、"environment" 和 "user"。类似地,Constraints
将 'facingMode' 限制为 ["user", "left",
"right"],则表示 用户代理 应选择一个摄像头(如果可能的话让摄像头指向),使 "facingMode" 为 "user"、"left" 或
"right"。此约束请求摄像头不要背向用户,但允许 用户代理 让用户选择其他方向。
WebIDLdictionary ConstrainDoubleRange
: DoubleRange
{
double exact
;
double ideal
;
};
WebIDLdictionary ULongRange
{
[Clamp] unsigned long max
;
[Clamp] unsigned long min
;
};
max
类型为 unsigned long
该属性的最大有效值。
min
类型为 unsigned long
该属性的最小值。
WebIDLdictionary ConstrainULongRange
: ULongRange
{
[Clamp] unsigned long exact
;
[Clamp] unsigned long ideal
;
};
exact
类型为 unsigned long
该属性的精确要求值。
ideal
类型为 unsigned long
该属性的理想(目标)值。
WebIDLdictionary ConstrainDOMStringParameters
{
(DOMString or sequence<DOMString>) exact
;
(DOMString or sequence<DOMString>) ideal
;
};
WebIDLdictionary ConstrainBooleanOrDOMStringParameters
{
(boolean or DOMString) exact
;
(boolean or DOMString) ideal
;
};
WebIDLtypedef ([Clamp] unsigned long or ConstrainULongRange
) ConstrainULong
;
ConstrainULong
用于指代 ([Clamp] unsigned long 或
ConstrainULongRange) 类型。
WebIDLtypedef (double or ConstrainDoubleRange
) ConstrainDouble
;
ConstrainDouble
用于指代 (double 或 ConstrainDoubleRange) 类型。
WebIDLtypedef (boolean or ConstrainBooleanParameters
) ConstrainBoolean
;
ConstrainBoolean
用于指代 (boolean 或 ConstrainBooleanParameters) 类型。
WebIDLtypedef (DOMString or
sequence<DOMString> or
ConstrainDOMStringParameters
) ConstrainDOMString
;
ConstrainDOMString
用于指代 (DOMString 或 sequence<DOMString> 或
ConstrainDOMStringParameters) 类型。
WebIDLtypedef (boolean or DOMString or ConstrainBooleanOrDOMStringParameters
) ConstrainBooleanOrDOMString
;
ConstrainBooleanOrDOMString
用于指代
(boolean 或 DOMString 或 ConstrainBooleanOrDOMStringParameters)
类型。
Capabilities
是一个包含一个或多个键值对的字典,其中每个键必须是可约束属性,每个值必须是该属性允许值集合的子集。值表达式的具体语法取决于属性的类型。Capabilities 字典指定了哪些可约束属性可以作为约束应用到 constrainable object。注意,一个 constrainable object 的 Capabilities 可以是 Web 平台定义的属性的子集,并且这些属性的值集合也是子集。注意 Capabilities 是由 用户代理返回给应用程序,不能由应用程序指定。但是,应用程序可以通过 Constraints 控制 用户代理为可约束属性选择的 Settings。
下面是一个 Capabilities 字典的示例。在此情况下,constrainable object 是一个可用能力非常有限的视频源。
{
frameRate: {min: 1.0, max: 60.0},
facingMode: ['user', 'left']
}
下一个示例指出,针对范围值的能力是为各个可约束属性分别给出范围,而不是组合。这对于视频宽度和高度尤其重要,因为宽度和高度的范围是分别报告的。在示例中,如果 constrainable object 只能提供 640x480 和 800x600 分辨率,则返回的相关能力如下:
{
width: {min: 640, max: 800},
height: {min: 480, max: 600},
aspectRatio: {min: 4/3, max: 4/3}
}
注意上述示例中,aspectRatio 可以明确表示宽高不能任意组合,尽管它仍然暗示可用分辨率不止两个。
A 使用 Constrainable Pattern 的规范不应继承下面的字典,而应提供自己的定义。详见MediaTrackCapabilities
示例。
WebIDLdictionary Capabilities
{};
Settings
是一个包含一个或多个键值对的字典。它必须包含在
getCapabilities()
返回的、在该对象类型上定义的每个属性的键;例如,一个音频 MediaStreamTrack
没有 "width" 属性。每个键必须有唯一值,并且值必须为 getCapabilities()
为该属性定义的集合成员。Settings
字典包含用户代理为对象可约束属性最终选择的实际值。值的具体语法取决于属性类型。
符合规范的用户代理必须支持本规范定义的所有可约束属性。
下面是一个 Settings 字典的示例。这个例子并不现实,因为用户代理实际上需要支持的可约束属性远不止这些。
{
frameRate: 30.0,
facingMode: 'user'
}
MediaTrackSettings
示例。
由于 WebIDL 的限制,实现 Constrainable Pattern 的接口不能直接继承此处定义的 Constraints 和 ConstraintSet。它们必须提供遵循此模式的自己的定义。详见 MediaTrackConstraints 示例。
WebIDLdictionary ConstraintSet
{};
ConstraintSet
的每个成员对应一个可约束属性,并指定该属性有效能力值集合的子集。应用
ConstraintSet 会指导 用户代理 将对应的可约束属性设置限制为指定的值或值范围。某属性可以同时出现在基本 Constraints 集和高级 ConstraintSets 列表中,并且可以在高级列表中的每个 ConstraintSet 中最多出现一次。
WebIDLdictionary Constraints
: ConstraintSet
{
sequence<ConstraintSet
> advanced
;
};
advanced
类型为 sequence<ConstraintSet
>这是 用户代理必须尝试依次满足的 ConstraintSet
列表,只跳过无法满足的项。列表中这些 ConstraintSet 的顺序是有意义的。特别是,当它们作为 applyConstraints
参数时,用户代理必须按指定顺序尝试满足。如果高级
ConstraintSet C1 和 C2 各自可以满足但不能同时满足,则列表中靠前的 C1 或 C2 会被满足,另一个不会。用户代理必须尝试满足列表中所有
ConstraintSet,即使有的无法满足。因此,若约束 C3 在 C1 和 C2 之后指定,则用户代理将尝试满足
C3,即便 C2 无法满足。注意某属性名在每个 ConstraintSet 中只能出现一次,但可以出现在多个 ConstraintSet 中。
下面的示例代码展示了一个按钮。当点击时,按钮会被禁用,并提示用户提供一个媒体流。用户可以通过提供流(例如授予页面本地摄像头访问权限),然后禁用流(例如撤销该访问权限)来重新启用按钮。
<button id="startBtn">开始</button>
<script>
const startBtn = document.getElementById('startBtn');
startBtn.onclick = async () => {
try {
startBtn.disabled = true;
const constraints = {
audio: true,
video: true
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
for (const track of stream.getTracks()) {
track.onended = () => {
startBtn.disabled = stream.getTracks().some((t) => t.readyState == 'live');
};
}
} catch (err) {
console.error(err);
}
};
</script>
此示例允许用户通过本地摄像头为自己拍照。注意,Image Capture 规范 [image-capture] 提供了更简单的实现方式。
<script>
window.onload = async () => {
const video = document.getElementById('monitor');
const canvas = document.getElementById('photo');
const shutter = document.getElementById('shutter');
try {
video.srcObject = await navigator.mediaDevices.getUserMedia({video: true});
await new Promise(resolve => video.onloadedmetadata = resolve);
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
document.getElementById('splash').hidden = true;
document.getElementById('app').hidden = false;
shutter.onclick = () => canvas.getContext('2d').drawImage(video, 0, 0);
} catch (err) {
console.error(err);
}
};
</script>
<h1>自拍亭</h1>
<section id="splash">
<p id="errorMessage">加载中...</p>
</section>
<section id="app" hidden>
<video id="monitor" autoplay></video>
<button id="shutter">📷</button>
<canvas id="photo"></canvas>
</section>
本规范定义了两个强大功能,其名称为
names
"camera"
和
"microphone"
。
它定义了以下类型和算法:
WebIDLdictionary CameraDevicePermissionDescriptor
: PermissionDescriptor {
boolean panTiltZoom
= false;
};
一个权限涵盖对至少一种设备的访问。
描述符的语义是:它查询对该类任意设备的访问权限。
因此,如果查询 "camera"
权限返回 "granted
",
客户端知道将可以访问一个摄像头且不会弹出权限提示;如果返回 "denied
",
则知道所有摄像头的 getUserMedia 请求都不会成功。
如果用户代理认为对某些(但不是全部)此类设备已授权,查询将返回
"granted
"。
如果用户代理认为对所有此类设备都拒绝了权限,查询将返回
"denied
"。
{name: "camera", panTiltZoom: true}
比 {name: "camera", panTiltZoom: false}
更强。
"granted
"
权限不能保证 getUserMedia 一定成功。
它只表示用户不会被弹出权限提示。还有很多其他因素(如约束或摄像头正在被占用)会导致 getUserMedia 失败。
name
的结果。
本规范定义了两个策略控制功能
其字符串标识分别为 "camera"
和 "microphone"
。
二者的默认允许列表为
"self"
。
一个文档的权限策略
决定该文档内的任何内容是否允许使用
getUserMedia
请求摄像头或麦克风。如果
在任一文档中禁用,则文档内任何内容都不允许使用
getUserMedia
请求摄像头或麦克风。
这由请求使用权限算法强制执行。
此外,enumerateDevices
只会枚举文档
允许使用的设备。
本规范以单个 MediaDevices
对象视角表达隐私指示器要求。
鼓励实现者将这些原则外推以统一指示器展示,覆盖因 iframe 共存可在页面上存在的多个
MediaDevices
对象。
对于每一种 kind 设备,getUserMedia
()
都会暴露:
[[kindsAccessibleMap]]
[kind]
值与所有该类设备的
[[devicesAccessibleMap]]
[deviceId]
值的逻辑或。
[[kindsAccessibleMap]]
[kind]
值与所有该类设备的
[[devicesLiveMap]]
[deviceId] 值的逻辑或。
定义 anyAccessible 为所有 any<kind>Accessible 的逻辑或。
定义 anyLive 为所有 any<kind>Live 的逻辑或。
则对用户代理有如下要求:
[[devicesAccessibleMap]]
[deviceId]
和
[[devicesLiveMap]]
[deviceId]
至少要在值变化时进行提示。
对用户代理还鼓励如下行为:
[[devicesAccessibleMap]]
[deviceId]
和
[[devicesLiveMap]]
[deviceId]
鼓励持续指示当前状态,并让设备专属硬件指示灯与 [[devicesLiveMap]]
[deviceId] 匹配。
本节为非规范性内容;不规定新行为,而是总结规范其他部分已有的信息。
本规范扩展了 Web 平台对媒体输入设备(特别是麦克风和摄像头)的管理能力。它也可能涉及其他媒体设备(如音频输出设备——扬声器和耳机)的信息暴露,但此类细节由其他规范规定。 从用户的麦克风和摄像头采集音视频会向应用暴露个人身份信息,本规范要求在共享前获得用户明确同意。
在摄像头或麦克风采集开始前,应用(“路过的网页”)只能获知用户是否有摄像头或麦克风(但不能知道数量)。设备标识符设计为不具有跨源跟踪用户的能力,但摄像头或麦克风能力的存在会为指纹表面增加两位。建议像对待其他持久化存储(如
Cookie)一样对待每源持久化标识符 deviceId
。
一旦开始摄像头或麦克风采集,本规范描述了如何访问并使用相关设备的媒体数据。这些数据可能敏感;建议应有指示器提示设备正在使用,但权限性质和设备使用指示器均由平台决定。
开始采集的权限可能是临时的,也可能是持久的。对于临时权限,重要的是用户可以“拒绝”,且不会因等待授权而导致界面阻塞——可以提供“永久拒绝”选项,或避免使用模态权限对话框。
一旦摄像头或麦克风采集开始,网页文档可以列出所有可用媒体采集设备及其标签。此能力持续到文档关闭,不能持久化。多数情况下,标签在不同源间是稳定的,因此有可能作为跨源追踪设备的手段。
本规范暴露了未被使用设备的信息。这是为了兼容和历史原因。建议今后的规范不要采用这种模式,而应遵循 设备枚举设计原则中的最佳实践。
对于已开启或曾开启采集的开放网页文档,或处于可视状态的网页文档, 每当有新媒体设备被添加或移除时, devicechange 事件可能会同时在多个 navigable 和源上触发;用户代理可通过模糊事件触发时机或延迟到文档进入可视状态时触发,来降低跨源浏览活动关联的风险。
一旦网页文档获得采集设备的媒体流访问权限,也会获得关于设备的详细信息,包括其可操作能力范围(如摄像头可用分辨率)。这些操作能力在不同会话和源间大多是持久的,因此可作为跨时空、跨源追踪设备的手段。
一旦获得采集设备的视频流访问权限,该流极可能可用于唯一指纹识别设备(例如通过坏点检测)。同样地,获得音频流后也极可能可用于识别用户位置,甚至同一房间内不同用户(例如通过环境音频分析或设备扬声器播放的独特音频)。用户层面的缓解措施包括遮盖摄像头和/或麦克风或通过用户代理界面撤销权限。
可以利用约束让 getUserMedia 调用失败时返回有关系统设备的信息而不提示用户,这会增加指纹表面的暴露。用户代理应考虑限制 getUserMedia 失败调用的速率,以限制该暴露面。
对于存储的持久采集权限,重要的是用户能容易找到已授权列表并撤销不需要的权限。
权限被授予后,用户代理应让用户明确感知两点:
带有持久权限的站点开发者应谨防权限被滥用。可使用 [permissions] API 撤销这些权限。
尤其不应允许自动将授权媒体设备的音视频流发送到第三方可选的终端。
例如,若某站点提供如下 URL:
https://webrtc.example.org/?call=user
可自动建立呼叫并向
user
传输音视频,则可能被滥用为如下攻击场景:
已授予 https://webrtc.example.org/
持久权限的用户,若点击或被重定向到
https://webrtc.example.org/?user=EvilSpy
,就可能被诱导将自己的音视频流发送给攻击者 EvilSpy
。
本节为非规范性内容。
虽然未来可能会发布新版本规范,也预计其他标准需要定义新的扩展能力以在本规范基础上构建。本节旨在为扩展制定者提供参考。
规范中所有 WebIDL 定义的接口、方法或属性均可扩展。两个常见扩展点是定义新的媒体类型和新的可约束属性。
kind
(超越音频与视频)至少需定义:
MediaStream
接口上添加 getXXXXTracks() 方法,kind
属性的额外有效值,
用于 MediaStreamTrack
接口,
HTMLMediaElement
如何处理包含新媒体类型轨道的
MediaStream
(见 6.
媒体元素中的 MediaStream),包括为新类型添加与 audible/inaudible
对应的逻辑,
MediaDeviceKind
,getCapabilities
()
和
getUserMedia
()
的说明,
MediaStreamConstraints
字典,
kind
关联的新 PermissionDescriptor
名称,并定义权限、访问开始与结束、静音/禁用对新旧“直播”与“设备可访问”指示状态的影响(见 MediaDevices)。
还应更新:
label
属性在
MediaStreamTrack
接口上的说明,
还可以包括:
MediaStreamTrackState
中举例说明此类轨道可能如何结束。
需要思考并定义该属性的 Constraints、Capabilities 和 Settings(见 3. 术语)如何工作。相关内容请参考
MediaTrackSupportedConstraints
、
MediaTrackCapabilities
、
MediaTrackConstraints
、
MediaTrackSettings
、4.3.8 可约束属性和
MediaStreamConstraints
。
扩展规范的制定者强烈建议在规范仓库通知规范维护者。
未来版本规范或 WebRTC 工作组制定的其他规范将考虑所有已知扩展,以减少潜在用法冲突。
MediaStreamTrack
和 MediaStream
定义新的 sink其他规范可为 MediaStream
和/或
MediaStreamTrack
定义新的 sink。至少,一个新的
MediaStreamTrack
消费者需定义:
MediaStreamTrack
。
MediaStreamTrack
其他规范可为 MediaStreamTrack
定义新的源。
至少,新的 MediaStreamTrack
源需:
kind
来自该新 source;
(getUserMedia
()
专用于摄像头和麦克风源),
kind
适用的可约束属性(见 4.3.8
可约束属性)及其与此源的工作方式,编辑们感谢工作组主席和团队联系人 Harald Alvestrand、Stefan Håkansson、Erik Lagerway 和 Dominique Hazaël-Massieux 的支持。本规范中的大量文本由许多人提供,包括 Jim Barnett、Harald Alvestrand、Travis Leithead、Josh Soref、Martin Thomson、 Jan-Ivar Bruaroey、Peter Thatcher、 Dominique Hazaël-Massieux 和 Stefan Håkansson。Dan Burnett 感谢 Voxeo 和 Aspect 在本规范开发过程中给予的重大支持。
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:
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:
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: