←

PyAudioWPatch para acceso a WASAPI en Python

Contexto

PyAudio estandar no expone dispositivos WASAPI loopback en Windows. Para capturar audio del sistema (lo que suena por los parlantes) necesitas PyAudioWPatch, un fork que agrega soporte WASAPI con campos extra como isLoopbackDevice.

Lo que aprendi

pyaudiowpatch es un drop-in replacement de pyaudio. Se importa igual pero expone mas informacion de dispositivos:

import pyaudiowpatch as pyaudio

pa = pyaudio.PyAudio()

# Listar dispositivos WASAPI con sus propiedades extra
wasapi_info = pa.get_host_api_info_by_type(pyaudio.paWASAPI)

for i in range(pa.get_device_count()):
    dev = pa.get_device_info_by_index(i)
    if dev.get("hostApi") == wasapi_info["index"]:
        print(f"{i}: {dev['name']}")
        print(f"   Loopback: {dev.get('isLoopbackDevice', False)}")
        print(f"   Channels: {dev['maxInputChannels']}")
        print(f"   Rate: {int(dev['defaultSampleRate'])}")

La diferencia clave con PyAudio normal: cada dispositivo de output tiene un "espejo" loopback que captura lo que se reproduce. PyAudio normal no los muestra.

Para abrir un stream del loopback, los parametros deben coincidir con los del dispositivo:

device = get_loopback_device(pa)  # Ver TIL de WASAPI Loopback
rate = int(device["defaultSampleRate"])  # Usualmente 48000
channels = device["maxInputChannels"]    # Usualmente 2 (stereo)

stream = pa.open(
    format=pyaudio.paInt16,
    channels=channels,
    rate=rate,
    input=True,
    input_device_index=int(device["index"]),
    frames_per_buffer=int(rate * 0.5),  # 500ms de buffer
)

El audio capturado viene en el formato nativo del dispositivo (48kHz stereo). Whisper necesita 16kHz mono, asi que hay que convertir:

import numpy as np

def prepare_for_whisper(raw_bytes, sample_width, channels, src_rate, dst_rate=16000):
    """Convierte audio de WASAPI (48kHz stereo) a Whisper (16kHz mono)."""
    # Bytes a float32
    if sample_width == 4:
        audio = np.frombuffer(raw_bytes, dtype=np.float32)
    elif sample_width == 2:
        audio = np.frombuffer(raw_bytes, dtype=np.int16).astype(np.float32) / 32768.0

    # Stereo a mono (promediar canales)
    if channels > 1:
        audio = audio.reshape(-1, channels).mean(axis=1)

    # Resamplear con interpolacion lineal
    if src_rate != dst_rate:
        ratio = dst_rate / src_rate
        n_samples = int(len(audio) * ratio)
        indices = np.linspace(0, len(audio) - 1, n_samples)
        audio = np.interp(indices, np.arange(len(audio)), audio).astype(np.float32)

    return audio

Por que importa

pip install PyAudioWPatch en vez de pip install PyAudio y tienes acceso a WASAPI loopback sin software extra. Es la forma mas directa de capturar audio del sistema en Windows con Python.