diff options
Diffstat (limited to 'gateway/src/opus.js')
| -rw-r--r-- | gateway/src/opus.js | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/gateway/src/opus.js b/gateway/src/opus.js new file mode 100644 index 0000000..b1805d6 --- /dev/null +++ b/gateway/src/opus.js @@ -0,0 +1,59 @@ +// Opus codec wrapper. Uses the native @discordjs/opus addon when it happens to +// be installed (faster), otherwise opusscript (WASM): no compiler needed, so it +// installs cleanly on arm64 SBCs. +import { createRequire } from "node:module"; + +const require = createRequire(import.meta.url); + +export const SAMPLE_RATE = 48_000; +export const FRAME_SAMPLES = 960; // 20 ms @ 48 kHz +export const FRAME_BYTES = FRAME_SAMPLES * 2; // mono Int16 + +let backend = null; + +function loadBackend() { + if (backend) return backend; + try { + const { OpusEncoder } = require("@discordjs/opus"); + backend = { + name: "@discordjs/opus (native)", + create(channels) { + const codec = new OpusEncoder(SAMPLE_RATE, channels); + return { + encode: (pcm) => codec.encode(pcm), + decode: (data) => codec.decode(data), + setBitrate: (bps) => codec.setBitrate(bps), + dispose() {}, + }; + }, + }; + } catch { + const OpusScript = require("opusscript"); + backend = { + name: "opusscript (wasm)", + create(channels) { + const codec = new OpusScript(SAMPLE_RATE, channels, OpusScript.Application.VOIP); + return { + encode: (pcm) => Buffer.from(codec.encode(pcm, pcm.length / (2 * channels))), + decode: (data) => Buffer.from(codec.decode(data)), + setBitrate: (bps) => codec.setBitrate(bps), + dispose: () => codec.delete(), + }; + }, + }; + } + return backend; +} + +export function opusBackendName() { + return loadBackend().name; +} + +/** Mono 48 kHz Opus codec (encoder + decoder state). */ +export function createOpusCodec({ bitrate } = {}) { + const codec = loadBackend().create(1); + if (bitrate) { + try { codec.setBitrate(bitrate); } catch { /* keep the library default */ } + } + return codec; +} |
