perfect negotiation 3

by jib1

JavaScript

async function peer(other, polite, width = 160, height = 120) {
  // This creates all the buttons. You can skip this part
  const create = (container, type) => container.appendChild(document.createElement(type));
  const body = create(document.documentElement, "body");
  const camera = createCheckbox("Camera"), noise = createCheckbox("Noise");
  const both = polite && createCheckbox("Both noise");
  function createCheckbox(textContent) {
    const label = create(body, "label");
    const input = Object.assign(create(label, "input"), {type: "checkbox"});
    Object.assign(create(label, "text"), {textContent});
    return input;
  }
  const div = create(body, "div");
  const log = msg => div.innerHTML += `${msg}<br>`;
  const signaling = window;
  signaling.send = msg => other.postMessage(JSON.parse(JSON.stringify(msg)), "*");

  // This is the main application logic
  try {
    const pc = new RTCPeerConnection();
    const dc = pc.createDataChannel("both", {negotiated: true, id: 0});
    if (polite) pc.oniceconnectionstatechange = () => log(pc.iceConnectionState);

    camera.onclick = () => onOff(camera, () => navigator.mediaDevices.getUserMedia({video: true}));
    noise.onclick = () => onOff(noise, whiteNoise);
    both.onclick = () => { dc.send(both.checked); dc.onmessage({data: both.checked}); }
    dc.onmessage = ({data}) => noise.checked == JSON.parse(data) || noise.click();

    const onOff = async (button, getMedia) => {
      try {
        if (button.checked) {
          if (!button.stream) button.stream = await getMedia();
          button.transceiver = pc.addTransceiver(button.stream.getTracks()[0], {streams: [button.stream]});
        } else {
          button.transceiver.stop();
        }
      } catch (e) {
        log(e);
      }
    }

    pc.ontrack = ({streams: [stream]}) => {
      if (!stream.video) {
        stream.video = Object.assign(create(body, "video"), {width, height, autoplay: true});
      }
      stream.video.srcObject = stream;
   ...