Capabilities、Constraints 和 Settings
Capabilities 是浏览器或媒体硬件设备可以提供的某方面的能力,还会附带所支持的指标范围。例如对于麦克风,采样频率有一个支持的范围;摄像头受硬件所限,支持的分辨率也是一个有限的范围。
Constraints(约束)是我们在请求媒体轨道时,指定所期望的能力及其指标,浏览器将尽可能满足这些约束。在之前的章节中出现的navigator.mediaDevices.getUserMedia()
调用中所传入的audio
和video
属性对象(非 boolean 值)即为约束。
Settings 是根据请求者所提供的 Constraints,最终获得的轨道的实际指标。
获取 InputDeviceInfo 的 Capabilities
通过mediaDevices.enumerateDevices()
获得的设备列表,其中的输入设备(kind
为audioinput
或videoinput
)为InputDeviceInfo
接口。
可通过调用inputDeviceInfo.getCapabilities()
获得某个设备的 Capabilities。
const devices = await navigator.mediaDevices.enumerateDevices();
const camera = devices.find(d => d.kind === "videoinput");
camera.getCapabilities(); /*
{
"aspectRatio": {
"max": 2560,
"min": 0.0006944444444444445
},
"deviceId": "ea3ff7be276fe47df7a03f80edb081a71bc3f2f14ce1bd88dc568c555f679f16",
"facingMode": [],
"frameRate": {
"max": 30,
"min": 1
},
"groupId": "2f7a0611aca123fc0106601ba80fc3e0cacb97d2e67cf768fdc30ad57194425c",
"height": {
"max": 1440,
"min": 1
},
"resizeMode": [
"none",
"crop-and-scale"
],
"width": {
"max": 2560,
"min": 1
}
}
*/
从上例可以看出,当前系统的摄像头支持 2K 分辨率采样,最大帧率为 30。
检查浏览器支持的 Constraints
mediaDevices.getSupportedConstraints()
方法返回浏览器支持的约束项。调用getUserMedia()
或getDisplayMedia()
时传入不支持的约束项,浏览器会静默忽略。getSupportedConstraints()
方法返回的信息提供了约束的支持情况,所有类型(音频和视频)的媒体约束都会混合在一起。
navigator.mediaDevices.getSupportedConstraints(); /*
{
"aspectRatio": true,
"autoGainControl": true,
"brightness": true,
"channelCount": true,
"colorTemperature": true,
"contrast": true,
"deviceId": true,
"displaySurface": true,
"echoCancellation": true,
"exposureCompensation": true,
"exposureMode": true,
"exposureTime": true,
"facingMode": true,
"focusDistance": true,
"focusMode": true,
"frameRate": true,
"groupId": true,
"height": true,
"iso": true,
"latency": true,
"noiseSuppression": true,
"pan": true,
"pointsOfInterest": true,
"resizeMode": true,
"sampleRate": true,
"sampleSize": true,
"saturation": true,
"sharpness": true,
"suppressLocalAudioPlayback": true,
"tilt": true,
"torch": true,
"voiceIsolation": true,
"whiteBalanceMode": true,
"width": true,
"zoom": true
}
*/
获取 MediaStreamTrack 的 Capabilities
可通过mediaStreamTrack.getCapabilities()
得到轨道对应设备的 Capabilities,方便后续调整 Constraints。
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const audioTrack = stream.getAudioTracks()[0];
audioTrack.getCapabilities(); /*
{
"autoGainControl": [
true,
false
],
"channelCount": {
"max": 2,
"min": 1
},
"deviceId": "default",
"echoCancellation": [
true,
false
],
"groupId": "74d7e3c7a9f43d956684714504d74e3533d49b65d60129da8515b1ed77dbcbaf",
"latency": {
"max": 0.021333,
"min": 0.01
},
"noiseSuppression": [
true,
false
],
"sampleRate": {
"max": 48000,
"min": 48000
},
"sampleSize": {
"max": 16,
"min": 16
},
"voiceIsolation": [
true,
false
]
}
*/
从上例可以看出,当前系统的麦克风最大支持双声道(channelCount
为 2),但仅支持 48kHz 一种采样频率。
获取/应用 MediaStreamTrack 的 Constraints
可以从mediaStreamTrack.getConstraints()
得到产生轨道时所用的约束,它是MediaTrackConstraints
接口对象。
可以调用mediaStreamTrack.applyConstraints()
使用新的约束来调整现有轨道:
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 640,
height: 360,
},
});
const videoTrack = stream.getVideoTracks()[0];
videoTrack.getConstraints(); /*
{
"height": 360,
"width": 640
}
*/
await videoTrack.applyConstraints({
width: 1280,
height: 720,
});
videoTrack.getConstraints(); /*
{
"height": 720,
"width": 1280
}
*/
获取 MediaStreamTrack 的 Settings
在获得了轨道之后,可以检查轨道当前实际使用的各项能力的指标。调用mediaStreamTrack.getSettings()
来获得这些值。
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 640,
height: 360,
},
});
const videoTrack = stream.getVideoTracks()[0];
videoTrack.getConstraints(); /*
{
"height": 360,
"width": 640
}
*/
videoTrack.getSettings(); /*
{
"aspectRatio": 1.7777777777777777,
"brightness": 128,
"colorTemperature": 4000,
"contrast": 128,
"deviceId": "ea3ff7be276fe47df7a03f80edb081a71bc3f2f14ce1bd88dc568c555f679f16",
"focusDistance": 0,
"focusMode": "continuous",
"frameRate": 30,
"groupId": "6a784b6fd71f7b51d7388cb6db75e98ec8f18a5d0b486a73eefa0841eb834235",
"height": 360,
"resizeMode": "none",
"saturation": 128,
"sharpness": 128,
"whiteBalanceMode": "continuous",
"width": 640
}
*/
await videoTrack.applyConstraints({
width: 1280,
height: 720,
});
videoTrack.getConstraints(); /*
{
"height": 720,
"width": 1280
}
*/
videoTrack.getSettings(); /*
{
"aspectRatio": 1.7777777777777777,
"brightness": 128,
"colorTemperature": 4000,
"contrast": 128,
"deviceId": "ea3ff7be276fe47df7a03f80edb081a71bc3f2f14ce1bd88dc568c555f679f16",
"focusDistance": 0,
"focusMode": "continuous",
"frameRate": 30,
"groupId": "6a784b6fd71f7b51d7388cb6db75e98ec8f18a5d0b486a73eefa0841eb834235",
"height": 720,
"resizeMode": "none",
"saturation": 128,
"sharpness": 128,
"whiteBalanceMode": "continuous",
"width": 1280
}
*/
在上例中,我们先请求了一个包含较小分辨率视频轨的流,通过mediaStreamTrack.getSettings()
完成了验证。
随后我们通过mediaStreamTrack.applyConstraints()
更新了该轨道的 Constrains,然后重新调用mediaStreamTrack.getSettings()
,发现新的 Constraints 已经成功应用。