Pa_OpenStream on Mac hangs when running multiple streams with different rates
Dinesh Iyer reported this bug. Excerpt from original email follows:
I am designing an application which allows users to playback multiple audio signals at different sample-rates to the same audio device. I implement this by opening a new stream to playback each signal. I let CoreAudio perform the mixing. The playback does not start simultaneously i.e the user can playback one signal, then after an arbitrary amount of time playback the next one even when the first signal is playing.
The stall occurs about 30% of the time.
I am able to consistently reproduce a stall when I am playing back two signals at 8192 hertz and attempt to open a stream at 44100 hz. The stall occurs at __psync_mutexwait in the call to Pa_OpenStream().
I am not receiving this stall when I match the sample rates of all my streams.
I am able to reproduce this using both the March 2011 and Jan 2014 versions of the library.
I am designing an application which allows users to playback multiple audio signals at different sample-rates to the same audio device. I implement this by opening a new stream to playback each signal. I let CoreAudio perform the mixing. The playback does not start simultaneously i.e the user can playback one signal, then after an arbitrary amount of time playback the next one even when the first signal is playing.
The stall occurs about 30% of the time.
I am able to consistently reproduce a stall when I am playing back two signals at 8192 hertz and attempt to open a stream at 44100 hz. The stall occurs at __psync_mutexwait in the call to Pa_OpenStream().
I am not receiving this stall when I match the sample rates of all my streams.
I am able to reproduce this using both the March 2011 and Jan 2014 versions of the library.
Leave a comment
Dinesh wrote:
I am using callback API's. The streams operating at 8192 Hz use a buffer
size of 256 samples and the stream operating at 44.1 Khz is operating is
using a buffer of 1024 samples.
I was inspecting the threads in my application when I receive the stall. I
noticed that the thread "com.apple.audio.IOThread.client" also has a call
to __psynch_mutexwait() on the top of the call-stack. I have observed this
repeatedly.
I am not doing any file I/O operations in the callback.
I am using a TBB::concurrent_bounded_queue to stream data from my
application's thread to the portaudio callback. A brief description of my
code.
Application Thread:
1. Break up data into chunks of buffer size.
2. Put each chunk in a newly allocated buffer AND
3. Push them into a concurrent queue.
In callback,
1. Pop the buffer at the top of the queue
2. Copy the popped buffer to output buffer pointer provided by the callback.
3. Free the popped buffer.
So there does appear to be memory allocation/deallocation. However, I
recently changed my architecture. I am able to reproduce this stall even in
my older architecture when no alloc/free was performed after the stream was
opened and started.
I modified my application to ensure that no buffers are pushed into the
queue on the main application thread and no pop's from the queue in the
callback thread (only writing zeros to output) and I still get the stall at
the call to PaOpenStream(). No operations are being performed on the TBB
queue.
I am using callback API's. The streams operating at 8192 Hz use a buffer
size of 256 samples and the stream operating at 44.1 Khz is operating is
using a buffer of 1024 samples.
I was inspecting the threads in my application when I receive the stall. I
noticed that the thread "com.apple.audio.IOThread.client" also has a call
to __psynch_mutexwait() on the top of the call-stack. I have observed this
repeatedly.
I am not doing any file I/O operations in the callback.
I am using a TBB::concurrent_bounded_queue to stream data from my
application's thread to the portaudio callback. A brief description of my
code.
Application Thread:
1. Break up data into chunks of buffer size.
2. Put each chunk in a newly allocated buffer AND
3. Push them into a concurrent queue.
In callback,
1. Pop the buffer at the top of the queue
2. Copy the popped buffer to output buffer pointer provided by the callback.
3. Free the popped buffer.
So there does appear to be memory allocation/deallocation. However, I
recently changed my architecture. I am able to reproduce this stall even in
my older architecture when no alloc/free was performed after the stream was
opened and started.
I modified my application to ensure that no buffers are pushed into the
queue on the main application thread and no pop's from the queue in the
callback thread (only writing zeros to output) and I still get the stall at
the call to PaOpenStream(). No operations are being performed on the TBB
queue.