From 899a74d1c06c7bf0743acf81dbfaae92343c87c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 9 Feb 2016 02:01:21 -0800 Subject: [PATCH] Qt: Fix hang if audio sync is enabled and audio fails to initialize --- CHANGES | 1 + src/platform/qt/AudioProcessor.h | 2 +- src/platform/qt/AudioProcessorQt.cpp | 5 +++-- src/platform/qt/AudioProcessorQt.h | 2 +- src/platform/qt/AudioProcessorSDL.cpp | 7 ++++--- src/platform/qt/AudioProcessorSDL.h | 2 +- src/platform/qt/GameController.cpp | 26 +++++++++++++++++++++----- 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index 3ef50f68f..2e1d98dad 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,7 @@ Bugfixes: - VFS: Fix reading 7z archives without rewinding first - Qt: Fix sending gameStopped twice + - Qt: Fix hang if audio sync is enabled and audio fails to initialize Misc: - GBA: Slightly optimize GBAProcessEvents diff --git a/src/platform/qt/AudioProcessor.h b/src/platform/qt/AudioProcessor.h index 74d76a345..d33ccdd7f 100644 --- a/src/platform/qt/AudioProcessor.h +++ b/src/platform/qt/AudioProcessor.h @@ -34,7 +34,7 @@ public: virtual unsigned sampleRate() const = 0; public slots: - virtual void start() = 0; + virtual bool start() = 0; virtual void pause() = 0; virtual void setBufferSamples(int samples) = 0; diff --git a/src/platform/qt/AudioProcessorQt.cpp b/src/platform/qt/AudioProcessorQt.cpp index c28d934b9..30b50cd58 100644 --- a/src/platform/qt/AudioProcessorQt.cpp +++ b/src/platform/qt/AudioProcessorQt.cpp @@ -34,10 +34,10 @@ void AudioProcessorQt::setInput(GBAThread* input) { } } -void AudioProcessorQt::start() { +bool AudioProcessorQt::start() { if (!input()) { LOG(WARN) << tr("Can't start an audio processor without input"); - return; + return false; } if (!m_device) { @@ -62,6 +62,7 @@ void AudioProcessorQt::start() { m_audioOutput->setBufferSize(input()->audioBuffers * 4); m_audioOutput->start(m_device); + return m_audioOutput->state() == QAudio::ActiveState; } void AudioProcessorQt::pause() { diff --git a/src/platform/qt/AudioProcessorQt.h b/src/platform/qt/AudioProcessorQt.h index 05aaae93d..1ae871841 100644 --- a/src/platform/qt/AudioProcessorQt.h +++ b/src/platform/qt/AudioProcessorQt.h @@ -23,7 +23,7 @@ public: virtual unsigned sampleRate() const override; public slots: - virtual void start() override; + virtual bool start() override; virtual void pause() override; virtual void setBufferSamples(int samples) override; diff --git a/src/platform/qt/AudioProcessorSDL.cpp b/src/platform/qt/AudioProcessorSDL.cpp index 2db807f3f..65a944012 100644 --- a/src/platform/qt/AudioProcessorSDL.cpp +++ b/src/platform/qt/AudioProcessorSDL.cpp @@ -23,19 +23,20 @@ AudioProcessorSDL::~AudioProcessorSDL() { GBASDLDeinitAudio(&m_audio); } -void AudioProcessorSDL::start() { +bool AudioProcessorSDL::start() { if (!input()) { LOG(WARN) << tr("Can't start an audio processor without input"); - return; + return false; } if (m_audio.thread) { GBASDLResumeAudio(&m_audio); + return true; } else { if (!m_audio.samples) { m_audio.samples = input()->audioBuffers; } - GBASDLInitAudio(&m_audio, input()); + return GBASDLInitAudio(&m_audio, input()); } } diff --git a/src/platform/qt/AudioProcessorSDL.h b/src/platform/qt/AudioProcessorSDL.h index bc9b43581..88fb33ea9 100644 --- a/src/platform/qt/AudioProcessorSDL.h +++ b/src/platform/qt/AudioProcessorSDL.h @@ -25,7 +25,7 @@ public: virtual unsigned sampleRate() const override; public slots: - virtual void start() override; + virtual bool start() override; virtual void pause() override; virtual void setBufferSamples(int samples) override; diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index b81b7356c..e0eb8943d 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -204,9 +204,7 @@ GameController::GameController(QObject* parent) m_audioThread->setObjectName("Audio Thread"); m_audioThread->start(QThread::TimeCriticalPriority); m_audioProcessor->moveToThread(m_audioThread); - connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start())); connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start())); connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(pollEvents())); connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updateAutofire())); } @@ -341,6 +339,17 @@ void GameController::openGame(bool biosOnly) { if (!GBAThreadStart(&m_threadContext)) { m_gameOpen = false; emit gameFailed(); + } else if (m_audioProcessor) { + bool started = false; + QMetaObject::invokeMethod(m_audioProcessor, "start", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, started)); + if (!started) { + LOG(ERROR) << tr("Failed to start audio processor"); + // Don't freeze! + m_audioSync = false; + m_videoSync = true; + m_threadContext.sync.audioWait = false; + m_threadContext.sync.videoFrameWait = true; + } } } @@ -900,12 +909,19 @@ void GameController::reloadAudioDriver() { m_audioProcessor->requestSampleRate(sampleRate); } m_audioProcessor->moveToThread(m_audioThread); - connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start())); connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start())); if (isLoaded()) { m_audioProcessor->setInput(&m_threadContext); - QMetaObject::invokeMethod(m_audioProcessor, "start"); + bool started = false; + QMetaObject::invokeMethod(m_audioProcessor, "start", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, started)); + if (!started) { + LOG(ERROR) << tr("Failed to start audio processor"); + // Don't freeze! + m_audioSync = false; + m_videoSync = true; + m_threadContext.sync.audioWait = false; + m_threadContext.sync.videoFrameWait = true; + } } }