<video id="v" controls muted style="max-width: 100%; max-height: 100%" onclick="undefined"> <source id="s" /> </video> <br /><button onclick="socket.emit('reqpos')">sync position</button> <button onclick="socket.emit('syncme')">resync all</button> <script src="/socket.io/socket.io.min.js"></script> <script> var video = document.getElementById("v"); var source = document.getElementById("s"); onclick = () => video.muted = false; var socket = io({ transports: ["websocket"] }); socket.emit("syncme"); socket.on("media", file => { source.src = file; video.load(); }); socket.on("pos", seek); socket.on("play", play); socket.on("pause", play); //socket.on("end", () => console.log("end")); // detect human-caused events and ignore echo from server video.onseeked = () => { socket.off("pos", seek); socket.once("pos", () => socket.on("pos", seek)); socket.emit("c_pos", video.currentTime * 1000); }; video.onpause = () => { socket.off("pause", pause); socket.once("pause", () => socket.on("pause", pause)); socket.emit("c_pause"); } video.onplay = () => { socket.off("play", play); socket.once("play", () => socket.on("play", play)); socket.emit("c_play"); }; // programatic play/pause/seek without triggering event listeners function play() { var e = video.onplay; video.onplay = () => video.onplay = e; video.play(); } function pause() { var e = video.onpause; video.onpause = () => video.onpause = e; video.pause(); } function seek(time) { var e = video.onseeked; video.onseeked = () => video.onseeked = e; video.currentTime = time / 1000; } </script>