遍历音视频设备

正如第 4 章中所述,进行一对一通信之前,需要对设备进行检测,看看主机上都支持哪些设备。在浏览器上遍历音视频设备特别简单,调用 enumerateDevices() 接口即可,其原型参见代码 5.1。

代码5.1 enumerateDevices()接口格式
navigater.mediaDevices.enumerateDevices();
代码5.2 MediaDeviceInfo结构体
interface MediaDeviceInfo {
  readonly attribute DOMString deviceId;
  readonly attribute MediaDeviceKind kind;
  readonly attribute DOMString label;
  readonly attribute DOMString groupId;
}

enum MediaDeviceKind {
  "audioinput",
  "audiooutput",
  "videoinput"
}

下面详细介绍一下 MediaDeviceInfo 结构。从上面的代码中可以看到,MediaDeviceInfo 包括 4 个属性,分别是 deviceIdkindlabelgroupId

deviceId 表示每个设备的唯一编号,通过该编号可以从 WebRTC 的音视频设备管理中找到该设备。

kind 表示设备的种类。音视频设备包括三种类型:音频输入设备、音频输出设备以及视频输入设备。音频的输入设备和输出设备是两种不同类型的设备。而对于视频设备来说,它只有输入设备,视频的输出则是由显示器完成的。由于显示器是默认设备,所以不需要通过音视频设备管理器进行管理。

label 是设备的名字。该名字是便于人们记忆的名字,不像 deviceId 那样是一串毫无规律的字符串。

groudId 表示组 Id。如果两个设备是在同一个硬件上,则它们属于同一组,因此它们的 groupId 是一致的,例如音频的输入与输出设备就是集成到一起的。

现在 enumerateDevices() 接口的作用及其参数含义你已经清楚了,下面我们来了解一下如何调用 enumerateDevices() 接口。在浏览器上使用 JavaScript 调用 enumerate Devices() 时,与我们通常使用 C/C++ 等语言调用接口的方式有些不同,JavaScript 采用 Promise 方式调用 enumerateDevices() 接口。关于 Promise 的内容在这里就不做进一步讲解了,如果你对其不熟悉,可以自行在网上查找相关内容。下面看一下使用 enumerate Devices() 接口的具体例子,如代码 5.3 所示。

代码5.3 枚举音视频设备
// 如果遍历设备失败,则回调该函数
function handleError(error) {
  console.log('err:', error);
}

// 如果得到音视频设备,则回调该函数
function gotDevices(deviceInfos) {
  // 遍历所有设备信息
  for (let i = 0; i !== deviceInfos.length; ++i) {
    // 取每个设备信息
    const deviceInfo = deviceInfos[i];
    // ...
  }
  // ...
}

// 遍历所有音视频设备
navigator.mediaDevices.enumerateDevices()
  .then(gotDevices)
  .catch(handleError);

当将上面的代码片段生成 js 文件放到浏览器下执行时,浏览器首先从第 19 行处的代码开始执行,即调用 enumerateDevices() 接口获得主机上的所有音视频设备。如果 enumerate Devices() 函数执行成功,则会回调 gotDevices() 方法,该方法的输入参数 deviceInfos 中存放的就是通过 enumerateDevices() 获得的所有音视频设备的信息。此时,可以通过一个 for 循环来遍历每一项设备信息。如果 enumerateDevices() 函数执行失败,则回调 handleError() 函数,此时可以通过该函数将错误信息打印出来。

这里需要注意的是,基于安全方面的原因,浏览器有可能不允许调用 enumerateDevices() 函数,此时需要手工将浏览器的安全访问设置为允许。另外,测试时最好使用 Chrome 浏览器,因为它对 WebRTC 的支持最全。