RTCIceCandidate role

by jib1

HTML

<video id="video1" width="160" height="120" autoplay muted></video>
<video id="video2" width="160" height="120" autoplay></video><br>
<div id="div"></div>

JavaScript

const console = {log: msg => div.innerHTML += `${msg}<br>`};
const dump = f => console.log(`${f.toString().slice(6)} = ${JSON.stringify(f(), null, 2)}`);
const wait = ms => new Promise(r => setTimeout(r, ms));
const pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();

(async () => {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({video: true});
    for (const track of stream.getTracks()) {
      pc1.addTrack(track, stream);
    }
    await pc1.setLocalDescription();
    console.log("PC1 after SLD(offer):");
    const {iceTransport} = pc1.getTransceivers()[0].sender.transport;
    dump(() => iceTransport);
    dump(() => iceTransport.role);
    dump(() => iceTransport.component);
    dump(() => iceTransport.state);
    dump(() => iceTransport.gatheringState);
    await pc2.setRemoteDescription(pc1.localDescription);
    console.log("PC2 after SRD(offer):");
    dump(() => pc2.getTransceivers()[0].receiver.transport);
    await pc2.setLocalDescription();
    console.log("PC2 after SLD(answer):");
    const iceTransport2 = pc2.getTransceivers()[0].receiver.transport.iceTransport;
    dump(() => iceTransport2);
    dump(() => iceTransport2.role);
    dump(() => iceTransport2.component);
    dump(() => iceTransport2.state);
    dump(() => iceTransport2.gatheringState);
    await pc1.setRemoteDescription(pc2.localDescription);

    console.log("PC1:");
    dump(() => iceTransport.role);
    await wait(1000);
    dump(() => iceTransport.role);
  } catch (e) {
    console.log(e);
  }
})();

pc1.onicecandidate = ({candidate}) => pc2.addIceCandidate(candidate);
pc2.onicecandidate = ({candidate}) => pc1.addIceCandidate(candidate);
pc1.oniceconnectionstatechange = () => console.log(pc1.iceConnectionState);