Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion pcsx2/Host/CubebAudioStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <objbase.h>

#include "wil/resource.h"
#endif

namespace
Expand All @@ -26,7 +28,7 @@ namespace
{
public:
CubebAudioStream(u32 sample_rate, const AudioStreamParameters& parameters);
~CubebAudioStream();
~CubebAudioStream() override;

void SetPaused(bool paused) override;

Expand All @@ -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;
};
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down
12 changes: 10 additions & 2 deletions pcsx2/USB/usb-eyetoy/cam-windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+

#include "common/Console.h"
#include "common/Error.h"
#include "common/StringUtil.h"

#include "videodev.h"
Expand Down Expand Up @@ -527,7 +528,13 @@ namespace usb_eyetoy

int DirectShow::Open(int width, int height, FrameFormat format, int mirror)
{
dshowCoInitialize = wil::CoInitializeEx_failfast(COINIT_MULTITHREADED);
const HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
Console.ErrorFmt("CoInitializeEx failed: {}", Error::CreateHResult(hr).GetDescription());
return -1;
}
wil::unique_couninitialize_call uninit;

frame_width = width;
frame_height = height;
Expand All @@ -545,7 +552,7 @@ namespace usb_eyetoy
int ret = InitializeDevice(StringUtil::UTF8StringToWideString(mHostDevice));
if (ret < 0)
{
Console.Warning("Camera: cannot find '%s'", mHostDevice.c_str());
Console.WarningFmt("Camera: cannot find '{}'", mHostDevice);
return -1;
}

Expand All @@ -559,6 +566,7 @@ namespace usb_eyetoy
return -1;
}

dshowCoInitialize = std::move(uninit);
return 0;
};

Expand Down
2 changes: 1 addition & 1 deletion pcsx2/USB/usb-eyetoy/cam-windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ namespace usb_eyetoy
int InitializeDevice(const std::wstring& selectedDevice);

private:
wil::unique_couninitialize_call dshowCoInitialize;
wil::unique_couninitialize_call dshowCoInitialize{false};
ICaptureGraphBuilder2* pGraphBuilder;
IFilterGraph2* pGraph;
IMediaControl* pControl;
Expand Down
38 changes: 36 additions & 2 deletions pcsx2/USB/usb-mic/audiodev-cubeb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
#include "Host.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Error.h"

#include "cubeb/cubeb.h"
#include "fmt/format.h"

#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <objbase.h>

#include "wil/resource.h"
#endif

// Since the context gets used to populate the device list, that unfortunately means
// we need locking around it, since the UI thread's gonna be saying hi. The settings
// callbacks don't actually modify the context itself, though, only look at the
Expand All @@ -22,7 +30,24 @@ static std::mutex s_cubeb_context_mutex;

static cubeb* GetCubebContext(const char* backend = nullptr)
{
std::unique_lock lock(s_cubeb_context_mutex);
std::lock_guard lock(s_cubeb_context_mutex);

#ifdef _WIN32
// For enumeration, we need *any* COM context. multi- or single-threaded.
// As COM is per-thread, initialize and tear it down every time.
// Doing it only on 0 refcount is a bad idea, because the Cubeb context could be created on one thread, and destroyed on another.
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (hr == RPC_E_CHANGED_MODE)
{
hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
}
if (FAILED(hr))
{
Console.ErrorFmt("CoInitializeEx failed: {}", Error::CreateHResult(hr).GetDescription());
return nullptr;
}
wil::unique_couninitialize_call uninit;
#endif

if (!s_cubeb_context)
{
Expand All @@ -41,12 +66,17 @@ static cubeb* GetCubebContext(const char* backend = nullptr)
if (s_cubeb_context)
s_cubeb_refcount++;

#ifdef _WIN32
// ReleaseCubebContext will call CoUninitialize
uninit.release();
#endif

return s_cubeb_context;
}

static void ReleaseCubebContext()
{
std::unique_lock lock(s_cubeb_context_mutex);
std::lock_guard lock(s_cubeb_context_mutex);

pxAssert(s_cubeb_refcount > 0);
if ((--s_cubeb_refcount) == 0)
Expand All @@ -59,6 +89,10 @@ static void ReleaseCubebContext()
cubeb_destroy(s_cubeb_context);
s_cubeb_context = nullptr;
}

#ifdef _WIN32
CoUninitialize();
#endif
}

static cubeb_devid FindCubebDevice(const char* devname, bool input)
Expand Down