WebRTC视频会议应用:屏幕共享后麦克风开关按钮失效问题
WebRTC视频会议麦克风按钮异常修复方案
问题原因
停止屏幕共享后麦克风按钮报错Cannot read properties of undefined (reading 'enabled'),核心原因有两点:
- 停止共享时创建了局部
localStream变量,未更新全局变量,导致流状态不一致 - 麦克风按钮逻辑未判断音频轨道是否存在,遇到轨道缺失时直接读取
enabled引发报错
修复代码及步骤
1. 新增全局变量保存原摄像头轨道
在全局变量声明处添加,用于复用原摄像头流,避免重复获取媒体权限:
let screenStream = null; let localStream = null; let audioTrack = null; let pc = null; let originalVideoTrack = null; // 保存原摄像头轨道,避免重复调用getUserMedia
2. 修复屏幕共享切换逻辑
修改屏幕共享按钮事件,优先复用原localStream,更新全局变量并同步PeerConnection的音频轨道:
// Toggle screen sharing on/off document.getElementById("share-screen-btn").addEventListener("click", async () => { try { const localVideo = document.getElementById("localVideo"); const displayMediaOptions = { video: true, audio: true, }; if (!screenStream) { screenStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions); const videoTracks = screenStream.getVideoTracks(); // 保存原摄像头轨道 if (localStream) { originalVideoTrack = localStream.getVideoTracks()[0]; } await pc.getSenders().find(sender => sender.track.kind === 'video').replaceTrack(videoTracks[0], videoTracks[0].clone()); localVideo.srcObject = screenStream; document.getElementById("share-screen-btn").classList.remove("btn-danger"); document.getElementById("share-screen-btn").classList.add("btn-primary"); // 禁用原本地流音频 if (localStream) { audioTrack = localStream.getAudioTracks()[0]; audioTrack.enabled = false; } } else { // 优先复用原localStream,无需重新获取媒体流 if (localStream && originalVideoTrack) { const videoSender = pc.getSenders().find(sender => sender.track.kind === 'video'); await videoSender.replaceTrack(originalVideoTrack); // 恢复原音频轨道 if (audioTrack) { audioTrack.enabled = true; } localVideo.srcObject = localStream; } else { // 兼容原逻辑,处理原localStream不存在的情况 const localVideoStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); const videoSender = pc.getSenders().find(sender => sender.track.kind === 'video'); const localVideoTrack = localVideoStream.getVideoTracks()[0]; const localAudioTrack = localVideoStream.getAudioTracks()[0]; // 更新全局localStream,而非创建局部变量 localStream = new MediaStream([localVideoTrack, localAudioTrack]); // 同步更新PeerConnection的音频轨道 const audioSender = pc.getSenders().find(sender => sender.track.kind === 'audio'); if (audioSender && localAudioTrack) { await audioSender.replaceTrack(localAudioTrack); } await videoSender.replaceTrack(localVideoTrack); localVideo.srcObject = localStream; audioTrack = localAudioTrack; } document.getElementById("share-screen-btn").classList.remove("btn-primary"); document.getElementById("share-screen-btn").classList.add("btn-danger"); screenStream.getTracks().forEach(track => track.stop()); screenStream = null; } } catch (e) { console.error("Error sharing screen: ", e); } })
3. 修复麦克风按钮逻辑
添加音频轨道存在性判断,避免undefined报错:
// Toggle microphone on/off document.getElementById("mute-audio-btn").addEventListener("click", () => { let localStream = document.getElementById("localVideo").srcObject; if (localStream) { let audioTrack = localStream.getAudioTracks()[0]; // 新增判断:音频轨道不存在时直接返回 if (!audioTrack) return; let enabled = audioTrack.enabled; if (enabled) { audioTrack.enabled = false; document.getElementById("mute-audio-btn").innerHTML = '<i class="fa-solid fa-microphone-slash"></i>' } else { audioTrack.enabled = true; document.getElementById("mute-audio-btn").innerHTML = '<i class="fa-solid fa-microphone"></i>' } } })
关键修复说明
- 复用原
localStream减少重复调用getUserMedia,避免权限冲突和轨道缺失问题 - 更新全局
localStream保证流状态一致性 - 同步PeerConnection的音频轨道,确保远端能接收音频状态变化
- 麦克风按钮添加轨道存在性判断,从根源避免undefined报错
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

