Skip to content

Commit

Permalink
Transfork - Major rewrite (#117)
Browse files Browse the repository at this point in the history
everything be changed
  • Loading branch information
kixelated authored Oct 11, 2024
1 parent decc897 commit 4c88f31
Show file tree
Hide file tree
Showing 62 changed files with 2,237 additions and 4,928 deletions.
7 changes: 6 additions & 1 deletion lib/common/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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
Expand All @@ -53,6 +53,10 @@ export class Watch<T> {
this.#current[1] = undefined
this.#next.resolve(this.#current)
}

closed() {
return !this.#next.pending
}
}

// Wakes up a multiple consumers.
Expand Down Expand Up @@ -88,6 +92,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()
Expand Down
11 changes: 11 additions & 0 deletions lib/common/hex.ts
Original file line number Diff line number Diff line change
@@ -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] = parseInt(str.slice(2 * i, 2 * i + 2), 16)
}
return bytes
}

export function encode(_bytes: Uint8Array): string {
throw "todo"
}
69 changes: 62 additions & 7 deletions lib/contribute/audio.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,67 @@
import { Deferred } from "../common/async"
import { Frame } from "../karp/frame"
import { Group, Track } from "../transfork"
import { Closed } from "../transfork/error"

const SUPPORTED = [
// TODO support AAC
// "mp4a"
"Opus",
]

export class Packer {
#source: MediaStreamTrackProcessor<AudioData>
#encoder: Encoder

#data: Track
#current?: Group

constructor(track: MediaStreamAudioTrack, encoder: Encoder, data: Track) {
this.#source = new MediaStreamTrackProcessor({ track })
this.#encoder = encoder
this.#data = data
}

async run() {
const output = new WritableStream({
write: (chunk) => this.#write(chunk),
close: () => this.#close(),
abort: (e) => this.#close(e),
})

return this.#source.readable.pipeThrough(this.#encoder.frames).pipeTo(output)
}

#write(frame: Frame) {
// TODO use a fixed interval instead of keyframes (audio)
// TODO actually just align with video
if (!this.#current || frame.type === "key") {
if (this.#current) {
this.#current.close()
}

this.#current = this.#data.appendGroup()
}

this.#current.writeFrame(frame.data)
}

#close(err?: any) {
const closed = Closed.from(err)
if (this.#current) {
this.#current.close(closed)
}

this.#data.close(closed)
}
}

export class Encoder {
#encoder!: AudioEncoder
#encoderConfig: AudioEncoderConfig
#decoderConfig?: AudioDecoderConfig
#decoderConfig = new Deferred<AudioDecoderConfig>()

frames: TransformStream<AudioData, AudioDecoderConfig | EncodedAudioChunk>
frames: TransformStream<AudioData, EncodedAudioChunk>

constructor(config: AudioEncoderConfig) {
this.#encoderConfig = config
Expand All @@ -21,7 +73,7 @@ export class Encoder {
})
}

#start(controller: TransformStreamDefaultController<AudioDecoderConfig | EncodedAudioChunk>) {
#start(controller: TransformStreamDefaultController<EncodedAudioChunk>) {
this.#encoder = new AudioEncoder({
output: (frame, metadata) => {
this.#enqueue(controller, frame, metadata)
Expand All @@ -40,17 +92,16 @@ export class Encoder {
}

#enqueue(
controller: TransformStreamDefaultController<AudioDecoderConfig | EncodedAudioChunk>,
controller: TransformStreamDefaultController<EncodedAudioChunk>,
frame: EncodedAudioChunk,
metadata?: EncodedAudioChunkMetadata,
) {
const config = metadata?.decoderConfig
if (config && !this.#decoderConfig) {
if (config && !this.#decoderConfig.pending) {
const config = metadata.decoderConfig
if (!config) throw new Error("missing decoder config")

controller.enqueue(config)
this.#decoderConfig = config
this.#decoderConfig.resolve(config)
}

controller.enqueue(frame)
Expand All @@ -72,4 +123,8 @@ export class Encoder {
get config() {
return this.#encoderConfig
}

async decoderConfig(): Promise<AudioDecoderConfig> {
return await this.#decoderConfig.promise
}
}
Loading

0 comments on commit 4c88f31

Please sign in to comment.