是否可以检查用户是否有摄像头和麦克风以及是否已通过 Javascript 授予权限?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/30047056/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to check if the user has a camera and microphone and if the permissions have been granted with Javascript?
提问by Amal Antony
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?
我想知道用户的设备是否有连接的摄像头和麦克风,如果有,是否已被授予使用 Javascript 获取音频和视频流的权限。我想至少在 Chrome 和 Firefox 上进行此检查。什么是一致的 API?
回答by Muaz Khan
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."
如果用户不允许网络摄像头和/或麦克风,则媒体设备的“标签”属性将具有“NULL”值。上面的页面将显示此消息:“请调用一次 getUserMedia。”
PS. You can type "DetectRTC.MediaDevices"in the Chrome Console developers tool.
附注。您可以在 Chrome 控制台开发人员工具中输入“DetectRTC.MediaDevices”。
Note: It works only in Chrome. Firefox isn't supporting similar API yet. (Updated:Firefox supports as well)
注意:它仅适用于 Chrome。 Firefox 尚不支持类似的 API. (更新:Firefox 也支持)
Updated at Dec 16, 2015
2015 年 12 月 16 日更新
Note: Following code snippet works both in Chrome and Firefox.
注意:以下代码片段适用于 Chrome 和 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>');
});
回答by imal hasaranga perera
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
     }
});
回答by John Balvin Arias
1)You should be using Media Recorderand understand promise
1)您应该使用Media Recorder并了解承诺
2)Check if browser support the API enumerateDevices
2) 检查浏览器是否支持enumerateDevicesAPI
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);
});
NotAllowedErrorNotAllowedError,所以现在我们只对这个错误感兴趣。If you read DOMExceptionyou can see you can acces DOMException.name, this is the one that you should be compared, so:
如果你阅读DOMException你可以看到你可以访问DOMException.name,这是你应该比较的,所以:
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 MediaRecorderas 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
PS:关于跨浏览器兼容性MediaRecorder至今天09/06/2018只支持chrome和firefox,IE和IOS兄弟不支持 https://caniuse.com/#search=MediaRecorder
回答by BOUDA wahiba
You can use the MediaStreamTrack which represent a media stream, then you can use its getSources method as explained here: html5rocks
您可以使用代表媒体流的 MediaStreamTrack,然后您可以使用其 getSources 方法,如下所述:html5rocks
If you don't get any media sources then your client hasn't a webcam. It's not supported by firefox.
如果您没有获得任何媒体资源,那么您的客户就没有网络摄像头。Firefox 不支持它。
回答by Andrej
Please try my simple cross browser code.
请尝试我的简单跨浏览器代码。
Attention!!! Use https protocol for open web page with my code! Please go to demo
注意力!!!使用 https 协议打开带有我的代码的网页!请去 演示
<!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
视窗 10
- Chrome 52
 - Edge 25
 - Firefox 47
 - IE11 Uncompatible browser!
 - Opera 39
 - Safari 5 Uncompatible browser!
 
- 铬 52
 - 边缘 25
 - 火狐 47
 - IE11 不兼容的浏览器!
 - 歌剧39
 - Safari 5 不兼容的浏览器!
 
Android
安卓
- Chrome 52
 - Firefox 48
 - Opera 37
 
- 铬 52
 - 火狐 48
 - 歌剧37
 

