From 70a3c2d9c9aa460d82721fb597625c0e61071a93 Mon Sep 17 00:00:00 2001 From: Jesse Casco Date: Mon, 20 Jul 2026 13:20:01 -0400 Subject: [PATCH] perf(discord): stream voice PCM to ffmpeg instead of a temp file pcm_to_wav staged every captured utterance in a NamedTemporaryFile just to hand ffmpeg an input path, then unlinked it. Feed the PCM to ffmpeg's stdin instead: one fewer file created, written, read back and removed per voice utterance, and the try/finally cleanup goes away with it. The WAV output deliberately still goes to output_path rather than being captured from stdout. ffmpeg cannot seek on a pipe, so a piped WAV is written with placeholder 0xFFFFFFFF RIFF/data chunk sizes -- Python's wave module then reports 2147483647 frames for a 1s clip, and strict readers misjudge the length. Writing to the real path lets ffmpeg seek back and patch the header. Tests cover both halves: that the PCM goes over stdin with no temp file, and (when ffmpeg is installed) that the resulting header reports the true frame count. Co-Authored-By: Claude Opus 4.8 --- plugins/platforms/discord/adapter.py | 52 +++++++++++++--------------- tests/gateway/test_voice_command.py | 51 +++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/plugins/platforms/discord/adapter.py b/plugins/platforms/discord/adapter.py index 88d87bc8b35cc..4033feca90b7b 100644 --- a/plugins/platforms/discord/adapter.py +++ b/plugins/platforms/discord/adapter.py @@ -838,34 +838,32 @@ class VoiceReceiver: @staticmethod def pcm_to_wav(pcm_data: bytes, output_path: str, src_rate: int = 48000, src_channels: int = 2): - """Convert raw PCM to 16kHz mono WAV via ffmpeg.""" - with tempfile.NamedTemporaryFile(suffix=".pcm", delete=False) as f: - f.write(pcm_data) - pcm_path = f.name - try: - from hermes_cli._subprocess_compat import windows_hide_flags + """Convert raw PCM to 16kHz mono WAV via ffmpeg. - subprocess.run( - [ - resolve_ffmpeg_executable(), "-y", "-loglevel", "error", - "-f", "s16le", - "-ar", str(src_rate), - "-ac", str(src_channels), - "-i", pcm_path, - "-ar", "16000", - "-ac", "1", - output_path, - ], - check=True, - timeout=10, - stdin=subprocess.DEVNULL, - creationflags=windows_hide_flags(), - ) - finally: - try: - os.unlink(pcm_path) - except OSError: - pass + The PCM is fed straight to ffmpeg's stdin, which avoids staging it in a + temp file on every utterance. The WAV is still written to *output_path* + rather than captured from stdout: ffmpeg cannot seek on a pipe, so a + piped WAV carries placeholder (0xFFFFFFFF) RIFF/data sizes that make + strict readers misreport the length. + """ + from hermes_cli._subprocess_compat import windows_hide_flags + + subprocess.run( + [ + resolve_ffmpeg_executable(), "-y", "-loglevel", "error", + "-f", "s16le", + "-ar", str(src_rate), + "-ac", str(src_channels), + "-i", "pipe:0", + "-ar", "16000", + "-ac", "1", + output_path, + ], + input=pcm_data, + check=True, + timeout=10, + creationflags=windows_hide_flags(), + ) def _read_dm_role_auth_guild() -> Optional[int]: diff --git a/tests/gateway/test_voice_command.py b/tests/gateway/test_voice_command.py index b2d4ab6832a83..4a988a6e036ac 100644 --- a/tests/gateway/test_voice_command.py +++ b/tests/gateway/test_voice_command.py @@ -1947,3 +1947,54 @@ class TestStreamTtsTempfileFallback: ) # And the temp file is cleaned up afterwards. assert not os.path.exists(played[0]), "temp WAV was not unlinked" + + +class TestPcmToWav: + """pcm_to_wav streams PCM through ffmpeg's stdin, not a temp file.""" + + def test_pcm_is_piped_to_stdin_not_staged_on_disk(self, tmp_path): + from plugins.platforms.discord.adapter import VoiceReceiver + + out = tmp_path / "out.wav" + with patch("plugins.platforms.discord.adapter.subprocess.run") as run: + VoiceReceiver.pcm_to_wav(b"\x00\x01" * 16, str(out)) + + args, kwargs = run.call_args + cmd = args[0] + assert kwargs["input"] == b"\x00\x01" * 16, "PCM must be fed via stdin" + assert "pipe:0" in cmd, "ffmpeg must read the PCM from stdin" + assert cmd[-1] == str(out), ( + "the WAV must be written to the real path; ffmpeg cannot seek on a " + "pipe, so a piped WAV gets placeholder RIFF/data sizes" + ) + assert not any(str(a).endswith(".pcm") for a in cmd), ( + "no temp .pcm file should be staged" + ) + + @pytest.mark.skipif( + __import__("shutil").which("ffmpeg") is None, reason="ffmpeg not installed", + ) + def test_output_wav_header_reports_true_length(self, tmp_path): + """A piped-stdout WAV reports 0xFFFFFFFF sizes; the written file must not.""" + import math + import struct + import wave + + from plugins.platforms.discord.adapter import VoiceReceiver + + frames = 48000 # 1s @ 48kHz stereo + pcm = b"".join( + struct.pack(" 16kHz is a 3x decimation of a 1s clip. + assert w.getnframes() == 16000