You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PeerJS WebRTC共享屏幕时麦克风与系统音频无法同时工作问题求助

问题原因分析
  1. 轨道覆盖冲突:你的代码仅通过getDisplayMedia请求屏幕视频+系统音频,且仅替换了视频轨道;若之前已存在麦克风音频的发送者,系统音频轨道会直接覆盖原有麦克风轨道,导致二者无法同时传输。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:33:16