frontend: stream and fullscreen cleanup
This commit is contained in:
@@ -12,13 +12,19 @@
|
|||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let fullscreen = $state(false);
|
let fullscreen = $state(false);
|
||||||
let gameplayView: HTMLDivElement;
|
let gameplayView: HTMLDivElement;
|
||||||
|
let gameplayCanvas: HTMLCanvasElement;
|
||||||
|
|
||||||
async function startStream() {
|
async function startStream() {
|
||||||
console.log(`Connecting to stream at ${url} with cert_hash ${certHash}`);
|
console.log(`Connecting to stream at ${url} with cert_hash ${certHash}`);
|
||||||
await streamUrl(url, certHash);
|
await streamUrl(url, certHash, gameplayCanvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestFullscreen() {
|
async function requestFullscreen() {
|
||||||
|
// Update fullscreen var if fullscreen was exited outside our control
|
||||||
|
if (document.fullscreenElement == null) {
|
||||||
|
fullscreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
await document.exitFullscreen();
|
await document.exitFullscreen();
|
||||||
fullscreen = false;
|
fullscreen = false;
|
||||||
@@ -36,7 +42,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="gameplay-view" class="gameplay-view" bind:this={gameplayView}>
|
<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>
|
<StreamUi fullscreenFunc={requestFullscreen}></StreamUi>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -26,92 +26,89 @@ type DecodeUnitPacket = {
|
|||||||
DecodeUnit: DecodeUnit
|
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 transport = new WebTransport(url, {
|
||||||
const buffer = new Uint8Array(cert_hash);
|
serverCertificateHashes: [
|
||||||
console.log('Hash: ', buffer);
|
{
|
||||||
try {
|
algorithm: "sha-256",
|
||||||
console.log(`Connecting to stream`);
|
value: certHash,
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
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();
|
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({
|
const videoDecoder = new VideoDecoder({
|
||||||
output: (frame) => {
|
output: (frame) => {
|
||||||
// Set canvas dimensions to match the frame
|
// Set canvas dimensions to match the frame
|
||||||
canvas.width = frame.displayWidth;
|
canvasElement.width = frame.displayWidth;
|
||||||
canvas.height = frame.displayHeight;
|
canvasElement.height = frame.displayHeight;
|
||||||
|
|
||||||
// Draw the decoded frame to canvas
|
// Draw the decoded frame to canvas
|
||||||
ctx.drawImage(frame, 0, 0);
|
canvasCtx.drawImage(frame, 0, 0);
|
||||||
|
|
||||||
// Important: close the frame to free memory
|
// Important: close the frame to free memory
|
||||||
frame.close();
|
frame.close();
|
||||||
@@ -174,9 +171,6 @@ export async function streamUrl(url: string, cert_hash: Array<number>) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Handle connection close
|
// Handle connection close
|
||||||
transport.closed.then(() => {
|
transport.closed.then(() => {
|
||||||
console.log('WebTransport connection closed');
|
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
|
// You can add more WebTransport handling logic here
|
||||||
// For example, handling incoming streams, sending data, etc.
|
// For example, handling incoming streams, sending data, etc.
|
||||||
|
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
|
var error = <Error>e;
|
||||||
console.error('Error connecting to stream:', error);
|
console.error('Error connecting to stream:', error);
|
||||||
alert('Failed to connect to stream: ' + error.message);
|
alert('Failed to connect to stream: ' + error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user