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.