Yamaha Steinberg USB ASIO Problems Since July Commit

I have a tester reporting problems with their Yamaha Steinberg USB ASIO device.
The issue is that the device usually fails to open, either when trying to reload settings or selecting it from the “Device” box in the audio settings panel.

Looking at the log file, there’s a whole host of ASIO error reported:

27 Oct 2019 16:47:10  ASIO: found Yamaha Steinberg USB ASIO
27 Oct 2019 16:47:10  ASIO: opening device: Yamaha Steinberg USB ASIO
27 Oct 2019 16:47:10  ASIO: closed
27 Oct 2019 16:47:10  ASIO: opening device: Realtek ASIO
27 Oct 2019 16:47:10  ASIO: 2 in, 6 out
27 Oct 2019 16:47:10  ASIO: 1024->1024, 1024, 0
27 Oct 2019 16:47:10  ASIO: setting default sample rate
27 Oct 2019 16:47:10  ASIO: error: setting sample rate - Not Present
27 Oct 2019 16:47:10  ASIO: Rates: 44100 48000 88200 96000 176400 192000
27 Oct 2019 16:47:10  ASIO: getLatencies() failed
27 Oct 2019 16:47:10  ASIO: creating buffers (dummy): 4, 1024
27 Oct 2019 16:47:10  ASIO: Latencies: in = 3211, out = 3211
27 Oct 2019 16:47:10  ASIO: device open
27 Oct 2019 16:47:10  ASIO: clock: Internal clock (cur)
27 Oct 2019 16:47:10  ASIO: rate change: 0 to 44100
27 Oct 2019 16:47:10  ASIO: disposing buffers
27 Oct 2019 16:47:10  ASIO: creating buffers: 8, 1024
27 Oct 2019 16:47:10  ASIO: channel format: 17
27 Oct 2019 16:47:10  ASIO: Latencies: in = 3211, out = 3211
27 Oct 2019 16:47:10  ASIO: starting
27 Oct 2019 16:47:13  ASIO: no callbacks - stopping..
27 Oct 2019 16:47:13  ASIO: closed
27 Oct 2019 16:47:13  *** ERROR: AudioDeviceManager init: Device didn't start correctly

I’ve dug through the commits and the only ASIO related addition between the last working build and the broken builds is this:

Which explicitly specialises some behaviour around the “Yamaha Steinberg USB ASIO”. It sounds like this is causing the problems.

Can you remember exactly what this was trying to fix? I don’t have a device to test with so this is a tricky one to debug. Any suggestions welcome…

It was added in response to this thread:

I’ll have another look today and see what it was fixing exactly.

Can I request that this change be reverted?
I’m getting more and more support tickets related to this now as users upgrade.

I don’t have a Steinberg IO to test with so can’t offer up much more by way of an alternative fix.
Perhaps @highcarbschwabe can check if reverting the change is still causing problems?

It seems odd this hasn’t been a problem in previous versions for us.
Were there specific steps to replicate it?

Unfortunately I don’t have a Steinberg interface to test with either but if I revert the change by making shouldReleaseObject() always return true, and attempt to open and close the “Yamaha Steinberg USB ASIO” driver I can reproduce the initial crash:

As far as I can tell, the asioObject is being released before we come to remove it.

What issues are your users reporting? If there is no compatible interface connected and they attempt to open the Steinberg ASIO driver device it’ll return a “device failed to open” error. The list of compatible devices is here under “supported hardware”: https://www.steinberg.net/en/support/downloads_hardware/yamaha_steinberg_usb_driver.html. Could that be the issue?

The problem is that if the app has a connection to the device and then closes (i.e. the device is selected from AudioDeviceManager), when the app is restarted, the same device is attempted to be started and this fails.
Manually selecting the device also fails continuously until at some point it doesn’t.

Basically to most users it looks like after a restart of the app, they can’t use their audio device.

It sounds like without doing the release, the driver is being left tied up so can’t be opened again after a restart.


Is tryCreatingDriver doing something odd like not crashing but failing to actually open the device but still assigning something to asioObject? Is that then invalid and crashing when you try to release it?

In your test, with no device connected, does CoCreateInstance actually return false but asioObject is some kind of junk? Or is it correctly left as nullptr?

I’ll check it again today.

Using JUCE 5.4.5, now I can not start the UR12. Here is what happens:

grafik

grafik

This is the behaviour in debug mode. However, no exception is thrown, my program continues to run.

I don’t know if this is an interesting observation: My program stores its IO configuration persistently. The first time I ran it today, it loaded the (old) UR12 ASIO configuration and started the UR12 correctly but I can not get back there now.

Edit: When I close my program, remove the UR12, plug it in again and start my program again, the UR12 driver is working again
grafik

Yes, this is the problem my users are facing.
Basically without shutting down the app and unplugging the interface, they can’t use it, getting the “Error when trying to open audio device!” message.

If you revert the original change, making shouldReleaseObject always return true, can the device be opened correctly?

If so, we’re back to the crash that change was intended to fix. Perhaps that can be mitigated in some other way?

After

everything seems to work nicely. The problem that led to the use of shouldReleaseObject seems to be gone, too, in JUCE 5.4.5 - very nice! Seems that shouldReleaseObject is not required any more :slight_smile:

Well that’s good… but does conflict with what @ed95 reported here:

So it sound like perhaps there is an orthogonal problem trying to open the driver with no device attached?

If so, I would recommend the removal of shouldReleaseObject to return to the original version of this code and take a deeper dive in to why the driver is crashing if there is no device attached. Perhaps this is something to do with tryCreatingDriver as I suggested above?

I just tried unplugging the UR12 while the program is running and then starting the ASIO driver.

Result : An exception in removeCurrentDriver()

When you say exception, is this a catchable exception or a crash?

The screenshot looks like a dangling pointer dereference to me?
But I’m not sure why that would happen during the assignment of a nullptr? Or is is actually happening in the Release() call above?

Seems to be catchable - my program keeps running.

I have an UR22 with the same kind of driver and it’s not just crashing JUCE hosts, but various random ASIO hosts, even if the device is not attached. I keep uninstalling the driver after each use as it’s just terrible. I always hoped for a driver update that would fix this annoying issue, but so far it hasn’t happened. I don’t think finding a workaround in JUCE is the correct solution. The fix should be done by Steinberg/Yamaha. They should finally deliver a stable windows driver and we’d tell customers to update to that. The crazy thing is that I bought the interface because I thought Steinberg surely will have a good driver…

2 Likes

P.S.: If you don’t believe me, just do a google search for “Steinberg Yamaha USB driver crash”.

It is happening in asioObject->Release();. When I comment out Release(), the exception is gone.

So does putting a C++ try/catch statement around it catch it can allow things to continue?
Or does it need a Windows try-except statement? (Similar to that in tryCreatingDriver).

grafik

Result: Again

Ausnahme ausgelöst bei 0x00007FF9087BFEEA (ntdll.dll) in VPOLAB.exe: 0xC0000008: An invalid handle was specified.

but crashed == false and exceptionDescription == "".

When I try to reproduce this behaviour a second time while the program keeps running and I only switch the UR12 off and on again… the exception is gone, and the UR12 driver starts as it should…

Maybe there is indeed something wrong with the UR12 driver itself? In that case I suppose Yamaha should fix it…

Yes, it definitely sounds like a driver problem.

Thinking about this more though, it almost certainly won’t be a C++ exception that is thrown here as it’s a C API.
So does using the Windows try-except statement (as in tryCreatingDriver) catch the exception?


The thing I’m trying to get at here is a way to mitigate the crash.
When this exception is thrown and you have a debugger attached, the debugger will catch it and you can choose to continue execution. When this happens without a debugger (such as in normal end-user use) this exception will be a termination.

So if we can catch it with that Windows try-except statement, we can at least hopefully avoid terminating the whole app.

trying __try/__except leads to compiler error C2712: Cannot use __try in functions that require object unwinding