initial commit

This commit is contained in:
AlexandreRouma
2025-10-31 18:38:33 -04:00
commit 140bc3c3f5
16 changed files with 1637 additions and 0 deletions

155
www/scripts/screen.js Normal file
View File

@@ -0,0 +1,155 @@
// Get or generate a display ID
let params = new URLSearchParams(document.location.search);
let dispID = params.get("dispID");
if (dispID === null) {
// Generate a random name (TODO)
dispID = self.crypto.randomUUID().substring(0, 6);
}
// App objects
let sock = null;
let conn = null;
// GUI Objects
let idleScreen = document.querySelector('#idleScreen');
let dispIDSpan = document.querySelector('#dispID');
let pinScreen = document.querySelector('#pinScreen');
let pinSpan = document.querySelector('#pin');
let playback = document.querySelector('#playback');
let credits = document.querySelector('#credits');
// Show the display ID
dispIDSpan.textContent = dispID;
async function reset() {
// Completely reset the state
playback.hidden = true;
pinScreen.hidden = true;
idleScreen.hidden = false;
credits.hidden = false;
playback.srcObject = null;
conn = null;
// Initialize WebRTC
await initRTC();
}
// WebSocket message handler
async function onMessage(data) {
// Parse the message
console.log(data)
const msg = JSON.parse(data);
// Process depending on the type
switch (msg.type) {
case 'conn-req':
// Show the pin
pinSpan.textContent = msg.pin;
// Switch to pin mode
idleScreen.hidden = true;
pinScreen.hidden = false;
break;
case 'offer':
console.log('Got offer')
// Pass on the offer to WebRTC
await conn.setRemoteDescription(new RTCSessionDescription(msg.offer));
// Create an answer
answer = await conn.createAnswer();
await conn.setLocalDescription(answer);
// Encode and send the answer
await sock.send(JSON.stringify({
type: 'answer',
answer: answer
}))
break;
case 'ice-candidate':
console.log('Got ice candidate')
// Add the ice candidate to the WebRTC connection
await conn.addIceCandidate(msg.candidate);
break;
case 'auth-ok':
break;
case 'disconnect':
// Reset the display
reset();
break;
default:
break;
}
}
async function initRTC() {
// Create the WebRTC connection
conn = new RTCPeerConnection({'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]});
// Handle new ice candidates
conn.addEventListener('icecandidate', async (event) => {
// If there is a new candidate, send it to the peer through websockets
if (event.candidate) {
await sock.send(JSON.stringify({
type: 'ice-candidate',
candidate: event.candidate
}))
}
});
// Handle connection and disconnection of peer
conn.addEventListener('connectionstatechange', (event) => {
switch (conn.connectionState) {
case 'connected':
// Switch to playback mode
pinScreen.hidden = true;
credits.hidden = true;
playback.hidden = false;
break;
case 'disconnected':
// Reset the display
reset();
break;
default:
break;
}
});
// Send remote stream to the playback widget
conn.addEventListener('track', (event) => {
const [remoteStream] = event.streams;
playback.srcObject = remoteStream;
});
}
// Main function for the app
async function main() {
// Connect to the server using WebSockets
console.log('Connecting to websocket...')
sock = new WebSocket(`ws://${location.host}/sig`);
// Add handlers for the socket
sock.addEventListener('message', (event) => { onMessage(event.data); })
sock.addEventListener('open', async (event) => {
console.log('Connected to websocket')
// Tell the server that this is a screen
await sock.send(JSON.stringify({
type: 'screen',
name: dispID
}))
// Initialize WebRTC
await initRTC();
});
}
// Run the main function
main();