"""Audio playback for WAV files.""" import asyncio import io import logging import sounddevice as sd import soundfile as sf logger = logging.getLogger(__name__) def play_wav(wav_data: bytes) -> None: """Play WAV audio data synchronously (blocking). Args: wav_data: Raw WAV file bytes. """ data, samplerate = sf.read(io.BytesIO(wav_data), dtype="float32") sd.play(data, samplerate) sd.wait() async def play_wav_async(wav_data: bytes) -> None: """Play WAV audio data asynchronously. Args: wav_data: Raw WAV file bytes. """ loop = asyncio.get_running_loop() await loop.run_in_executor(None, play_wav, wav_data) def get_output_devices() -> list[dict]: """List available audio output devices.""" devices = sd.query_devices() result = [] for i, dev in enumerate(devices): if dev["max_output_channels"] > 0: result.append({ "index": i, "name": dev["name"], "channels": dev["max_output_channels"], "default_samplerate": dev["default_samplerate"], }) return result