PeerJS WebRTC共享屏幕时麦克风与系统音频无法同时工作问题求助
问题原因分析
- 轨道覆盖冲突:你的代码仅通过
getDisplayMedia请求屏幕视频+系统音频,且仅替换了视频轨道;若之前已存在麦克风音频的发送者,系统音频轨道会直接覆盖原有麦克风轨道,导致二者无法同时传输。 - WebRTC轨道管理逻辑缺失:PeerConnection支持同时发送多个同类型(音频/视频)轨道,但需要显式添加,而非直接替换已有轨道。当前代码未处理双音频轨道的共存逻辑。
解决方案
需要分别请求屏幕共享流(含系统音频)、麦克风流,将两个音频轨道同时添加到PeerConnection中,或通过Web Audio API混合为单个轨道后发送。以下是具体实现代码:
1. 封装麦克风流获取函数
async function getMicrophoneStream() { try { return await navigator.mediaDevices.getUserMedia({ audio: true }); } catch (err) { console.error('麦克风获取失败:', err); return null; } }
2. 修改屏幕共享启动逻辑
async function startScreenShare() { if (screenSharing) { stopScreenSharing(); return; } try { // 请求屏幕共享流(包含系统音频) const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: { mediaSource: "screen" }, audio: true }); setScreenSharingStream(screenStream); // 请求麦克风流 const micStream = await getMicrophoneStream(); // 监听屏幕轨道结束事件,自动停止共享 const videoTrack = screenStream.getVideoTracks()[0]; videoTrack.onended = stopScreenSharing; if (peer && currentPeer) { const pc = currentPeer.peerConnection; // 替换或添加屏幕视频轨道 let videoSender = pc.getSenders().find(s => s.track.kind === 'video'); videoSender ? videoSender.replaceTrack(videoTrack) : pc.addTrack(videoTrack, screenStream); // 添加系统音频轨道 const systemAudioTrack = screenStream.getAudioTracks()[0]; if (systemAudioTrack) pc.addTrack(systemAudioTrack, screenStream); // 添加麦克风音频轨道(若存在) if (micStream) { const micAudioTrack = micStream.getAudioTracks()[0]; pc.addTrack(micAudioTrack, micStream); } screenSharing = true; // 存储流对象,用于停止时清理 window.activeStreams = { screenStream, micStream }; } } catch (err) { console.error('屏幕共享启动失败:', err); } }
3. 完善停止共享的清理逻辑
function stopScreenSharing() { if (!screenSharing || !currentPeer) return; const pc = currentPeer.peerConnection; const { screenStream, micStream } = window.activeStreams || {}; // 停止并移除屏幕相关轨道 if (screenStream) { screenStream.getTracks().forEach(t => t.stop()); pc.getSenders().forEach(sender => { if (screenStream.getTracks().includes(sender.track)) pc.removeTrack(sender); }); } // 停止并移除麦克风轨道(若需屏幕共享关闭后保留麦克风,可删除此段) if (micStream) { micStream.getTracks().forEach(t => t.stop()); pc.getSenders().forEach(sender => { if (micStream.getTracks().includes(sender.track)) pc.removeTrack(sender); }); } setScreenSharingStream(null); screenSharing = false; window.activeStreams = null; }
可选:音频轨道混合(合并系统音频与麦克风)
如果需要将两个音频轨道合并为一个传输(避免接收端处理双音频),可使用Web Audio API实现:
function mixAudioTracks(track1, track2) { const audioContext = new AudioContext(); const source1 = audioContext.createMediaStreamSource(new MediaStream([track1])); const source2 = audioContext.createMediaStreamSource(new MediaStream([track2])); const destination = audioContext.createMediaStreamDestination(); source1.connect(destination); source2.connect(destination); return destination.stream.getAudioTracks()[0]; }
使用时替换原双音频添加逻辑:
// 替换原有系统音频和麦克风添加代码 if (systemAudioTrack && micAudioTrack) { const mixedTrack = mixAudioTracks(systemAudioTrack, micAudioTrack); pc.addTrack(mixedTrack, new MediaStream([mixedTrack])); }
内容的提问来源于stack exchange,提问作者Raj Kanani
相关产品推荐
相关产品推荐

