refactor: extract recorder domain types and modules

This commit is contained in:
MythEclipse
2026-05-13 15:56:42 +07:00
parent da108c5d84
commit dbe593c6fd
5 changed files with 295 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
import prism from "prism-media";
export interface OpusDecoderOptions {
cooldownMs: number;
rotateMs: number;
createDecoder?: () => prism.opus.Decoder;
onData: (pcm: Buffer) => void;
}
export class OpusDecoder {
private decoder: prism.opus.Decoder | null = null;
private disabledUntil = 0;
private createdAt = 0;
private readonly cooldownMs: number;
private readonly rotateMs: number;
private readonly createDecoderFn: () => prism.opus.Decoder;
private readonly onData: (pcm: Buffer) => void;
constructor(options: OpusDecoderOptions) {
this.cooldownMs = options.cooldownMs;
this.rotateMs = options.rotateMs;
this.onData = options.onData;
this.createDecoderFn =
options.createDecoder ??
(() => new prism.opus.Decoder({ frameSize: 960, channels: 2, rate: 48000 }));
}
rotateIfNeeded(): void {
if (!this.decoder || this.rotateMs <= 0) return;
if (Date.now() - this.createdAt < this.rotateMs) return;
this.destroy();
this.ensureDecoder();
}
write(chunk: Buffer): void {
const decoder = this.ensureDecoder();
if (!decoder) return;
try {
decoder.write(chunk);
} catch (error) {
console.warn("[recorder] Opus decoder write failed, cooling down:", error);
this.coolDown();
}
}
destroy(): void {
if (!this.decoder) return;
this.decoder.removeAllListeners();
this.decoder.destroy();
this.decoder = null;
this.createdAt = 0;
}
private ensureDecoder(): prism.opus.Decoder | null {
if (this.decoder) return this.decoder;
if (Date.now() < this.disabledUntil) return null;
try {
const decoder = this.createDecoderFn();
decoder.on("data", this.onData);
decoder.on("error", (error) => {
console.warn("[recorder] Opus decoder error, cooling down:", error);
this.coolDown();
});
this.decoder = decoder;
this.createdAt = Date.now();
return decoder;
} catch (error) {
console.warn("[recorder] Opus decoder init failed, cooling down:", error);
this.disabledUntil = Date.now() + this.cooldownMs;
return null;
}
}
private coolDown(): void {
this.disabledUntil = Date.now() + this.cooldownMs;
this.destroy();
}
}