I have developed a python script that takes the audio from a .wav file and plays it out of multiple audio sources (currently configured such that it is out of laptop speakers and a paired bluetooth device). I am dealing with some delay and synchronisation issues. The audio is constructed very well and comes out with good quality, however, it is starting at different times on the two devices and I can't seem to figure it out.
I have tried implementing event's, positions, time stamps, and code to maybe even detect the latency to see if I can get it to sync up but even then I couldn't figure it out. Some help would be appreciated. Here is the code:
import sounddevice as sd
import wave
import numpy as np
# Query available devices
devices = sd.query_devices()
for device in devices:
print(device) #Find your device ID
audio_file = #Audio Path
speaker_ids = [3,5] #Device IDs to play out of, one is computer speakers the other is bluetooth
wf = wave.open(audio_file, 'rb')
samplerate = wf.getframerate()
channels = wf.getnchannels()
# Set volume (0.0 to 1.0)
volume = 1
# Reading and processing audio data
audio_data = wf.readframes(wf.getnframes())
audio_data = np.frombuffer(audio_data, dtype=np.int16)
audio_data = np.reshape(audio_data, (-1, channels))
audio_data = audio_data * volume # Apply volume control
# Function to create a callback for each stream
def create_callback(device_id):
position = 0 # Starting position for this stream
def callback(outdata, frames, time, status):
nonlocal position
end_index = position + frames
if end_index > len(audio_data):
# If the end of the audio data is reached, fill the rest with zeros
valid_frames = len(audio_data) - position
outdata[:valid_frames] = (audio_data[position:] / 32768.0)
outdata[valid_frames:] = 0
position = 0 # Reset position for looping
else:
# Normal playback
outdata[:] = (audio_data[position:end_index] / 32768.0)
position = end_index
return callback
streams = []
try:
for dev_id in speaker_ids:
stream_callback = create_callback(dev_id)
stream = sd.OutputStream(device=dev_id,
samplerate=samplerate,
channels=channels,
dtype='float32',
callback=stream_callback)
streams.append(stream)
stream.start()
input('Press Enter to stop playback\n')
finally:
for stream in streams:
stream.stop()
wf.close()