Web API WebRTC.getUserMedia() 方法
MediaDevices.getUserMedia() 是 webRTC 媒体捕获 API 的一部分,用于从浏览器访问连接到用户设备(用户计算机、智能手机等)的摄像头和麦克风。当调用getUserMedia()时,浏览器会请求用户允许使用连接到用户设备的媒体输入(相机或麦克风或两者)。
句法 :
navigator.mediaDevices.getUserMedia( MediaStreamConstraints )
.then( MediaStream => {
// Code that uses the MediaStream
}).catch( error => {
// Code to handle the error
});
使用 getUserMedia() API: getUserMedia()可以通过访问navigator.mediaDevices单例对象来访问,该对象提供了访问摄像头、麦克风以及屏幕共享的各种方法。调用getUserMedia( ) 时,浏览器会提示用户访问可用设备摄像头或麦克风的权限(基于给定的MediaStreamConstraints参数)。如果用户授予权限,则它返回一个解析为MediaStream的 Promise。
注意: getUserMedia()也可以通过navigator.getUserMedia()访问,但它已被弃用,因此不推荐使用。
什么是媒体流?
MediaStream 只是不保存在设备内存中的音频或视频内容数据流,而只是作为源数据“传递”到特定的视频或音频元素。请注意,媒体内容数据不会保存在运行内存中,这意味着如果您没有“预下载”的视频或音频数据,您仍然可以使用媒体流来播放视频或音频内容。不需要下载。
什么是媒体流约束?
MediaStreamConstraints 是一个包含所有约束的对象,例如要流式传输的数据类型(视频或音频或两者),相机的分辨率应该是多少等。
const mediaStreamConstraints = {
audio: true,
video: true
};
// It basically tells the getUserMedia() to
// open both the camera and the microphone
const stream = await navigator.mediaDevices
.getUserMedia(mediaStreamConstraints);
使用从 getUserMedia() 接收的 MediaStream:如果用户授予访问相机和麦克风的权限,则此方法返回一个 Promise,其实现处理程序接收一个我们可以在处理程序函数中使用的 MediaStream。通常,我们将接收到的 MediaStream 传递给一个视频或音频元素作为源(使用视频或音频元素的srcObject属性)。
Javascript
navigator.mediaDevices.getUserMedia( MediaStreamConstraints )
.then( MediaStream => {
/*assuming that there is a video tag having
an id 'video' in the index.html*/
const videoElem = document.getElementById( 'video');
/*it is important to use the srcObject
attribute and not the src attribute
because, the src attribute does not
support the mediaStream as a value*/
videoElem.srcObject = mediaStream;
//Don't forget to set the autoplay attribute to true
video.autoplay = true;
}).catch( error => {
//code to handle the error
});
//Or using async/await —
async function accessCamera() {
const videoElem = document.getElementById( 'video');
let stream = null;
try{
stream = await navigator.mediaDevices.getUserMedia(
MediaStreamConstraints );
//adding the received stream to the source of the video element
videoElem.srcObject = stream;
videoElem.autoplay = true;
}catch(err) {
//code to handle the error
}
}
Javascript
/* This constraints object tells the browser to
use the camera having 1200 X 800 resolution if available*/
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
width: 1200,
height: 800
}
// Inherently sets video content to true or "required"
};
Javascript
/* This constraints object tells the browser to use the camera
having resolution between 1200 X 720 and 1600 X 1080 resolution
if available otherwise the returned promise is rejected with
"NotFoundError" */
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
width: {
min: 1200,
max: 1600
},
height: {
min: 720,
max: 1080
}
}
}; // Inherently sets video content to true or "required"
Javascript
//initializing the deviceId with null
let deviceId = null;
//returns a promise that resolves to a list of
//connected devices
navigator.mediaDevices.enumerateDevices()
.then( devices => {
devices.forEach(device => {
//if the device is a video input
//then get its deviceId
if(device.kind === 'videoinput'){
deviceId = device.deviceId;
}
});
})
.catch(err => {
//handle the error
});
/* This constraints object tells the browser to
use the camera having the given deviceId if
available otherwise use other available devices*/
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
deviceId: deviceId
}
}; // Inherently sets video content to true or "required"
Javascript
// This constraints object tells the browser to use the camera having
exactly the given deviceId if available otherwise the returned
promise is rejected with "NotFoundError" */
const constraints = {
audio: {
/* browser prefers the device having the given
deviceId if available otherwise use other devices*/
deviceId: audioDeviceId
},
video: {
deviceId: {
exact: someId
}
}
}; // Inherently sets video and audio content to true or "required"
Javascript
/* This constraints object tells the browser
to use the camera having 1200 X 800
resolution if available */
const constraints = {
audio: true //enable the audio media track
video: {
width: 1200, // same as width: {ideal: 1200}
height: 800 // same as height: {ideal: 800}
}
}; // Inherently sets video content to true or "required"
Javascript
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
facingMode: "user" //prefers front camera if available
// or facingMode: "environment" --> perfers rear camera if available
}
}; // Inherently sets video content to true or "required"
HTML
GetUserMedia demo
WebRTC getUserMedia() demo
HTML
GetUserMedia demo
WebRTC getUserMedia() demo
如果用户不授予访问摄像头和麦克风的权限怎么办?
如果用户拒绝授予权限,则 getUserMedia() 会抛出NotAllowedError ,我们可以使用 catch 块捕获该错误。如果用户只是忽略了提示,那么什么都不会发生(promise 永远不会被解决也不会被拒绝)。
现在,让我们更详细地讨论MediaStreamConstraints :
媒体流约束:
这基本上是一个对象,其中包含有关要使用的媒体类型、相机的分辨率、用作媒体输入的设备等所有信息。最简单的 MediaStreamConstraints 对象如下所示 -
const constraints = {
audio: false, // or true if you want to enable audio
video: true // or false if you want to disable video
}; // Includes only the video media if available
MediaStreamConstraints 对象只有两个属性(成员):音频和视频,它们都接受一个布尔值,告诉浏览器是否在生成的媒体流中包含该特定媒体内容。 “true”使媒体在结果媒体流中成为“必需”,如果“必需”媒体不可用,则 getUserMedia() 抛出“NotFoundError”。例如,如果用户设备没有摄像头,getUserMedia() 将针对上述约束抛出“NotFoundError”。
此外,您可以添加更多限制以使用具有某些首选功能的媒体内容:
您可以指定浏览器应该首选的相机分辨率:
Javascript
/* This constraints object tells the browser to
use the camera having 1200 X 800 resolution if available*/
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
width: 1200,
height: 800
}
// Inherently sets video content to true or "required"
};
“首选”是因为上述约束对象并不能确保浏览器将使用具有该分辨率的相机。浏览器首先检查是否有任何类型的媒体输入与给定的约束匹配,如果有,则只有浏览器使用匹配的媒体输入。但是,如果没有匹配给定约束的设备,则浏览器使用最匹配的设备。
但是,如果您想让某些功能“必需”或强制或对功能应用一些限制,那么您可以使用各种关键字:
- “min”和“max”关键字:
正如关键字名称所暗示的那样,“ min ”关键字告诉浏览器相应的媒体必须至少具有给定的功能,类似地,“ max”关键字告诉浏览器这是强制性的使相应的媒体至多具有指定的约束。如果没有这样的媒体输入设备满足给定的约束,则返回的 Promise 会被“NotFoundError”拒绝。
Javascript
/* This constraints object tells the browser to use the camera
having resolution between 1200 X 720 and 1600 X 1080 resolution
if available otherwise the returned promise is rejected with
"NotFoundError" */
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
width: {
min: 1200,
max: 1600
},
height: {
min: 720,
max: 1080
}
}
}; // Inherently sets video content to true or "required"
- “deviceId”关键字:
“ deviceId ”属性要求浏览器使用具有给定 deviceId 的媒体输入设备(如果可用),否则使用其他可用的输入设备。 deviceId 可以从navigator.mediaDevices.enumerateDevices()方法获得,该方法返回一个 Promise,该 Promise 解析为连接的相机、麦克风、耳机等的列表。每个连接的设备都有一个唯一且不可猜测的 ID,称为“deviceId”。
Javascript
//initializing the deviceId with null
let deviceId = null;
//returns a promise that resolves to a list of
//connected devices
navigator.mediaDevices.enumerateDevices()
.then( devices => {
devices.forEach(device => {
//if the device is a video input
//then get its deviceId
if(device.kind === 'videoinput'){
deviceId = device.deviceId;
}
});
})
.catch(err => {
//handle the error
});
/* This constraints object tells the browser to
use the camera having the given deviceId if
available otherwise use other available devices*/
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
deviceId: deviceId
}
}; // Inherently sets video content to true or "required"
3. “精确”关键字:
“exact”属性告诉浏览器必须使用具有完全相应约束的媒体
Javascript
// This constraints object tells the browser to use the camera having
exactly the given deviceId if available otherwise the returned
promise is rejected with "NotFoundError" */
const constraints = {
audio: {
/* browser prefers the device having the given
deviceId if available otherwise use other devices*/
deviceId: audioDeviceId
},
video: {
deviceId: {
exact: someId
}
}
}; // Inherently sets video and audio content to true or "required"
4.“理想”属性:
“理想”属性告诉浏览器给定的约束值是理想值,应该使用具有“理想”约束的设备。任何正常的属性值本质上都是理想的
Javascript
/* This constraints object tells the browser
to use the camera having 1200 X 800
resolution if available */
const constraints = {
audio: true //enable the audio media track
video: {
width: 1200, // same as width: {ideal: 1200}
height: 800 // same as height: {ideal: 800}
}
}; // Inherently sets video content to true or "required"
5.“面临模式”属性:
指定是否使用前置摄像头或后置摄像头(如果可用)。它主要用于移动设备。
Javascript
const constraints = {
//disables the audio media content in the resulting media stream
audio: false,
video: {
facingMode: "user" //prefers front camera if available
// or facingMode: "environment" --> perfers rear camera if available
}
}; // Inherently sets video content to true or "required"
使用 getUserMedia() 的示例:
HTML
GetUserMedia demo
WebRTC getUserMedia() demo
输出:
现在,如果您单击“打开相机”按钮,浏览器将询问您的许可,如果您允许,那么您将在屏幕上看到自己。但如果你否认,那么你可以在红色框中看到视频元素正下方的错误:
如何关闭相机和麦克风:
到目前为止,我们已经讨论了如何从浏览器打开摄像头,我们还没有停止使用摄像头和麦克风。但是,如果您关闭选项卡或窗口,浏览器会自动停止使用摄像头和麦克风。但是如果你想自己关闭相机和麦克风,那么你可以按照下面的代码
示例 2:首先,添加“关闭相机”按钮和“closeCamera() 方法。
HTML
GetUserMedia demo
WebRTC getUserMedia() demo
输出:
前:
点击“关闭相机”按钮后:
closeCamera()方法通过检查 receivedMediaStream 变量来检查相机和麦克风是否都关闭。如果为null,则表示摄像头和麦克风都关闭,否则调用接收到的MediaStream的getTracks()方法,返回MediaStreamTracks数组。您可以通过调用其stop()方法来停止这些媒体轨道。