📜  Web API WebRTC.getUserMedia() 方法

📅  最后修改于: 2022-05-13 01:56:26.549000             🧑  作者: Mango

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()方法来停止这些媒体轨道。