// 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; }