mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 20:35:04 +02:00
Merge pull request #15637 from kencooke/audio-init-racecond-crashfix
BUGZ-158: Crash when switching audio devices on Mac
This commit is contained in:
commit
12996b2d7d
2 changed files with 47 additions and 41 deletions
|
@ -1869,6 +1869,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
|||
if (_audioOutput) {
|
||||
_audioOutputIODevice.close();
|
||||
_audioOutput->stop();
|
||||
_audioOutputInitialized = false;
|
||||
|
||||
//must be deleted in next eventloop cycle when its called from notify()
|
||||
_audioOutput->deleteLater();
|
||||
|
@ -1939,9 +1940,14 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
|||
int requestedSize = _sessionOutputBufferSizeFrames * frameSize * AudioConstants::SAMPLE_SIZE;
|
||||
_audioOutput->setBufferSize(requestedSize);
|
||||
|
||||
// initialize mix buffers on the _audioOutput thread to avoid races
|
||||
connect(_audioOutput, &QAudioOutput::stateChanged, [&, frameSize, requestedSize](QAudio::State state) {
|
||||
if (state == QAudio::ActiveState) {
|
||||
connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify);
|
||||
|
||||
// start the output device
|
||||
_audioOutputIODevice.start();
|
||||
_audioOutput->start(&_audioOutputIODevice);
|
||||
|
||||
// initialize mix buffers
|
||||
|
||||
// restrict device callback to _outputPeriod samples
|
||||
_outputPeriod = _audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE;
|
||||
// device callback may exceed reported period, so double it to avoid stutter
|
||||
|
@ -1962,6 +1968,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
|||
// this ensures lowest latency without stutter from underrun
|
||||
_localInjectorsStream.resizeForFrameSize(localPeriod);
|
||||
|
||||
_audioOutputInitialized = true;
|
||||
|
||||
int bufferSize = _audioOutput->bufferSize();
|
||||
int bufferSamples = bufferSize / AudioConstants::SAMPLE_SIZE;
|
||||
int bufferFrames = bufferSamples / (float)frameSize;
|
||||
|
@ -1973,17 +1981,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
|||
qCDebug(audioclient) << "period (samples):" << _outputPeriod;
|
||||
qCDebug(audioclient) << "local buffer (samples):" << localPeriod;
|
||||
|
||||
disconnect(_audioOutput, &QAudioOutput::stateChanged, 0, 0);
|
||||
|
||||
// unlock to avoid a deadlock with the device callback (which always succeeds this initialization)
|
||||
localAudioLock.unlock();
|
||||
}
|
||||
});
|
||||
connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify);
|
||||
|
||||
_audioOutputIODevice.start();
|
||||
|
||||
_audioOutput->start(&_audioOutputIODevice);
|
||||
|
||||
// setup a loopback audio output device
|
||||
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||
|
@ -2082,6 +2081,12 @@ float AudioClient::gainForSource(float distance, float volume) {
|
|||
|
||||
qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||
|
||||
// lock-free wait for initialization to avoid races
|
||||
if (!_audio->_audioOutputInitialized.load(std::memory_order_acquire)) {
|
||||
memset(data, 0, maxSize);
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
// samples requested from OUTPUT_CHANNEL_COUNT
|
||||
int deviceChannelCount = _audio->_outputFormat.channelCount();
|
||||
int samplesRequested = (int)(maxSize / AudioConstants::SAMPLE_SIZE) * OUTPUT_CHANNEL_COUNT / deviceChannelCount;
|
||||
|
|
|
@ -340,6 +340,7 @@ private:
|
|||
QIODevice* _inputDevice;
|
||||
int _numInputCallbackBytes;
|
||||
QAudioOutput* _audioOutput;
|
||||
std::atomic<bool> _audioOutputInitialized { false };
|
||||
QAudioFormat _desiredOutputFormat;
|
||||
QAudioFormat _outputFormat;
|
||||
int _outputFrameSize;
|
||||
|
|
Loading…
Reference in a new issue