WEBRTC基于Socket切换输入设备后远端无法同步视频的实现咨询
问题根因
切换本地视频输入设备后仅更新了本地预览的媒体流,未同步替换RTCPeerConnection中的视频发送轨道,也未触发对应的SDP重协商流程,导致远端始终接收的是最初的旧视频流。
修复实现示例
1. Meeting类核心修改代码
class Meeting { constructor() { this.localStream = null; this.peerConnections = new Map(); // 存储所有远端的RTCPeerConnection实例,key为远端用户id this.socket = null; // Socket信令实例 this.isNegotiating = new Map(); // 防止协商嵌套,key为远端用户id } // 原有初始化、建连、信令处理逻辑保留即可 /** * 切换视频输入设备 * @param {string} deviceId 目标摄像头设备id */ async switchVideoDevice(deviceId) { try { // 获取新的视频流,音频可复用原有轨避免麦克风重启 const newStream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: deviceId } }, audio: false }); // 复用旧流的音频轨 this.localStream.getAudioTracks().forEach(track => { newStream.addTrack(track); }); // 停止旧视频轨释放设备资源 this.localStream.getVideoTracks().forEach(track => track.stop()); // 更新本地预览 document.getElementById('local-video').srcObject = newStream; const newVideoTrack = newStream.getVideoTracks()[0]; // 遍历所有peerConnection替换发送轨 for (const [userId, pc] of this.peerConnections.entries()) { const videoSender = pc.getSenders().find(s => s.track?.kind === 'video'); if (videoSender) { // 直接替换轨道,大部分场景下无需重协商即可生效 await videoSender.replaceTrack(newVideoTrack); // 兼容旧浏览器/自定义流属性场景,触发重协商 this.triggerNegotiation(userId, pc); } } // 更新本地存储的流实例 this.localStream = newStream; } catch (err) { console.error('切换视频设备失败:', err); } } /** * 触发SDP重协商 * @param {string} userId 远端用户id * @param {RTCPeerConnection} pc 对应的peerConnection实例 */ async triggerNegotiation(userId, pc) { if (this.isNegotiating.get(userId)) return; this.isNegotiating.set(userId, true); try { const offer = await pc.createOffer(); await pc.setLocalDescription(offer); // 通过Socket发送Offer到远端 this.socket.emit('webrtc_offer', { targetUserId: userId, offer: pc.localDescription }); } catch (err) { console.error('发起协商失败:', err); } finally { this.isNegotiating.set(userId, false); } } }
2. 配套逻辑说明
- 信令层不需要新增类型,对端收到
webrtc_offer后执行原有建连时的setRemoteDescription、createAnswer、回发answer逻辑即可 - 远端无需修改流渲染逻辑,WebRTC底层会自动同步新轨道数据,原有渲染video元素会自动更新画面
- 若使用
addTransceiver预先创建收发器的实现,替换轨道时对应对应transceiver的sender即可
内容的提问来源于stack exchange,提问作者Özgür Can Karagöz
相关产品推荐
相关产品推荐

