frontend: stream and fullscreen cleanup
This commit is contained in:
@@ -12,13 +12,19 @@
|
||||
let loading = $state(true);
|
||||
let fullscreen = $state(false);
|
||||
let gameplayView: HTMLDivElement;
|
||||
let gameplayCanvas: HTMLCanvasElement;
|
||||
|
||||
async function startStream() {
|
||||
console.log(`Connecting to stream at ${url} with cert_hash ${certHash}`);
|
||||
await streamUrl(url, certHash);
|
||||
await streamUrl(url, certHash, gameplayCanvas);
|
||||
}
|
||||
|
||||
async function requestFullscreen() {
|
||||
// Update fullscreen var if fullscreen was exited outside our control
|
||||
if (document.fullscreenElement == null) {
|
||||
fullscreen = false;
|
||||
}
|
||||
|
||||
if (fullscreen) {
|
||||
await document.exitFullscreen();
|
||||
fullscreen = false;
|
||||
@@ -36,7 +42,7 @@
|
||||
</script>
|
||||
|
||||
<div id="gameplay-view" class="gameplay-view" bind:this={gameplayView}>
|
||||
<canvas id="gamestream-canvas" class="gamestream-canvas"></canvas>
|
||||
<canvas id="gamestream-canvas" class="gamestream-canvas" bind:this={gameplayCanvas}></canvas>
|
||||
<StreamUi fullscreenFunc={requestFullscreen}></StreamUi>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,92 +26,89 @@ type DecodeUnitPacket = {
|
||||
DecodeUnit: DecodeUnit
|
||||
}
|
||||
|
||||
async function connectToUrl(url: string, certHash: Uint8Array): Promise<WebTransport> {
|
||||
console.log('Hash: ', certHash);
|
||||
console.log(`Connecting to stream`);
|
||||
|
||||
// Check if WebTransport is supported
|
||||
if (!window.WebTransport) {
|
||||
throw new Error('WebTransport is not supported in this browser');
|
||||
}
|
||||
|
||||
export async function streamUrl(url: string, cert_hash: Array<number>) {
|
||||
const buffer = new Uint8Array(cert_hash);
|
||||
console.log('Hash: ', buffer);
|
||||
try {
|
||||
console.log(`Connecting to stream`);
|
||||
|
||||
// Check if WebTransport is supported
|
||||
if (!window.WebTransport) {
|
||||
throw new Error('WebTransport is not supported in this browser');
|
||||
}
|
||||
|
||||
//const url = new URL();
|
||||
const transport = new WebTransport(url, {
|
||||
serverCertificateHashes: [
|
||||
{
|
||||
algorithm: "sha-256",
|
||||
value: buffer,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
console.log('Connecting to WebTransport at ', url);
|
||||
// Wait for the connection to be ready
|
||||
await transport.ready;
|
||||
console.log('WebTransport connection established');
|
||||
|
||||
|
||||
console.log('Creating WebTransport bidirectional stream');
|
||||
const stream = await transport.createBidirectionalStream();
|
||||
console.log('Bidirectional stream created');
|
||||
|
||||
const reader = stream.readable.getReader();
|
||||
|
||||
function parseData(newBuffer: Uint8Array, oldBuffer: Uint8Array): [Array<Object>, Uint8Array<ArrayBuffer>] {
|
||||
let packets = new Array<Object>();
|
||||
let unparsedData = new Uint8Array();
|
||||
|
||||
let data = new Uint8Array([...oldBuffer, ...newBuffer]);
|
||||
let index = 0;
|
||||
while (true) {
|
||||
if (index >= data.length) {
|
||||
break
|
||||
}
|
||||
const view = new DataView(data.buffer.slice(index, index + 4));
|
||||
const dataLength = view.getUint32(0, true);
|
||||
|
||||
const slice_start_index = index + 4;
|
||||
const slice_end_index = index + 4 + dataLength;
|
||||
|
||||
if (data.length < slice_end_index) {
|
||||
unparsedData = new Uint8Array(data.buffer.slice(index, data.length));
|
||||
break;
|
||||
}
|
||||
|
||||
const dataToParse = data.buffer.slice(slice_start_index, slice_end_index);
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const jsonString = decoder.decode(dataToParse);
|
||||
|
||||
packets.push(JSON.parse(jsonString));
|
||||
|
||||
index += 4 + dataLength;
|
||||
const transport = new WebTransport(url, {
|
||||
serverCertificateHashes: [
|
||||
{
|
||||
algorithm: "sha-256",
|
||||
value: certHash,
|
||||
}
|
||||
return [packets, unparsedData];
|
||||
]
|
||||
});
|
||||
|
||||
console.log('Connecting to WebTransport at ', url);
|
||||
// Wait for the connection to be ready
|
||||
await transport.ready;
|
||||
console.log('WebTransport connection established');
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
||||
function parseData(newBuffer: Uint8Array, oldBuffer: Uint8Array): [Array<Object>, Uint8Array<ArrayBuffer>] {
|
||||
let packets = new Array<Object>();
|
||||
let unparsedData = new Uint8Array();
|
||||
|
||||
let data = new Uint8Array([...oldBuffer, ...newBuffer]);
|
||||
let index = 0;
|
||||
while (true) {
|
||||
if (index >= data.length) {
|
||||
break
|
||||
}
|
||||
const view = new DataView(data.buffer.slice(index, index + 4));
|
||||
const dataLength = view.getUint32(0, true);
|
||||
|
||||
const slice_start_index = index + 4;
|
||||
const slice_end_index = index + 4 + dataLength;
|
||||
|
||||
if (data.length < slice_end_index) {
|
||||
unparsedData = new Uint8Array(data.buffer.slice(index, data.length));
|
||||
break;
|
||||
}
|
||||
|
||||
const dataToParse = data.buffer.slice(slice_start_index, slice_end_index);
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const jsonString = decoder.decode(dataToParse);
|
||||
|
||||
packets.push(JSON.parse(jsonString));
|
||||
|
||||
index += 4 + dataLength;
|
||||
}
|
||||
return [packets, unparsedData];
|
||||
}
|
||||
|
||||
export async function streamUrl(url: string, certHash: Array<number>, canvasElement: HTMLCanvasElement) {
|
||||
const certHashArray = new Uint8Array(certHash);
|
||||
|
||||
const transport = await connectToUrl(url, certHashArray);
|
||||
console.log('Creating WebTransport bidirectional stream');
|
||||
const stream = await transport.createBidirectionalStream();
|
||||
console.log('Bidirectional stream created');
|
||||
|
||||
const canvasCtx: CanvasRenderingContext2D | null = canvasElement.getContext('2d');
|
||||
if (canvasCtx == null) {
|
||||
throw new Error(`Could not get 2d canvas context`);
|
||||
}
|
||||
|
||||
const reader = stream.readable.getReader();
|
||||
try {
|
||||
let unparsedData = new Uint8Array();
|
||||
|
||||
const canvas: HTMLCanvasElement | null = <HTMLCanvasElement>document.getElementById('gamestream-canvas');
|
||||
if (canvas == null) {
|
||||
throw new Error(`Could not find canvas`);
|
||||
}
|
||||
const ctx: CanvasRenderingContext2D | null = canvas.getContext('2d');
|
||||
if (ctx == null) {
|
||||
throw new Error(`Could not get 2d canvas context`);
|
||||
}
|
||||
|
||||
const videoDecoder = new VideoDecoder({
|
||||
output: (frame) => {
|
||||
// Set canvas dimensions to match the frame
|
||||
canvas.width = frame.displayWidth;
|
||||
canvas.height = frame.displayHeight;
|
||||
canvasElement.width = frame.displayWidth;
|
||||
canvasElement.height = frame.displayHeight;
|
||||
|
||||
// Draw the decoded frame to canvas
|
||||
ctx.drawImage(frame, 0, 0);
|
||||
canvasCtx.drawImage(frame, 0, 0);
|
||||
|
||||
// Important: close the frame to free memory
|
||||
frame.close();
|
||||
@@ -174,9 +171,6 @@ export async function streamUrl(url: string, cert_hash: Array<number>) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Handle connection close
|
||||
transport.closed.then(() => {
|
||||
console.log('WebTransport connection closed');
|
||||
@@ -187,7 +181,8 @@ export async function streamUrl(url: string, cert_hash: Array<number>) {
|
||||
// You can add more WebTransport handling logic here
|
||||
// For example, handling incoming streams, sending data, etc.
|
||||
|
||||
} catch (error) {
|
||||
} catch (e) {
|
||||
var error = <Error>e;
|
||||
console.error('Error connecting to stream:', error);
|
||||
alert('Failed to connect to stream: ' + error.message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user