Is it possible to check if the user has a camera and microphone and if the permissions have been granted with Javascript?
Solution 1
Live Demo:
If user didn't allow webcam and/or microphone, then media-devices will be having "NULL" value for the "label" attribute. Above page will show this message: "Please invoke getUserMedia once."
PS. You can type "DetectRTC.MediaDevices" in the Chrome Console developers tool.
Note: It works only in Chrome. Firefox isn't supporting similar API yet. (Updated: Firefox supports as well)
Updated at Dec 16, 2015
Note: Following code snippet works both in Chrome and Firefox.
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
// Firefox 38+ seems having support of enumerateDevicesx
navigator.enumerateDevices = function(callback) {
navigator.mediaDevices.enumerateDevices().then(callback);
};
}
var MediaDevices = [];
var isHTTPs = location.protocol === 'https:';
var canEnumerate = false;
if (typeof MediaStreamTrack !== 'undefined' && 'getSources' in MediaStreamTrack) {
canEnumerate = true;
} else if (navigator.mediaDevices && !!navigator.mediaDevices.enumerateDevices) {
canEnumerate = true;
}
var hasMicrophone = false;
var hasSpeakers = false;
var hasWebcam = false;
var isMicrophoneAlreadyCaptured = false;
var isWebcamAlreadyCaptured = false;
function checkDeviceSupport(callback) {
if (!canEnumerate) {
return;
}
if (!navigator.enumerateDevices && window.MediaStreamTrack && window.MediaStreamTrack.getSources) {
navigator.enumerateDevices = window.MediaStreamTrack.getSources.bind(window.MediaStreamTrack);
}
if (!navigator.enumerateDevices && navigator.enumerateDevices) {
navigator.enumerateDevices = navigator.enumerateDevices.bind(navigator);
}
if (!navigator.enumerateDevices) {
if (callback) {
callback();
}
return;
}
MediaDevices = [];
navigator.enumerateDevices(function(devices) {
devices.forEach(function(_device) {
var device = {};
for (var d in _device) {
device[d] = _device[d];
}
if (device.kind === 'audio') {
device.kind = 'audioinput';
}
if (device.kind === 'video') {
device.kind = 'videoinput';
}
var skip;
MediaDevices.forEach(function(d) {
if (d.id === device.id && d.kind === device.kind) {
skip = true;
}
});
if (skip) {
return;
}
if (!device.deviceId) {
device.deviceId = device.id;
}
if (!device.id) {
device.id = device.deviceId;
}
if (!device.label) {
device.label = 'Please invoke getUserMedia once.';
if (!isHTTPs) {
device.label = 'HTTPs is required to get label of this ' + device.kind + ' device.';
}
} else {
if (device.kind === 'videoinput' && !isWebcamAlreadyCaptured) {
isWebcamAlreadyCaptured = true;
}
if (device.kind === 'audioinput' && !isMicrophoneAlreadyCaptured) {
isMicrophoneAlreadyCaptured = true;
}
}
if (device.kind === 'audioinput') {
hasMicrophone = true;
}
if (device.kind === 'audiooutput') {
hasSpeakers = true;
}
if (device.kind === 'videoinput') {
hasWebcam = true;
}
// there is no 'videoouput' in the spec.
MediaDevices.push(device);
});
if (callback) {
callback();
}
});
}
// check for microphone/camera support!
checkDeviceSupport(function() {
document.write('hasWebCam: ', hasWebcam, '<br>');
document.write('hasMicrophone: ', hasMicrophone, '<br>');
document.write('isMicrophoneAlreadyCaptured: ', isMicrophoneAlreadyCaptured, '<br>');
document.write('isWebcamAlreadyCaptured: ', isWebcamAlreadyCaptured, '<br>');
});
Solution 2
Yes it is quite possible to detect whether a microphone and a camera is available after granting the permission.
Using the old API:
navigator.getUserMedia({ audio: true, video: true}, function (stream) {
if (stream.getVideoTracks().length > 0 && stream.getAudioTracks().length > 0) {
//code for when none of the devices are available
} else {
// code for when both devices are available
}
}, function (error) {
// code for when there is an error
});
Using the newer, promise-based API:
navigator.mediaDevices.getUserMedia({ audio: true, video: true})
.then(function (stream) {
if (stream.getVideoTracks().length > 0 && stream.getAudioTracks().length > 0){
//code for when none of the devices are available
} else {
// code for when both devices are available
}
})
.catch(function (error) {
// code for when there is an error
});
Solution 3
Now you can use navigator.permissions
also to check permissions already exist
navigator.permissions.query({ name: "camera" }).then(res => {
if(res.state == "granted"){
// has permission
}
});
But note that support is patchy as of Jan 2021:
- Chrome supports
navigator.permissions.query
as of Chrome 43+, and supports queryingcamera
andmicrophone
permissions, at least as of Chrome 87+. - Firefox supports
navigator.permissions.query
as of Firefox 46+, but does not support queryingcamera
ormicrophone
permissions as of Firefox 84. - Safari does not even support
navigator.permissions.query
.
Solution 4
1)You should be using Media Recorder and understand promise
2)Check if browser support the API enumerateDevices
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
console.log("This browser does not support the API yet");
}
let checking=["audioinput","videoinput"];
let onlyHas=[];
navigator.mediaDevices.enumerateDevices()
.then((devices)=> {
let haveAllDevices=true;
devices.forEach((device)=>{
onlyHas.push(device.kind);
if(!(device.kind==checking[0] || device.kind==checking[1])){
haveAllDevices=false;
}
});
//do something about ...
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
NotAllowedError
, so for now we are only interested in this error.
If you read DOMException you can see you can acces DOMException.name
, this is the one that you should be compared, so:
let constraints={audio:true,video:true};
navigator.mediaDevices.getUserMedia(constraints)
.then((stream)=>{.....})
.catch((err)=>
{if(err.name=="NotAllowedError"){console.log("User has denied accessed")}
});
PS: About cross browser compatibility MediaRecorder as for today 09/06/2018 it is only supported in chrome and firefox, and the brothers IE and IOS don't https://caniuse.com/#search=MediaRecorder
Solution 5
Please try my simple cross browser code.
Attention!!! Use https protocol for open web page with my code! Please go to demo
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<h1>Web camera</h1>
<video autoplay></video>
<script>
function errorMessage(message, e) {
console.error(message, typeof e == 'undefined' ? '' : e);
//alert(message);
}
if (location.protocol === 'https:') {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({ audio: true, video: true }, function (stream) {
document.querySelector('video').src = window.URL.createObjectURL(stream);
var mediaStreamTrack = stream.getVideoTracks()[0];
if (typeof mediaStreamTrack != "undefined") {
mediaStreamTrack.onended = function () {//for Chrome.
errorMessage('Your webcam is busy!')
}
} else errorMessage('Permission denied!');
}, function (e) {
var message;
switch (e.name) {
case 'NotFoundError':
case 'DevicesNotFoundError':
message = 'Please setup your webcam first.';
break;
case 'SourceUnavailableError':
message = 'Your webcam is busy';
break;
case 'PermissionDeniedError':
case 'SecurityError':
message = 'Permission denied!';
break;
default: errorMessage('Reeeejected!', e);
return;
}
errorMessage(message);
});
} else errorMessage('Uncompatible browser!');
} else errorMessage('Use https protocol for open this page.')
</script>
</body>
</html>
I have tested it into follow browsers:
Windows 10
- Chrome 52
- Edge 25
- Firefox 47
- IE11 Uncompatible browser!
- Opera 39
- Safari 5 Uncompatible browser!
Android
- Chrome 52
- Firefox 48
- Opera 37
Amal Antony
Updated on November 09, 2021Comments
-
Amal Antony over 2 years
I would like to find out if the user's device has an attached camera and microphone, and if so, has permissions been granted to get the audio and video stream using Javascript. I want to make this check to be made across Chrome and Firefox at the very least. What's a consistent API for this?
-
Amal Antony about 9 yearsThis looks interesting! How about browser compatibility though?
-
Muaz Khan about 9 yearsFirefox isn't supporting enumerateDevices or getMediaDevices or MediaStreamTrack.getSources API yet; which means that we can't detect if Firefox is having access to microphone/webcam without manually making getUserMedia requests. Whenever we'll make getUserMedia request in Firefox, it'll show permission popup/dropdown which isn't good for real life usecases.
-
Muaz Khan about 9 yearsAbove demo works both in desktop and Andriod ---- using Chrome. It even works in Opera as well.
-
xdumaine about 9 yearsFirefox 38+ has an API for enumerating devices that works different, but still returns null values for device labels when permission aren't granted. See here for an example that uses my helper library to wrap up the different apis: xdumaine.com/enumerateDevices/test
-
xdumaine about 9 yearsJust to expand on this - you don't have to use DetectRTC or my library enumerateDevices, you can just use
MediaStreamTrack.getSources
(chrome only) for listing devices and just checking to see if the results have labels or not. -
Muaz Khan about 9 years@xdumaine +1 to know that Firefox 38+ is supporting enumerateDevices API. I'll investigate further & implement soon. BTW, its harder for newcomers to learn and use tricky APIs. They prefer solution like your library or javascript-shims.
-
Bergi over 8 yearsCan you please add the relevant code to your answer itself, instead of only linking that demo page? And maybe additionally provide links to the documentation of the methods you used?
-
Vitaliy Terziev almost 8 yearsThis appears to be working Ffox too, at least on the latest version. I assume that there is still no "industry standard" way for checking this
-
Miron almost 6 yearsI see this error
Uncaught TypeError: Failed to execute 'getUserMedia' on 'Navigator': 3 arguments required, but only 2 present.
. What's the problem? -
sertsedat over 5 years@MuazKhan why checking
!navigator.enumerateDevices && navigator.enumerateDevices
at all? Doesn't it give false every time? -
octavn about 5 yearsWhy exactly should he be using the MediaStream Recording API ?
-
John Balvin Arias about 5 yearsbecause he wants to record audio and video, and one way to record its to use getUserMedia
-
Shahid Kamal over 4 yearsKeep in mind that this will keep the camera/microphone stream running unless you close it.
-
Baart about 4 yearsreplace by navigator.mediaDevices.getUserMedia
-
Darren G over 3 yearsUnfortunately this doesn't work on safari either
-
gimp3695 over 3 yearsTechnically you can use this also on localhost in developer testing if you want to check for that make this change
if (location.protocol === 'https:' || location.hostname === 'localhost') {
-
Hitesh Jangid almost 3 yearscall your media permission in
DetectRTC.load(callback)
function, where callback will benavigator.mediaDevices.getUserMedia
& you can passvideo: DetectRTC.hasWebcam
&audio:DetectRTC.hasMicrophone
to avoid catch issue in case one of video or audio device is not available. -
Alejandro B. over 2 yearsjust a comment:
device.label
will only have a value if it is currently streaming or has persistent permission granted, thus this code may incorrectly return false