Is it possible to check if the user has a camera and microphone and if the permissions have been granted with Javascript?

有些话、适合烂在心里 提交于 2019-11-28 17:19:09

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>');
});

Yes it is quite possible to detect whether a microphone and a camera is available after granting the permission,

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
     }
});

You can use the MediaStreamTrack which represent a media stream, then you can use its getSources method as explained here: html5rocks

If you don't get any media sources then your client hasn't a webcam. It's not supported by firefox.

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

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");
}
3) Check if user has conected audio and camera, the only values are "videoinput", "audioinput" or "audiooutput" DeviceInfo.kind

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);
});
4)Permissions are reused,it means that if user already has denied permission then when you call getUserMedia the bowser won't prompt anything and will reject the promise promise throwing an error of type DOMException, otherwise it will resolve the promise. When the promise rejects it can be many reasons read, one of then is when user has denied access, when this happens it will throw an DOMException of type 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!