PeerConnection 2 gUMs

by Andreas Pehrson

HTML

<button onclick="start()">Start</button>
<button onclick="swap()">Change Audio track</button>
<br>
<video id="remote" style="width:120px;height:80px;"></video>
<div id="div"></div>

JavaScript

var log = msg => div.innerHTML += msg + "<br>";

let stream, pc1, pc2, videoTrack, audioTrack;
async function sendTracks() {
  // Start the 1st gUM
  stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
  videoTrack = stream.getVideoTracks()[0];
  audioTrack = stream.getAudioTracks()[0];
  
  // Set up the PCs
  pc1 = new RTCPeerConnection();
  pc2 = new RTCPeerConnection();
  
  pc1.addEventListener('icecandidate', async e => await pc2.addIceCandidate(e.candidate));
  pc1.addTrack(videoTrack, stream);
  pc1.addTrack(audioTrack, stream);
  const offer = await pc1.createOffer({
    offerToReceiveAudio: 1
  });
  await pc1.setLocalDescription(offer);

  pc2.addEventListener('icecandidate', async e => await pc1.addIceCandidate(e.candidate));
  pc2.addEventListener('track', e => {
    remote.srcObject = e.streams[0];
    remote.play();
  });
  await pc2.setRemoteDescription(offer);
  const answer = await pc2.createAnswer();
  
  await pc2.setLocalDescription(answer);
  await pc1.setRemoteDescription(answer);
}

async function start() {
  try {
    await sendTracks();
  } catch(e) {
    console.log(e);
    log(e);
  }
};

async function swap() {
  try {
    const devices = await navigator.mediaDevices.enumerateDevices();
    let newId = "";
    for (const device of devices) {
      if (device.kind == "audioinput" && device.label != audioTrack.label) {
        // First *other* microphone
        newId = device.deviceId;
        break;
      }
    }

    // First stop the existing audio track
    audioTrack.stop();

    // 2nd gUM
    const newStream = await navigator.mediaDevices.getUserMedia({
      audio: {
        deviceId: {
          exact: newId,
        },
      },
    });

    // Replace track in PC
    await pc1.getSenders()
             .filter(s => s.track == audioTrack)[0]
             .replaceTrack(newStream.getAudioTracks()[0]);
    audioTrack = newStream.getAudioTracks()[0];
  } catch(e) {
    console.log(e);
    log(e);
  }
}