Skip to content

Commit 0d1f622

Browse files
authored
Merge pull request #67 from Ryan-M-Frank/fix/windows-voice-playback
fix(voice): add Windows support for voice playback
2 parents 86896aa + b44dbda commit 0d1f622

2 files changed

Lines changed: 21 additions & 11 deletions

File tree

plugins/voice/hooks/stop_hook.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -379,17 +379,16 @@ def speak_summary(session_id: str, summary: str, voice: str) -> None:
379379
say_script = PLUGIN_ROOT / "scripts" / "say"
380380

381381
try:
382+
# On Windows, bash scripts can't be executed directly by subprocess.Popen
383+
# (WinError 193: not a valid Win32 application). Must invoke through bash.
384+
import platform
385+
if platform.system() == "Windows":
386+
cmd = ["bash", str(say_script), "--session", session_id, "--voice", voice, summary]
387+
else:
388+
cmd = [str(say_script), "--session", session_id, "--voice", voice, summary]
389+
382390
# Run in background so we can return JSON immediately
383-
subprocess.Popen(
384-
[
385-
str(say_script),
386-
"--session", session_id,
387-
"--voice", voice,
388-
summary,
389-
],
390-
stdout=subprocess.DEVNULL,
391-
stderr=subprocess.DEVNULL,
392-
)
391+
subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
393392
except Exception:
394393
pass
395394

plugins/voice/scripts/say

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,23 @@ play_audio_file() {
117117
local file="$1"
118118
if [[ "$(uname)" == "Darwin" ]]; then
119119
afplay "$file"
120+
elif [[ "$(uname -o 2>/dev/null)" == "Msys" ]] || [[ -n "$MSYSTEM" ]]; then
121+
# Windows (Git Bash / MSYS2) - use WPF MediaPlayer with dynamic duration detection
122+
# SoundPlayer often routes audio to the wrong device on multi-output Windows systems
123+
# Calculate duration from file size (WAV headers from pocket-tts can be malformed)
124+
# WAV format: (filesize - 44 header) / (sample_rate * bytes_per_sample * channels)
125+
# pocket-tts outputs 24kHz, 16-bit, mono
126+
local winpath filesize duration_ms
127+
winpath=$(cygpath -w "$file")
128+
filesize=$(stat -c%s "$file" 2>/dev/null || wc -c < "$file")
129+
duration_ms=$(( (filesize - 44) * 1000 / (24000 * 2 * 1) + 1000 ))
130+
powershell.exe -NoProfile -Command "Add-Type -AssemblyName PresentationCore; \$mp = New-Object System.Windows.Media.MediaPlayer; \$mp.Open([uri]::new('file:///$winpath')); Start-Sleep -Milliseconds 500; \$mp.Play(); Start-Sleep -Milliseconds $duration_ms; \$mp.Close()"
120131
elif command -v aplay > /dev/null 2>&1; then
121132
aplay -q "$file"
122133
elif command -v paplay > /dev/null 2>&1; then
123134
paplay "$file"
124135
else
125-
echo "Error: No audio player found (tried afplay, aplay, paplay)" >&2
136+
echo "Error: No audio player found (tried afplay, powershell, aplay, paplay)" >&2
126137
exit 1
127138
fi
128139
}

0 commit comments

Comments
 (0)