【发布时间】:2015-07-14 20:06:33
【问题描述】:
我想了解用户的设备是否连接了摄像头和麦克风,如果有,是否已获得使用 Javascript 获取音频和视频流的权限。我想至少在 Chrome 和 Firefox 上进行这项检查。什么是一致的 API?
【问题讨论】:
标签: javascript html html5-video webrtc html5-audio
我想了解用户的设备是否连接了摄像头和麦克风,如果有,是否已获得使用 Javascript 获取音频和视频流的权限。我想至少在 Chrome 和 Firefox 上进行这项检查。什么是一致的 API?
【问题讨论】:
标签: javascript html html5-video webrtc html5-audio
现场演示:
如果用户不允许使用网络摄像头和/或麦克风,则媒体设备的 "label" 属性将具有 "NULL" 值。以上页面将显示此消息:“请调用 getUserMedia 一次。”
附言。您可以在 Chrome 控制台开发者工具中输入“DetectRTC.MediaDevices”。
注意:它仅适用于 Chrome。 Firefox 还不支持类似的 API。 (更新: Firefox 也支持)
注意:以下代码 sn-p 适用于 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>');
});
【讨论】:
MediaStreamTrack.getSources(仅限 chrome)列出设备并检查结果是否有标签与否。
是的,很可能在授予权限后检测麦克风和摄像头是否可用。
使用旧 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
});
使用更新的、基于 Promise 的 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
});
【讨论】:
Uncaught TypeError: Failed to execute 'getUserMedia' on 'Navigator': 3 arguments required, but only 2 present.。有什么问题?
1)你应该使用Media Recorder并理解promise
2)检查浏览器是否支持APIenumerateDevices
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 类型的 DOMException,所以现在我们只对这个错误感兴趣。
如果您阅读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:关于跨浏览器兼容性MediaRecorder至今天09/06/2018只支持chrome和firefox,IE和IOS兄弟不支持 https://caniuse.com/#search=MediaRecorder
【讨论】:
现在您也可以使用navigator.permissions 来检查权限是否存在
navigator.permissions.query({ name: "camera" }).then(res => {
if(res.state == "granted"){
// has permission
}
});
但请注意,截至 2021 年 1 月,支持并不完整:
navigator.permissions.query,并支持查询 camera 和 microphone 权限,至少从 Chrome 87+ 开始。navigator.permissions.query,但从 Firefox 84 开始不支持查询 camera 或 microphone 权限。navigator.permissions.query。【讨论】:
您可以使用表示媒体流的 MediaStreamTrack,然后您可以使用它的 getSources 方法,如下所述:html5rocks
如果您没有获得任何媒体资源,则说明您的客户没有网络摄像头。 Firefox 不支持。
【讨论】:
请尝试我的简单跨浏览器代码。
注意!!!用我的代码使用 https 协议打开网页!请转至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>
我已经在以下浏览器中进行了测试:
Windows 10
安卓
【讨论】:
if (location.protocol === 'https:' || location.hostname === 'localhost') {,您也可以在开发人员测试中的本地主机上使用它
此函数检查用户是否有音频和视频访问权限:
checkMediaAccess = async() => {
navigator.mediaDevices.enumerateDevices().then( devices =>
devices.forEach( device => {
if(device.kind == 'audioinput' && device.label) console.log('Has Audio Access');
if(device.kind == 'videoinput' && device.label) console.log('Has Video Access');
}
));
}
【讨论】:
device.label 只有在当前正在流式传输时才会有一个值或已授予持久权限,因此此代码可能会错误地返回 false