dechamps / FlexASIO

A flexible universal ASIO driver that uses the PortAudio sound I/O library. Supports WASAPI (shared and exclusive), KS, DirectSound and MME.
Other
1.34k stars 72 forks source link

Sample rate reported as unavailable after stream open when using exclusive backend #66

Closed nickph7 closed 4 years ago

nickph7 commented 4 years ago

Hi, I am trying to use flexASIO to use MaxMSP with Ableton as slave to create a generative music system. In an ideal world, I would like to run both MaxMSP and Ableton side by side, without having to switch driver when going from one software to another. When selecting FlexASIO as a driver, MaxMSP return the following error in the console:

ad_asio: no samplerates work for us!
ad_asio: adasio_setsr() no rates available.
ad_asio: ASIOStop() returned -997.
ad_asio: no samplerates work for us!

This is my current setting of flexASIO

backend = "Windows WASAPI"
bufferSizeSamples = 512

[input]
suggestedLatencySeconds = 0.0
wasapiExclusiveMode = true

[output]
suggestedLatencySeconds = 0.0
wasapiExclusiveMode = true

I have no problem using flexASIO in Ableton. I have also attached the flexASIO.log document I have created to diagnose the problem

FlexASIO.log

Is there a work around or a configuration that would allow me to use FlexASIO for the use case I am looking for.

dechamps commented 4 years ago

Okay, I see the problem:

--- ENTERING CONTEXT: canSampleRate()
Checking for sample rate: 48000
Sample rate 48000 is available
--- EXITING CONTEXT: canSampleRate() [OK]
--- ENTERING CONTEXT: createBuffers()
--- EXITING CONTEXT: createBuffers() [OK]
--- ENTERING CONTEXT: canSampleRate()
Checking for sample rate: 48000
Sample rate 48000 is unavailable

This is actually a fairly subtle scenario that fails because of the following combination of factors:

  1. The ASIO host application calls createBuffers(). FlexASIO opens a stream as a result.
  2. The ASIO host application calls canSampleRate() after calling createBuffers().
  3. The way FlexASIO implements canSampleRate() is by opening a stream and see if that works.
  4. In this case, FlexASIO cannot open a stream because there is already one opened (see step 1) and you're using an exclusive backend.
  5. Therefore, FlexASIO reports the sample rate as unavailable, which confuses the host application and results in failure.

The reason why the bug went unnoticed until now is because you might the first person who uses an application that calls canSampleRate() after createBuffers() and using an exclusive backend at the same time.

Arguably the behaviour of your host application is a bit weird (what's the point of checking sample rates again after it already opened a stream?), but technically it's not wrong, so, ultimately, this is a bug in FlexASIO. It can be fixed by making canSampleRate() behave in a smarter way if it's called after createBuffers(), by always reporting the sample rate as available if it happens to match the sample rate of the currently running stream.

I'm not sure when I'll find the time to make the fix however. In the mean time, as a workaround I would suggest using a non-exclusive backend, such as WASAPI in shared (not exclusive) mode.

aleksati commented 4 years ago

I am getting the same error messages in the Max MSP console with WASAPI in shared mode, but the audio in the application seems to stream just fine.

dechamps commented 4 years ago

72 from @iamelec shows some similar behaviour:

2020-04-29T17:08:49.7281517+02:00 9580 15708 --- EXITING STREAM CALLBACK (0 [paContinue])
2020-04-29T17:08:49.7295737+02:00 9580 2572 --- ENTERING CONTEXT: canSampleRate()
...
2020-04-29T17:17:39.6626086+02:00 15964 10388 --- EXITING STREAM CALLBACK (0 [paContinue])
2020-04-29T17:17:39.6678424+02:00 15964 3080 --- ENTERING CONTEXT: canSampleRate()

However, in the case of #72 that seems legitimate because the application is truly attempting to change sample rates on the fly. It makes sense that the application does not necessarily want to interrupt the stream just so that it can list the available sample rates.

The possible fix I described in my previous comment was to report the specific sample rate of the currently running stream as available. It does not involve changing the logic in the case where the sample rate being requested is not the sample rate of the running stream. So that wouldn't work for the purposes of determining the complete list of usable sample rates while an exclusive stream is running. Fixing that would likely require a more thoughtful solution, such as probing the backend for some set of sample rates in advance and then remembering the results if asked when the stream is running. Or perhaps FlexASIO could simply always answer "yes" to any canSampleRate() query made while a stream is running - which is technically wrong, but it's not as bad as what FlexASIO currently does, which is always answering "no" in that situation.

dechamps commented 4 years ago

Just for reference: judging from a log provided in #83, Ableton seems to trigger a similar issue where it calls canSampleRate() after createBuffers() (but before start(), though).

That makes at least 3 separate applications that exhibit this behaviour. Clearly FlexASIO needs to be fixed to adapt to what these applications are doing.

dechamps commented 4 years ago

This is fixed in FlexASIO 1.6, which now reports all sample rates as available while an exclusive stream is running, instead of rejecting all sample rates.

dechamps commented 3 months ago

FlexASIO 1.10 includes a better fix for this, which makes it possible to actually probe sample rates and get the correct results when an excusive stream is running.