spatialaudio / python-sounddevice

:sound: Play and Record Sound with Python :snake:
https://python-sounddevice.readthedocs.io/
MIT License
980 stars 145 forks source link

Latency 30mSec #524

Open RezaYazdi604 opened 3 months ago

RezaYazdi604 commented 3 months ago

Hi there,

I'm currently using sounddevice together with SamplerBox on a RPI device. I'm measuring about 30mSec latency from the time I hit a note until the note is played on the speaker. I was wondering if there's a way to reduce this latency. Reading PortAudio documentation, it's mentioned there is a way to reduce the latency to 10mSec but I don't know how to do that? The audiocallback() is called every 8mSec. Is there anyway to make this faster? The buffer size is 384 but I have tried lowering that and it didn't help.

I appreciate any help in this regards.

From PortAudio website

_Unix PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS. This gives you decent but not great latency. But if you raise the priority of the background thread to a very priority then you can get under 10 milliseconds latency. In order to raise your priority you must run the PortAudio program as root! You must also set PA_MIN_LATENCYMSEC using the appropriate command for your shell.

mgeier commented 3 months ago

Which buffer sizes did you try? Did you try powers of 2?

There is a PortAudio test program called pa_minlat, maybe that gives some insights?

Did you try setting blocksize=0 and varying latency?

PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS.

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA?

You must also set PA_MIN_LATENCY_MSEC

That's something I have never heard before, and if you search for it in the PortAudio source code, it only appears in the file https://github.com/PortAudio/portaudio/blob/master/src/hostapi/dsound/pa_win_ds.c, which is irrelevant for Linux.

RezaYazdi604 commented 3 months ago

Thank you Mathias for your prompt reply. Please see my comments below

Which buffer sizes did you try? Did you try powers of 2? -> I use blocksize=384 which has so far delivered the best performance. I've also tried 128,16 and 0 but didn't see any significant difference in the latency measurement.

There is a PortAudio test program called pa_minlat, maybe that gives some insights? -> Didn't know about this. Does it work on RPI? I can give it a try.

Did you try setting blocksize=0 and varying latency? -> Yes. Didn't see a big difference. See the shared Google sheet for more details.

I tried the following latencies. The best option that I'm currently using with buffer size =384 is highlighted below.

# sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency='low',callback=AudioCallback)
# print ("Latency = low ~20-30msec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.010,callback=AudioCallback)
    # print ("Latency = 10mSec 20-30mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.013483,callback=AudioCallback)
    # print ("Latency = 13.483mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.015,callback=AudioCallback)
    # print ("Latency = 15mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.0175,callback=AudioCallback)
    # print ("Latency = 17.5mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.020,callback=AudioCallback)
    # print ("Latency = 20mSec 30-40mSec")

    latency_org=0.03482993197278/2      sd =

sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', latency=latency_org, callback=AudioCallback) print ("Latency = %.15f" %latency_org)

sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',

callback=AudioCallback)

print ("No Latency defined - default is HIGH 50 - 60 mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.100,callback=AudioCallback)
    # print ("Latency = 100mSec")

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA? -> Yes. I'm pretty sure I'm using ALSA

You must also set PA_MIN_LATENCY_MSEC -> Maybe an old comment from Port Audio developers. I didn't know how to use it.

I should mention that I'm using an external DAC too and not the RPi internal DAC as the audio quality is not that great. Does this add to the latency? I wanted to know what kind of latency is common with sounddevice? Is it possible to get to 10mSec or lower?

I will share my investigation results to you through a google document. It takes my system about 5mSec to call a function in SamplerBox to play a note. From that point it takes 17.5mSec before the audio buffer go non-zero and from that point it takes another 15mSec to hear the audio. Why is the AudiocallBack() called every 8mSec? Any chance to speed that up?

I also tried to increase the priority of the SamplerBox application using htop to MAX (-19, 0) but didn't see any difference in latency. Let me know if you want me to try any new combinations and measure the delay. It will be great if I can reduce this delay as much as possible.

Thanks again for your help. Really appreciate it.

Reza

On Wed, Mar 6, 2024 at 10:51 AM Matthias Geier @.***> wrote:

Which buffer sizes did you try? Did you try powers of 2?

There is a PortAudio test program called pa_minlat, maybe that gives some insights?

Did you try setting blocksize=0 and varying latency?

PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS.

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA?

You must also set PA_MIN_LATENCY_MSEC

That's something I have never heard before, and if you search for it in the PortAudio source code, it only appears in the file https://github.com/PortAudio/portaudio/blob/master/src/hostapi/dsound/pa_win_ds.c, which is irrelevant for Linux.

— Reply to this email directly, view it on GitHub https://github.com/spatialaudio/python-sounddevice/issues/524#issuecomment-1981565472, or unsubscribe https://github.com/notifications/unsubscribe-auth/A2ARXN2DR62MJ4M7DBC2KRLYW5QULAVCNFSM6AAAAABEGOEN6WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBRGU3DKNBXGI . You are receiving this because you authored the thread.Message ID: @.***>

RezaYazdi604 commented 3 months ago

Sorry forgot to add the link to google sheet --> https://docs.google.com/spreadsheets/d/1NFkqyEGW1DZmFUpbkyHF5ob7DfHAVK4PeZypDVyEInM/edit?usp=sharing

On Wed, Mar 6, 2024 at 2:31 PM Reza Yazdi @.***> wrote:

Thank you Mathias for your prompt reply. Please see my comments below

Which buffer sizes did you try? Did you try powers of 2? -> I use blocksize=384 which has so far delivered the best performance. I've also tried 128,16 and 0 but didn't see any significant difference in the latency measurement.

There is a PortAudio test program called pa_minlat, maybe that gives some insights? -> Didn't know about this. Does it work on RPI? I can give it a try.

Did you try setting blocksize=0 and varying latency? -> Yes. Didn't see a big difference. See the shared Google sheet for more details.

I tried the following latencies. The best option that I'm currently using with buffer size =384 is highlighted below.

sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency='low',callback=AudioCallback)

print ("Latency = low ~20-30msec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.010,callback=AudioCallback)
  # print ("Latency = 10mSec 20-30mSec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.013483,callback=AudioCallback)
  # print ("Latency = 13.483mSec 30-40mSec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.015,callback=AudioCallback)
  # print ("Latency = 15mSec 30-40mSec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.0175,callback=AudioCallback)
  # print ("Latency = 17.5mSec 30-40mSec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.020,callback=AudioCallback)
  # print ("Latency = 20mSec 30-40mSec")

    latency_org=0.03482993197278/2        sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', latency=latency_org, callback=AudioCallback)

print ("Latency = %.15f" %latency_org)

sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', callback=AudioCallback)

print ("No Latency defined - default is HIGH 50 - 60 mSec")

  # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.100,callback=AudioCallback)
  # print ("Latency = 100mSec")

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA? -> Yes. I'm pretty sure I'm using ALSA

You must also set PA_MIN_LATENCY_MSEC -> Maybe an old comment from Port Audio developers. I didn't know how to use it.

I should mention that I'm using an external DAC too and not the RPi internal DAC as the audio quality is not that great. Does this add to the latency? I wanted to know what kind of latency is common with sounddevice? Is it possible to get to 10mSec or lower?

I will share my investigation results to you through a google document. It takes my system about 5mSec to call a function in SamplerBox to play a note. From that point it takes 17.5mSec before the audio buffer go non-zero and from that point it takes another 15mSec to hear the audio. Why is the AudiocallBack() called every 8mSec? Any chance to speed that up?

I also tried to increase the priority of the SamplerBox application using htop to MAX (-19, 0) but didn't see any difference in latency. Let me know if you want me to try any new combinations and measure the delay. It will be great if I can reduce this delay as much as possible.

Thanks again for your help. Really appreciate it.

Reza

On Wed, Mar 6, 2024 at 10:51 AM Matthias Geier @.***> wrote:

Which buffer sizes did you try? Did you try powers of 2?

There is a PortAudio test program called pa_minlat, maybe that gives some insights?

Did you try setting blocksize=0 and varying latency?

PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS.

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA?

You must also set PA_MIN_LATENCY_MSEC

That's something I have never heard before, and if you search for it in the PortAudio source code, it only appears in the file https://github.com/PortAudio/portaudio/blob/master/src/hostapi/dsound/pa_win_ds.c, which is irrelevant for Linux.

— Reply to this email directly, view it on GitHub https://github.com/spatialaudio/python-sounddevice/issues/524#issuecomment-1981565472, or unsubscribe https://github.com/notifications/unsubscribe-auth/A2ARXN2DR62MJ4M7DBC2KRLYW5QULAVCNFSM6AAAAABEGOEN6WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBRGU3DKNBXGI . You are receiving this because you authored the thread.Message ID: @.***>

RezaYazdi604 commented 3 months ago

Hello Mathias,Just wondering if you had a chance to see my feedback. I appreciate if you can help in anyway. Cheers,RezaOn Mar 7, 2024, at 6:34 AM, Reza Yazdi @.> wrote:Sorry forgot to add the link to google sheet --> https://docs.google.com/spreadsheets/d/1NFkqyEGW1DZmFUpbkyHF5ob7DfHAVK4PeZypDVyEInM/edit?usp=sharingOn Wed, Mar 6, 2024 at 2:31 PM Reza Yazdi @.> wrote:Thank you Mathias for your prompt reply. Please see my comments belowWhich buffer sizes did you try? Did you try powers of 2?->  I use blocksize=384 which has so far delivered the best performance. I've also tried 128,16 and 0 but didn't see any significant difference in the latency measurement.There is a PortAudio test program called pa_minlat, maybe that gives some insights?-> Didn't know about this. Does it work on RPI? I can give it a try.Did you try setting blocksize=0 and varying latency?-> Yes. Didn't see a big difference. See the shared Google sheet for more details. I tried the following latencies. The best option that I'm currently using with buffer size =384 is highlighted below. # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency='low',callback=AudioCallback)

print ("Latency = low ~20-30msec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.010,callback=AudioCallback)
    # print ("Latency = 10mSec 20-30mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.013483,callback=AudioCallback)
    # print ("Latency = 13.483mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.015,callback=AudioCallback)
    # print ("Latency = 15mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.0175,callback=AudioCallback)
    # print ("Latency = 17.5mSec 30-40mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.020,callback=AudioCallback)
    # print ("Latency = 20mSec 30-40mSec")        latency_org=0.03482993197278/2    
sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', latency=latency_org, callback=AudioCallback)
print ("Latency = %.15f" %latency_org)

# sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', callback=AudioCallback)
# print ("No Latency defined - default is HIGH  50 - 60 mSec")

    # sd = sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16',latency=0.100,callback=AudioCallback)
    # print ("Latency = 100mSec")

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA?-> Yes. I'm pretty sure I'm using ALSAYou must also set PA_MIN_LATENCY_MSEC-> Maybe an old comment from Port Audio developers. I didn't know how to use it.I should mention that I'm using an external DAC too and not the RPi internal DAC as the audio quality is not that great. Does this add to the latency? I wanted to know what kind of latency is common with sounddevice? Is it possible to get to 10mSec or lower?I will share my investigation results to you through a google document. It takes my system about 5mSec to call a function in SamplerBox to play a note. From that point it takes 17.5mSec before the audio buffer go non-zero and from that point it takes another 15mSec to hear the audio.Why is the AudiocallBack() called every 8mSec? Any chance to speed that up?I also tried to increase the priority of the SamplerBox application using htop to MAX (-19, 0) but didn't see any difference in latency. Let me know if you want me to try any new combinations and measure the delay. It will be great if I can reduce this delay as much as possible.Thanks again for your help.Really appreciate it.RezaOn Wed, Mar 6, 2024 at 10:51 AM Matthias Geier @.***> wrote: Which buffer sizes did you try? Did you try powers of 2? There is a PortAudio test program called pa_minlat, maybe that gives some insights? Did you try setting blocksize=0 and varying latency?

PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS.

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA?

You must also set PA_MIN_LATENCY_MSEC

That's something I have never heard before, and if you search for it in the PortAudio source code, it only appears in the file https://github.com/PortAudio/portaudio/blob/master/src/hostapi/dsound/pa_win_ds.c, which is irrelevant for Linux.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

mgeier commented 3 months ago

if you had a chance to see my feedback

Yeah, I've seen it, it's kinda hard to read. Can you try formatting it a bit nicer?

RezaYazdi604 commented 3 months ago

Sorry about that! The formatting looks OK on my side but I tried to clean my responses a little bit more. Hopefully this will address the formatting issue. Please let me know if it's good or not. Thank you for your help.

Which buffer sizes did you try? Did you try powers of 2? -> I use blocksize=384 which has so far delivered the best performance. I've also tried 128,16 and 0 but didn't see any significant difference in the latency measurement.

There is a PortAudio test program called pa_minlat, maybe that gives some insights? -> Didn't know about this. Does it work on RPI? I can give it a try.

Did you try setting blocksize=0 and varying latency? -> Yes. Didn't see a big difference. See the shared Google sheet for more details.

I tried many different combinations and the best one working for me now is

    latency_org=0.03482993197278/2      sd =

sounddevice.OutputStream(device=AUDIO_DEVICE_ID,blocksize=BLOCKSIZE,samplerate=f,channels=2,dtype='int16', latency=latency_org, callback=AudioCallback) print ("Latency = %.15f" %latency_org)

OSS is an audio backend that hasn't really been used for decades. I guess you are using ALSA? -> Yes. I'm pretty sure I'm using ALSA

You must also set PA_MIN_LATENCY_MSEC -> Maybe an old comment from Port Audio developers. I didn't know how to use it.

I should mention that I'm using an external DAC too and not the RPi internal DAC as the audio quality is not that great. Does this add to the latency? I wanted to know what kind of latency is common with sounddevice? Is it possible to get to 10mSec or lower?

I will share my investigation results to you through a google document. https://docs.google.com/spreadsheets/d/1NFkqyEGW1DZmFUpbkyHF5ob7DfHAVK4PeZypDVyEInM/edit?usp=sharing https://docs.google.com/spreadsheets/d/1NFkqyEGW1DZmFUpbkyHF5ob7DfHAVK4PeZypDVyEInM/edit?usp=sharing It takes my system about 5mSec to call a function in SamplerBox to play a note. From that point it takes 17.5mSec before the audio buffer goes non-zero and from that point it takes another 15mSec to hear the audio. Why is the AudiocallBack() called every 8mSec? Any chance to speed that up?

I also tried to increase the priority of the SamplerBox application using htop to MAX (-19, 0) but didn't see any difference in latency. Let me know if you want me to try any new combinations and measure the delay. It will be great if I can reduce this delay as much as possible.

Thanks again for your help. Really appreciate it.

Reza

On Wed, Mar 13, 2024 at 1:11 PM Matthias Geier @.***> wrote:

if you had a chance to see my feedback

Yeah, I've seen it, it's kinda hard to read. Can you try formatting it a bit nicer?

— Reply to this email directly, view it on GitHub https://github.com/spatialaudio/python-sounddevice/issues/524#issuecomment-1995634163, or unsubscribe https://github.com/notifications/unsubscribe-auth/A2ARXNYQ2BUVP7VSQYOVL7LYYCXGZAVCNFSM6AAAAABEGOEN6WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOJVGYZTIMJWGM . You are receiving this because you authored the thread.Message ID: @.***>

mgeier commented 3 months ago

Please let me know if it's good or not.

Still not great. Maybe you should use the web interface instead of replying by e-mail.

Did you try pa_minlat?

RezaYazdi604 commented 3 months ago

Hi Mathias,

I have not tried the pa_minlat yet. Are you referring to this? --> https://portaudio.com/docs/v19-doxydocs-dev/pa__minlat_8c.html#details

mgeier commented 3 months ago

yes.