ASIO freeze (switch Buffersize) + FIX


#1

If the buffersize of my RME-Fireface is changing, there will be no additional processBuffer-Callbacks, the audio-output hangs.
After that changes below, i can change the buffersize in driver-control panel and audio is still working HOORAY, without that changes it hangs.

First: The reset-procedure should activated outside the processBuffer-Callback! (because if processBuffer is not called, nothing will happen!)

In juce\modules\juce_audio_devices\native\juce_win32_ASIO.cpp

  void resetRequest() noexcept
    {
		// Lets have a little more time than 20ms
	   	startTimer (500);
	}

    void resyncRequest() noexcept
    {
        isReSync = true;  
		resetRequest();
    }

If the driver changes the BufferSize it should also initiate a reset!!

in static long asioMessagesCallback (long selector, long value, const int deviceIndex)

[code]

    case kAsioBufferSizeChange:									
		if (currentASIODev[deviceIndex] != nullptr)				//NEW!!!!!!!!!!
			currentASIODev[deviceIndex]->resetRequest();		//NEW!!!!!!!!!!

		return 1;

[/code]

The driver should also be unloaded, reloaded like when changing the sample-rate. I’ve done this through a quick hack, but maybe it needs some better redesign.

[code]

IN String open (const BigInteger& inputChannels,

	...
	...
	...
    if (err == 0)
    {
        currentSampleRate = sampleRate;

        if (needToReset || forceReset)     // QUICK HACK TO FORCE A RESET
        {
			forceReset=false;
            if (isReSync)
            {
                log ("Resync request");
            }
			
			
			log ("! Resetting ASIO after sample rate change");
            removeCurrentDriver();

            loadDriver();
			
			

	[/code]		

[code]
void timerCallback()
{
if (! insideControlPanelModalLoop)
{
stopTimer();

        // used to cause a reset
        log ("! ASIO restart request!");

        if (deviceIsOpen)
        {
            AudioIODeviceCallback* const oldCallback = currentCallback;

            close();
			forceReset=true;		// NEW!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            open (BigInteger (currentChansIn), BigInteger (currentChansOut),
                  currentSampleRate, currentBlockSizeSamples);

            if (oldCallback != nullptr)
                start (oldCallback);
        }
    }
    else
    {
        startTimer (100);
    }
}[/code]

#2

I don’t really understand why you had that forceReset flag in there, but I’ve checked in something that may do what you need - please have a go and let me know if it works!


#3

Just an fyi: your modifications, without the macro ASIO_DEBUGGING defined, cause a small compiler error.

My quick fix is wrapping the contents of the if/else with {}

                if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
                {
                    JUCE_ASIO_LOG ("ASIO - no latencies");
                }
                else
                {
                    JUCE_ASIO_LOG ("ASIO latencies: " + String ((int) outputLatency) + ", " + String ((int) inputLatency));
                }

#4

Yes, sorry - I noticed that and checked in a fix, but I guess you grabbed it before that.


#5

Yes, i grab it before :), but the problem is still there:

No - it does not work.
Looking at you new commit in Line 512 it does " needToReset = false “
A few lines later, there is a if statement (LINE 538)
” if (needToReset) "
which makes no sense, that’s why i hacked my “forceReset” into it, to be sure that removeCurrentDriver() and loadDriver() will happen!

removeCurrentDriver(); and loadDriver(); should be done on sample-rate change and on blocksize change!
If it doesn’t do it, the driver will fail to open, because no callback will happen. “ASIO didn’t callback - stopping…”


#6

Ah yes. Well, I think all that needs to happen would be to remove that needToReset = false statement on line 512, right?


#7

mhh…yes, i think so … in the old code needToReset, was used for two reasons, first it triggers the timer, second i was set when the sampleRates changed (EDIT: to indicate that the driver should reload), i think this was a little but obscure…

Also you could remove this part (below) from processBuffer, because the timer should only triggerd by resetRequest() directly, and the needToReset is now that flag the only indicates that the driver should be reloaded in open()

1726 if (needToReset)\r 1277 {\r 1278 needToReset = false;\r 1279 \r 1280 if (isReSync)\r 1281 {\r 1282 JUCE_ASIO_LOG ("! ASIO resync");\r 1283 isReSync = false;\r 1284 }\r 1285 else\r 1286 {\r 1287 startTimer (20);\r 1288 }\r 1289 }\r

You could also remove the isReSync - Flag, it looks it has no function


#8

Ok, try now.


#9

Thanks, changing the buffer-size is now working perfect, but there is still is another problem that needs to be fixed (and also exists before this patch)

After changing the samplerate in AudioDeviceSelectorComponent, the device wont start again, and the driver is unselected. If you selected it again, it will run.
This can fixed, if the driver will be reloaded every time the device is opened (just remove the needToReset-Flag, reload it everytime in open(), is there any reason why not to do it? )

The second problem is, that the app doesn’t get the right samplerate everytime (so we listen to pitched audio), not sure what the problem is…

[attachment=0]clock.png[/attachment]


#10

Did this stuff work before the changes you suggested?


#11

no, these problem also exists before the changes!


#12

the needToReset flag stops it needlessly re-opening a device that it has just opened. There are a lot of incredibly flakey ASIO drivers out there, and forcing the drivers to reopen every time is just bound to break something.


#13

mmhh yes, but at least it should reload the driver when changing the samplerate in the AudioDeviceSelectorComponent, this would be consequent (and is the only way to get it run)