WebRTC、getDisplayMedia() 不捕获远程流中的声音

问题描述 投票:0回答:3

我有一个自己的Web应用程序,它基于peerjs库(它是一个视频会议)。

我正在尝试使用“MediaRecorder”进行录制,但我遇到了一个非常不愉快的情况。

捕获我的桌面流的代码如下:

let chooseScreen = document.querySelector('.chooseScreenBtn')
chooseScreen.onclick = async () => {
    let desktopStream = await navigator.mediaDevices.getDisplayMedia({ video:true, audio: true });
}

然后我成功地将收到的desktopStream应用到DOM中的videoElement

const videoElement = doc.querySelector('.videoElement')
  videoElement.srcObject = desktopStream 
  videoElement.muted = false;
  videoElement.onloadedmetadata = ()=>{videoElement.play();}

例如,我在页面上看到 desktopStream,其中有一个正在进行的会议,每个人都可以听到和看到对方。

要检查desktopStream中的视频和音频,我在桌面上的视频播放器上播放一些视频。 我可以听到桌面上的任何音频,但无法听到任何参与者的音频。 当然,当我将desktopStream放入MediaRecorder中时,我得到的视频文件除了我的桌面之外没有任何声音。有什么想法可以解决吗?

javascript webrtc webapi peerjs
3个回答
4
投票

Chrome 的

MediaRecorder
API 只能输出一个
track
createMediaStreamSource
可以从桌面音频和麦克风获取流,通过将两者连接到
createMediaStreamDestination
创建的一个对象中,它使您能够将这一流传输到
MediaRecorder
API。

const mergeAudioStreams = (desktopStream, voiceStream) => {
    const context = new AudioContext();

    // Create a couple of sources
    const source1 = context.createMediaStreamSource(desktopStream);
    const source2 = context.createMediaStreamSource(voiceStream);
    const destination = context.createMediaStreamDestination();

    const desktopGain = context.createGain();
    const voiceGain = context.createGain();

    desktopGain.gain.value = 0.7;
    voiceGain.gain.value = 0.7;

    source1.connect(desktopGain).connect(destination);
    // Connect source2
    source2.connect(voiceGain).connect(destination);

    return destination.stream.getAudioTracks();
}; 

也可以使用两个或多个音频输入+视频输入。

window.onload = () => {
    const warningEl = document.getElementById('warning');
    const videoElement = document.getElementById('videoElement');
    const captureBtn = document.getElementById('captureBtn');
    const startBtn = document.getElementById('startBtn');
    const stopBtn = document.getElementById('stopBtn');
    const download = document.getElementById('download');
    const audioToggle = document.getElementById('audioToggle');
    const micAudioToggle = document.getElementById('micAudioToggle');
    
    if('getDisplayMedia' in navigator.mediaDevices) warningEl.style.display = 'none';

    let blobs;
    let blob;
    let rec;
    let stream;
    let voiceStream;
    let desktopStream;
    
    const mergeAudioStreams = (desktopStream, voiceStream) => {
        const context = new AudioContext();
        const destination = context.createMediaStreamDestination();
        let hasDesktop = false;
        let hasVoice = false;
        if (desktopStream && desktopStream.getAudioTracks().length > 0) {
        // If you don't want to share Audio from the desktop it should still work with just the voice.
        const source1 = context.createMediaStreamSource(desktopStream);
        const desktopGain = context.createGain();
        desktopGain.gain.value = 0.7;
        source1.connect(desktopGain).connect(destination);
        hasDesktop = true;
        }
        
        if (voiceStream && voiceStream.getAudioTracks().length > 0) {
        const source2 = context.createMediaStreamSource(voiceStream);
        const voiceGain = context.createGain();
        voiceGain.gain.value = 0.7;
        source2.connect(voiceGain).connect(destination);
        hasVoice = true;
        }
        
        return (hasDesktop || hasVoice) ? destination.stream.getAudioTracks() : [];
    };

    captureBtn.onclick = async () => {
        download.style.display = 'none';
        const audio = audioToggle.checked || false;
        const mic = micAudioToggle.checked || false;
        
        desktopStream = await navigator.mediaDevices.getDisplayMedia({ video:true, audio: audio });
        
        if (mic === true) {
        voiceStream = await navigator.mediaDevices.getUserMedia({ video: false, audio: mic });
        }
    
        const tracks = [
        ...desktopStream.getVideoTracks(), 
        ...mergeAudioStreams(desktopStream, voiceStream)
        ];
        
        console.log('Tracks to add to stream', tracks);
        stream = new MediaStream(tracks);
        console.log('Stream', stream)
        videoElement.srcObject = stream;
        videoElement.muted = true;
        
        blobs = [];
    
        rec = new MediaRecorder(stream, {mimeType: 'video/webm; codecs=vp8,opus'});
        rec.ondataavailable = (e) => blobs.push(e.data);
        rec.onstop = async () => {
        
        blob = new Blob(blobs, {type: 'video/webm'});
        let url = window.URL.createObjectURL(blob);
        download.href = url;
        download.download = 'test.webm';
        download.style.display = 'block';
        };
        startBtn.disabled = false;
        captureBtn.disabled = true;
        audioToggle.disabled = true;
        micAudioToggle.disabled = true;
    };

    startBtn.onclick = () => {
        startBtn.disabled = true;
        stopBtn.disabled = false;
        rec.start();
    };

    stopBtn.onclick = () => {
        captureBtn.disabled = false;
        audioToggle.disabled = false;
        micAudioToggle.disabled = false;
        startBtn.disabled = true;
        stopBtn.disabled = true;
        
        rec.stop();
        
        stream.getTracks().forEach(s=>s.stop())
        videoElement.srcObject = null
        stream = null;
    };
};

2
投票

仅 Windows 版 Chrome 完全支持使用

getDisplayMedia
进行音频捕获。其他平台有许多限制:

  • Firefox 或 Safari 下根本不支持音频捕获;
  • 在适用于 Linux 和 Mac OS 的 Chrome/Chromium 上,只能捕获 Chrome/Chromium 选项卡的音频,而不能捕获非浏览器应用程序窗口的音频。

0
投票

const displayMediaOptions = {audio: { echoCancellation: false }};

这也将捕获您的会议选项卡。

© www.soinside.com 2019 - 2024. All rights reserved.