WebRTC(一):通过WebRTC技术检测摄像头和麦克风

WebRTC 检测摄像头/麦克风:完整实现 + 2017年浏览器兼容方案

基于 WebRTC 技术检测摄像头、麦克风的核心方法,以及 2017 年主流浏览器(Chrome、IE、QQ/360 浏览器等)下的兼容问题(比如 device.label 显示异常、Firefox 无法获取音频输出列表)。我会结合当时的浏览器环境,给出可直接运行的完整实现方案,并解释核心兼容痛点的解决思路。


一、核心需求确认

通过 WebRTC 实现:

  1. 枚举设备列表(区分摄像头/麦克风/扬声器);
  2. 解决 2017 年主流浏览器(Chrome 62、Firefox 56、QQ/360 浏览器等)下 device.label(设备名称)显示异常的问题;
  3. 结合 webrtc-adapter 做跨浏览器兼容;
  4. 适配当时的浏览器市场环境(IE 仍占 20%+ 份额)。

二、核心原理:为什么 device.label 显示异常?

关键痛点
WebRTC 的 enumerateDevices() 方法返回的 device.label(设备名称),只有在用户授予「摄像头/麦克风权限」后才会显示真实名称;未授权时,Chrome/Firefox 仅返回 default/communications 等占位符,这不是浏览器 bug,而是隐私安全机制。

而 QQ/360 浏览器能显示 label,是因为其内核(Chrome 53/55)对权限的校验更宽松,或默认授予了基础设备访问权限。

WebRTC 检测设备的核心 API

API 作用
navigator.mediaDevices.enumerateDevices() 枚举所有媒体设备(摄像头/麦克风/扬声器)
navigator.mediaDevices.getUserMedia() 请求媒体设备权限(核心:获取权限后 label 才显示)
webrtc-adapter 抹平不同浏览器的 WebRTC API 前缀差异(如 webkitGetUserMedia

三、完整实现方案(2017年浏览器适配版)

步骤 1:引入兼容库(webrtc-adapter)

先引入 adapter.js 抹平浏览器差异(2017 年主流用 6.0.0 版本):

1
2
3
4
<!-- 优先用CDN,本地备用 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/webrtc-adapter/6.0.0/adapter.min.js"></script>
<!-- 备用CDN -->
<script src="https://public.yitong.com/libs/webrtc-adapter/6.0.0/adapter.min.js"></script>

步骤 2:完整代码实现(HTML + JS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebRTC 检测摄像头/麦克风</title>
<style>
.device-list { margin: 20px 0; }
.device-item { padding: 8px; margin: 4px 0; background: #f5f5f5; }
.error { color: red; }
</style>
</head>
<body>
<button id="detectBtn">检测摄像头/麦克风</button>
<div class="error" id="errorMsg"></div>
<div class="device-list">
<h3>麦克风(audioinput):</h3>
<div id="microphoneList"></div>

<h3>摄像头(videoinput):</h3>
<div id="cameraList"></div>

<h3>扬声器(audiooutput):</h3>
<div id="speakerList"></div>
</div>

<script>
// 1. 浏览器兼容性检测
function checkBrowserSupport() {
// 2017年IE完全不支持WebRTC,直接提示
if (!!window.ActiveXObject || "ActiveXObject" in window) {
throw new Error("IE浏览器不支持WebRTC,请更换Chrome/QQ/360浏览器");
}
// 检测MediaDevices API
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
throw new Error("当前浏览器不支持WebRTC设备检测");
}
}

// 2. 核心:请求媒体权限 + 枚举设备
async function detectMediaDevices() {
try {
// 清空之前的结果
document.getElementById('errorMsg').textContent = '';
document.getElementById('microphoneList').innerHTML = '';
document.getElementById('cameraList').innerHTML = '';
document.getElementById('speakerList').innerHTML = '';

// 第一步:检测浏览器兼容性
checkBrowserSupport();

// 第二步:请求媒体权限(关键!获取权限后label才显示)
// 注:2017年部分浏览器需要同时请求audio+video才能获取完整权限
const stream = await navigator.mediaDevices.getUserMedia({
audio: true, // 请求麦克风权限
video: true // 请求摄像头权限
});

// 第三步:停止流(避免摄像头一直开启)
stream.getTracks().forEach(track => track.stop());

// 第四步:枚举设备列表
const devices = await navigator.mediaDevices.enumerateDevices();

// 第五步:分类处理设备
devices.forEach(device => {
const deviceItem = document.createElement('div');
deviceItem.className = 'device-item';
deviceItem.innerHTML = `
名称:${device.label || '未获取到设备名称(权限不足)'} <br>
ID:${device.deviceId} <br>
类型:${device.kind}
`;

// 按类型分类展示
switch (device.kind) {
case 'audioinput': // 麦克风
document.getElementById('microphoneList').appendChild(deviceItem);
break;
case 'videoinput': // 摄像头
document.getElementById('cameraList').appendChild(deviceItem);
break;
case 'audiooutput': // 扬声器
document.getElementById('speakerList').appendChild(deviceItem);
break;
}
});

// 2017年Firefox无audiooutput列表,提示
if (devices.filter(d => d.kind === 'audiooutput').length === 0) {
document.getElementById('speakerList').innerHTML = '<div class="device-item">当前浏览器不支持扬声器列表检测(Firefox特性)</div>';
}

} catch (err) {
// 捕获错误(用户拒绝权限/设备不存在等)
document.getElementById('errorMsg').textContent = `检测失败:${err.message}`;
console.error('设备检测错误:', err);
}
}

// 绑定按钮点击事件
document.getElementById('detectBtn').addEventListener('click', detectMediaDevices);
</script>
</body>
</html>

四、2017年主流浏览器兼容细节

浏览器(2017版本) 兼容性表现 解决方法
Chrome 62 1. 需先请求权限才能显示label;
2. audiooutput列表正常;
3. 必须调用getUserMedia后枚举设备
按上述代码先请求权限再枚举
Firefox 56 1. 需先请求权限才能显示label;
2. 无audiooutput列表;
3. 仅支持audio/video权限同时请求
提示“不支持扬声器检测”,忽略audiooutput
QQ浏览器9.6(Chrome 53内核) 1. 权限后label正常显示;
2. 全类型设备列表正常
无需额外处理,按标准流程即可
360安全/极速9.x(Chrome 55内核) 1. 权限后label正常显示;
2. 全类型设备列表正常
无需额外处理
2345浏览器8.7/9.0(Chrome 47/56内核) 1. 需请求权限才能显示label;
2. 部分版本audiooutput异常
同Chrome处理逻辑
IE(所有版本) 完全不支持WebRTC 直接提示用户更换浏览器

五、关键问题解决

1. Chrome/Firefox 无法显示 device.label

✅ 解决方案:必须先调用 getUserMedia 请求音频/视频权限,权限授予后再调用 enumerateDevices,此时 label 会显示真实设备名称(如“麦克风 (HD Webcam C525)”)。

2. Firefox 无法获取 audiooutput 列表

✅ 解决方案:2017年Firefox的 enumerateDevices 暂不返回音频输出设备,属于浏览器特性,可在代码中检测并提示用户(如上述代码中的“当前浏览器不支持扬声器列表检测”)。

3. 调用 getUserMedia 时报错

常见错误原因及解决:

错误类型 原因 解决方法
NotAllowedError 用户拒绝了权限请求 提示用户“请允许摄像头/麦克风权限后重试”
NotFoundError 无可用的摄像头/麦克风 提示用户“未检测到摄像头/麦克风设备”
NotReadableError 设备被占用(如被其他软件打开) 提示用户“摄像头/麦克风已被占用,请关闭其他程序后重试”

4. IE 浏览器兼容

✅ 解决方案:2017年IE完全不支持WebRTC,无任何兼容方案,直接提示用户更换浏览器(Chrome/QQ/360)。


六、扩展优化(2017年实战建议)

  1. 权限请求优化:如果只需要检测麦克风,可只请求 audio: true(减少用户感知);
  2. 设备去重:部分浏览器会返回 default/communications 占位设备,可过滤重复设备ID;
  3. 降级处理:对不支持 getUserMedia 的浏览器,提供手动选择设备的兜底方案;
  4. 样式适配:2017年移动端浏览器也需适配,可添加响应式样式。

总结

关键点回顾

  1. 核心前提device.label 显示的关键是先调用 getUserMedia 获取摄像头/麦克风权限,而非浏览器本身的问题;
  2. 兼容核心:引入 webrtc-adapter 抹平不同浏览器的 API 差异,2017年IE直接放弃兼容;
  3. 浏览器特性:Firefox 56 无 audiooutput 列表,需提示用户;QQ/360 浏览器对权限更宽松,label 显示更友好;
  4. 安全细节:获取权限后需停止媒体流(track.stop()),避免摄像头一直开启。

这份方案完全适配你文中2017年的浏览器环境,可直接运行,解决了当时主流浏览器的核心兼容痛点。


WebRTC(一):通过WebRTC技术检测摄像头和麦克风
https://cszy.top/2017-11-13 webrtc(一):通过webrtc技术检测摄像头和麦克风/
作者
csorz
发布于
2017年11月13日
许可协议