Files
alsa_latency_test/sd_ioutput.py
pstruebi c681e4ce39 feat: refactor audio input to use dedicated reader thread instead of per-frame executor
- 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
2025-11-19 18:52:37 +01:00

66 lines
1.7 KiB
Python

import os
import sounddevice as sd
def main() -> None:
in_device = 'hw:0,0' # Shure MVX2U input
out_device = 'hw:1,0' # USB Audio output
sample_rate = 48000
frame_size = 480
dinfo = sd.query_devices(in_device)
doutfo = sd.query_devices(out_device)
print(f"Input device {in_device} has no input channels: {dinfo}")
inputs = [
(d['index'], d['name'], d['max_input_channels'])
for d in sd.query_devices()
if d.get('max_input_channels', 0) > 0
]
print('Input-capable devices:', inputs)
print(f"Output device {out_device} has no output channels: {doutfo}")
outputs = [
(d['index'], d['name'], d['max_output_channels'])
for d in sd.query_devices()
if d.get('max_output_channels', 0) > 0
]
print('Output-capable devices:', outputs)
istream = sd.RawInputStream(
samplerate=sample_rate,
device=in_device,
channels=1,
dtype='int16',
blocksize=frame_size,
)
ostream = sd.RawOutputStream(
samplerate=sample_rate,
device=out_device,
channels=1,
dtype='int16',
blocksize=frame_size,
)
istream.start()
ostream.start()
try:
while True:
data, overflowed = istream.read(frame_size)
if overflowed:
print("an overflow happened")
ostream.write(data)
except KeyboardInterrupt:
pass
finally:
try:
istream.stop(); istream.close()
except Exception:
pass
try:
ostream.stop(); ostream.close()
except Exception:
pass
if __name__ == '__main__':
main()