555d4e10ad
`_play_via_tempfile` passes the NamedTemporaryFile *object* to `wave.open()`. `wave.open()` flushes but does not close a file it did not open itself (by name), so the OS handle to the temp WAV stays open. On Windows that open write handle blocks the system player from reading the file and blocks the `os.unlink()` cleanup (WinError 32, silently swallowed by `except OSError: pass`), leaving orphaned temp .wav files piling up. The fallback runs whenever no sounddevice output stream is available (sounddevice not installed / no audio device), which is common on headless and Windows setups. Close the temp file handle before invoking the player and again in the finally block (idempotent), so the player can read the file and `os.unlink()` can remove it. Regression test drives `stream_tts_to_speaker` with the sounddevice path forced unavailable and asserts the temp handle is closed before `play_audio_file` is called (mutation-verified: reverting the close leaves the handle open at play time and the test fails). Cross-platform.