Search code examples
audiovideo-streamingwebrtcweb-audio-apigetusermedia

Can I connect to multiple audio input devices using MediaDevices.getUserMedia() for a webrtc stream?


I haven't found any support for this in the getUserMedia docs. If I can only request a single audio device via constraints, I'm wondering if it's possible to call getUserMedia again for the second audio device, then merge/combine the resulting streams into one so I can attach it to a single audio/video element.

My end goal is to set up a webrtc stream that consists of video and 2 audio input devices. I already have a webrtc stream setup with video and a single audio input device working, I am just looking to merge in an additional audio stream. I mention this in case there is some option for this on the webrtc side as well.

With all of that said, if there is a solution for combining streams, will there be a concern for keeping the audio in sync?

Thanks in advance!


Solution

  • So I ended up creating this function to accomplish the stream merging:

    function createMergedStream(...streams: MediaStream[]): MediaStream {
        const audioContext = new AudioContext()
    
        const audioSources: MediaStreamAudioSourceNode[] = []
        const videoTracks: MediaStreamTrack[] = []
    
        streams.forEach((stream) => {
            stream.getTracks().forEach((track) => {
                if (track.kind === "video") {
                    videoTracks.push(track)
                }
            })
            audioSources.push(audioContext.createMediaStreamSource(stream))
        })
    
        const destination = audioContext["createMediaStreamDestination"]()
        audioSources.forEach((audioSource) => {
            audioSource.connect(destination)
        })
    
        videoTracks.forEach((track) => {
            destination.stream.addTrack(track)
        })
    
        return destination.stream
    }
    

    Turns out the client was actually looking to access multiple channels from a multi-channel audio interface, so I have some more digging to do. Figured I'd shared this code regardless, in case someone ever stumbles across this post.