mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-13 01:05:37 +02:00
This adds: - [x] Keyboard and mouse handling on the frontend - [x] Video and audio streaming from the backend to the frontend - [x] Input server that works with Websockets Update - 17/11 - [ ] Master docker container to run this - [ ] Steam runtime - [ ] Entrypoint.sh --------- Co-authored-by: Kristian Ollikainen <14197772+DatCaptainHorse@users.noreply.github.com> Co-authored-by: Kristian Ollikainen <DatCaptainHorse@users.noreply.github.com>
65 lines
1.7 KiB
TypeScript
65 lines
1.7 KiB
TypeScript
import type { Group, GroupReader } from "../transfork/model"
|
|
import { setVint62 } from "../transfork/stream"
|
|
|
|
export type FrameType = "key" | "delta"
|
|
|
|
export class Frame {
|
|
type: FrameType
|
|
timestamp: number
|
|
data: Uint8Array
|
|
|
|
constructor(type: FrameType, timestamp: number, data: Uint8Array) {
|
|
this.type = type
|
|
this.timestamp = timestamp
|
|
this.data = data
|
|
}
|
|
|
|
static async decode(group: GroupReader): Promise<Frame | undefined> {
|
|
const kind = group.index === 0 ? "key" : "delta"
|
|
const payload = await group.readFrame()
|
|
if (!payload) {
|
|
return undefined
|
|
}
|
|
|
|
const [timestamp, data] = decode_timestamp(payload)
|
|
return new Frame(kind, timestamp, data)
|
|
}
|
|
|
|
encode(group: Group) {
|
|
if ((group.length === 0) !== (this.type === "key")) {
|
|
throw new Error(`invalid ${this.type} position`)
|
|
}
|
|
|
|
let frame = new Uint8Array(8 + this.data.byteLength)
|
|
const size = setVint62(frame, BigInt(this.timestamp)).byteLength
|
|
frame.set(this.data, size)
|
|
frame = new Uint8Array(frame.buffer, 0, this.data.byteLength + size)
|
|
|
|
group.writeFrame(frame)
|
|
}
|
|
}
|
|
|
|
// QUIC VarInt
|
|
function decode_timestamp(buf: Uint8Array): [number, Uint8Array] {
|
|
const size = 1 << ((buf[0] & 0xc0) >> 6)
|
|
|
|
const view = new DataView(buf.buffer, buf.byteOffset, size)
|
|
const remain = new Uint8Array(buf.buffer, buf.byteOffset + size, buf.byteLength - size)
|
|
let v: number
|
|
|
|
if (size === 1) {
|
|
v = buf[0] & 0x3f
|
|
} else if (size === 2) {
|
|
v = view.getInt16(0) & 0x3fff
|
|
} else if (size === 4) {
|
|
v = view.getUint32(0) & 0x3fffffff
|
|
} else if (size === 8) {
|
|
// NOTE: Precision loss above 2^52
|
|
v = Number(view.getBigUint64(0) & 0x3fffffffffffffffn)
|
|
} else {
|
|
throw new Error("impossible")
|
|
}
|
|
|
|
return [v, remain]
|
|
}
|