调用getUserMedia报Could not start video source DOM异常怎么解决
错误根因
这个偶发报错的核心原因是摄像头设备被占用导致新的媒体流请求失败,和你的代码逻辑缺陷直接相关:
- 你在请求新的摄像头流前,没有停止释放上一次创建的媒体轨道,笔记本内置摄像头大多仅支持单进程/单实例占用,重复请求会直接触发启动失败
setCamera和getDevices方法里都分开两次调用getUserMedia分别请求音视频,额外增加了设备冲突概率- 异步方法没有做异常捕获,导致Promise抛出的错误没有被处理
getDevices里的enumerateDevices是异步方法,你没有等待执行完成就发起媒体流请求,存在设备ID还未正确填充就调用setCamera的可能
修复方案
1. 先释放旧的媒体流再请求新设备
每次调用getUserMedia前,先停止上一个流的所有轨道,释放设备占用,先在全局/组件内增加当前流实例的存储变量:
currentStream: null,
2. 优化setCamera方法,合并请求、加错误捕获
修改后的setCamera代码示例:
setCamera: async function(){ try { // 先停止之前的所有轨道,释放设备 if(this.currentStream) { this.currentStream.getTracks().forEach(track => track.stop()) } // 一次请求同时获取音视频流,不需要分开两次调用 const stream = await navigator.mediaDevices.getUserMedia({ video: {deviceId: this.selectedCamera}, audio: true }); this.currentStream = stream document.getElementById("myVideo").srcObject = stream; document.getElementById("myVideo").muted = true; } catch (e) { // 捕获错误,可增加重试逻辑,最多重试2次 console.error("摄像头启动失败", e) // 示例:间隔1秒重试1次 setTimeout(() => { this.setCamera() }, 1000) } },
3. 修复getDevices的异步等待问题
修改getDevices方法,等待设备枚举完成再往下执行:
getDevices: async function(){ let $this = this; // 加await等待设备枚举完成 await navigator.mediaDevices.enumerateDevices().then(function(devices) { devices.forEach(function(device) { if(device.kind == "audioinput"){ $this.microphones.push(device); } else if(device.kind == "audiooutput"){ $this.speakers.push(device); } else if(device.kind == "videoinput"){ $this.cameras.push(device); } }); }); // 同样复用释放逻辑和合并请求逻辑 if(this.currentStream) { this.currentStream.getTracks().forEach(track => track.stop()) } const stream = await navigator.mediaDevices.getUserMedia({video: true,audio: true}); this.currentStream = stream document.getElementById("myVideo").srcObject = stream; document.getElementById("myVideo").muted = true; },
如果修改后还是偶发报错,可以排查后台是否有其他应用正在占用摄像头,部分安全软件也会限制浏览器的摄像头高频调用权限。
内容的提问来源于stack exchange,提问作者Rhytham
相关产品推荐
相关产品推荐

