First working version

This commit is contained in:
2023-09-14 11:43:36 +02:00
commit b6fb65eb0a
7 changed files with 356 additions and 0 deletions

95
static/js/display.js Normal file
View File

@ -0,0 +1,95 @@
async function init(
name="loled-display",
width = window.innerWidth,
height = window.innerHeight,
){
const display = document.getElementById("display")
const video = document.getElementById("display-video")
const nameEl = document.getElementById("display-name")
let peerConnection = null
async function setNewConnection(offer, iceCandidates){
const connection = new RTCPeerConnection({
iceServers: [
{urls: ["stun:stun.nextcloud.com:443"]}
]
})
connection.addEventListener("track", (e) => {
if(e.streams.length > 0){
video.srcObject = e.streams[0]
video.play()
}
})
connection.addEventListener("connectionstatechange", () => {
if(connection.connectionState == "connected"){
nameEl.hidden = true
} else if(["closed", "failed", "disconnected"].indexOf(connection.connectionState)) {
nameEl.hidden = false
}
})
connection.setRemoteDescription(new RTCSessionDescription(offer))
for(const it of iceCandidates){
connection.addIceCandidate(it ? new RTCIceCandidate(it) : undefined)
}
const answr = await connection.createAnswer()
connection.setLocalDescription(answr)
await fetch("/_loled/display/put-answer", {
method: "POST",
body: JSON.stringify(answr),
headers: {"content-type": "application/json"}
})
console.log("New offer received")
if(peerConnection){
peerConnection.close()
}
peerConnection = connection
nameEl.hidden = true
}
display.style.width = width+"px"
display.style.height = height+"px"
display.style.setProperty("--display-width", width+"px")
display.style.setProperty("--display-height", height+"px")
const [registration, registerdName] = await getRegistration(name)
name = registerdName;
nameEl.hidden = false
registration.addEventListener("message", e => {
const message = JSON.parse(e.data)
if(message.type == "offer"){
setNewConnection(message.offer, message.iceCandidates)
}
})
}
async function getRegistration(name){
console.info("Waiting welcome message")
const reg = new EventSource("/_loled/display/register?name="+name)
const registeredName = await new Promise((res, rej) => {
reg.addEventListener("message", e => {
const message = JSON.parse(e.data)
if(message.type != 'welcome'){
rej(new Error("Invalid message received"))
}
res(message.name)
}, {once: true})
})
console.info(`display registerd with name ${registeredName}`)
return [reg, registeredName]
}
const args = new URLSearchParams(location.search);
init(
args.get("name"),
parseInt(args.get("width")),
parseInt(args.get("height"))
)

48
static/js/grab-canvas.js Normal file
View File

@ -0,0 +1,48 @@
(async () => {
const globalConnnection = Symbol("grab-canvas-connection")
const currentScriptSrc = document.currentScript.src;
const canvas = document.querySelector("canvas");
if(!canvas){
console.error("No canvas found on this page")
}
const conn = new RTCPeerConnection({
iceServers: [
{urls: ["stun:stun.nextcloud.com:443"]}
]
});
const iceCandidates = []
conn.addEventListener("icecandidate", e => {
iceCandidates.push(e.candidate)
})
const allCandidatesCollected = new Promise(res =>
conn.addEventListener("icecandidate", e => e.candidate == null && res() ))
const canvasStream = canvas.captureStream()
const canvasStreamTracks = canvasStream.getVideoTracks()
if(canvasStreamTracks.length > 0){
conn.addTrack(canvasStreamTracks[0], canvasStream)
}
const offer = await conn.createOffer();
await conn.setLocalDescription(offer);
await allCandidatesCollected
const res = await fetch(new URL("/_loled/grab-display", currentScriptSrc), {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
offer,
iceCandidates
})
})
const response = new RTCSessionDescription(await res.json());
conn.setRemoteDescription(response);
window[globalConnnection] = conn
})()