Once you get getUserMedia()
working with audio and video constraints you immediately start hitting problems like:
- user has no webcam, just a microphone
- user has (accidentally) denied access to the webcam
- user plugs in the webcam/microphone after your
getUserMedia()
code has initialized - the device is already used by another app on Windows
- Firefox only: the device is already used by another Firefox tab
- Chrome only: the user dismisses the privacy dialog
To tackle these situations the Media Capture and Streams spec that governs getUserMedia()
defines several errors that you can look out for in your code (and correctly inform the user).
The table below lists the top 5 errors. They’re different between Firefox, which currently follows the spec more closely, and Chrome. On top of these 5, the spec also defines AbortError
& SecurityError
, but I was never able to trigger them.
FIREFOX 56 | CHROME 62 |
---|---|
NotFoundError | DevicesNotFoundError |
NotReadableError | TrackStartError |
OverconstrainedError | ConstraintNotSatisfiedError |
NotAllowedError | PermissionDeniedError |
NotFoundError
This one’s
very common, it’s thrown in these 3 cases:
- when you’re requesting just a video track through constraints but the user does not have a webcam.
- when you request just an audio track but the user does not have a microphonedevice:
- the computer or device has no sound card or
- the computer or device has a sound card but the recording device is disabled because there’s no mic plugged in or
- the recording device is disabled manually from the OS (can be done on Windows) but that’s rare.
- when you’re requesting both video and audio tracks but the user does not have a webcam OR a microphone (it’s enough for one device to be missing for the error to be thrown)
Firefox will throw a MediaStreamError
with it’s name
property set to “NotFoundError” and the message “The object can not be found here”.
Chrome will throw a NavigatorUserMediaError
with it’s name
property set to “DevicesNotFoundError”.
NotReadableError
It most commonly happens on Windows when the browser tries to access the webcam or mic but they’re already in use (by Skype, etc.) –
on Windows where processes get exclusive access to the webcam – but people have also been reporting the error showing up when using experimental constraints removed by Chrome or because of bugs in the Chrome screen recording code. On macOS, where processes share the webcam and microphone, I’ve only seen it reported by Firefox.
The Mozilla Developer Network Web Docs explanation covers all these situations:
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.
On Windows Firefox will throw a MediaStreamError
with it’s name
property set to “NotReadableError” and it’s message property set to “Failed to allocate videosource” when another app (or Firefox tab) is using the webcam or microphone.
On Windows Chrome will throw a NavigatorUserMediaError
with it’s name
property set to “TrackStartError”, the non-spec Chrome-specific version, with no message. Different Chrome tabs can share the same webcam.
On macOS it’s only thrown by Firefox when another Firefox tab tries to get access to the webcam and mic. On macOs it’s paired with the message: “Concurrent mic process limit”.
OverconstrainedError
The specified constraints resulted in no candidate devices which met the criteria requested. The error is an object of type
OverconstrainedError
, and has aconstraint
property whose string value is the name of a constraint which was impossible to meet, and amessage
property containing a human-readable string explaining the problem.
It’s thrown when you’re requesting a constraint that can not be satisfied by the available hardware, for example a high frame rate or high resolution requested using the min
or exact
keywords.
Firefox will throw a MediaStreamError
with it’s name
property set to “OverconstrainedError” .
Chrome will throw a NavigatorUserMediaError
with it’s name
property set to “ConstraintNotSatisfiedError”, the non-spec Chrome-specific version.
Chrome & Firefox will return the requested resolution or the closest one when using ideal
values but if you start using the min
keyword with high values or the exact
keyword with unsupported values you will immediately trigger the error.
The error object will also mention the constraint that could not be satisfied through the constraintName
property and the message
“Constraints could be not satisfied.”.
NotAllowedError
Is thrown when the user denies (or has previously denied) access to the webcam or microphone.
Firefox will throw a MediaStreamError
with it’s name
property set to “NotAllowedError” and the message “The request is not allowed by the user agent or the platform in the current context”.
Chrome will throw a NavigatorUserMediaError
with it’s name
property set to “PermissionDeniedError”.
TypeError
It’s thrown when the constraints object passed to getUserMedia()
is empty or has all tracks (audio, video or both) set to false.
Firefox will throw a MediaStreamError
with it’s name
property set to “TypeError” and the message “audio and/or video is required”.
Chrome will throw a “TypeError: Failed to execute ‘getUserMedia’ on ‘MediaDevices’: At least one of audio and video must be requested”.
PermissionDismissedError
It’s thrown by Chrome when the user closes the privacy dialog asking for mic and webcam access.
Dismissing the dialog is only possible on Chrome so there’s no equivalent error on other browsers. It’s not spec compliant so the error might be removed in Chrome 64 in the move towards spec compliant errors.
Handling these errors
Handling these errors is quite simple when using the newer promise based getUserMedia()
. You can use the code below or this code pen.
var constraints = {
video: false,
audio: false
}
navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
/* do stuff */
}).catch(function(err) {
//log to console first
console.log(err); /* handle the error */
if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
//required track is missing
} else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
//webcam or mic are already in use
} else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
//constraints can not be satisfied by avb. devices
} else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
//permission denied in browser
} else if (err.name == "TypeError" || err.name == "TypeError") {
//empty constraints object
} else {
//other errors
}
});
The code starts out with false for both the video and audio track to immediately trigger the TypeError
.