MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

这篇翻译不完整。请帮忙从英语翻译这篇文章

MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。如果用户给予许可,就返回一个Promise 对象,MediaStream对象作为此Promise对象的Resolved[成功]状态的回调函数参数,相应的,如果用户拒绝了许可,或者没有媒体可用的情况下,PermissionDeniedError 或者NotFoundError作为此Promise的Rejected[失败]状态的回调函数参数。注意,由于用户不会被要求必须作出允许或者拒绝的选择,所以返回的Promise对象可能既不会触发resolve 也不会触发 reject。

 

语法

navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) { ... })
.catch(function(error) { ... })

参数

constraints

作为一个MediaStreamConstraints 对象,指定了请求的媒体类型和相对应的参数。

constraints 参数是一个包含了videoaudio两个成员MediaStreamConstraints 对象,用于说明请求的媒体类型。必须至少一个类型或者两个同时可以被指定。如果浏览器无法找到指定的媒体类型或者无法满足相对应的参数要求,那么返回的Promise对象就会处于rejected[失败]状态,NotFoundError作为rejected[失败]回调的参数。 

以下同时请求不带任何参数的音频和视频:

{ audio: true, video: true }

当由于隐私保护的原因,无法访问用户的摄像头和麦克风信息时,应用可以使用额外的constraints参数请求它所需要或者想要的摄像头和麦克风能力。下面演示了应用想要使用1280x720的摄像头分辨率:

{
  audio: true,
  video: { width: 1280, height: 720 }
}

浏览器会试着满足这个请求参数,但是如果无法准确满足此请求中参数要求或者用户选择覆盖了请求中的参数时,有可能返回其它的分辨率。

强制要求获取特定的尺寸时,可以使用关键字min, max, 或者 exact(就是 min == max). 以下参数表示要求获取最低为1280x720的分辨率。

{
  audio: true,
  video: {
    width: { min: 1280 },
    height: { min: 720 }
  }
}

如果摄像头不支持请求的或者更高的分辨率,返回的Promise会处于rejected状态,NotFoundError作为rejected回调的参数,而且用户将不会得到要求授权的提示。

造成不同表现的原因是,相对于简单的请求值和ideal关键字而言,关键字min, max, 和 exact有着内在关联的强制性,请看一个更详细的例子:

{
  audio: true,
  video: {
    width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 776, ideal: 720, max: 1080 }
  }
}

当请求包含一个ideal(应用最理想的)值时,这个值有着更高的权重,意味着浏览器会先尝试找到最接近指定的理想值的设定或者摄像头(如果设备拥有不止一个摄像头)。

 

简单的请求值也可以理解为是应用理想的值,因此我们的第一个指定分辨率的请求也可以写成如下:

{
  audio: true,
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 }
  }
}

并不是所有的constraints 都是数字。例如, 在移动设备上面,如下的例子表示优先使用前置摄像头(如果有的话):

{ audio: true, video: { facingMode: "user" } }

强制使用后置摄像头,请用:

{ audio: true, video: { facingMode: { exact: "environment" } } }

返回值

返回一个 Promise , 这个Promise成功后的回调函数带一个 MediaStream 对象作为其参数。

异常

返回一个失败状态的Promise,这个Promise失败后的回调函数带一个DOMException对象作为其参数。 可能的异常有:

AbortError[中止错误]
尽管用户和操作系统都授予了访问设备硬件的权利,而且未出现可能抛出NotReadableError异常的硬件问题,但仍然有一些问题的出现导致了设备无法被使用。
NotAllowedError[拒绝错误]
用户拒绝了当前的浏览器实例的访问请求;或者用户拒绝了当前会话的访问;或者用户在全局范围内拒绝了所有媒体访问请求。
较旧版本的规范使用了SecurityError;但在新版本当中SecurityError被赋予了新的意义。
NotFoundError[找不到错误]
找不到满足请求参数的媒体类型。
NotReadableError[无法读取错误]
尽管用户已经授权使用相应的设备,操作系统上某个硬件、浏览器或者网页层面发生的错误导致设备无法被访问。
OverConstrainedError[无法满足要求错误]
指定的要求无法被设备满足,此异常是一个类型为OverconstrainedError的对象,拥有一个constraint属性,这个属性包含了当前无法被满足的constraint对象,还拥有一个message属性,包含了阅读友好的字符串用来说明情况。
因为这个异常甚至可以在用户尚未授权使用当前设备的情况下抛出,所以应当可以当作一个探测设备能力属性的手段[fingerprinting surface]。
SecurityError[安全错误]
getUserMedia() 被调用的 Document 上面,使用设备媒体被禁止。这个机制是否开启或者关闭取决于单个用户的偏好设置。
TypeError[类型错误]
constraints对象未设置[空],或者都被设置为false。

示例

使用Promise

这个例子把返回的MediaStream对象赋值给合适的元素。

var p = navigator.mediaDevices.getUserMedia({ audio: true, video: true });

p.then(function(mediaStream) {
  var video = document.querySelector('video');
  video.src = window.URL.createObjectURL(mediaStream);
  video.onloadedmetadata = function(e) {
    // Do something with the video here.
  };
});

p.catch(function(err) { console.log(err.name); }); // always check for errors at the end.

宽度和高度

这是个使用mediaDevices.getUserMedia()的例子,包含了polyfill来适配旧版的浏览器。

var promisifiedOldGUM = function(constraints) {

  // First get ahold of getUserMedia, if present
  var getUserMedia = (navigator.getUserMedia ||
      navigator.webkitGetUserMedia ||
      navigator.mozGetUserMedia);

  // Some browsers just don't implement it - return a rejected promise with an error
  // to keep a consistent interface
  if(!getUserMedia) {
    return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
  }

  // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
  return new Promise(function(resolve, reject) {
    getUserMedia.call(navigator, constraints, resolve, reject);
  });
		
}

// Older browsers might not implement mediaDevices at all, so we set an empty object first
if(navigator.mediaDevices === undefined) {
  navigator.mediaDevices = {};
}

// Some browsers partially implement mediaDevices. We can't just assign an object
// with getUserMedia as it would overwrite existing properties.
// Here, we will just add the getUserMedia property if it's missing.
if(navigator.mediaDevices.getUserMedia === undefined) {
  navigator.mediaDevices.getUserMedia = promisifiedOldGUM;
}


// Prefer camera resolution nearest to 1280x720.
var constraints = { audio: true, video: { width: 1280, height: 720 } };

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
  var video = document.querySelector('video');
  video.src = window.URL.createObjectURL(stream);
  video.onloadedmetadata = function(e) {
    video.play();
  };
})
.catch(function(err) {
  console.log(err.name + ": " + err.message);
});

帧率

在某些情况下,比如WebRTC上使用受限带宽传输时,低帧率可能更适宜。

var constraints = { video: { frameRate: { ideal: 10, max: 15 } } };

前置或者后置摄像头

在移动设备(电话)上

var front = false;
document.getElementById('flip-button').onclick = function() { front = !front; };

var constraints = { video: { facingMode: (front? "user" : "environment") } };

权限

在一个可安装的app(如Firefox OS app)中使用 getUserMedia() ,你需要在声明文件中指定以下的权限:

"permissions": {
  "audio-capture": {
    "description": "Required to capture audio using getUserMedia()"
  },
  "video-capture": {
    "description": "Required to capture video using getUserMedia()"
  }
}

参见 permission: audio-capturepermission: video-capture 来获取更多信息。

规范

规范 状态 备注
Media Capture and Streams
MediaDevices.getUserMedia()
Editor's Draft 初始定义

浏览器兼容

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Stream API (Yes)[1][3]
47
36 (36) [2] 未实现 (Yes)[1] 未实现
Feature Android Android Webview Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile Chrome for Android 
Stream API 未实现 未实现 36.0 (36) [2] 未实现 未实现 未实现 未实现

[1] 旧版本的Chrome或Opera浏览器使用navigator.webkitGetUserMedia--navigator.getUserMedia的历史版本。

在Chrome(版本号47-52)中, 这种基于Promise的接口只能通过 adapter.js 提供, 或者使用 flag chrome://flags/#enable-experimental-web-platform-features来开启。从版本53开始,这种基于Promise的接口被默认开启,但仍未在navigator中提供。

[2] 旧版本的Firefox浏览器使用navigator.mozGetUserMedia()--navigator.getUserMedia的历史版本。

上述的此方法的基于Promise的版本与约束语法在Firefox的38版本开始支持。早先版本(32-37)使用了过时的约束语法,但可以通过adapter.js使用新的约束语法。

这里提到的这种基于Promise的接口与约束语法只在Firefox的38以上的版本提供。早先的版本 (32-37) 使用了过时的约束语法,但是这里提到的这种新的基于Promise的接口与约束语法,可以通过adapter.js 使用。

Firefox 49 includes changes to bring the thrown exceptions up to date with the specification, including the change to the meaning of the SecurityError exception.

Opera使用了过时的约束语法, 但新的约束语法可以通过adapter.js使用。

[3] Chrome throws error if the page serving the script is loaded from insecure origin (i.e. HTTP).

参考

文档标签和贡献者

 此页面的贡献者: CauserLee, xgqfrms-GitHub, c1ngular
 最后编辑者: CauserLee,