PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.43k stars 296 forks source link

Pa_OpenStream on Mac hangs when running multiple streams with different rates #227

Open PortAudio-admin opened 9 years ago

PortAudio-admin commented 9 years ago

Issue created by @philburk

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.

PortAudio-admin commented 9 years ago

Comment by @philburk

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.