summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon/CubebStream.cpp
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2022-06-18 05:31:14 +0200
committerAdmiral H. Curtiss <pikachu025@gmail.com>2022-11-26 05:05:57 +0100
commite085bf14f99c52eff514e2317af740869691ba82 (patch)
tree9b0af1b7f78364bbf498eb37f46c23af2a4f44fd /Source/Core/AudioCommon/CubebStream.cpp
parentca10e92ab92afeb4cb6d3ac935cf86767ab469eb (diff)
Core: Use extra thread for Cubeb on Windows to not disturb the CoInitialize state of whatever thread happens to call a Cubeb function.
Diffstat (limited to 'Source/Core/AudioCommon/CubebStream.cpp')
-rw-r--r--Source/Core/AudioCommon/CubebStream.cpp136
1 files changed, 105 insertions, 31 deletions
diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp
index afef4f467e..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,61 +37,129 @@ void CubebStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_sta
{
}
+CubebStream::CubebStream()
+#ifdef _WIN32
+ : m_work_queue([](const std::function<void()>& func) { func(); })
+{
+ 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
+
bool CubebStream::Init()
{
- m_ctx = CubebUtils::GetContext();
- if (!m_ctx)
- return false;
+ bool return_value = false;
- m_stereo = !Config::ShouldUseDPL2Decoder();
+#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(), &params, &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, &params, std::max(BUFFER_SAMPLES, minimum_latency),
+ DataCallback, StateCallback, this) == CUBEB_OK;
+ }
+
+#ifdef _WIN32
+ });
+ sync_event.Wait();
+#endif
- 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(), &params, &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, &params, std::max(BUFFER_SAMPLES, minimum_latency),
- DataCallback, StateCallback, this) == CUBEB_OK;
+ return return_value;
}
bool CubebStream::SetRunning(bool running)
{
bool return_value = false;
- CubebUtils::RunInCubebContext([&] {
+
+#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()
{
- CubebUtils::RunInCubebContext([&] {
- SetRunning(false);
+#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)
{
- CubebUtils::RunInCubebContext([&] { 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
}