mirror of
https://github.com/bluenviron/mediamtx
synced 2025-01-11 17:39:51 +00:00
b20abbed6c
The WebSocket connection is kept open in order to use it to notify shutdowns.
165 lines
3.5 KiB
HTML
165 lines
3.5 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<style>
|
|
html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
#video {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: black;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<video id="video" muted controls autoplay playsinline></video>
|
|
|
|
<script>
|
|
|
|
const restartPause = 2000;
|
|
|
|
class Receiver {
|
|
constructor() {
|
|
this.terminated = false;
|
|
this.ws = null;
|
|
this.pc = null;
|
|
this.restartTimeout = null;
|
|
this.start();
|
|
}
|
|
|
|
start() {
|
|
console.log("connecting");
|
|
|
|
this.ws = new WebSocket(window.location.href.replace(/^http/, "ws") + 'ws');
|
|
|
|
this.ws.onerror = () => {
|
|
console.log("ws error");
|
|
if (this.ws === null) {
|
|
return;
|
|
}
|
|
this.ws.close();
|
|
this.ws = null;
|
|
};
|
|
|
|
this.ws.onclose = () => {
|
|
console.log("ws closed");
|
|
this.ws = null;
|
|
this.scheduleRestart();
|
|
};
|
|
|
|
this.ws.onmessage = (msg) => this.onIceServers(msg);
|
|
}
|
|
|
|
onIceServers(msg) {
|
|
if (this.ws === null) {
|
|
return;
|
|
}
|
|
|
|
const iceServers = JSON.parse(msg.data);
|
|
|
|
this.pc = new RTCPeerConnection({
|
|
iceServers,
|
|
});
|
|
|
|
this.ws.onmessage = (msg) => this.onRemoteDescription(msg);
|
|
this.pc.onicecandidate = (evt) => this.onIceCandidate(evt);
|
|
|
|
this.pc.oniceconnectionstatechange = () => {
|
|
if (this.pc === null) {
|
|
return;
|
|
}
|
|
|
|
console.log("peer connection state:", this.pc.iceConnectionState);
|
|
|
|
switch (this.pc.iceConnectionState) {
|
|
case "disconnected":
|
|
this.scheduleRestart();
|
|
}
|
|
};
|
|
|
|
this.pc.ontrack = (evt) => {
|
|
console.log("new track " + evt.track.kind);
|
|
document.getElementById("video").srcObject = evt.streams[0];
|
|
};
|
|
|
|
const direction = "sendrecv";
|
|
this.pc.addTransceiver("video", { direction });
|
|
this.pc.addTransceiver("audio", { direction });
|
|
|
|
this.pc.createOffer()
|
|
.then((desc) => {
|
|
if (this.pc === null || this.ws === null) {
|
|
return;
|
|
}
|
|
|
|
this.pc.setLocalDescription(desc);
|
|
|
|
console.log("sending offer");
|
|
this.ws.send(JSON.stringify(desc));
|
|
});
|
|
}
|
|
|
|
onRemoteDescription(msg) {
|
|
if (this.pc === null || this.ws === null) {
|
|
return;
|
|
}
|
|
|
|
this.pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(msg.data)));
|
|
this.ws.onmessage = (msg) => this.onRemoteCandidate(msg);
|
|
}
|
|
|
|
onIceCandidate(evt) {
|
|
if (this.ws === null) {
|
|
return;
|
|
}
|
|
|
|
if (evt.candidate !== null) {
|
|
if (evt.candidate.candidate !== "") {
|
|
this.ws.send(JSON.stringify(evt.candidate));
|
|
}
|
|
}
|
|
}
|
|
|
|
onRemoteCandidate(msg) {
|
|
if (this.pc === null) {
|
|
return;
|
|
}
|
|
|
|
this.pc.addIceCandidate(JSON.parse(msg.data));
|
|
}
|
|
|
|
scheduleRestart() {
|
|
if (this.terminated) {
|
|
return;
|
|
}
|
|
|
|
if (this.ws !== null) {
|
|
this.ws.close();
|
|
this.ws = null;
|
|
}
|
|
|
|
if (this.pc !== null) {
|
|
this.pc.close();
|
|
this.pc = null;
|
|
}
|
|
|
|
this.restartTimeout = window.setTimeout(() => {
|
|
this.restartTimeout = null;
|
|
this.start();
|
|
}, restartPause);
|
|
}
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', () => new Receiver());
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|