Establish a peer-to-peer connection and manage data channels for audio transmission.

by fippo

HTML

<video  id="remoteVideo" autoplay muted></video>
<div id="log"></div>

JavaScript

function log(text) {
  document.getElementById('log').innerText += text + '\n';
}

const pc1 = new RTCPeerConnection({alwaysNegotiateDataChannels: true});
const pc2 = new RTCPeerConnection();
pc1.onicecandidate = (e) => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = (e) => pc1.addIceCandidate(e.candidate);
pc2.ontrack = e => remoteVideo.srcObject = e.streams[0];
pc1.addEventListener('connectionstatechange', () => log(pc1.connectionState));
async function run() {
  const stream = await navigator.mediaDevices.getUserMedia({video: true});
  pc1.createDataChannel('...');
  pc1.addTransceiver('audio');
  pc1.addTrack(stream.getTracks()[0], stream);
  await pc1.setLocalDescription();
  await pc2.setRemoteDescription(pc1.localDescription);
  await pc2.setLocalDescription();
  await pc1.setRemoteDescription(pc2.localDescription);

  await new Promise(r => {
    if (pc1.connectionState === 'connected') return r();
    pc1.addEventListener('connectionstatechange', () => {
      if (pc1.connectionState === 'connected') return r();
    });
  });
  log('connected');
  await new Promise(r => setTimeout(r, 1000)); // wait 1 seconds.

  pc1.getTransceivers()[0].stop(); // stops the audio transceiver.
  log('stopped transceiver, video will freeze');
  await pc1.setLocalDescription();
  await pc2.setRemoteDescription(pc1.localDescription);
  await new Promise(r => setTimeout(r, 4000)); // wait 4 seconds.
  log('renegotiated');
  await pc2.setLocalDescription();
  await pc1.setRemoteDescription(pc2.localDescription);
  await new Promise(r => setTimeout(r, 1000)); // wait 1 seconds.
  const stats = await pc2.getStats();
  const freezes = [...stats.values()].filter(s => s.type === 'inbound-rtp' && s.kind === 'video').map(s => s.totalFreezesDuration);
  log('FREEZE ' + JSON.stringify(freezes) + ' seconds');
}
run();