Audaspace: Workaround Core Audio clock quirk

This commit is contained in:
Sebastian Parborg
2025-05-02 14:56:16 +02:00
committed by Sebastian Parborg
parent 034478fe07
commit 898877e8b3
2 changed files with 21 additions and 8 deletions

View File

@@ -46,6 +46,22 @@ OSStatus CoreAudioDevice::CoreAudio_mix(void* data, AudioUnitRenderActionFlags*
device->notifyMixingThread();
}
if (!device->m_audio_clock_ready) {
// Workaround CoreAudio quirk that corrupts the clock time data when the first mix callback occurs.
// Both the start time and current time will be invalid. We need to reset them.
if(device->isSynchronizerPlaying())
CAClockStop(device->m_clock_ref);
CAClockTime clock_time;
clock_time.format = kCAClockTimeFormat_Seconds;
clock_time.time.seconds = device->m_synchronizerStartTime;
CAClockSetCurrentTime(device->m_clock_ref, &clock_time);
if(device->isSynchronizerPlaying())
CAClockStart(device->m_clock_ref);
device->m_audio_clock_ready = true;
}
return noErr;
}
@@ -62,7 +78,7 @@ void CoreAudioDevice::playing(bool playing)
m_playback = playing;
}
CoreAudioDevice::CoreAudioDevice(DeviceSpecs specs, int buffersize) : m_buffersize(uint32_t(buffersize)), m_playback(false), m_audio_unit(nullptr)
CoreAudioDevice::CoreAudioDevice(DeviceSpecs specs, int buffersize) : m_buffersize(uint32_t(buffersize)), m_playback(false), m_audio_unit(nullptr), m_audio_clock_ready(false)
{
if(specs.channels == CHANNELS_INVALID)
specs.channels = CHANNELS_STEREO;
@@ -208,12 +224,6 @@ CoreAudioDevice::CoreAudioDevice(DeviceSpecs specs, int buffersize) : m_buffersi
throw;
}
/* Workaround CoreAudio quirk that makes the Clock (m_clock_ref) be in an invalid state
* after we try to re-init the device. (It is fine the first time we init the device...)
* We have to do a start/stop toggle to get it into a valid state again. */
AudioOutputUnitStart(m_audio_unit);
AudioOutputUnitStop(m_audio_unit);
create();
startMixingThread(buffersize * 2 * AUD_DEVICE_SAMPLE_SIZE(specs));
@@ -244,6 +254,7 @@ void CoreAudioDevice::seekSynchronizer(double time)
clock_time.format = kCAClockTimeFormat_Seconds;
clock_time.time.seconds = time;
CAClockSetCurrentTime(m_clock_ref, &clock_time);
m_synchronizerStartTime = time;
if(isSynchronizerPlaying())
CAClockStart(m_clock_ref);
@@ -257,7 +268,7 @@ double CoreAudioDevice::getSynchronizerPosition()
OSStatus status;
if(isSynchronizerPlaying())
if(isSynchronizerPlaying() && m_audio_clock_ready)
status = CAClockGetCurrentTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);
else
status = CAClockGetStartTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);

View File

@@ -56,6 +56,8 @@ private:
/// The CoreAudio clock referene.
CAClockRef m_clock_ref;
bool m_audio_clock_ready;
double m_synchronizerStartTime{0};
/**
* Mixes the next bytes into the buffer.