mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-09 10:19:26 +00:00
⚡️(frontend) lazy-load @libreaudio/la-call via dynamic import
The noise-suppression processor is now imported on demand with a dynamic import() instead of a top-level static import, so it lands in its own code-split chunk rather than the main bundle. Why this is necessary: * @libreaudio/la-call is fully self-contained. It inlines *everything* as JavaScript: two WASM binaries (SIMD and non-SIMD variants), the Emscripten glue, the worklet processor source, and the noise model plus its weights — the model is compiled into the .wasm, so we ship effectively two copies of it. * The WASM is inlined as numeric array literals (new Uint8Array([...])), the least compact representation possible (~2-4 source chars/byte) and not meaningfully minifiable. The result is a large module that also can't be stream-compiled the way an external .wasm asset would be. * A static import would pull all of that into the initial bundle, inflating critical-path download size and lengthening build time (parsing/minifying the big literal) — for a feature that's only used when the user actually turns on noise suppression. * Dynamic import() isolates the whole payload in a separate, content-hashed, browser-cached chunk. The cost (chunk fetch + WASM instantiation) becomes a one-time hit deferred to first activation, and is fully off the page's initial load path. Notes: * The library self-bundles its AudioWorklet at runtime from a Blob URL and inlines the WASM, so it needs no build-tool asset plumbing (no ?worker&url / ?url, no Vite asset config). The dynamic import is therefore the only splitting mechanism required. * Audio processing still runs off the main thread on the AudioWorklet path (desktop/most browsers); only the Android ScriptProcessor fallback runs on the main thread. Import style does not affect this. * To hide the first-activation latency, the chunk can be prefetched (e.g. import() on idle or <link rel="modulepreload">) so it's warm before the user enables suppression.
This commit is contained in:
committed by
aleb_the_flash
parent
13036f6ab7
commit
ac85a20271
@@ -1,11 +1,30 @@
|
||||
|
||||
import type { Track, TrackProcessor, ProcessorOptions } from 'livekit-client'
|
||||
import { createWasmProcessor } from '@libreaudio/la-call'
|
||||
|
||||
// Use Jitsi's approach: maintain a global AudioContext variable
|
||||
// and suspend/resume it as needed to manage audio state
|
||||
let audioContext: AudioContext
|
||||
|
||||
/**
|
||||
* Lazily load the WASM processor factory.
|
||||
*
|
||||
* '@libreaudio/la-call' pulls in a WebAssembly payload, so we defer importing
|
||||
* it until a processor is actually initialized rather than at module load.
|
||||
* The import promise is cached so repeated init() calls reuse the same module.
|
||||
*/
|
||||
type CreateWasmProcessor =
|
||||
(typeof import('@libreaudio/la-call'))['createWasmProcessor']
|
||||
|
||||
let wasmProcessorPromise: Promise<CreateWasmProcessor> | undefined
|
||||
|
||||
function loadWasmProcessor(): Promise<CreateWasmProcessor> {
|
||||
if (!wasmProcessorPromise) {
|
||||
wasmProcessorPromise = import('@libreaudio/la-call').then(
|
||||
(mod) => mod.createWasmProcessor
|
||||
)
|
||||
}
|
||||
return wasmProcessorPromise
|
||||
}
|
||||
|
||||
export interface AudioProcessorInterface extends TrackProcessor<Track.Kind.Audio> {
|
||||
name: string
|
||||
}
|
||||
@@ -36,6 +55,7 @@ export class RnnNoiseProcessor implements AudioProcessorInterface {
|
||||
new MediaStream([this.source])
|
||||
)
|
||||
|
||||
const createWasmProcessor = await loadWasmProcessor()
|
||||
this.noiseSuppressionNode = await createWasmProcessor(audioContext, {
|
||||
intensity: 90,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user