mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 16:55:37 +02:00
✨ feat: Add streaming support (#125)
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>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
export class Deferred<T> {
|
||||
promise: Promise<T>
|
||||
resolve!: (value: T | PromiseLike<T>) => void
|
||||
reject!: (reason: any) => void
|
||||
reject!: (reason: unknown) => void
|
||||
pending = true
|
||||
|
||||
constructor() {
|
||||
@@ -35,16 +35,19 @@ export class Watch<T> {
|
||||
|
||||
update(v: T | ((v: T) => T)) {
|
||||
if (!this.#next.pending) {
|
||||
throw new Error("already closed")
|
||||
throw new Error("closed")
|
||||
}
|
||||
|
||||
// If we're given a function, call it with the current value
|
||||
let value: T
|
||||
if (v instanceof Function) {
|
||||
v = v(this.#current[0])
|
||||
value = v(this.#current[0])
|
||||
} else {
|
||||
value = v
|
||||
}
|
||||
|
||||
const next = new Deferred<WatchNext<T>>()
|
||||
this.#current = [v, next.promise]
|
||||
this.#current = [value, next.promise]
|
||||
this.#next.resolve(this.#current)
|
||||
this.#next = next
|
||||
}
|
||||
@@ -53,6 +56,10 @@ export class Watch<T> {
|
||||
this.#current[1] = undefined
|
||||
this.#next.resolve(this.#current)
|
||||
}
|
||||
|
||||
closed() {
|
||||
return !this.#next.pending
|
||||
}
|
||||
}
|
||||
|
||||
// Wakes up a multiple consumers.
|
||||
@@ -88,6 +95,7 @@ export class Queue<T> {
|
||||
}
|
||||
|
||||
async push(v: T) {
|
||||
if (this.#closed) throw new Error("closed")
|
||||
const w = this.#stream.writable.getWriter()
|
||||
await w.write(v)
|
||||
w.releaseLock()
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// I hate javascript
|
||||
export function asError(e: any): Error {
|
||||
export function asError(e: unknown): Error {
|
||||
if (e instanceof Error) {
|
||||
return e
|
||||
} else if (typeof e === "string") {
|
||||
return new Error(e)
|
||||
} else {
|
||||
return new Error(String(e))
|
||||
}
|
||||
if (typeof e === "string") {
|
||||
return new Error(e)
|
||||
}
|
||||
return new Error(String(e))
|
||||
}
|
||||
|
||||
export function isError(e: any): e is Error {
|
||||
export function isError(e: unknown): e is Error {
|
||||
return e instanceof Error
|
||||
}
|
||||
|
||||
11
packages/moq/common/hex.ts
Normal file
11
packages/moq/common/hex.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export function decode(str: string): Uint8Array {
|
||||
const bytes = new Uint8Array(str.length / 2)
|
||||
for (let i = 0; i < bytes.length; i += 1) {
|
||||
bytes[i] = Number.parseInt(str.slice(2 * i, 2 * i + 2), 16)
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
export function encode(_bytes: Uint8Array): string {
|
||||
throw "todo"
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
enum STATE {
|
||||
READ_POS = 0, // The current read position
|
||||
WRITE_POS, // The current write position
|
||||
LENGTH, // Clever way of saving the total number of enums values.
|
||||
WRITE_POS = 1, // The current write position
|
||||
LENGTH = 2, // Clever way of saving the total number of enums values.
|
||||
}
|
||||
|
||||
interface FrameCopyToOptions {
|
||||
@@ -62,16 +62,12 @@ export class Ring {
|
||||
const readPos = Atomics.load(this.state, STATE.READ_POS)
|
||||
const writePos = Atomics.load(this.state, STATE.WRITE_POS)
|
||||
|
||||
const startPos = writePos
|
||||
let endPos = writePos + frame.numberOfFrames
|
||||
const available = this.capacity - (writePos - readPos)
|
||||
if (available <= 0) return 0
|
||||
|
||||
if (endPos > readPos + this.capacity) {
|
||||
endPos = readPos + this.capacity
|
||||
if (endPos <= startPos) {
|
||||
// No space to write
|
||||
return 0
|
||||
}
|
||||
}
|
||||
const toWrite = Math.min(frame.numberOfFrames, available)
|
||||
const startPos = writePos
|
||||
const endPos = writePos + toWrite
|
||||
|
||||
const startIndex = startPos % this.capacity
|
||||
const endIndex = endPos % this.capacity
|
||||
@@ -114,7 +110,7 @@ export class Ring {
|
||||
|
||||
Atomics.store(this.state, STATE.WRITE_POS, endPos)
|
||||
|
||||
return endPos - startPos
|
||||
return toWrite
|
||||
}
|
||||
|
||||
read(dst: Float32Array[]): number {
|
||||
|
||||
Reference in New Issue
Block a user