JSFiddle - React, Tailwind, and code Playground

HTML

<button onclick="start()">start</button>
<br>
<video id="video1" autoplay playsInline controls></video>
<video id="video2" autoplay playsInline controls></video>
<br>
<div id="log"></div>

JavaScript

async function exchange(useRemote, stream)
{
  if (!stream) {
	  const context = new AudioContext();
  	const oscillator = context.createOscillator();
  	const streamDestination = context.createMediaStreamDestination();
  	oscillator.connect(streamDestination);
  	oscillator.start();
    stream = streamDestination.stream;
  }
	if (!useRemote) {
		video2.srcObject = stream;
	 	await video2.play();
  	return;
	}


  const localPC = new RTCPeerConnection();
  const remotePC = new RTCPeerConnection();
  remotePC.onicecandidate = event => event.candidate && localPC.addIceCandidate(event.candidate);
  localPC.onicecandidate = event => event.candidate && remotePC.addIceCandidate(event.candidate);

  const result = new Promise(resolve => {
    remotePC.ontrack = event => {
      console.log('got track:', event.track);
      resolve({
        remoteTrack: event.track,
        remoteStream: new MediaStream([event.track]),
        localPC,
        remotePC
      });
    };
  });

	localPC.addTrack(stream.getAudioTracks()[0], stream);
  const offer = await localPC.createOffer();
  await localPC.setLocalDescription(offer);
  await remotePC.setRemoteDescription(offer);
  const answer = await remotePC.createAnswer();
  await remotePC.setLocalDescription(answer);
  await localPC.setRemoteDescription(answer);
  const res = await result;
  video2.srcObject = res.remoteStream;
  await video2.play();
  return localPC.getSenders()[0];
}

async function start()
{
		const defaultAudioConstraints = {
    		sampleRate: 48000,
    		sampleSize: 16,
    		channelCount: 1,
    		echoCancellation: true,
    		noiseSuppression: true
  	};
	  const musicModeAudioConstraints = {
    		sampleRate: 48000,
    		sampleSize: 16,
    		channelCount: 2,
    		echoCancellation: false,
  	  	noiseSuppression: false
	  };

		const stream1 = await navigator.mediaDevices.getUserMedia({ audio: defaultAudioConstraints}); 
    video1.srcObject = stream1;
		const sender = await exchange(true,...