Skip to content

Instantly share code, notes, and snippets.

@lynaghk
Last active July 15, 2022 14:21
Show Gist options
  • Save lynaghk/e37f7dc54305382e803f8f6ddac4f40d to your computer and use it in GitHub Desktop.
Save lynaghk/e37f7dc54305382e803f8f6ddac4f40d to your computer and use it in GitHub Desktop.

Revisions

  1. lynaghk renamed this gist Feb 15, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. lynaghk created this gist Feb 15, 2022.
    4 changes: 4 additions & 0 deletions 0_readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    "Serverless" WebRTC demo

    Start a server on localhost and open `index.html` (the host) and `index.html#client` (the client) in two different browser windows.
    They'll do their lil' p2p connection discovery dance via the wonderful public service that is https://patchbay.pub/ and, once established, a video-only camera feed from the client will display on the host.
    101 changes: 101 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@
    <html>
    <body>
    <h1 id="status">Loading</h1>
    <video id="remoteVideo" muted autoplay style="width: 100%;"></video>
    <script>
    let is_client = window.location.hash === "#client";

    let url_send = "https://patchbay.pub/pubsub/webrtc-demo-12345-" + (is_client ? "host" : "client");
    let url_recv = "https://patchbay.pub/pubsub/webrtc-demo-12345-" + (is_client ? "client" : "host");

    function log(msg) {
    document.getElementById("status").innerText = `${msg}\n\n`;
    console.log(msg);
    }

    function send (msg) {
    let json = JSON.stringify(msg);
    fetch(url_send, {method: "POST", body: `data: ${json}\n\n`});
    }


    let pc = new RTCPeerConnection({
    "iceServers": [
    {"urls": ["stun:stun.l.google.com:19302",
    "stun:stun.stunprotocol.org:3478"]},
    ]
    });


    pc.onicecandidate = (e) => {
    if(e.candidate != null) {
    send({"ice": e.candidate});
    }
    }

    pc.onconnectionstatechange = (e) => {
    let state = pc.connectionState;
    log(`Connection: ${state}`);
    }


    if(!is_client){
    pc.ontrack = ({track, streams: [stream]}) => {
    //"unmute" here actually means "track is able to send data"
    track.onunmute = () => {
    status.innerText = "";
    //Chrome will autoplay muted video.
    remoteVideo.srcObject = stream;
    };
    }
    }


    if(is_client){

    pc.onnegotiationneeded = (e) => {
    pc.createOffer({offerToReceiveVideo: 1})
    .then((offer) => pc.setLocalDescription(offer))
    .then(() => {
    log("Connecting to host.");
    send({"sdp": pc.localDescription})
    })
    .catch(log)
    }

    log("Requesting camera.");
    navigator.mediaDevices.getUserMedia({
    video: {width: { ideal: 4096 }}, //Go big or go home; odds are we'll get a p2p connection over LAN
    audio: false,
    }).then((stream) => {
    stream.getTracks().forEach((t) => pc.addTrack(t, stream));
    }).catch(log);

    }

    let incoming = new EventSource(`${url_recv}?mime=text%2Fevent-stream&persist=true`);
    incoming.onmessage = (e) => {
    let msg = JSON.parse(e.data);

    if(msg.sdp){
    pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
    .then(() => {
    if("offer" == msg.sdp.type){
    //create and send answer
    pc.createAnswer()
    .then((answer) => pc.setLocalDescription(answer))
    .then(() => send({"sdp": pc.localDescription}))
    .catch(log)
    }
    }).catch(log)
    }

    if(msg.ice){
    pc.addIceCandidate(new RTCIceCandidate(msg.ice)).catch(log)
    }

    }

    </script>
    </body>
    </html>