diff options
Diffstat (limited to 'Source/Core/AudioCommon/CubebStream.cpp')
| -rw-r--r-- | Source/Core/AudioCommon/CubebStream.cpp | 150 |
1 files changed, 115 insertions, 35 deletions
diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp index b8ccbbdaee..5d3d70d9cb 100644 --- a/Source/Core/AudioCommon/CubebStream.cpp +++ b/Source/Core/AudioCommon/CubebStream.cpp @@ -7,10 +7,16 @@ #include "AudioCommon/CubebUtils.h" #include "Common/CommonTypes.h" +#include "Common/Event.h" #include "Common/Logging/Log.h" +#include "Common/ScopeGuard.h" #include "Common/Thread.h" #include "Core/Config/MainSettings.h" +#ifdef _WIN32 +#include <Objbase.h> +#endif + // ~10 ms - needs to be at least 240 for surround constexpr u32 BUFFER_SAMPLES = 512; @@ -31,55 +37,129 @@ void CubebStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_sta { } -bool CubebStream::Init() +CubebStream::CubebStream() +#ifdef _WIN32 + : m_work_queue([](const std::function<void()>& func) { func(); }) { - m_ctx = CubebUtils::GetContext(); - if (!m_ctx) - return false; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); + auto result = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + m_coinit_success = result == S_OK; + }); + sync_event.Wait(); +} +#else + = default; +#endif - m_stereo = !Config::ShouldUseDPL2Decoder(); +bool CubebStream::Init() +{ + bool return_value = false; - cubeb_stream_params params; - params.rate = m_mixer->GetSampleRate(); - if (m_stereo) - { - params.channels = 2; - params.format = CUBEB_SAMPLE_S16NE; - params.layout = CUBEB_LAYOUT_STEREO; - } - else - { - params.channels = 6; - params.format = CUBEB_SAMPLE_FLOAT32NE; - params.layout = CUBEB_LAYOUT_3F2_LFE; - } - - u32 minimum_latency = 0; - if (cubeb_get_min_latency(m_ctx.get(), ¶ms, &minimum_latency) != CUBEB_OK) - ERROR_LOG_FMT(AUDIO, "Error getting minimum latency"); - INFO_LOG_FMT(AUDIO, "Minimum latency: {} frames", minimum_latency); - - return cubeb_stream_init(m_ctx.get(), &m_stream, "Dolphin Audio Output", nullptr, nullptr, - nullptr, ¶ms, std::max(BUFFER_SAMPLES, minimum_latency), - DataCallback, StateCallback, this) == CUBEB_OK; +#ifdef _WIN32 + if (!m_coinit_success) + return false; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &return_value, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + + m_ctx = CubebUtils::GetContext(); + if (m_ctx) + { + m_stereo = !Config::ShouldUseDPL2Decoder(); + + cubeb_stream_params params{}; + params.rate = m_mixer->GetSampleRate(); + if (m_stereo) + { + params.channels = 2; + params.format = CUBEB_SAMPLE_S16NE; + params.layout = CUBEB_LAYOUT_STEREO; + } + else + { + params.channels = 6; + params.format = CUBEB_SAMPLE_FLOAT32NE; + params.layout = CUBEB_LAYOUT_3F2_LFE; + } + + u32 minimum_latency = 0; + if (cubeb_get_min_latency(m_ctx.get(), ¶ms, &minimum_latency) != CUBEB_OK) + ERROR_LOG_FMT(AUDIO, "Error getting minimum latency"); + INFO_LOG_FMT(AUDIO, "Minimum latency: {} frames", minimum_latency); + + return_value = + cubeb_stream_init(m_ctx.get(), &m_stream, "Dolphin Audio Output", nullptr, nullptr, + nullptr, ¶ms, std::max(BUFFER_SAMPLES, minimum_latency), + DataCallback, StateCallback, this) == CUBEB_OK; + } + +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif + + return return_value; } bool CubebStream::SetRunning(bool running) { - if (running) - return cubeb_stream_start(m_stream) == CUBEB_OK; - else - return cubeb_stream_stop(m_stream) == CUBEB_OK; + bool return_value = false; + +#ifdef _WIN32 + if (!m_coinit_success) + return false; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, running, &return_value, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + if (running) + return_value = cubeb_stream_start(m_stream) == CUBEB_OK; + else + return_value = cubeb_stream_stop(m_stream) == CUBEB_OK; +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif + + return return_value; } CubebStream::~CubebStream() { - SetRunning(false); - cubeb_stream_destroy(m_stream); +#ifdef _WIN32 + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + cubeb_stream_stop(m_stream); + cubeb_stream_destroy(m_stream); +#ifdef _WIN32 + if (m_coinit_success) + { + m_coinit_success = false; + CoUninitialize(); + } + }); + sync_event.Wait(); +#endif m_ctx.reset(); } void CubebStream::SetVolume(int volume) { - cubeb_stream_set_volume(m_stream, volume / 100.0f); +#ifdef _WIN32 + if (!m_coinit_success) + return; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, volume, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + cubeb_stream_set_volume(m_stream, volume / 100.0f); +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif } |
