mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +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,9 +1,8 @@
|
||||
import { Segment } from "./segment"
|
||||
import { Notify } from "../common/async"
|
||||
import { Chunk } from "./chunk"
|
||||
import { Container } from "./container"
|
||||
import { BroadcastConfig } from "./broadcast"
|
||||
import type { BroadcastConfig } from "./broadcast"
|
||||
import { Segment } from "./segment"
|
||||
|
||||
import type { Frame } from "../karp/frame"
|
||||
import * as Audio from "./audio"
|
||||
import * as Video from "./video"
|
||||
|
||||
@@ -36,7 +35,6 @@ export class Track {
|
||||
async #runAudio(track: MediaStreamAudioTrack, config: AudioEncoderConfig) {
|
||||
const source = new MediaStreamTrackProcessor({ track })
|
||||
const encoder = new Audio.Encoder(config)
|
||||
const container = new Container()
|
||||
|
||||
// Split the container at keyframe boundaries
|
||||
const segments = new WritableStream({
|
||||
@@ -45,13 +43,12 @@ export class Track {
|
||||
abort: (e) => this.#close(e),
|
||||
})
|
||||
|
||||
return source.readable.pipeThrough(encoder.frames).pipeThrough(container.encode).pipeTo(segments)
|
||||
return source.readable.pipeThrough(encoder.frames).pipeTo(segments)
|
||||
}
|
||||
|
||||
async #runVideo(track: MediaStreamVideoTrack, config: VideoEncoderConfig) {
|
||||
const source = new MediaStreamTrackProcessor({ track })
|
||||
const encoder = new Video.Encoder(config)
|
||||
const container = new Container()
|
||||
|
||||
// Split the container at keyframe boundaries
|
||||
const segments = new WritableStream({
|
||||
@@ -60,18 +57,12 @@ export class Track {
|
||||
abort: (e) => this.#close(e),
|
||||
})
|
||||
|
||||
return source.readable.pipeThrough(encoder.frames).pipeThrough(container.encode).pipeTo(segments)
|
||||
return source.readable.pipeThrough(encoder.frames).pipeTo(segments)
|
||||
}
|
||||
|
||||
async #write(chunk: Chunk) {
|
||||
if (chunk.type === "init") {
|
||||
this.#init = chunk.data
|
||||
this.#notify.wake()
|
||||
return
|
||||
}
|
||||
|
||||
async #write(frame: Frame) {
|
||||
let current = this.#segments.at(-1)
|
||||
if (!current || chunk.type === "key") {
|
||||
if (!current || frame.type === "key") {
|
||||
if (current) {
|
||||
await current.input.close()
|
||||
}
|
||||
@@ -88,7 +79,7 @@ export class Track {
|
||||
const first = this.#segments[0]
|
||||
|
||||
// Expire after 10s
|
||||
if (chunk.timestamp - first.timestamp < 10_000_000) break
|
||||
if (frame.timestamp - first.timestamp < 10_000_000) break
|
||||
this.#segments.shift()
|
||||
this.#offset += 1
|
||||
|
||||
@@ -99,7 +90,7 @@ export class Track {
|
||||
const writer = current.input.getWriter()
|
||||
|
||||
if ((writer.desiredSize || 0) > 0) {
|
||||
await writer.write(chunk)
|
||||
await writer.write(frame)
|
||||
} else {
|
||||
console.warn("dropping chunk", writer.desiredSize)
|
||||
}
|
||||
@@ -147,7 +138,8 @@ export class Track {
|
||||
if (this.#error) {
|
||||
controller.error(this.#error)
|
||||
return
|
||||
} else if (this.#closed) {
|
||||
}
|
||||
if (this.#closed) {
|
||||
controller.close()
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user