From 042fde30c4d2f39ed484fcd372186ad28d2606d1 Mon Sep 17 00:00:00 2001 From: neru Date: Sat, 17 Jan 2026 20:48:10 -0300 Subject: [PATCH] fix: refactor AudioMixer logic --- src/modules/audioStreams.ts | 92 ++++++++++--------------------------- 1 file changed, 24 insertions(+), 68 deletions(-) diff --git a/src/modules/audioStreams.ts b/src/modules/audioStreams.ts index b1872bc..5058582 100644 --- a/src/modules/audioStreams.ts +++ b/src/modules/audioStreams.ts @@ -1,5 +1,6 @@ import { AudioPlayer, + AudioPlayerStatus, createAudioPlayer, createAudioResource, StreamType, @@ -11,7 +12,7 @@ import { PassThrough, Readable } from 'stream'; import prism from 'prism-media'; -const DURATION_EXTRA_MS = 500; +const DURATION_EXTRA_MS = 1000; export class StreamQueue { private queue: Readable[] = []; @@ -65,8 +66,7 @@ export class StreamQueue { export class MixedStream { public readonly player: AudioPlayer; private mixer: AudioMixer; - private output: PassThrough; - private silenceInterval: NodeJS.Timeout; + private output: PassThrough | undefined; private queues: Map = new Map(); @@ -78,34 +78,10 @@ export class MixedStream { bitDepth: 16, sampleRate: 48000, autoClose: false, - generateSilence: false // does not work :< + generateSilence: true }); - const silenceInput = this.mixer.createAudioInput({ - channels: 2, - sampleRate: 48000, - bitDepth: 16, - volume: 100 - }); - - const chunk = Buffer.alloc(3840); - this.silenceInterval = setInterval(() => { - if (silenceInput.writable && silenceInput.writableLength < 3840 * 10) { - silenceInput.write(chunk); - } - }, 20); - - this.output = new PassThrough({ highWaterMark: 1024 * 16 }); - this.mixer.pipe(this.output); - - const resource = createAudioResource(this.output, { - inputType: StreamType.Raw - }); - - this.player.play(resource); - this.player.on('error', (error) => { - console.error('Error: ', error.message); - }); + this.setupPipeline(); } public getQueue(name: string): StreamQueue { @@ -121,6 +97,10 @@ export class MixedStream { completion: Promise; stop: () => void; } { + if (this.player.state.status === AudioPlayerStatus.Idle) { + this.setupPipeline(); + } + let stopCallback: () => void = () => {}; const completion = new Promise((resolve) => { const mixerInput = this.mixer.createAudioInput({ @@ -154,41 +134,15 @@ export class MixedStream { const cleanup = () => { if (resolved) return; resolved = true; - try { - source.unpipe(transcoder); - source.destroy(); - } catch (e) { - console.error('Error destroying source:', e); - } - try { - transcoder.unpipe(mixerInput); - transcoder.destroy(); - } catch (e) { - console.error('Error destroying transcoder:', e); - } + source.unpipe(transcoder); + source.destroy(); - try { - this.mixer.removeAudioinput(mixerInput); - } catch (e) { - console.error('Error removing audio input:', e); - } + transcoder.unpipe(mixerInput); + transcoder.destroy(); - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (typeof (this.mixer as any).removeAudioInput === 'function') { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.mixer as any).removeAudioInput(mixerInput); - } - } catch (_) { - /* ignore */ - } - - try { - mixerInput.destroy(); - } catch (e) { - console.error('Error destroying mixer input:', e); - } + this.mixer.removeAudioinput(mixerInput); + mixerInput.destroy(); resolve(); }; @@ -216,24 +170,26 @@ export class MixedStream { public destroy(): void { this.player.stop(); - this.output.destroy(); + if (this.output) this.output.destroy(); this.mixer.destroy(); - clearInterval(this.silenceInterval); } public flush(): void { this.player.stop(); + this.setupPipeline(); + } - this.mixer.unpipe(this.output); - this.output.destroy(); - - this.output = new PassThrough({ highWaterMark: 1024 * 16 }); + private setupPipeline(): void { + if (this.output) { + this.mixer.unpipe(this.output); + this.output.destroy(); + } + this.output = new PassThrough({ highWaterMark: 1024 * 256 }); this.mixer.pipe(this.output); const resource = createAudioResource(this.output, { inputType: StreamType.Raw }); - this.player.play(resource); } }