Add a typescript linter.

This commit is contained in:
Luke Curley 2023-05-22 15:54:30 -07:00
parent 5410a3767f
commit a2371dada6
20 changed files with 5303 additions and 345 deletions

View File

@ -9,5 +9,14 @@ module.exports = {
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"no-unused-vars": "off", // note you must disable the base rule as it can report incorrect errors
"@typescript-eslint/no-unused-vars": [
"warn", // or "error"
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
],
} }
}; };

4253
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,21 @@
"scripts": { "scripts": {
"serve": "parcel serve --https --cert ../cert/localhost.crt --key ../cert/localhost.key --port 4444 --open", "serve": "parcel serve --https --cert ../cert/localhost.crt --key ../cert/localhost.key --port 4444 --open",
"build": "parcel build", "build": "parcel build",
"check": "tsc --noEmit" "check": "tsc --noEmit",
"lint": "eslint ."
}, },
"devDependencies": { "devDependencies": {
"@parcel/transformer-inline-string": "2.8.3", "@parcel/transformer-inline-string": "2.8.3",
"@parcel/validator-typescript": "^2.6.0", "@parcel/validator-typescript": "^2.6.0",
"@types/audioworklet": "^0.0.41", "@types/audioworklet": "^0.0.41",
"@types/dom-webcodecs": "^0.1.6", "@types/dom-webcodecs": "^0.1.6",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"eslint": "^8.41.0",
"parcel": "^2.8.0", "parcel": "^2.8.0",
"typescript": ">=3.0.0" "typescript": "^5.0.4"
}, },
"dependencies": { "dependencies": {
"mp4box": "^0.5.2" "mp4box": "^0.5.2"
} }
} }

View File

@ -69,7 +69,7 @@ export class Encoder {
dts: frame.timestamp, dts: frame.timestamp,
}); });
const stream = this.container.createSingleSampleMoof(sample); const _stream = this.container.createSingleSampleMoof(sample);
} }
onVideo(frame: EncodedVideoChunk, metadata?: EncodedVideoChunkMetadata) { onVideo(frame: EncodedVideoChunk, metadata?: EncodedVideoChunkMetadata) {
@ -99,6 +99,6 @@ export class Encoder {
dts: frame.timestamp, dts: frame.timestamp,
}); });
const stream = this.container.createSingleSampleMoof(sample); const _stream = this.container.createSingleSampleMoof(sample);
} }
} }

View File

@ -1,4 +1,5 @@
export default class Broadcaster { export default class Broadcaster {
constructor() { constructor() {
// TODO
} }
} }

View File

@ -5,7 +5,7 @@ import Transport from "./transport"
import fingerprintHex from 'bundle-text:../fingerprint.hex'; import fingerprintHex from 'bundle-text:../fingerprint.hex';
// Convert the hex to binary. // Convert the hex to binary.
let fingerprint = []; const fingerprint = [];
for (let c = 0; c < fingerprintHex.length - 1; c += 2) { for (let c = 0; c < fingerprintHex.length - 1; c += 2) {
fingerprint.push(parseInt(fingerprintHex.substring(c, c + 2), 16)); fingerprint.push(parseInt(fingerprintHex.substring(c, c + 2), 16));
} }

View File

@ -26,11 +26,11 @@ export class InitParser {
push(data: Uint8Array) { push(data: Uint8Array) {
// Make a copy of the atom because mp4box only accepts an ArrayBuffer unfortunately // Make a copy of the atom because mp4box only accepts an ArrayBuffer unfortunately
let box = new Uint8Array(data.byteLength); const box = new Uint8Array(data.byteLength);
box.set(data) box.set(data)
// and for some reason we need to modify the underlying ArrayBuffer with fileStart // and for some reason we need to modify the underlying ArrayBuffer with fileStart
let buffer = box.buffer as MP4.ArrayBuffer const buffer = box.buffer as MP4.ArrayBuffer
buffer.fileStart = this.offset buffer.fileStart = this.offset
// Parse the data // Parse the data

View File

@ -121,10 +121,10 @@ declare module "mp4box" {
mapUint8Array(length: number): Uint8Array; mapUint8Array(length: number): Uint8Array;
readInt32Array(length: number, littleEndian: boolean): Int32Array; readInt32Array(length: number, littleEndian: boolean): Int32Array;
readInt16Array(length: number, littleEndian: boolean): Int16Array; readInt16Array(length: number, littleEndian: boolean): Int16Array;
readInt8(length: number): Int8Array; readInt8Array(length: number): Int8Array;
readUint32Array(length: number, littleEndian: boolean): Uint32Array; readUint32Array(length: number, littleEndian: boolean): Uint32Array;
readUint16Array(length: number, littleEndian: boolean): Uint16Array; readUint16Array(length: number, littleEndian: boolean): Uint16Array;
readUint8(length: number): Uint8Array; readUint8Array(length: number): Uint8Array;
readFloat64Array(length: number, littleEndian: boolean): Float64Array; readFloat64Array(length: number, littleEndian: boolean): Float64Array;
readFloat32Array(length: number, littleEndian: boolean): Float32Array; readFloat32Array(length: number, littleEndian: boolean): Float32Array;

View File

@ -8,7 +8,7 @@ export default class Audio {
render?: number; // non-zero if requestAnimationFrame has been called render?: number; // non-zero if requestAnimationFrame has been called
last?: number; // the timestamp of the last rendered frame, in microseconds last?: number; // the timestamp of the last rendered frame, in microseconds
constructor(config: Message.Config) { constructor(_config: Message.Config) {
this.queue = [] this.queue = []
} }
@ -47,7 +47,7 @@ export default class Audio {
} }
while (this.queue.length) { while (this.queue.length) {
let frame = this.queue[0]; const frame = this.queue[0];
if (ring.size() + frame.numberOfFrames > ring.capacity) { if (ring.size() + frame.numberOfFrames > ring.capacity) {
// Buffer is full // Buffer is full
break break

View File

@ -16,8 +16,8 @@ export default class Decoder {
} }
async receiveInit(msg: Message.Init) { async receiveInit(msg: Message.Init) {
let stream = new Stream.Reader(msg.reader, msg.buffer); const stream = new Stream.Reader(msg.reader, msg.buffer);
while (1) { for (;;) {
const data = await stream.read() const data = await stream.read()
if (!data) break if (!data) break
@ -29,14 +29,14 @@ export default class Decoder {
async receiveSegment(msg: Message.Segment) { async receiveSegment(msg: Message.Segment) {
// Wait for the init segment to be fully received and parsed // Wait for the init segment to be fully received and parsed
const info = await this.init.info const init = await this.init.info
const input = MP4.New(); const input = MP4.New();
input.onSamples = this.onSamples.bind(this); input.onSamples = this.onSamples.bind(this);
input.onReady = (info: any) => { input.onReady = (track: any) => {
// Extract all of the tracks, because we don't know if it's audio or video. // Extract all of the tracks, because we don't know if it's audio or video.
for (let track of info.tracks) { for (const i of init.tracks) {
input.setExtractionOptions(track.id, track, { nbSamples: 1 }); input.setExtractionOptions(track.id, i, { nbSamples: 1 });
} }
input.start(); input.start();
@ -45,7 +45,7 @@ export default class Decoder {
// MP4box requires us to reparse the init segment unfortunately // MP4box requires us to reparse the init segment unfortunately
let offset = 0; let offset = 0;
for (let raw of this.init.raw) { for (const raw of this.init.raw) {
raw.fileStart = offset raw.fileStart = offset
offset = input.appendBuffer(raw) offset = input.appendBuffer(raw)
} }
@ -61,11 +61,11 @@ export default class Decoder {
const atom = await stream.bytes(size) const atom = await stream.bytes(size)
// Make a copy of the atom because mp4box only accepts an ArrayBuffer unfortunately // Make a copy of the atom because mp4box only accepts an ArrayBuffer unfortunately
let box = new Uint8Array(atom.byteLength); const box = new Uint8Array(atom.byteLength);
box.set(atom) box.set(atom)
// and for some reason we need to modify the underlying ArrayBuffer with offset // and for some reason we need to modify the underlying ArrayBuffer with offset
let buffer = box.buffer as MP4.ArrayBuffer const buffer = box.buffer as MP4.ArrayBuffer
buffer.fileStart = offset buffer.fileStart = offset
// Parse the data // Parse the data
@ -79,7 +79,7 @@ export default class Decoder {
if (!decoder) { if (!decoder) {
// We need a sample to initalize the video decoder, because of mp4box limitations. // We need a sample to initalize the video decoder, because of mp4box limitations.
let sample = samples[0]; const sample = samples[0];
if (isVideoTrack(track)) { if (isVideoTrack(track)) {
// Configure the decoder using the AVC box for H.264 // Configure the decoder using the AVC box for H.264
@ -124,7 +124,7 @@ export default class Decoder {
this.decoders.set(track_id, decoder) this.decoders.set(track_id, decoder)
} }
for (let sample of samples) { for (const sample of samples) {
// Convert to microseconds // Convert to microseconds
const timestamp = 1000 * 1000 * sample.dts / sample.timescale const timestamp = 1000 * 1000 * sample.dts / sample.timescale
const duration = 1000 * 1000 * sample.duration / sample.timescale const duration = 1000 * 1000 * sample.duration / sample.timescale

View File

@ -45,7 +45,7 @@ export default class Player {
return worker return worker
} }
private async setupWorklet(config: Config): Promise<AudioWorkletNode> { private async setupWorklet(_config: Config): Promise<AudioWorkletNode> {
// Load the worklet source code. // Load the worklet source code.
const url = new URL('worklet.ts', import.meta.url) const url = new URL('worklet.ts', import.meta.url)
await this.context.audioWorklet.addModule(url) await this.context.audioWorklet.addModule(url)

View File

@ -37,7 +37,7 @@ export class Ring {
this.state = new Int32Array(buffer.state) this.state = new Int32Array(buffer.state)
this.channels = [] this.channels = []
for (let channel of buffer.channels) { for (const channel of buffer.channels) {
this.channels.push(new Float32Array(channel)) this.channels.push(new Float32Array(channel))
} }
@ -46,8 +46,8 @@ export class Ring {
// Write samples for single audio frame, returning the total number written. // Write samples for single audio frame, returning the total number written.
write(frame: AudioData): number { write(frame: AudioData): number {
let readPos = Atomics.load(this.state, STATE.READ_POS) const readPos = Atomics.load(this.state, STATE.READ_POS)
let writePos = Atomics.load(this.state, STATE.WRITE_POS) const writePos = Atomics.load(this.state, STATE.WRITE_POS)
const startPos = writePos const startPos = writePos
let endPos = writePos + frame.numberOfFrames; let endPos = writePos + frame.numberOfFrames;
@ -60,8 +60,8 @@ export class Ring {
} }
} }
let startIndex = startPos % this.capacity; const startIndex = startPos % this.capacity;
let endIndex = endPos % this.capacity; const endIndex = endPos % this.capacity;
// Loop over each channel // Loop over each channel
for (let i = 0; i < this.channels.length; i += 1) { for (let i = 0; i < this.channels.length; i += 1) {
@ -102,10 +102,10 @@ export class Ring {
} }
read(dst: Float32Array[]): number { read(dst: Float32Array[]): number {
let readPos = Atomics.load(this.state, STATE.READ_POS) const readPos = Atomics.load(this.state, STATE.READ_POS)
let writePos = Atomics.load(this.state, STATE.WRITE_POS) const writePos = Atomics.load(this.state, STATE.WRITE_POS)
let startPos = readPos; const startPos = readPos;
let endPos = startPos + dst[0].length; let endPos = startPos + dst[0].length;
if (endPos > writePos) { if (endPos > writePos) {
@ -116,8 +116,8 @@ export class Ring {
} }
} }
let startIndex = startPos % this.capacity; const startIndex = startPos % this.capacity;
let endIndex = endPos % this.capacity; const endIndex = endPos % this.capacity;
// Loop over each channel // Loop over each channel
for (let i = 0; i < dst.length; i += 1) { for (let i = 0; i < dst.length; i += 1) {
@ -147,8 +147,8 @@ export class Ring {
size() { size() {
// TODO is this thread safe? // TODO is this thread safe?
let readPos = Atomics.load(this.state, STATE.READ_POS) const readPos = Atomics.load(this.state, STATE.READ_POS)
let writePos = Atomics.load(this.state, STATE.WRITE_POS) const writePos = Atomics.load(this.state, STATE.WRITE_POS)
return writePos - readPos return writePos - readPos
} }

View File

@ -89,7 +89,7 @@ export default class Video {
frame.close() frame.close()
} }
play(play: Message.Play) { play(_play: Message.Play) {
// Queue up to render the next frame. // Queue up to render the next frame.
if (!this.render) { if (!this.render) {
this.render = self.requestAnimationFrame(this.draw.bind(this)) this.render = self.requestAnimationFrame(this.draw.bind(this))

View File

@ -10,7 +10,7 @@ class Renderer extends AudioWorkletProcessor {
ring?: Ring; ring?: Ring;
base: number; base: number;
constructor(params: AudioWorkletNodeOptions) { constructor(_params: AudioWorkletNodeOptions) {
// The super constructor call is required. // The super constructor call is required.
super(); super();
@ -29,7 +29,7 @@ class Renderer extends AudioWorkletProcessor {
} }
// Inputs and outputs in groups of 128 samples. // Inputs and outputs in groups of 128 samples.
process(inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record<string, Float32Array>): boolean { process(inputs: Float32Array[][], outputs: Float32Array[][], _parameters: Record<string, Float32Array>): boolean {
if (!this.ring) { if (!this.ring) {
// Paused // Paused
return true return true

View File

@ -28,7 +28,7 @@ export default class Reader {
async readAll(): Promise<Uint8Array> { async readAll(): Promise<Uint8Array> {
const r = this.reader.getReader() const r = this.reader.getReader()
while (1) { for (;;) {
const result = await r.read() const result = await r.read()
if (result.done) { if (result.done) {
break break
@ -164,18 +164,22 @@ export default class Reader {
const size = (first & 0xc0) >> 6 const size = (first & 0xc0) >> 6
switch (size) { switch (size) {
case 0: case 0: {
const v0 = await this.uint8() const v = await this.uint8()
return BigInt(v0) & 0x3fn return BigInt(v) & 0x3fn
case 1: }
const v1 = await this.uint16() case 1: {
return BigInt(v1) & 0x3fffn const v = await this.uint16()
case 2: return BigInt(v) & 0x3fffn
const v2 = await this.uint32() }
return BigInt(v2) & 0x3fffffffn case 2: {
case 3: const v = await this.uint32()
const v3 = await this.uint64() return BigInt(v) & 0x3fffffffn
return v3 & 0x3fffffffffffffffn }
case 3: {
const v = await this.uint64()
return v & 0x3fffffffffffffffn
}
default: default:
throw "impossible" throw "impossible"
} }
@ -183,7 +187,7 @@ export default class Reader {
async done(): Promise<boolean> { async done(): Promise<boolean> {
try { try {
const peek = await this.peek(1) await this.peek(1)
return false return false
} catch (err) { } catch (err) {
return true // Assume EOF return true // Assume EOF

View File

@ -29,7 +29,7 @@ export default class Transport {
// Helper function to make creating a promise easier // Helper function to make creating a promise easier
private async connect(config: Config): Promise<WebTransport> { private async connect(config: Config): Promise<WebTransport> {
let options: WebTransportOptions = {}; const options: WebTransportOptions = {};
if (config.fingerprint) { if (config.fingerprint) {
options.serverCertificateHashes = [ config.fingerprint ] options.serverCertificateHashes = [ config.fingerprint ]
} }

View File

@ -1,5 +1,6 @@
export interface Init {} // TODO fill in required fields
export interface Segment {} export type Init = any
export type Segment = any
export interface Debug { export interface Debug {
max_bitrate: number max_bitrate: number

View File

@ -29,7 +29,7 @@ interface WebTransport {
readonly incomingUnidirectionalStreams: ReadableStream; readonly incomingUnidirectionalStreams: ReadableStream;
} }
declare var WebTransport: { declare const WebTransport: {
prototype: WebTransport; prototype: WebTransport;
new(url: string, options?: WebTransportOptions): WebTransport; new(url: string, options?: WebTransportOptions): WebTransport;
}; };
@ -71,7 +71,7 @@ interface WebTransportError extends DOMException {
readonly streamErrorCode: number; readonly streamErrorCode: number;
} }
declare var WebTransportError: { declare const WebTransportError: {
prototype: WebTransportError; prototype: WebTransportError;
new(init?: WebTransportErrorInit): WebTransportError; new(init?: WebTransportErrorInit): WebTransportError;
}; };

View File

@ -2,11 +2,11 @@ export default class Deferred<T> {
promise: Promise<T> promise: Promise<T>
resolve: (value: T | PromiseLike<T>) => void resolve: (value: T | PromiseLike<T>) => void
reject: (value: T | PromiseLike<T>) => void reject: (value: T | PromiseLike<T>) => void
constructor() { constructor() {
// Set initial values so TS stops being annoying. // Set initial values so TS stops being annoying.
this.resolve = (value: T | PromiseLike<T>) => {}; this.resolve = (_value: T | PromiseLike<T>) => { /* noop */ };
this.reject = (value: T | PromiseLike<T>) => {}; this.reject = (_value: T | PromiseLike<T>) => { /* noop */ };
this.promise = new Promise((resolve, reject) => { this.promise = new Promise((resolve, reject) => {
this.resolve = resolve this.resolve = resolve

File diff suppressed because it is too large Load Diff