采集音视频数据
通过 enumerateDevices() 接口获得音视频设备后,就可以选择其中的设备进行数据采集了。在浏览器下采集音视频数据也很方便,调用 getUserMedia() 这个 API 就可以采集到。getUserMedia 的接口格式如代码 5.4 所示。
navigator.mediaDevices.getUserMedia(MediaStreamConstrains);
该接口有一个 MediaStreamConstrains 类型的输入参数,可以用来控制从哪个设备上采集音视频数据,以及限制采集到的数据的格式,如限制采集到的视频分辨率、音频数据的采样率、采样大小等。其结构如代码 5.5 所示。
dictionary MediaStreamConstrains {
(boolean) or (MediaTrackConstrains) video = false;
(boolean) or (MediaTrackConstrains) audio = false;
}
从上面 MediaStreamConstrains 类型的定义可以看出,video 和 audio 属性既可以是 boolean 类型,也可以是 MediaTrackConstrains 类型(只有像 JavaScript 这种弱类型语言才可以做这一点)。因此,我们既可以直接给 video 和 audio 赋值 true/false,简单地指明是否采集视频或音频数据,也可以给它赋值一个 MediaTrackConstrains 类型的值,对音视频设备做更精准的设置。
如果直接给 video/audio 属性赋值 true,则浏览器会使用默认设备和默认参数采集音视频数据,否则如果给 video/audio 赋值 MediaTrackConstrains 类型值,则浏览器会按 MediaTrackConstrains 中的限制,从指定的设备中采集音视频数据。MediaTrackConstrains 结构如代码 5.6 所示。
dictionary MediaTrackConstraintSet {
// 视频相关
ConstrainULong width;
ConstrainULong height;
ConstrainDouble aspectRatio; // 宽高比
ConstrainDouble frameRate;
ConstrainDOMString facingMode; // 前置/后置摄像头
ConstrainDOMString resizeMode; // 缩放或裁剪
// 音频相关
ConstrainULong sampleRate;
ConstrainULong sampleSize;
ConstrainBoolean echoCancellation;
ConstrainBoolean autoGainControl;
ConstrainBoolean noiseSuppression;
ConstrainDouble latency; // 目标延迟
ConstrainULong channelCount;
// 设备相关
ConstrainDOMString deviceId;
ConstrainDOMString groupId;
};
从上面的代码片段中可以看到,MediaTrackConstrains 结构由三部分组成,即视频相关属性、音频相关属性以及设备相关属性。视频属性中包括分辨率、视频宽高比、帧率、前置/后置摄像头、视频缩放;音频属性包括采样率、采样大小、是否开启回音消除、是否开启自动增益、是否开启降噪、目标延迟、声道数;设备相关属性包括设备ID、设备组ID。
我们来看一个具体的例子,看看如何通过 getUserMedia() 接口来采集音视频数据。具体代码参见代码 5.7。
// 采集到某路流
function gotMediaStream(stream) {
// ...
}
// 从设备选项栏里选择某个设备
var deviceId = xxx;
// 设置采集限制
var constraints = {
video: {
width: 640,
height: 480,
frameRate: 15,
facingMode: 'environment',
deviceId: deviceId ? { exact: deviceId } : undefined
},
audio: false
};
// 开始采集数据
navigator.mediaDevices.getUserMedia(constraints)
.then(gotMediaStream)
.catch(handleError);
// ...
在上面的代码片段中,首先执行第 22 行代码,即调用 getUserMedia() 接口,然后根据 constraints 中的限制获取音视频数据。在这个例子中,getUserMedia() 从指定设备(deviceId)上按指定参数采集视频数据,具体参数如下:分辨率为 640×480、帧率为 15 帧/秒、使用后置摄像头(environment)。因为 audio 属性为 false,所以此例中仅采集视频数据而不采集音频数据。
此外,从上面的代码中还可以看到,调用 getUserMedia() 接口的方式与调用 enumerateDevices() 接口的方式是一样的,也是使用 Promise 方式。当调用 getUserMedia() 成功时,会回调 gotMediaStream() 函数,该函数的输入参数 MediaStream 里存放的就是音视频数据流。当获得音视频数据后,既可以把它作为本地预览,也可以将它传送给远端,从而实现一对一通信。如果调用 getUserMedia() 接口失败,则调用错误处理函数 handleError。