From 001c9a6a61cc71d5e63d75d4875d92c1d400d1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 25 May 2021 12:12:15 +0200 Subject: [PATCH] Audio/Music: Rework Play() (ensure music has started before return and handle exceptions in thread) --- include/Nazara/Audio/Music.hpp | 5 +- src/Nazara/Audio/Music.cpp | 87 +++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp index 48c7ffb32..2d951e2a0 100644 --- a/include/Nazara/Audio/Music.hpp +++ b/include/Nazara/Audio/Music.hpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include namespace Nz { @@ -56,7 +59,7 @@ namespace Nz std::unique_ptr m_impl; bool FillAndQueueBuffer(unsigned int buffer); - void MusicThread(); + void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err); void StopThread(); }; } diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index a6cad6961..1eaa067e7 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -6,10 +6,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include #include @@ -27,6 +28,7 @@ namespace Nz struct MusicImpl { ALenum audioFormat; + std::atomic_bool streaming = false; std::atomic processedSamples; std::vector chunkSamples; std::mutex bufferLock; @@ -34,7 +36,6 @@ namespace Nz std::thread thread; UInt64 playingOffset; bool loop = false; - bool streaming = false; unsigned int sampleRate; }; @@ -304,9 +305,22 @@ namespace Nz } else { - // Starting streaming's thread + std::mutex mutex; + std::condition_variable cv; + + // Starting streaming thread m_impl->streaming = true; - m_impl->thread = std::thread(&Music::MusicThread, this); + + std::exception_ptr exceptionPtr; + + std::unique_lock lock(mutex); + m_impl->thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr)); + + // Wait until thread signal it has properly started (or an error occurred) + cv.wait(lock); + + if (exceptionPtr) + std::rethrow_exception(exceptionPtr); } } @@ -387,19 +401,59 @@ namespace Nz return sampleRead != sampleCount; // End of stream (Does not happen when looping) } - void Music::MusicThread() + void Music::MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err) { // Allocation of streaming buffers - ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT]; - alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers); + std::array buffers; + alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data()); - for (unsigned int buffer : buffers) + CallOnExit freebuffers([&] { - if (FillAndQueueBuffer(buffer)) - break; // We have reached the end of the stream, there is no use to add new buffers + alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data()); + }); + + + try + { + for (ALuint buffer : buffers) + { + if (FillAndQueueBuffer(buffer)) + break; // We have reached the end of the stream, there is no use to add new buffers + } } + catch (const std::exception&) + { + err = std::current_exception(); + + std::unique_lock lock(m); + cv.notify_all(); + return; + } + + CallOnExit unqueueBuffers([&] + { + // We delete buffers from the stream + ALint queuedBufferCount; + alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); + + ALuint buffer; + for (ALint i = 0; i < queuedBufferCount; ++i) + alSourceUnqueueBuffers(m_source, 1, &buffer); + }); alSourcePlay(m_source); + + CallOnExit stopSource([&] + { + // Stop playing of the sound (in the case where it has not been already done) + alSourceStop(m_source); + }); + + // Signal we're good + { + std::unique_lock lock(m); + cv.notify_all(); + } // m & cv no longer exists from here // Reading loop (Filling new buffers as playing) while (m_impl->streaming) @@ -438,19 +492,6 @@ namespace Nz // We go back to sleep std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - - // Stop playing of the sound (in the case where it has not been already done) - alSourceStop(m_source); - - // We delete buffers from the stream - ALint queuedBufferCount; - alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); - - ALuint buffer; - for (ALint i = 0; i < queuedBufferCount; ++i) - alSourceUnqueueBuffers(m_source, 1, &buffer); - - alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers); } void Music::StopThread()