|
<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> |