I'm facing an issue with my Python audio streaming code. Currently, when running the code, I can only hear a "tuuuut" sound on the Bluetooth audio speaker. I expected the audio from the input sound device to be properly streamed to the speaker.
The magic happens in the function _process_audio and I am not able to figure out, how to enter the data from capture to the playback.
Does anybody has an idea what is wrong and how to improve it?
EDIT:
I found out, that if I just record it to a wav and play it with aplay, it's the same.
on the bash I can do it like this
arecord -D hw:0,0 -f cd -r 44100 -c 2 | aplay -D bluealsa
and it works!
Why not with my python solution??
import alsaaudio
import multiprocessing
class AudioProcessor:
def __init__(
self,
playback_device="bluealsa",
capture_device="hw:0,0",
channels=2,
rate=44100,
format=alsaaudio.PCM_FORMAT_S16_LE,
mode=alsaaudio.PCM_NONBLOCK,
buffer_size=128,
):
"""
Initializes the AudioProcessor class.
Args:
playback_device (str): The playback device name.
capture_device (str): The capture device name.
channels (int): The number of audio channels.
rate (int): The audio sample rate.
format (int): The audio sample format.
mode (int): The audio mode.
buffer_size (int): The audio buffer size.
"""
# Set up the capture (record) device
self.capture = alsaaudio.PCM(
type=alsaaudio.PCM_CAPTURE,
device=capture_device,
format=format,
rate=rate,
channels=channels,
periodsize=buffer_size,
mode=mode,
)
# Set up the playback device
self.playback = alsaaudio.PCM(
type=alsaaudio.PCM_PLAYBACK,
device=playback_device,
format=format,
rate=rate,
channels=channels,
periodsize=buffer_size,
mode=mode,
)
# Flag for graceful termination
self.terminate_flag = multiprocessing.Event()
def _process_audio(self):
"""
Continuously processes audio data from the capture device and plays it back.
This method is intended to be run in a separate process.
"""
while not self.terminate_flag.is_set():
try:
# Capture audio
# _, input_data = self.capture.read()
# Playback audio
self.playback.write(self.capture.read()[1])
except alsaaudio.ALSAAudioError as e:
print(f"Error in audio processing: {e}")
def start_playback(self):
"""Starts the audio playback process"""
self.playback_process = multiprocessing.Process(
target=self._process_audio, name="playback_process"
)
self.playback_process.start()
def close_streams(self):
"""
Closes the audio streams and terminates the playback process.
This method should be called to gracefully stop audio processing.
"""
self.terminate_flag.set()
self.playback_process.join() # Wait for the process to finish
with self.playback, self.capture:
pass
here is my solution. I added a multiprocessing queue and starts the capture a half second before the playback. So I can use the PCM_NORMAL mode. It works fine!