MediaDevices:devicechange 事件

安全上下文:此功能仅在安全上下文(HTTPS)中可用,且仅在部分或全部支持的浏览器中可用。

每当将媒体设备(例如摄像头、麦克风或扬声器)连接到系统或从系统中移除时,都会向MediaDevices实例发送devicechange事件。

此事件不可取消,也不冒泡。

语法

在诸如addEventListener()之类的 方法中使用事件名称,或设置事件处理程序属性。

js
addEventListener("devicechange", (event) => {});

ondevicechange = (event) => {};

事件类型

一个通用的Event

示例

在此示例中,我们创建一个名为 updateDeviceList() 的函数,该函数在MediaDevices.getUserMedia()成功获取流时调用一次,然后在设备列表发生更改时调用。它在浏览器窗口中显示两个列表:一个音频设备列表和一个视频设备列表,两个列表都显示设备的标签(名称)以及它是输入设备还是输出设备。由于该示例为 devicechange 事件提供了一个处理程序,因此每次将媒体设备连接到或从运行示例的设备上移除时,列表都会刷新。

我们设置了全局变量,这些变量包含对用于列出音频和视频设备的<ul>元素的引用

js
const audioList = document.getElementById("audioList");
const videoList = document.getElementById("videoList");

获取和绘制设备列表

现在让我们看一下 updateDeviceList() 本身。每当我们想要获取当前的媒体设备列表,然后使用该信息更新显示的音频和视频设备列表时,都会调用此方法。

js
function updateDeviceList() {
  navigator.mediaDevices.enumerateDevices().then((devices) => {
    audioList.textContent = "";
    videoList.textContent = "";

    devices.forEach((device) => {
      const elem = document.createElement("li");
      const [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);
      }
    });
  });
}

updateDeviceList() 完全由对enumerateDevices()函数(在navigator.mediaDevices属性中引用的MediaDevices对象上)的调用以及 enumerateDevices() 返回的promise 完成时运行的代码组成。当设备列表准备就绪时,将调用完成处理程序。该列表作为MediaDeviceInfo对象的数组传递到完成处理程序中,每个对象描述一个媒体输入或输出设备。

一个forEach()循环用于扫描所有设备。对于每个设备,我们创建一个新的<li>对象,用于将其显示给用户。

let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i); 这一行值得特别注意。它使用解构赋值String.match()返回的数组中的前三个项目的value分配给变量 kindtype 和 direction。我们这样做是因为MediaDeviceInfo.kind的值是一个包含媒体类型和媒体流方向(例如“audioinput”或“videooutput”)的单个字符串。然后,此行提取类型(“audio”或“video”)和方向(“input”或“output”),以便可以将其用于构建显示在列表中的字符串。

组装好字符串后,该字符串包含设备名称(加粗)和方向(括号内),然后通过在相应的 audioList 或 videoList 上调用appendChild()将其附加到相应的列表中,具体取决于设备类型。

处理设备列表更改

我们在两个地方调用 updateDeviceList()。第一个是在getUserMedia() promise 的完成处理程序中,在打开流时最初填充列表。第二个是在此 devicechange 事件的事件处理程序中

js
navigator.mediaDevices.ondevicechange = (event) => {
  updateDeviceList();
};

有了这段代码,每次用户插入摄像头、麦克风或其他媒体设备,或打开或关闭某个设备时,我们都会调用 updateDeviceList() 来重新绘制连接设备的列表。

结果

规范

规范
媒体捕获和流
# event-mediadevices-devicechange
媒体捕获和流
# dom-mediadevices-ondevicechange

浏览器兼容性

BCD 表格仅在启用了 JavaScript 的浏览器中加载。