Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getLatencies() before createBuffers() returns error in violation of ASIO spec (triggers failure in NAudio) #122

Closed
bj-rn opened this issue Jun 23, 2021 · 7 comments
Labels
asiohost Relates to a specific ASIO Host Application. bug
Milestone

Comments

@bj-rn
Copy link

bj-rn commented Jun 23, 2021

Hey, I am trying to use FlexAsio together with an application called vvvv, which in turn uses NAudio for audio playback. It works fine with other drivers like ASIO4All and the ASIO drivers that come with FL Studio.

According to the FlexAsio log the cause of the exception is the following:

2021-06-23T11:55:00.8155006+02:00 9752 8212 --- ENTERING CONTEXT: getLatencies()
2021-06-23T11:55:00.8155629+02:00 9752 8212 --- EXITING CONTEXT: getLatencies() (-997 [ASE_InvalidMode] getLatencies() called before createBuffers())

FlexASIO.log

I don't know if this is a driver issue or if NAudio does somehow not handle the ASIO spec correctly.

Going through their source the following seems to take place:

this.AsioOut = new AsioOut(driverName);

  public AsioOut(string driverName)
        {
            this.syncContext = SynchronizationContext.Current;
            InitFromName(driverName);
        }

->

 private void InitFromName(string driverName)
        {
            this.driverName = driverName;

            // Get the basic driver
            AsioDriver basicDriver = AsioDriver.GetAsioDriverByName(driverName);

            // Instantiate the extended driver
            driver = new AsioDriverExt(basicDriver);
            driver.ResetRequestCallback = OnDriverResetRequest;
            this.ChannelOffset = 0;
        }

->

 public AsioDriverExt(AsioDriver driver)
        {
            this.driver = driver;

            if (!driver.Init(IntPtr.Zero))
            {
                throw new InvalidOperationException(driver.GetErrorMessage());
            }

            callbacks = new AsioCallbacks();
            callbacks.pasioMessage = AsioMessageCallBack;
            callbacks.pbufferSwitch = BufferSwitchCallBack;
            callbacks.pbufferSwitchTimeInfo = BufferSwitchTimeInfoCallBack;
            callbacks.psampleRateDidChange = SampleRateDidChangeCallBack;

            BuildCapabilities();
        }

->

 private void BuildCapabilities()
        {
            capability = new AsioDriverCapability();

            capability.DriverName = driver.GetDriverName();

            // Get nb Input/Output channels
            driver.GetChannels(out capability.NbInputChannels, out capability.NbOutputChannels);

            capability.InputChannelInfos = new AsioChannelInfo[capability.NbInputChannels];
            capability.OutputChannelInfos = new AsioChannelInfo[capability.NbOutputChannels];

            // Get ChannelInfo for Inputs
            for (int i = 0; i < capability.NbInputChannels; i++)
            {
                capability.InputChannelInfos[i] = driver.GetChannelInfo(i, true);
            }

            // Get ChannelInfo for Output
            for (int i = 0; i < capability.NbOutputChannels; i++)
            {
                capability.OutputChannelInfos[i] = driver.GetChannelInfo(i, false);
            }

            // Get the current SampleRate
            capability.SampleRate = driver.GetSampleRate();

            var error = driver.GetLatencies(out capability.InputLatency, out capability.OutputLatency);
            // focusrite scarlett 2i4 returns ASE_NotPresent here

            if (error != AsioError.ASE_OK && error != AsioError.ASE_NotPresent)
            {
                var ex = new AsioException("ASIOgetLatencies");
                ex.Error = error;
                throw ex;
            }

            // Get BufferSize
            driver.GetBufferSize(out capability.BufferMinSize, out capability.BufferMaxSize, out capability.BufferPreferredSize, out capability.BufferGranularity);
        }

->

@dechamps dechamps added asiohost Relates to a specific ASIO Host Application. bug labels Jun 23, 2021
@dechamps
Copy link
Owner

Yeah I think it's FlexASIO that's at fault here, sorry about that. Quoting the ASIO SDK (emphasis mine):

Note: As ASIOGetLatencies() will also have to include the audio buffer size of the ASIOCreateBuffers() call, the application has to call this function after the buffer creation. In the case that the call occurs beforehand the driver should assume preferred buffer size.

FlexASIO does not follow this guidance and returns an error instead of using the preferred buffer size. My mistake. I will prepare a fix the next time I resume work on FlexASIO.

(It should be noted, though, that calling getLatencies() before createBuffers() doesn't make a ton of sense. Other applications don't do this which is likely why this bug didn't surface until now. That logic in NAudio, while technically ASIO-compliant, seems highly questionable IMHO.)

I'm a bit curious as to why you are trying to use FlexASIO with NAudio though. That doesn't seem to make sense because NAudio can already access most Windows APIs directly (MME, DirectSound, WASAPI). FlexASIO is therefore just an additional layer of indirection; in theory, it will not provide any benefit and will just make things slower/more complicated/more likely to break. That seems a bit pointless. I guess the only exception is if you're trying to interface with WDM/KS, which NAudio doesn't seem to support.

@dechamps dechamps changed the title Exception when trying to use FlexAsio with NAudio getLatencies() before createBuffers() returns error in violation of ASIO spec (triggers failure in NAudio) Jun 23, 2021
@bj-rn
Copy link
Author

bj-rn commented Jun 23, 2021

Thanks for your quick reply.

I'm a bit curious as to why you are trying to use FlexASIO with NAudio though

VVVV only supports ASIO currently and I am but a mere user... ASIO4ALL needs exclusive access to the sound device and this unfortunatlely is not compatible with my usecase. So FlexAudio seemed to be an ideal solution.

@tebjan
Copy link

tebjan commented Sep 17, 2021

Hello, I'd like to bump this issue a little bit. FlexASIO seems to be the solution to many of our current audio troubles in media projects. Could you somehow lift this restriction and publish a new alpha release? That would be fantastic, thank you!

@dechamps dechamps added this to the FlexASIO 1.8 milestone Oct 3, 2021
dechamps added a commit to dechamps/ASIOTest that referenced this issue Oct 3, 2021
@dechamps
Copy link
Owner

dechamps commented Oct 3, 2021

This will be fixed in FlexASIO 1.8. In the meantime, here's an interim build that contains the fix: https://github.com/dechamps/FlexASIO/suites/3943985639/artifacts/98883891

@dechamps
Copy link
Owner

This is fixed in FlexASIO 1.8.

@bj-rn
Copy link
Author

bj-rn commented Oct 19, 2021

Thanks. I've just run some simple tests and it seems to work as expected.

@tebjan
Copy link

tebjan commented Nov 23, 2021

Works here too, thanks a lot, this is great news!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
asiohost Relates to a specific ASIO Host Application. bug
Projects
None yet
Development

No branches or pull requests

3 participants