PortAudio / portaudio

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

Allow to open stream with "current" sample rate #970

Open Spacechild1 opened 1 month ago

Spacechild1 commented 1 month ago

Sometimes we just want to open a stream with its "current" sample rate. This is particularly true for backends where the sample rate is fixed or has been set by another application. Prominent examples are Jack and ASIO.

Now, you might thank that we could simply use PaDeviceInfo.sampleRate for this purpose. Unfortunately, this does not always work.

While Jack gets the default sample rate directly from the Jack server, ASIO follows a rather peculiar strategy:

  1. Iterate over an arbitrary list of sample rates and ask the driver if the rate is supported.
  2. Pick the first rate that works.

Typically, this always results in a default sample rate of 44100 Hz, as this rate is pretty much always supported.

Now here's the problem: Just because ASIO tells you that the rate is supported does not mean that you can actually use it for opening a new stream!

Modern ASIO drivers typically support multiple client, but they all must use the same sample rate. If another ASIO client has already opened a stream at, say, 48000 Hz, the device has been set to that rate. If you then attempt to open a new stream using the "default sample rate" as reported by PortAudio, you would get an error!

IMO a "default sample rate" should be a sample rate that is guaranteed to work. In the case of ASIO that would be the current driver sample rate (as reported by ASIOGetSampleRate).


Originally, I thought that we could simple set PaDeviceInfo.defaultSampleRate to the current ASIO device sample rate and be done.

However, there's a more fundamental issue: since PaDeviceInfo is immutable, defaultSampleRate is chosen at the time of library initialization. However, the ASIO/Jack sample rate may change anytime!

I think the best solution would be an option that tells Pa_OpenStream to use the actual current sample rate. This could be a new stream flag like paUseCurrentSampleRate. After the stream has been opened, the user could query the actual sample rate with Pa_GetStreamInfo.

Any thoughts?

dechamps commented 1 month ago

However, there's a more fundamental issue: since PaDeviceInfo is immutable, defaultSampleRate is chosen at the time of library initialization. However, the ASIO/Jack sample rate may change anytime!

This is just a specific instance of the wider problem of the PortAudio API not having a way to report changes to device properties. The same problem applies to reporting addition and removal of devices, for example.

You could work around the issue by completely re-initializing PortAudio every time you want to "refresh" the device list, though obviously this is not exactly a cheap operation.

Spacechild1 commented 1 month ago

I'm aware of the wider problem, but I think it would be impossible to fix without a complete redesign of the library (which likely isn't going to happen).

However, I've raised a specific issue and proposed a very concrete and workable fix. (I might also make a PR if there is some positive feedback.)

RossBencina commented 3 weeks ago

This is just a specific instance of the wider problem

No question there are multiple problems. I would say it's a related problem, not part of "the" wider problem. Even if we address hot-plug device support it will do nothing to help with devices that have complex dynamic sample rate behavior.

Another factor for the dynamic sample rate issue is that the sample rate can change due to purely hardware behavior (e.g. a word clock source changes sample rate, or the user flips the sample rate selector switch on the front of the rack).

There are at least two separate conversations that could be had at this point:

  1. What kind of hacks, changes and workarounds are viable within the scope of V19
  2. What could be changed for a future API revision (i.e. V20)

Having an "open with current sample rate" option to Pa_OpenStream has two obvious advantages: (1) it extends the current API in a backward compatible way and (2) it avoids race conditions which would happen with any alternative approach. (although it may just push the race inside PortAudio).

Spacechild1 commented 3 weeks ago

Thanks for chiming in!

Having an "open with current sample rate" option to Pa_OpenStream has two obvious advantages: (1) it extends the current API in a backward compatible way and (2) it avoids race conditions which would happen with any alternative approach. (although it may just push the race inside PortAudio).

That have been exactly my thoughts!