feat: Host a relay on Hetzner (#114)

We are hosting a [MoQ](https://quic.video) relay on a remote (bare
metal) server on Hetzner

With a lot of help from @victorpahuus
This commit is contained in:
Wanjohi
2024-09-26 21:34:42 +03:00
committed by GitHub
parent c4a6895726
commit bae089e223
74 changed files with 7107 additions and 96 deletions

View File

@@ -0,0 +1,37 @@
// Rename some stuff so it's on brand.
// We need a separate file so this file can use the rename too.
import * as MP4 from "./rename"
export * from "./rename"
export * from "./parser"
export function isAudioTrack(track: MP4.Track): track is MP4.AudioTrack {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
return (track as MP4.AudioTrack).audio !== undefined
}
export function isVideoTrack(track: MP4.Track): track is MP4.VideoTrack {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
return (track as MP4.VideoTrack).video !== undefined
}
// TODO contribute to mp4box
MP4.BoxParser.dOpsBox.prototype.write = function (stream: MP4.Stream) {
this.size = this.ChannelMappingFamily === 0 ? 11 : 13 + this.ChannelMapping!.length
this.writeHeader(stream)
stream.writeUint8(this.Version)
stream.writeUint8(this.OutputChannelCount)
stream.writeUint16(this.PreSkip)
stream.writeUint32(this.InputSampleRate)
stream.writeInt16(this.OutputGain)
stream.writeUint8(this.ChannelMappingFamily)
if (this.ChannelMappingFamily !== 0) {
stream.writeUint8(this.StreamCount!)
stream.writeUint8(this.CoupledCount!)
for (const mapping of this.ChannelMapping!) {
stream.writeUint8(mapping)
}
}
}

View File

@@ -0,0 +1,71 @@
import * as MP4 from "./index"
export interface Frame {
track: MP4.Track // The track this frame belongs to
sample: MP4.Sample // The actual sample contain the frame data
}
// Decode a MP4 container into individual samples.
export class Parser {
info!: MP4.Info
#mp4 = MP4.New()
#offset = 0
#samples: Array<Frame> = []
constructor(init: Uint8Array) {
this.#mp4.onError = (err) => {
console.error("MP4 error", err)
}
this.#mp4.onReady = (info: MP4.Info) => {
this.info = info
// Extract all of the tracks, because we don't know if it's audio or video.
for (const track of info.tracks) {
this.#mp4.setExtractionOptions(track.id, track, { nbSamples: 1 })
}
}
this.#mp4.onSamples = (_track_id: number, track: MP4.Track, samples: MP4.Sample[]) => {
for (const sample of samples) {
this.#samples.push({ track, sample })
}
}
this.#mp4.start()
// For some reason we need to modify the underlying ArrayBuffer with offset
const copy = new Uint8Array(init)
const buffer = copy.buffer as MP4.ArrayBuffer
buffer.fileStart = this.#offset
this.#mp4.appendBuffer(buffer)
this.#offset += buffer.byteLength
this.#mp4.flush()
if (!this.info) {
throw new Error("could not parse MP4 info")
}
}
decode(chunk: Uint8Array): Array<Frame> {
const copy = new Uint8Array(chunk)
// For some reason we need to modify the underlying ArrayBuffer with offset
const buffer = copy.buffer as MP4.ArrayBuffer
buffer.fileStart = this.#offset
// Parse the data
this.#mp4.appendBuffer(buffer)
this.#mp4.flush()
this.#offset += buffer.byteLength
const samples = [...this.#samples]
this.#samples.length = 0
return samples
}
}

View File

@@ -0,0 +1,13 @@
// Rename some stuff so it's on brand.
export { createFile as New, DataStream as Stream, ISOFile, BoxParser, Log } from "mp4box"
export type {
MP4ArrayBuffer as ArrayBuffer,
MP4Info as Info,
MP4Track as Track,
MP4AudioTrack as AudioTrack,
MP4VideoTrack as VideoTrack,
Sample,
TrackOptions,
SampleOptions,
} from "mp4box"