Hey Jules, an external sample rate change to a different value causes the audio device to be stopped without any notification. Can we get a call to audioDeviceStopped (or perhaps some other preferred solution, (audioDeviceError?) ) so the application can respond to it?
CoreAudioInternal: timerCallback calls stop(false) if the sample rate has been changed to something different than we set it to.
I think the idea there was that it should just re-start at the new rate and carry on… Not sure how I’d test this myself (?) but perhaps just a simple change would do it:
Well I think we need a notification somewhere. If the sample rate changes then you’re going to want to update any graphs/plugins you’ve got going and so forth.
In my case the sample rate change was due to a sync’d ADAT connection silently forcing 48 khz (had to do some digging to figure out what was going on) but a basic test can be done with two instances of the plugin host demo and manually changing the sample rate in one instance and pressing the “Test” button in the settings panel of the other instance. The first instance’s test sound works but the second instance’s doesn’t.
I’ve patched my version of timerCallback in a similar way but instead of automatically restarting I use the callback to call audioDeviceStopped. In the callback I check my stored settings against what the device is set to. If the settings are different then I issue a message to the user and ask if they want to try resetting the stored setting or accept the new one. Maybe there’s a better solution for using the callback but I do think the notification is important.
if (oldBufferSize != bufferSize || oldSampleRate != sampleRate)
{
AudioIODeviceCallback* oldCallback = callback;
callbacksAllowed = false;
stop (false);
updateDetailsFromDevice();
callbacksAllowed = true;
//notify the application that the device has stopped.
oldCallback->audioDeviceStopped()
}
Ah, sorry, I was looking at the wrong bit of code, and assuming that the stop/start calls would send the audioDeviceStopped/started callbacks. But that happens in the other class, not this one.
I’ve made a few changes now that should restart it properly, but haven’t got a system I could test it on, so would appreciate you trying it and letting me know what happens!
Sorry, my suggestion wasn’t quite right. owner’s stop() expects the internal callback to be in place. Not sure how to go with that one without resorting to some hackery.
void stop()
{
if (isStarted)
{
AudioIODeviceCallback* const lastCallback = internal->callback; //this will be null.
isStarted = false;
internal->stop (true);
if (lastCallback != nullptr)
lastCallback->audioDeviceStopped();
}
}
This looks great and a quick test shows that things are handling properly. I had the same approach going here but was trying to maintain the call to stop (false) from within restart, which was mucking things up design wise. But it doesn’t look like there was any point in recreating the io proc anyway, so this is a nice improvement all around.