- Replaced per-frame `run_in_executor` calls with single background reader thread in `ThreadedAudioInput` - Reader thread continuously calls `_read()` and enqueues data via `call_soon_threadsafe` to asyncio.Queue - Reduces per-frame scheduling overhead and context-switch jitter while preserving async API - Added thread lifecycle management: lazy start on first `frames()` call, graceful stop in `aclose()` - Update
32 lines
1.2 KiB
Python
32 lines
1.2 KiB
Python
#!/usr/bin/env python3
|
|
import sys
|
|
try:
|
|
import sounddevice as sd
|
|
except Exception as e:
|
|
sys.stderr.write("sounddevice is not installed or failed to import. Install with: pip install sounddevice\n")
|
|
raise
|
|
|
|
ha = sd.query_hostapis()
|
|
print("Host APIs:")
|
|
for i, h in enumerate(ha):
|
|
print(f"{i}: {h.get('name')}")
|
|
|
|
print("\nDevices:")
|
|
for i, d in enumerate(sd.query_devices()):
|
|
api_idx = d.get('hostapi')
|
|
api = ha[api_idx].get('name') if isinstance(api_idx, int) and 0 <= api_idx < len(ha) else '?'
|
|
name = d.get('name')
|
|
mi = int(d.get('max_input_channels') or 0)
|
|
mo = int(d.get('max_output_channels') or 0)
|
|
sr = int(d.get('default_samplerate') or 0)
|
|
print(f"{i:2d} | in={mi:<2d} out={mo:<2d} sr={sr:<6d} api={api} name={name}")
|
|
|
|
print("\nHints:")
|
|
print("- Pick an INPUT index with in>0 that matches your capture device name (e.g., 'USB Audio Device').")
|
|
print("- Pick an OUTPUT index with out>0 that matches your playback device name (e.g., 'USB Audio').")
|
|
print("- We will use mono (channels=1). If mono fails, we can fall back to 2 channels.")
|
|
|
|
print("\nALSA hw: device suggestions for your setup:")
|
|
print("- Input (Shure MVX2U: USB Audio (hw:0,0)) -> use 'hw:0,0'")
|
|
print("- Output (USB Audio: - (hw:1,0)) -> use 'hw:1,0'")
|