diff options
Diffstat (limited to 'files/zh-cn/web/api/mediadevices')
7 files changed, 1131 insertions, 0 deletions
diff --git a/files/zh-cn/web/api/mediadevices/devicechange_event/index.html b/files/zh-cn/web/api/mediadevices/devicechange_event/index.html new file mode 100644 index 0000000000..7ebc7fb71f --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/devicechange_event/index.html @@ -0,0 +1,153 @@ +--- +title: devicechange +slug: Web/API/MediaDevices/devicechange_event +translation_of: Web/API/MediaDevices/devicechange_event +--- +<p>每当媒体设备(例如相机,麦克风或扬声器)连接到系统或从系统中移除时,<code>devicechange </code>事件就会被发送到 {{domxref("MediaDevices")}} 实例。 这是一个没有附加属性的通用 {{domxref("Event")}} 。</p> + +<h2 id="一般信息">一般信息</h2> + +<dl> + <dt style="float: left; text-align: right; width: 120px;">规范</dt> + <dd style="margin: 0 0 0 120px;">{{SpecName('Media Capture')}}</dd> + <dt style="float: left; text-align: right; width: 120px;">接口</dt> + <dd style="margin: 0 0 0 120px;">Event</dd> + <dt style="float: left; text-align: right; width: 120px;">是否冒泡</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">是否可取消</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">对象</dt> + <dd style="margin: 0 0 0 120px;">{{domxref('MediaDevices')}}</dd> + <dt style="float: left; text-align: right; width: 120px;">默认动作</dt> + <dd style="margin: 0 0 0 120px;">None</dd> +</dl> + +<h2 id="属性">属性</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col">Type</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>target</code>{{readonlyinline}}</td> + <td>{{domxref("EventTarget")}}</td> + <td>事件对象 (位于DOM树最上面的元素).</td> + </tr> + <tr> + <td><code>type</code> {{readonlyinline}}</td> + <td>{{domxref("DOMString")}}</td> + <td>事件类型.</td> + </tr> + <tr> + <td><code>bubbles</code> {{readonlyinline}}</td> + <td>{{domxref("Boolean")}}</td> + <td>是否冒泡</td> + </tr> + <tr> + <td><code>cancelable</code> {{readonlyinline}}</td> + <td>{{domxref("Boolean")}}</td> + <td>是否可被取消</td> + </tr> + </tbody> +</table> + +<h2 id="相关事件">相关事件</h2> + +<p><em>无</em>.</p> + +<h2 id="样例">样例</h2> + +<p>有关使用 <code>devicechange</code> 事件更新屏幕上设备列表的示例,请参阅 {{SectionOnPage("/en-US/docs/Web/API/MediaDevices/ondevicechange", "Example")}}。</p> + +<h2 id="Specifications">Specifications</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ SpecName('Media Capture', '#event-mediadevices-devicechange', 'devicechange') }}</td> + <td>{{ Spec2('Media Capture') }}</td> + <td>Initial specification.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>{{CompatibilityTable}}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Edge</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatChrome(52.0)}}</td> + <td>{{CompatGeckoDesktop(51)}}<sup>[1]</sup></td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>39</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Android Webview</th> + <th>Edge</th> + <th>Firefox Mobile (Gecko)</th> + <th>Firefox OS</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + <th>Chrome for Android</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>39</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatNo}}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1] Support for the <code>devicechange</code> event and for {{domxref("MediaDevices.ondevicechange")}} landed in Firefox 51, but <em>only for Mac</em>, and disabled by default. It can be enabled by setting the preference <code>media.ondevicechange.enabled</code> to <code>true</code>. Support for this event was added for Linux and Windows—and it was enabled by default—starting in Firefox 52.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>{{domxref("MediaDevices.ondevicechange")}}</li> +</ul> diff --git a/files/zh-cn/web/api/mediadevices/enumeratedevices/index.html b/files/zh-cn/web/api/mediadevices/enumeratedevices/index.html new file mode 100644 index 0000000000..02a65eb991 --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/enumeratedevices/index.html @@ -0,0 +1,93 @@ +--- +title: MediaDevices.enumerateDevices() +slug: Web/API/MediaDevices/enumerateDevices +tags: + - API + - WebRTC + - 方法 +translation_of: Web/API/MediaDevices/enumerateDevices +--- +<div>{{APIRef("WebRTC")}}</div> + +<p>{{domxref("MediaDevices")}} 的方法 <strong><code>enumerateDevices()</code></strong> 请求一个可用的媒体输入和输出设备的列表,例如麦克风,摄像机,耳机设备等。 返回的 {{domxref("Promise")}} 完成时,会带有一个描述设备的 {{domxref("MediaDeviceInfo")}} 的数组。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">var <em>enumeratorPromise</em> = navigator.mediaDevices.enumerateDevices(); +</pre> + +<h3 id="返回值">返回值</h3> + +<p>返回一个 {{ domxref("Promise") }} 。当完成时,它接收一个 {{domxref("MediaDeviceInfo")}} 对象的数组。每个对象描述一个可用的媒体输入输出设备。.</p> + +<p>如果枚举失败,promise 也会被拒绝(rejected)。</p> + +<h2 id="示例">示例</h2> + +<p>这是一个使用 <code>enumerateDevices()</code> 的例子。它只是输出一个带有标签(有标签的情况下)的 <a href="/zh-CN/docs/Web/API/MediaDeviceInfo/deviceId">device ID</a> 的列表。</p> + + + +<pre class="brush: js">if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { + console.log("不支持 enumerateDevices() ."); + return; +} + +// 列出相机和麦克风。 + +navigator.mediaDevices.enumerateDevices() +.then(function(devices) { + devices.forEach(function(device) { + console.log(device.kind + ": " + device.label + + " id = " + device.deviceId); + }); +}) +.catch(function(err) { + console.log(err.name + ": " + err.message); +});</pre> + +<p>这将会输出类似以下的内容:</p> + +<pre>videoinput: id = csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8= +audioinput: id = RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM= +audioinput: id = r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0= +</pre> + +<p>或者,如果有一个或多个 {{domxref("MediaStream")}} 处于活动状态或者获得了持久授权,将会输出以下内容:</p> + +<pre>videoinput: FaceTime HD Camera (Built-in) id=csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8= +audioinput: default (Built-in Microphone) id=RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM= +audioinput: Built-in Microphone id=r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0= +</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">注释</th> + </tr> + <tr> + <td>{{SpecName('Media Capture', '#dom-mediadevices-enumeratedevices', 'mediaDevices: enumerateDevices')}}</td> + <td>{{Spec2('Media Capture')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<div>{{Compat("api.MediaDevices.enumerateDevices")}}</div> + +<h2 id="See_also">See also</h2> + +<ul> + <li>{{domxref("navigator.mediaDevices.getUserMedia()")}}</li> + <li><a href="/zh-CN/docs/WebRTC" title="WebRTC">WebRTC</a> - the introductory page to the API</li> + <li><a href="/zh-CN/docs/WebRTC/MediaStream_API" title="WebRTC/MediaStream_API">MediaStream API</a> - the API for the media stream objects</li> + <li><a href="/zh-CN/docs/WebRTC/taking_webcam_photos" title="WebRTC/taking_webcam_photos">Taking webcam photos</a> - a tutorial on using <code>getUserMedia()</code> for taking photos rather than video.</li> +</ul> diff --git a/files/zh-cn/web/api/mediadevices/getdisplaymedia/index.html b/files/zh-cn/web/api/mediadevices/getdisplaymedia/index.html new file mode 100644 index 0000000000..4f9df6b55b --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/getdisplaymedia/index.html @@ -0,0 +1,118 @@ +--- +title: MediaDevices.getDisplayMedia() +slug: Web/API/MediaDevices/getDisplayMedia +tags: + - API + - 会谈 + - 分享 + - 参考 + - 多媒体 + - 多媒体设备 + - 屏幕 + - 屏幕捕捉 + - 屏幕捕捉API + - 捕捉 + - 方法 + - 显示 + - 获取显示多媒体 + - 视频 +translation_of: Web/API/MediaDevices/getDisplayMedia +--- +<div>{{DefaultAPISidebar("Screen Capture API")}}</div> + +<p>这个 {{domxref("MediaDevices")}} 接口的 <code><strong>getDisplayMedia() 方法提示用户去选择和授权捕获展示的内容或部分内容(如一个窗口)在一个</strong></code> {{domxref("MediaStream")}} 里. 然后,这个媒体流可以通过使用 <a href="/en-US/docs/Web/API/MediaStream_Recording_API">MediaStream Recording API</a> 被记录或者作为<a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> 会话的一部分被传输。</p> + +<p>去 <a href="/en-US/docs/Web/API/Screen_Capture_API/Using_Screen_Capture">Using the Screen Capture API</a> 查找更多详情和例子.</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">var <em>promise</em> = navigator.mediaDevices.getDisplayMedia(<em>constraints</em>); +</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>constraints</code> {{optional_inline}}</dt> + <dd>一个可选的{{domxref("MediaStreamConstraints")}}对象,它指定了返回的{{domxref("MediaStream")}}的要求。 因为<code>getDisplayMedia()</code>需要视频轨道,所以即使<code>constraints</code> 对象没有明确请求视频轨道,返回的流也会有一个。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>一个被解析为 {{domxref("MediaStream")}} 的 {{jsxref("Promise")}},其中包含一个视频轨道。视频轨道的内容来自用户选择的屏幕区域以及一个可选的音频轨道。</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> 浏览器对音频的支持程度各不相同,既取决于是否支持,也取决于音频源. 点击 {{anch("Browser compatibility", "compatibility table")}} 来查看各个浏览器的支持性.</p> +</div> + +<h3 id="异常">异常</h3> + +<p>来自返回的promise的拒绝是通过将{{domxref("DOMException")}}错误对象传递给promise的失败处理程序来进行的。可能的错误是:</p> + +<dl> + <dt><code>AbortError</code> [中止错误]</dt> + <dd>发生了与以下任何其他异常不匹配的错误或故障。</dd> + <dt><code>InvalidStateError</code> [拒绝错误]</dt> + <dd>调用 <code>getDisplayMedia()</code> 的context中的 {{domxref("document")}} 不是完全激活的; 例如,也许它不是最前面的标签。</dd> + <dt><code>NotAllowedError</code> [拒绝错误]</dt> + <dd>用户拒绝授予访问屏幕区域的权限,或者不允许当前浏览实例访问屏幕共享。</dd> + <dt><code>NotFoundError</code> [找不到错误]</dt> + <dd>没有可用于捕获的屏幕视频源。</dd> + <dt><code>NotReadableError</code> [无法读取错误]</dt> + <dd>用户选择了屏幕,窗口,标签或其他屏幕数据源,但发生了硬件或操作系统级别错误或锁定,从而预先占用了共享所选源。</dd> + <dt><code>OverconstrainedError</code> [转换错误]</dt> + <dd>创建流后,由于无法生成兼容的流导致应用指定的 <code>constraints</code> 失效。</dd> + <dt><code>TypeError</code> [类型错误]</dt> + <dd>指定的 <code>constraints</code> 包括调用 <code>getDisplayMedia()</code> 时不允许的<code>constraints</code>。 这些不受支持的<code>constraints</code>是 <code>advanced</code> 的,任何约束又有一个名为 <code>min</code> 或 <code>exact</code> 的成员。</dd> +</dl> + +<h2 id="示例">示例</h2> + +<p>在下面的示例中,我们创建了一个 <code>startCapture()</code> 方法,该方法在给定由 <code>displayMediaOptions</code> 参数指定的一组选项的情况下启动屏幕捕获。 选项以 {{domxref("MediaStreamConstraints")}}对象的形式指定,该对象指定首选流配置和从中捕获视频的显示表面</p> + +<pre class="brush: js">async function startCapture(displayMediaOptions) { + let captureStream = null; + + try { + captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions); + } catch(err) { + console.error("Error: " + err); + } + return captureStream; +}</pre> + +<p>这里使用 {{jsxref("await")}} 来进行异步等待 <code>getDisplayMedia()</code>来进行 {{domxref("MediaStream")}}解析,其中包含指定选项所请求的显示内容。 之后,流被返回给调用者以供其使用,可能是使用 {{domxref("RTCPeerConnection.addTrack()")}}添加到WebRTC调用来从流中添加视频轨道。</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('Screen Capture', '#dom-mediadevices-getdisplaymedia', 'MediaDevices.getDisplayMedia()')}}</td> + <td>{{Spec2('Screen Capture')}}</td> + <td>初始定义</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div> +<div class="hidden">此页面上的兼容性表是根据结构化数据生成的。 如果您想为数据做出贡献,请查看 <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> 并向我们发送拉取请求。</div> + +<p>{{Compat("api.MediaDevices.getDisplayMedia")}}</p> +</div> + +<h2 id="参考">参考</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Screen_Capture_API">Screen Capture API</a></li> + <li><a href="/en-US/docs/Web/API/Screen_Capture_API/Using_Screen_Capture">Using the Screen Capture API</a></li> + <li><a href="/en-US/docs/Web/API/Media_Streams_API">Media Capture and Streams API</a></li> + <li><a href="/en-US/docs/Web/API/WebRTC_API">WebRTC API</a></li> + <li>{{domxref("MediaDevices.getUserMedia", "getUserMedia()")}}: Capturing media from a camera and/or microphone</li> +</ul> diff --git a/files/zh-cn/web/api/mediadevices/getsupportedconstraints/index.html b/files/zh-cn/web/api/mediadevices/getsupportedconstraints/index.html new file mode 100644 index 0000000000..1dbc22edcf --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/getsupportedconstraints/index.html @@ -0,0 +1,132 @@ +--- +title: MediaDevices.getSupportedConstraints() +slug: Web/API/MediaDevices/getSupportedConstraints +translation_of: Web/API/MediaDevices/getSupportedConstraints +--- +<p>{{APIRef("Media Capture and Streams")}}</p> + +<p> </p> + +<p>{{domxref("MediaDevices")}} 接口的<code><strong>getSupportedConstraints</strong></code><strong><code>()</code></strong>方法返回一个基于{{domxref("MediaTrackSupportedConstraints")}}的对象, 其成员字段都是客户端({{Glossary("user agent")}})所支持的约束属性(如帧率,窗口大小)。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">var <em>supportedConstraints</em> = navigator.mediaDevices.getSupportedConstraints();</pre> + +<h3 id="参数">参数</h3> + +<p>无</p> + +<h3 id="返回值">返回值</h3> + +<p>一个新的基于{{domxref("MediaTrackSupportedConstraints")}} 的对象用来监视客户端所支持的约束属性.因为只有客户端所支持的约束属性才能被展示在这个列表中 , 这些布尔值(Boolean)属性的每一个都为true。</p> + +<h2 id="Example" name="Example">示例</h2> + +<p>这个示例展示了你的客户端所支持的约束属性的列表。</p> + +<div class="hidden"> +<h3 id="HTML_内容">HTML 内容</h3> + +<pre class="brush: html"><p>The following media constraints are supported by your browser:</p> + +<ul id="constraintList"> +</ul></pre> + +<h3 id="CSS_内容">CSS 内容</h3> + +<pre class="brush: css">body { + font: 15px Arial, sans-serif; +}</pre> + +<h3 id="JavaScript_内容">JavaScript 内容</h3> +</div> + +<pre class="brush: js">let constraintList = document.getElementById("constraintList"); +let supportedConstraints = navigator.mediaDevices.getSupportedConstraints(); + +for (let constraint in supportedConstraints) { + if (supportedConstraints.hasOwnProperty(constraint)) { + let elem = document.createElement("li"); + + elem.innerHTML = "<code>" + constraint + "</code>"; + constraintList.appendChild(elem); + } +}</pre> + +<h3 id="结果">结果</h3> + +<p>{{ EmbedLiveSample('Example', 600, 350) }}</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('Media Capture', '#widl-MediaDevices-getSupportedConstraints-MediaTrackSupportedConstraints', 'getSupportedConstraints()')}}</td> + <td>{{Spec2('Media Capture')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器支持情况">浏览器支持情况</h2> + +<p>{{ CompatibilityTable }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Microsoft Edge</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatVersionUnknown }}</td> + <td>{{CompatGeckoDesktop(50) }}</td> + <td>{{CompatUnknown}}</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatUnknown }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Android Webview</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + <th>Chrome for Android</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatGeckoMobile(48) }}</td> + <td>{{ CompatGeckoMobile(50) }}</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatUnknown }}</td> + <td>{{ CompatVersionUnknown }}</td> + </tr> + </tbody> +</table> +</div> diff --git a/files/zh-cn/web/api/mediadevices/getusermedia/index.html b/files/zh-cn/web/api/mediadevices/getusermedia/index.html new file mode 100644 index 0000000000..a9afcece9f --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/getusermedia/index.html @@ -0,0 +1,259 @@ +--- +title: MediaDevices.getUserMedia() +slug: Web/API/MediaDevices/getUserMedia +translation_of: Web/API/MediaDevices/getUserMedia +--- +<div>{{APIRef("WebRTC")}}</div> + +<div> +<p><code><strong>MediaDevices.getUserMedia()</strong></code> 会提示用户给予使用媒体输入的许可,媒体输入会产生一个{{domxref("MediaStream")}},里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。</p> + +<p>它返回一个 {{jsxref("Promise")}} 对象,成功后会<code>resolve</code>回调一个 {{domxref("MediaStream")}} 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,<code>promise</code>会<code>reject</code>回调一个 <code>PermissionDeniedError</code> 或者 <code>NotFoundError</code> 。</p> +</div> + +<div class="note"> +<p>返回的promise对象可能既不会resolve也不会reject,因为用户不是必须选择允许或拒绝。</p> +</div> + +<p>通常你可以使用 {{domxref("navigator.mediaDevices")}} 来获取 {{domxref("MediaDevices")}} ,例如:</p> + +<pre class="brush: js notranslate">navigator.mediaDevices.getUserMedia(constraints) +.then(function(stream) { + /* 使用这个stream stream */ +}) +.catch(function(err) { + /* 处理error */ +});</pre> + +<h2 id="语法">语法</h2> + +<pre class="brush: js notranslate">var <em>promise</em> = navigator.mediaDevices.getUserMedia(<em>constraints</em>);</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>constraints</code></dt> + <dd> + <p>作为一个{{domxref("MediaStreamConstraints")}} 对象,指定了请求的媒体类型和相对应的参数。</p> + + <p>constraints 参数是一个包含了<code>video</code> 和 <code>audio</code>两个成员<font face="Open Sans, Arial, sans-serif">的</font><code>MediaStreamConstraints</code> 对象,用于说明请求的媒体类型。必须至少一个类型或者两个同时可以被指定。如果浏览器无法找到指定的媒体类型或者无法满足相对应的参数要求,那么返回的Promise对象就会处于rejected[失败]状态,<code>NotFoundError</code>作为rejected[失败]回调的参数。 </p> + + <p>以下同时请求不带任何参数的音频和视频:</p> + + <pre class="brush: js notranslate">{ audio: true, video: true }</pre> + + <p>如果为某种媒体类型设置了 <code>true</code> ,得到的结果的流中就需要有此种类型的轨道。如果其中一个由于某种原因无法获得,<code>getUserMedia()</code> 将会产生一个错误。</p> + + <p>当由于隐私保护的原因,无法访问用户的摄像头和麦克风信息时,应用可以使用额外的constraints参数请求它所需要或者想要的摄像头和麦克风能力。下面演示了应用想要使用1280x720的摄像头分辨率:</p> + + <pre class="brush: js notranslate">{ + audio: true, + video: { width: 1280, height: 720 } +}</pre> + + <p id="successCallback">浏览器会试着满足这个请求参数,但是如果无法准确满足此请求中参数要求或者用户选择覆盖了请求中的参数时,有可能返回其它的分辨率。</p> + + <p>强制要求获取特定的尺寸时,可以使用关键字<code>min</code>, <code>max</code>, 或者 <code>exact</code>(就是 min == max). 以下参数表示要求获取最低为1280x720的分辨率。</p> + + <pre class="brush: js notranslate">{ + audio: true, + video: { + width: { min: 1280 }, + height: { min: 720 } + } +}</pre> + + <p>如果摄像头不支持请求的或者更高的分辨率,返回的Promise会处于rejected状态,<code>NotFoundError作为</code>rejected回调的参数,而且用户将不会得到要求授权的提示。</p> + + <p>造成不同表现的原因是,相对于简单的请求值和<code>ideal</code>关键字而言,关键字<code>min</code>, <code>max</code>, 和 <code>exact</code>有着内在关联的强制性,请看一个更详细的例子:</p> + + <pre class="brush: js notranslate">{ + audio: true, + video: { + width: { min: 1024, ideal: 1280, max: 1920 }, + height: { min: 776, ideal: 720, max: 1080 } + } +}</pre> + + <p>当请求包含一个ideal(应用最理想的)值时,这个值有着更高的权重,意味着浏览器会先尝试找到最接近指定的理想值的设定或者摄像头(如果设备拥有不止一个摄像头)。</p> + + <p>简单的请求值也可以理解为是应用理想的值,因此我们的第一个指定分辨率的请求也可以写成如下:</p> + + <pre class="brush: js notranslate">{ + audio: true, + video: { + width: { ideal: 1280 }, + height: { ideal: 720 } + } +}</pre> + + <p>并不是所有的constraints 都是数字。例如, 在移动设备上面,如下的例子表示优先使用前置摄像头(如果有的话):</p> + + <pre class="brush: js notranslate">{ audio: true, video: { facingMode: "user" } }</pre> + + <p>强制使用后置摄像头,请用:</p> + + <pre class="brush: js notranslate">{ audio: true, video: { facingMode: { exact: "environment" } } }</pre> + </dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>返回一个 {{jsxref("Promise")}} , 这个Promise成功后的回调函数带一个 {{domxref("MediaStream")}} 对象作为其参数。</p> + +<h3 id="异常">异常</h3> + +<p>返回一个失败状态的Promise,这个Promise失败后的回调函数带一个{{domxref("DOMException")}}对象作为其参数。 可能的异常有:</p> + +<dl> + <dt><code>AbortError</code>[中止错误]</dt> + <dd>尽管用户和操作系统都授予了访问设备硬件的权利,而且未出现可能抛出<code>NotReadableError</code>异常的硬件问题,但仍然有一些问题的出现导致了设备无法被使用。</dd> + <dt><code>NotAllowedError</code>[拒绝错误]</dt> + <dd>用户拒绝了当前的浏览器实例的访问请求;或者用户拒绝了当前会话的访问;或者用户在全局范围内拒绝了所有媒体访问请求。</dd> + <dd> + <div class="note">较旧版本的规范使用了<code>SecurityError</code>,但在新版本当中<code>SecurityError</code>被赋予了新的意义。</div> + </dd> + <dt><code>NotFoundError</code>[找不到错误]</dt> + <dd>找不到满足请求参数的媒体类型。</dd> + <dt><code>NotReadableError</code>[无法读取错误]</dt> + <dd>尽管用户已经授权使用相应的设备,操作系统上某个硬件、浏览器或者网页层面发生的错误导致设备无法被访问。</dd> + <dt><code>OverConstrainedError</code>[无法满足要求错误]</dt> + <dd>指定的要求无法被设备满足,此异常是一个类型为<code>OverconstrainedError</code>的对象,拥有一个<code>constraint</code>属性,这个属性包含了当前无法被满足的<code>constraint</code>对象,还拥有一个<code>message</code>属性,包含了阅读友好的字符串用来说明情况。</dd> + <dd> + <div class="note">因为这个异常甚至可以在用户尚未授权使用当前设备的情况下抛出,所以应当可以当作一个探测设备能力属性的手段[fingerprinting surface]。</div> + </dd> + <dt><code>SecurityError</code>[安全错误]</dt> + <dd>在<code>getUserMedia()</code> 被调用的 {{domxref("Document")}} 上面,使用设备媒体被禁止。这个机制是否开启或者关闭取决于单个用户的偏好设置。</dd> + <dt><code>TypeError</code>[类型错误]</dt> + <dd>constraints对象未设置[空],或者都被设置为<code>false</code>。</dd> +</dl> + +<h2 id="示例">示例</h2> + +<h3 id="宽度和高度">宽度和高度</h3> + +<p>这个例子设置了摄像头分辨率,并把结果的 {{domxref("MediaStream")}} 分配给了一个video元素。 </p> + +<pre class="brush: js notranslate">// 想要获取一个最接近 1280x720 的相机分辨率 +var constraints = { audio: true, video: { width: 1280, height: 720 } }; + +navigator.mediaDevices.getUserMedia(constraints) +.then(function(mediaStream) { + var video = document.querySelector('video'); + video.srcObject = mediaStream; + video.onloadedmetadata = function(e) { + video.play(); + }; +}) +.catch(function(err) { console.log(err.name + ": " + err.message); }); // 总是在最后检查错误</pre> + +<h3 id="在旧的浏览器中使用新的API">在旧的浏览器中使用新的API</h3> + +<p>这是一个使用 <code>navigator.mediaDevices.getUserMedia()</code>的例子,带一个polyfill以适应旧的浏览器。 要注意的是这个polyfill并不能修正一些约束语法上的遗留差异,这表示约束在某些浏览器上可能不会很好地运行。推荐使用处理了约束的 <a href="https://github.com/webrtc/adapter">adapter.js</a> polyfill 来替代。</p> + +<pre class="brush: js notranslate">// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象 +if (navigator.mediaDevices === undefined) { + navigator.mediaDevices = {}; +} + +// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia +// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。 +if (navigator.mediaDevices.getUserMedia === undefined) { + navigator.mediaDevices.getUserMedia = function(constraints) { + + // 首先,如果有getUserMedia的话,就获得它 + var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; + + // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口 + if (!getUserMedia) { + return Promise.reject(new Error('getUserMedia is not implemented in this browser')); + } + + // 否则,为老的navigator.getUserMedia方法包裹一个Promise + return new Promise(function(resolve, reject) { + getUserMedia.call(navigator, constraints, resolve, reject); + }); + } +} + +navigator.mediaDevices.getUserMedia({ audio: true, video: true }) +.then(function(stream) { + var video = document.querySelector('video'); + // 旧的浏览器可能没有srcObject + if ("srcObject" in video) { + video.srcObject = stream; + } else { + // 防止在新的浏览器里使用它,应为它已经不再支持了 + video.src = window.URL.createObjectURL(stream); + } + video.onloadedmetadata = function(e) { + video.play(); + }; +}) +.catch(function(err) { + console.log(err.name + ": " + err.message); +}); +</pre> + +<h3 id="帧率">帧率</h3> + +<p>在某些情况下,比如WebRTC上使用受限带宽传输时,低帧率可能更适宜。</p> + +<pre class="brush: js notranslate">var constraints = { video: { frameRate: { ideal: 10, max: 15 } } }; +</pre> + +<h3 id="前置或者后置摄像头">前置或者后置摄像头</h3> + +<p>在移动设备(电话)上</p> + +<pre class="brush: js notranslate">var front = false; +document.getElementById('flip-button').onclick = function() { front = !front; }; + +var constraints = { video: { facingMode: (front? "user" : "environment") } }; +</pre> + +<h2 id="权限">权限</h2> + +<p>在一个可安装的app(如<a href="/en-US/Apps/Build/Building_apps_for_Firefox_OS/Firefox_OS_app_beginners_tutorial">Firefox OS app</a>)中使用 <code>getUserMedia()</code> ,你需要在声明文件中指定以下的权限:</p> + +<pre class="brush: js notranslate">"permissions": { + "audio-capture": { + "description": "Required to capture audio using getUserMedia()" + }, + "video-capture": { + "description": "Required to capture video using getUserMedia()" + } +}</pre> + +<p>参见 <a href="/en-US/Apps/Developing/App_permissions#audio-capture">permission: audio-capture</a> 和 <a href="/en-US/Apps/Developing/App_permissions#video-capture">permission: video-capture</a> 来获取更多信息。</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('Media Capture', '#dom-mediadevices-getusermedia', 'MediaDevices.getUserMedia()')}}</td> + <td>{{Spec2('Media Capture')}}</td> + <td>初始定义</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div>{{Compat("api.MediaDevices.getUserMedia")}}</div> + +<h2 id="参考">参考</h2> + +<ul> + <li>旧的 <a href="/en-US/docs/Web/API/Navigator/getUserMedia">navigator.getUserMedia</a> 遗留API</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices">navigator.enumerateDevices</a> - 获取用户可用的设备类型和数量</li> + <li><a href="/en-US/docs/WebRTC">WebRTC</a> - WebRTC API的介绍页面</li> + <li><a href="/en-US/docs/WebRTC/MediaStream_API">MediaStream API</a> - 媒体流对象的API</li> + <li><a href="/en-US/docs/WebRTC/taking_webcam_photos">Taking webcam photos</a> - 一个关于使用 <code>getUserMedia()</code> 拍照而非录视频的教程</li> +</ul> diff --git a/files/zh-cn/web/api/mediadevices/index.html b/files/zh-cn/web/api/mediadevices/index.html new file mode 100644 index 0000000000..19a922ce2d --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/index.html @@ -0,0 +1,124 @@ +--- +title: MediaDevices +slug: Web/API/MediaDevices +tags: + - API + - Experimental + - Interface + - Media + - MediaDevices + - NeedsTranslation + - TopicStub + - WebRTC + - 媒体 + - 媒体流 + - 媒体设备 +translation_of: Web/API/MediaDevices +--- +<div>{{APIRef("Media Capture and Streams")}}</div> + +<p><span class="seoSummary"><strong><code>MediaDevices</code></strong> 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。</span></p> + +<h2 id="属性">属性</h2> + +<p><em>从父类{{domxref("EventTarget")}}中继承的属性.</em></p> + +<h2 id="事件">事件</h2> + +<dl> + <dt>{{domxref("MediaDevices.devicechange_event", "devicechange")}}</dt> + <dd>返回 {{event("devicechange")}} 事件类型的事件处理程序。<br> + 也可通过 {{domxref("MediaDevices/ondevicechange", "ondevicechange")}} 访问</dd> +</dl> + +<h2 id="方法">方法</h2> + +<p><em>从其父项继承方法 {{domxref("EventTarget")}}.</em></p> + +<dl> + <dt>{{ domxref("MediaDevices.enumerateDevices()") }}</dt> + <dd>获取有关系统中可用的媒体输入和输出设备的一系列信息。</dd> + <dt>{{domxref("MediaDevices.getSupportedConstraints", "getSupportedConstraints()")}}</dt> + <dd>返回一个符合 {{domxref("MediaTrackSupportedConstraints")}} 的对象。该对象指明了 {{domxref("MediaStreamTrack")}} 接口支持的可约束的属性。查看 {{SectionOnPage("/en-US/docs/Web/API/Media_Streams_API", "Capabilities and constraints")}} 去了解更多相关信息。</dd> + <dt>{{domxref("MediaDevices.getDisplayMedia", "getDisplayMedia()")}}</dt> + <dd>提示用户选择显示器或显示器的一部分(例如窗口)以捕获为{{domxref("MediaStream")}} 以便共享或记录。返回解析为MediaStream的Promise。</dd> + <dt>{{ domxref("MediaDevices.getUserMedia()") }}</dt> + <dd>在用户通过提示允许的情况下,打开系统上的相机或屏幕共享和/或麦克风,并提供 {{domxref("MediaStream")}} 包含视频轨道和/或音频轨道的输入。</dd> + <dt></dt> +</dl> + +<h2 id="示例">示例</h2> + +<pre class="brush:js notranslate">'use strict'; + +// Put variables in global scope to make them available to the browser console. +var video = document.querySelector('video'); +var constraints = window.constraints = { + audio: false, + video: true +}; +var errorElement = document.querySelector('#errorMsg'); + +navigator.mediaDevices.getUserMedia(constraints) +.then(function(stream) { + var videoTracks = stream.getVideoTracks(); + console.log('Got stream with constraints:', constraints); + console.log('Using video device: ' + videoTracks[0].label); + stream.onended = function() { + console.log('Stream ended'); + }; + window.stream = stream; // make variable available to browser console + video.srcObject = stream; +}) +.catch(function(error) { + if (error.name === 'ConstraintNotSatisfiedError') { + errorMsg('The resolution ' + constraints.video.width.exact + 'x' + + constraints.video.width.exact + ' px is not supported by your device.'); + } else if (error.name === 'PermissionDeniedError') { + errorMsg('Permissions have not been granted to use your camera and ' + + 'microphone, you need to allow the page access to your devices in ' + + 'order for the demo to work.'); + } + errorMsg('getUserMedia error: ' + error.name, error); +}); + +function errorMsg(msg, error) { + errorElement.innerHTML += '<p>' + msg + '</p>'; + if (typeof error !== 'undefined') { + console.error(error); + } +}</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">评论</th> + </tr> + <tr> + <td>{{SpecName('Media Capture', '#mediadevices', 'MediaDevices')}}</td> + <td>{{Spec2('Media Capture')}}</td> + <td>初始定义</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("api.MediaDevices")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/API/Media_Streams_API">Media Capture and Streams API</a>: The API this interface is part of.</li> + <li><a href="/zh-CN/docs/Web/API/Screen_Capture_API">Screen Capture API</a>: The API defining the {{domxref("MediaDevices.getDisplayMedia", "getDisplayMedia()")}} method.</li> + <li><a href="/zh-CN/docs/Web/API/WebRTC_API">WebRTC API</a></li> + <li>{{domxref("Navigator.mediaDevices")}}: Returns a reference to a <code>MediaDevices</code> object that can be used to access devices.</li> + <li><a href="https://github.com/chrisjohndigital/CameraCaptureJS">CameraCaptureJS:</a> HTML5 video capture and playback using <code>MediaDevices</code> and the MediaStream Recording API (<a href="https://github.com/chrisjohndigital/CameraCaptureJS">source on GitHub</a>)</li> + <li><a href="https://github.com/chrisjohndigital/OpenLang">OpenLang</a>: HTML5 video language lab web application using <code>MediaDevices</code> and the MediaStream Recording API for video recording (<a href="https://github.com/chrisjohndigital/OpenLang">source on GitHub</a>)</li> +</ul> diff --git a/files/zh-cn/web/api/mediadevices/ondevicechange/index.html b/files/zh-cn/web/api/mediadevices/ondevicechange/index.html new file mode 100644 index 0000000000..4c9c9cb0e0 --- /dev/null +++ b/files/zh-cn/web/api/mediadevices/ondevicechange/index.html @@ -0,0 +1,252 @@ +--- +title: MediaDevices.ondevicechange +slug: Web/API/MediaDevices/ondevicechange +translation_of: Web/API/MediaDevices/ondevicechange +--- +<p>{{APIRef("Media Capture and Streams")}}</p> + +<p><span class="seoSummary"> <strong><code>MediaDevices.ondevicechange</code></strong> 属性是一种{{domxref("EventHandler")}},当{{domxref("MediaDevices")}} 接口的{{event("devicechange")}}事件被触发时会被调用. 不论{{Glossary("user agent")}}媒体设备的设置是否可用, 或者网站或者应用发生变了都会触发。无论何时你都可以使用 {{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}} 去更新可用设备列表.</span></p> + +<h2 id="Syntax">Syntax</h2> + +<pre class="syntaxbox"><em>MediaDevices</em>.ondevicechange = <em>eventHandler</em>; +</pre> + +<h3 id="Value">Value</h3> + +<p>A function you provide which accepts as input a {{domxref("Event")}} object describing the {{domxref("devicehange")}} event that occurred. There is no information about the change included in the event object; to get the updated list of devices, you'll have to use {{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}}.</p> + +<h2 id="Example" name="Example">Example</h2> + +<p>In this example, we create a function called <code>updateDeviceList()</code>, which is called once when {{domxref("MediaDevices.getUserMedia()")}} successfully obtains a stream, and then is called any time the device list changes. It displays in the browser window two lists: one of audio devices and one of video devices, with both the device's label (name) and whether it's an input or an output device. Because the example provides a handler for the {{event("devicechange")}} event, the list is refreshed any time a media device is attached to or removed from the device running the sample.</p> + +<div class="hidden"> +<h3 id="HTML_content">HTML content</h3> + +<pre class="brush: html"><p>Click the start button below to begin the demonstration.</p> +<div id="startButton" class="button"> + Start +</div> +<video id="video" width="160" height="120" autoplay></video><br> + +<div class="left"> + <h2>Audio devices:</h2> + <ul class="deviceList" id="audioList"></ul> +</div> +<div class="right"> + <h2>Video devices:</h2> + <ul class="deviceList" id="videoList"></ul> +</div> + +<div id="log"></div></pre> + +<h3 id="CSS_content">CSS content</h3> + +<pre class="brush: css">body { + font: 14px "Open Sans", "Arial", sans-serif; +} + +video { + margin-top: 20px; + border: 1px solid black; +} + +.button { + cursor: pointer; + width: 160px; + border: 1px solid black; + font-size: 16px; + text-align: center; + padding-top: 2px; + padding-bottom: 4px; + color: white; + background-color: darkgreen; +} + +h2 { + margin-bottom: 4px; +} + +.left { + float:left; + width: 48%; + margin-right: 2% +} + +.right { + float:right; + width: 48%; + margin-left: 2% +} + +.deviceList { + border: 1px solid black; + list-style-type: none; + margin-top: 2px; + padding: 6px; +}</pre> + +<h3 id="JavaScript_content">JavaScript content</h3> + +<h4 id="Other_code">Other code</h4> + +<p>Below is other code which, while needed to make this example work, isn'tt related directly to <code>ondevicechange</code>, so we won't go into any detail.</p> + +<pre class="brush: js">let videoElement = document.getElementById("video"); +let logElement = document.getElementById("log"); + +function log(msg) { + logElement.innerHTML += msg + "<br>"; +} + +document.getElementById("startButton").addEventListener("click", function() { + navigator.mediaDevices.getUserMedia({ + video: { + width: 160, + height: 120, + frameRate: 30 + }, + audio: { + sampleRate: 44100, + sampleSize: 16, + volume: 0.25 + } + }).then(stream => { + videoElement.srcObject = stream; + updateDeviceList(); + }) + .catch(err => log(err.name + ": " + err.message)); +}, false);</pre> +</div> + +<p>We set up global variables that contain references to the {{HTMLElement("ul")}} elements that are used to list the audio and video devices:</p> + +<pre class="brush: js">let audioList = document.getElementById("audioList"); +let videoList = document.getElementById("videoList");</pre> + +<h4 id="Getting_and_drawing_the_device_list">Getting and drawing the device list</h4> + +<p>Now let's take a look at <code>updateDeviceList()</code> itself. This method is called any time we want to fetch the current list of media devices and then update the displayed lists of audo and video devices using that information.</p> + +<pre class="brush: js">function updateDeviceList() { + navigator.mediaDevices.enumerateDevices() + .then(function(devices) { + audioList.innerHTML = ""; + videoList.innerHTML = ""; + + devices.forEach(function(device) { + let elem = document.createElement("li"); + let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i); + + elem.innerHTML = "<strong>" + device.label + "</strong> (" + direction + ")"; + if (type === "audio") { + audioList.appendChild(elem); + } else if (type === "video") { + videoList.appendChild(elem); + } + }); + }); +}</pre> + +<p><code>updateDeviceList()</code> consists entirely of a call to the function {{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}} on the {{domxref("MediaDevices")}} object referenced in the {{domxref("navigator.mediaDevices")}} property, as well as the code that's run when the {{jsxref("promise")}} returned by <code>enumerateDevices()</code> is fulfilled. The fulfillment handler is called when the device list is ready. The list is passed into the fulfillment handler as an array of {{domxref("MediaDeviceInfo")}} objects, each describing one media input or output device.</p> + +<p>A {{jsxref("Array.forEach", "forEach()")}} loop is used to scan through all the devices. For each device, we create a new {{HTMLElement("li")}} object to be used to display it to the user.</p> + +<p>The line <code>let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i);</code> deserves special notice. This uses <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring assignment</a> (a new feature of <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla">ECMAScript 6</a>) to assign the values of the first three items in the array returned by {{jsxref("String.match()")}} to the variables <code>kind</code>, <code>type</code>, and <code>direction</code>. We do this because the value of {{domxref("MediaDeviceInfo.kind")}} is a single string that includes both the media type and the direction the media flows, such as "audioinput" or "videooutput". This line, then, pulls out the type ("audio" or "video") and direction ("input" or "output") so they can be used to construct the string displayed in the list.</p> + +<p>Once the string is assembled, containing the device's name in bold and the direction in parentheses, it's appended to the appropriate list by calling {{domxref("Node.appendChild", "appendChild()")}} on either <code>audioList</code> or <code>videoList</code>, as appropriate based on the device type.</p> + +<h4 id="Handling_device_list_changes">Handling device list changes</h4> + +<p>We call <code>updateDeviceList()</code> in two places. The first is in the {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} promise's fulfillment handler, to initially fill out the list when the stream is opened. The second is in the event handler for {{event("devicechange")}}:</p> + +<pre class="brush: js">navigator.mediaDevices.ondevicechange = function(event) { + updateDeviceList(); +}</pre> + +<p>With this code in place, each time the user plugs in a camera, microphone, or other media device, or turns one on or off, we call <code>updateDeviceList()</code> to redraw the list of connected devices.</p> + +<h3 id="Result">Result</h3> + +<p>{{ EmbedLiveSample('Example', 600, 460) }}</p> + +<h2 id="Specifications">Specifications</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ SpecName('Media Capture', '#dom-mediadevices-ondevicechange', 'ondevicechange') }}</td> + <td>{{ Spec2('Media Capture') }}</td> + <td>Initial specification.</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility">Browser compatibility</h2> + +<div>{{CompatibilityTable}}</div> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatChrome(57)}}</td> + <td>{{CompatGeckoDesktop(51)}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatOpera(34)}}</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android Webview</th> + <th>Chrome for Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatOperaMobile(34)}}</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1] Support for the <code>devicechange</code> event and for {{domxref("MediaDevices.ondevicechange")}} landed in Firefox 51, but <em>only for Mac</em>, and disabled by default. It can be enabled by setting the preference <code>media.ondevicechange.enabled</code> to <code>true</code>. Support for this event was added for Linux and Windows—and it was enabled by default—starting in Firefox 52.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>The {{event("devicechange")}} event and its type, {{domxref("Event")}}.</li> + <li>{{domxref("MediaDevices.enumerateDevices()")}}</li> + <li>{{domxref("MediaDeviceInfo")}}</li> +</ul> |