CubebAudioStream: Call CoInitializeEx before creating cubeb

This commit is contained in:
Silent 2025-10-14 18:20:58 +02:00 committed by Ty
parent baa00e4d38
commit 190b525ca6

View File

@ -18,6 +18,8 @@
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <objbase.h>
#include "wil/resource.h"
#endif
namespace
@ -26,7 +28,7 @@ namespace
{
public:
CubebAudioStream(u32 sample_rate, const AudioStreamParameters& parameters);
~CubebAudioStream();
~CubebAudioStream() override;
void SetPaused(bool paused) override;
@ -40,6 +42,11 @@ namespace
void DestroyContextAndStream();
#ifdef _WIN32
// Keep it as the first field, as COM must uninitialize last.
wil::unique_couninitialize_call m_coUninit{false};
#endif
cubeb* m_context = nullptr;
cubeb_stream* stream = nullptr;
};
@ -105,12 +112,25 @@ void CubebAudioStream::DestroyContextAndStream()
cubeb_destroy(m_context);
m_context = nullptr;
}
#ifdef _WIN32
m_coUninit.reset();
#endif
}
bool CubebAudioStream::Initialize(const char* driver_name, const char* device_name, bool stretch_enabled, Error* error)
{
cubeb_set_log_callback(CUBEB_LOG_NORMAL, LogCallback);
#ifdef _WIN32
const HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
Error::SetHResult(error, "CoInitializeEx() failed: ", hr);
return false;
}
wil::unique_couninitialize_call uninit;
#endif
int rv = cubeb_init(&m_context, "PCSX2", (driver_name && *driver_name) ? driver_name : nullptr);
if (rv != CUBEB_OK)
{
@ -244,6 +264,9 @@ bool CubebAudioStream::Initialize(const char* driver_name, const char* device_na
return false;
}
#ifdef _WIN32
m_coUninit = std::move(uninit);
#endif
return true;
}
@ -300,6 +323,23 @@ std::vector<AudioStream::DeviceInfo> AudioStream::GetCubebOutputDevices(const ch
std::vector<AudioStream::DeviceInfo> ret;
ret.emplace_back(std::string(), TRANSLATE_STR("AudioStream", "Default"), 0);
#ifdef _WIN32
// For enumeration, we need *any* COM context. multi- or single-threaded.
// Cubeb theoretically wants an MTA context, but this is only relevant when creating streams,
// which enumerating devices does not do.
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (hr == RPC_E_CHANGED_MODE)
{
hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
}
if (FAILED(hr))
{
ERROR_LOG("CoInitializeEx failed: {}", Error::CreateHResult(hr).GetDescription());
return ret;
}
wil::unique_couninitialize_call uninit;
#endif
cubeb* context;
int rv = cubeb_init(&context, "PCSX2", (driver && *driver) ? driver : nullptr);
if (rv != CUBEB_OK)