Search code examples
javascripthtmlhtml5-videowebrtchtml5-audio

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


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?


Solution

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