From 82a23d291e2f04360590e06a6158be356f7a7d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=A2=93=E5=96=B5=5F=E3=81=82=E3=81=9A=E3=81=AB?= =?UTF-8?q?=E3=82=83=E3=82=93?= Date: Tue, 21 Apr 2026 02:03:20 +0800 Subject: [PATCH] =?UTF-8?q?ffmpeg=E8=BF=9B=E7=A8=8B=E5=A0=86=E7=A7=AF?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ffmpeg进程堆积优化(*) 减小缓冲区 降低100音量响度 *此处仍有问题 没招了 每次切歌会有几帧前面一首歌的残留 我不知道哪里出问题了 --- src/audio/player.ts | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/audio/player.ts b/src/audio/player.ts index 66fcefe..56962e4 100644 --- a/src/audio/player.ts +++ b/src/audio/player.ts @@ -95,8 +95,8 @@ export class AudioPlayer extends EventEmitter { private seekOffset = 0; private framesPlayed = 0; // ground truth: number of 20ms frames sent private sessionId = 0; - private static readonly BUFFER_HIGH_WATER = 960 * 1024; // ~5s of PCM at 48kHz stereo - private static readonly BUFFER_LOW_WATER = 480 * 1024; // ~2.5s + private static readonly BUFFER_HIGH_WATER = 640 * 1024; // ~5s of PCM at 48kHz stereo + private static readonly BUFFER_LOW_WATER = 256 * 1024; // ~2.5s private ffmpegPaused = false; private spawnFailed = false; // true if ffmpeg spawn errored (prevent trackEnd cascade) private consecutiveFailures = 0; @@ -294,7 +294,9 @@ export class AudioPlayer extends EventEmitter { private applyVolume(pcm: Buffer): Buffer { if (this.volume === 100) return Buffer.from(pcm); - const factor = this.volume / 100; + // Apply volume + fixed 6dB attenuation (factor ≈ 0.5) + const BASE_ATTENUATION = 0.2; // -6dB (10^(-6/20) ≈ 0.5012) + const factor = (this.volume / 100) * BASE_ATTENUATION; const out = Buffer.alloc(pcm.length); for (let i = 0; i < pcm.length; i += 2) { let sample = pcm.readInt16LE(i); @@ -347,7 +349,32 @@ export class AudioPlayer extends EventEmitter { this.sessionId++; this.frameLoopRunning = false; if (this.ffmpeg) { + const ffmpegPid = this.ffmpeg.pid; + this.logger.debug({ pid: ffmpegPid }, "Stopping ffmpeg process"); + + // Try SIGTERM first for graceful shutdown this.ffmpeg.kill("SIGTERM"); + + // If process doesn't exit after 1 second, force kill with SIGKILL + const killTimeout = setTimeout(() => { + if (this.ffmpeg && this.ffmpeg.pid) { + this.logger.warn({ pid: this.ffmpeg.pid }, "FFmpeg didn't exit from SIGTERM, sending SIGKILL"); + try { + this.ffmpeg.kill("SIGKILL"); + } catch (err) { + this.logger.debug({ err }, "Error killing ffmpeg process"); + } + } + }, 1000); + + // Store timeout ID for cleanup on next stop call + const tempProc = this.ffmpeg; + const onClose = () => { + clearTimeout(killTimeout); + tempProc.removeListener("close", onClose); + }; + tempProc.once("close", onClose); + this.ffmpeg = null; } this.pcmBuffer = Buffer.alloc(0);