MediaDevices
.getUserMedia()
method prompts the user for permission to use a media input which produces a
MediaStream
with tracks containing the requested types of media.
That stream can include, for example, a video track (produced by either a hardware or virtual video source such as a camera, video recording device, screen sharing service, and so forth), an audio track (similarly, produced by a physical or virtual audio source like a microphone, A/D converter, or the like), and possibly other track types.
It returns a
Promise
解析为
MediaStream
object. If the user denies permission, or matching media is not available, then the promise is rejected with
NotAllowedError
or
NotFoundError
分别。
注意: It's possible for the returned promise to neither resolve nor reject, as the user is not required to make a choice at all and may simply ignore the request.
Generally, you will access the
MediaDevices
singleton object using
navigator.mediaDevices
,像这样:
async function getMedia(constraints) {
let stream = null;
try {
stream = await navigator.mediaDevices.getUserMedia(constraints);
/* use the stream */
} catch(err) {
/* handle the error */
}
}
Similarly, using the raw promises directly, the code looks like this:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
/* use the stream */
})
.catch(function(err) {
/* handle the error */
});
注意:
If the current document isn't loaded securely,
navigator.mediaDevices
将是
undefined
, and you cannot use
getUserMedia()
。见
安全性
for more information on this and other security issues related to using
getUserMedia()
.
var promise = navigator.mediaDevices.getUserMedia(constraints);
constraints
A
MediaStreamConstraints
object specifying the types of media to request, along with any requirements for each type.
constraints
parameter is a
MediaStreamConstraints
object with two members:
视频
and
audio
, describing the media types requested. Either or both must be specified. If the browser cannot find all media tracks with the specified types that meet the constraints given, then the returned promise is rejected with
NotFoundError
.
The following requests both audio and video without any specific requirements:
{ audio: true, video: true }
若
true
is specified for a media type, the resulting stream is
required
to have that type of track in it. If one cannot be included for any reason, the call to
getUserMedia()
will result in an error.
While information about a user's cameras and microphones are inaccessible for privacy reasons, an application can request the camera and microphone capabilities it needs and wants, using additional constraints. The following expresses a preference for 1280x720 camera resolution:
{
audio: true,
video: { width: 1280, height: 720 }
}
The browser will try to honour this, but may return other resolutions if an exact match is not available, or the user overrides it.
到
require
a capability, use the keywords
min
,
max
,或
exact
(也称为
min == max
). The following demands a minimum resolution of 1280x720:
{
audio: true,
video: {
width: { min: 1280 },
height: { min: 720 }
}
}
If no camera exists with this resolution or higher, then the returned promise will be rejected with
OverconstrainedError
, and the user will not be prompted.
The reason for the difference in behaviour is that the keywords
min
,
max
,和
exact
are inherently mandatory. Whereas plain values and a keyword called
ideal
are not. Here's a full example:
{
audio: true,
video: {
width: { min: 1024, ideal: 1280, max: 1920 },
height: { min: 576, ideal: 720, max: 1080 }
}
}
An
ideal
value, when used, has gravity, which means that the browser will try to find the setting (and camera, if you have more than one), with the smallest
fitness distance
from the ideal values given.
Plain values are inherently ideal, which means that the first of our resolution examples above could have been written like this:
{
audio: true,
video: {
width: { ideal: 1280 },
height: { ideal: 720 }
}
}
Not all constraints are numbers. For example, on mobile devices, the following will prefer the front camera (if one is available) over the rear one:
{ audio: true, video: { facingMode: "user" } }
到 require the rear camera, use:
{ audio: true, video: { facingMode: { exact: "environment" } } }
Another non-number constraint is the
deviceId
constraint. If you have a
deviceId
from
mediaDevices.enumerateDevices()
, you can use it to request a specific device:
{ video: { deviceId: myPreferredCameraDeviceId } }
The above will return the camera you requested, or a different camera if that specific camera is no longer available. Again, to require the specific camera, you would use:
{ video: { deviceId: { exact: myExactCameraOrBustDeviceId } } }
A
Promise
whose fulfillment handler receives a
MediaStream
object when the requested media has successfully been obtained.
Rejections of the returned promise are made by passing a
DOMException
error object to the promise's failure handler. Possible errors are:
AbortError
NotReadableError
, some problem occurred which prevented the device from being used.
NotAllowedError
SecurityError
for this instead;
SecurityError
has taken on a new meaning.
NotFoundError
No media tracks of the type specified were found that satisfy the given constraints.
NotReadableError
Although the user granted permission to use the matching devices, a hardware error occurred at the operating system, browser, or Web page level which prevented access to the device.
OverconstrainedError
OverconstrainedError
, and has a
constraint
property whose string value is the name of a constraint which was impossible to meet, and a
message
property containing a human-readable string explaining the problem.
Because this error can occur even when the user has not yet granted permission to use the underlying device, it can potentially be used as a fingerprinting surface.
SecurityError
Document
on which
getUserMedia()
was called. The mechanism by which user media support is enabled and disabled is left up to the individual user agent.
TypeError
false
. This can also happen if you try to call
getUserMedia()
in an insecure context, since
navigator.mediaDevices
is
undefined
in an insecure context.
As an API that may involve significant privacy concerns,
getUserMedia()
's specification lays out a wide array of privacy and security requirements that browsers are obligated to meet.
getUserMedia()
is a powerful feature which can only be used in
安全上下文
; in insecure contexts,
navigator.mediaDevices
is
undefined
, preventing access to
getUserMedia()
. A secure context is, in short, a page loaded using HTTPS or the
file:///
URL scheme, or a page loaded from
localhost
.
In addition, user permission is always required to access the user's audio and video inputs. Only a window's top-level document context for a valid origin can even request permission to use
getUserMedia()
, unless the top-level context expressly grants permission for a given
<iframe>
to do so using
Feature Policy
. Otherwise, the user will never even be asked for permission to use the input devices.
For additional details on these requirements and rules, how they are reflected in the context in which your code is running, and about how browsers manage user privacy and security issues, read on.
As an API that may involve significant privacy concerns,
getUserMedia()
is held by the specification to very specific requirements for user notification and permission management. First,
getUserMedia()
must always get user permission before opening any media gathering input such as a webcam or microphone. Browsers may offer a once-per-domain permission feature, but they must ask at least the first time, and the user must specifically grant ongoing permission if they choose to do so.
Of equal importance are the rules around notification. Browsers are required to display an indicator that shows that a camera or microphone is in use, above and beyond any hardware indicator that may exist. They must also show an indicator that permission has been granted to use a device for input, even if the device is not actively recording at the moment.
For example in Firefox, the URL bar displays a pulsing red icon to indicate that recording is underway. The icon is gray if the permission is in place but recording is not currently underway. The device's physical light is used to indicate whether or not recording is currently active. If you've muted your camera (so-called "facemuting"), your camera's activity light goes out to indicate that the camera is not actively recording you, without discarding the permission to resume using the camera once muting is over.
There are a number of ways security management and controls in a
用户代理
can cause
getUserMedia()
to return a security-related error.
注意:
The security model for
getUserMedia()
is still somewhat in flux. The originally-designed security mechanism is in the process of being replaced with Feature Policy, so various browsers have different levels of security support, using different mechanisms. You should test your code carefully on a variety of devices and browsers to be sure it is as broadly compatible as possible
Feature Policy
security management feature of
HTTP
is in the process of being introduced into browsers, with support available to some extent in many browsers (though not always enabled by default, as in Firefox).
getUserMedia()
is one method which will require the use of Feature Policy, and your code needs to be prepared to deal with this. For example, you may need to use the
allow
attribute on any
<iframe>
使用
getUserMedia()
, and pages that use
getUserMedia()
will eventually need to supply the
Feature-Policy
头。
The two permissions that apply to
getUserMedia()
are
camera
and
microphone
.
For example, this line in the HTTP headers will enable use of a camera for the document and any embedded
<iframe>
elements that are loaded from the same origin:
Feature-Policy: camera 'self'
This will request access to the microphone for the current origin and the specific origin https://developer.mozilla.org:
Feature-Policy: microphone 'self' https://developer.mozilla.org
若正使用
getUserMedia()
within an
<iframe>
, you can request permission just for that frame, which is clearly more secure than requesting a more general permission. Here, indicate we need the ability to use both camera and microphone:
<iframe src="https://mycode.example.net/etc" allow="camera;microphone"> </iframe>
Read our guide, Using Feature Policy , to learn more about how it works.
getUserMedia()
method is only available in
安全上下文
. A secure context is one the browser is reasonably confident contains a document which was loaded securely, using HTTPS/TLS, and has limited exposure to insecure contexts. If a document isn't loaded in a secure context, the
navigator.mediaDevices
特性为
undefined
, making access to
getUserMedia()
impossible.
Attempting to access
getUserMedia()
in this situation will result in a
TypeError
.
Because of the obvious security concern associated with
getUserMedia()
if used unexpectedly or without security being carefully managed, it can only be used in secure contexts. There are a number of insecure ways to load a document that might, in turn, attempt to call
getUserMedia()
. The following are examples of situations in which
getUserMedia()
is not permitted to be called:
<iframe>
element cannot call
getUserMedia()
除非
<iframe>
有它自己的
sandbox
属性设置为
allow-same-origin
.
data://
or
blob://
URL which has no origin (such as when one of these URLs is typed by the user into the address bar) cannot call
getUserMedia()
. These kinds of URLs loaded from JavaScript code inherit the script's permissions.
srcdoc
attribute is used to specify the contents of a frame.
This example gives a preference for camera resolution, and assigns the resulting
MediaStream
object to a video element.
// Prefer camera resolution nearest to 1280x720.
var constraints = { audio: true, video: { width: 1280, height: 720 } };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
var video = document.querySelector('video');
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.
此处范例,使用
navigator.mediaDevices.getUserMedia()
, with a polyfill to cope with older browsers. Note that this polyfill does not correct for legacy differences in constraints syntax, which means constraints won't work well across browsers. It is recommended to use the
adapter.js
polyfill instead, which does handle constraints.
// 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 = function(constraints) {
// First get ahold of the legacy getUserMedia, if present
var 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);
});
}
}
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
var video = document.querySelector('video');
// Older browsers may not have srcObject
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// Avoid using this in new browsers, as it is going away.
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
Lower frame-rates may be desirable in some cases, like WebRTC transmissions with bandwidth restrictions.
var constraints = { video: { frameRate: { ideal: 10, max: 15 } } };
On mobile phones.
var front = false;
document.getElementById('flip-button').onclick = function() { front = !front; };
var constraints = { video: { facingMode: (front? "user" : "environment") } };
| 规范 | 状态 | 注释 |
|---|---|---|
|
媒体捕获和流
The definition of 'MediaDevices.getUserMedia()' in that specification. |
候选推荐 | 初始定义 |
| 桌面 | 移动 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
getUserMedia
|
Chrome
52
|
Edge 12 |
Firefox
36
|
IE No |
Opera
40
|
Safari 11 | WebView Android 53 |
Chrome Android
52
|
Firefox Android
36
|
Opera Android
41
|
Safari iOS 11 | Samsung Internet Android 6.0 |
| Secure context required | Chrome Yes | Edge 79 | Firefox 68 | IE No | Opera ? | Safari ? | WebView Android Yes | Chrome Android Yes | Firefox Android 68 | Opera Android ? | Safari iOS ? | Samsung Internet Android Yes |
完整支持
不支持
兼容性未知
见实现注意事项。
用户必须明确启用此特征。
navigator.getUserMedia()
legacy API.
mediaDevices.enumerateDevices()
: Listing available media devices
MediaStream
mediaDevices.getDisplayMedia()
: Getting a stream containing screen contents
getUserMedia()
to take still photos rather than video
MediaDevices
enumerateDevices()
getDisplayMedia()
getSupportedConstraints()
getUserMedia()
AudioStreamTrack
BlobEvent
CanvasCaptureMediaStream
ConstrainBoolean
ConstrainDOMString
ConstrainDouble
ConstrainLong
DoubleRange
HTMLCanvasElement.captureStream()
LongRange
MediaStream
MediaStreamTrack
MediaStreamTrackEvent
MediaTrackCapabilities
MediaTrackConstraints
MediaTrackSettings
MediaTrackSupportedConstraints
Navigator.mediaDevices
NavigatorUserMedia
NavigatorUserMediaError
VideoStreamTrack
navigator.mediaDevices.getUserMedia()