From 1ac40f25a2ced19f8a7729f1974cefacf207c845 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Thu, 9 May 2024 14:51:30 +0400 Subject: IOS/USB: Emulate Wii Speak using cubeb Based on @noahpistilli (Sketch) PR: https://github.com/dolphin-emu/dolphin/pull/12567 Fixed the Windows support and the heisenbug caused by uninitialized members. Config system integration finalized. --- Source/Core/AudioCommon/CubebUtils.cpp | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'Source/Core/AudioCommon/CubebUtils.cpp') diff --git a/Source/Core/AudioCommon/CubebUtils.cpp b/Source/Core/AudioCommon/CubebUtils.cpp index 6ad94f612c..e63f75c26e 100644 --- a/Source/Core/AudioCommon/CubebUtils.cpp +++ b/Source/Core/AudioCommon/CubebUtils.cpp @@ -72,3 +72,101 @@ std::shared_ptr CubebUtils::GetContext() weak = shared = {ctx, DestroyContext}; return shared; } + +std::vector> CubebUtils::ListInputDevices() +{ + std::vector> devices; + + cubeb_device_collection collection; + auto cubeb_ctx = CubebUtils::GetContext(); + const int r = cubeb_enumerate_devices(cubeb_ctx.get(), CUBEB_DEVICE_TYPE_INPUT, &collection); + + if (r != CUBEB_OK) + { + ERROR_LOG_FMT(AUDIO, "Error listing cubeb input devices"); + return devices; + } + + INFO_LOG_FMT(AUDIO, "Listing cubeb input devices:"); + for (uint32_t i = 0; i < collection.count; i++) + { + const auto& info = collection.device[i]; + const auto device_state = info.state; + const char* state_name = [device_state] { + switch (device_state) + { + case CUBEB_DEVICE_STATE_DISABLED: + return "disabled"; + case CUBEB_DEVICE_STATE_UNPLUGGED: + return "unplugged"; + case CUBEB_DEVICE_STATE_ENABLED: + return "enabled"; + default: + return "unknown?"; + } + }(); + + // According to cubeb_device_info definition in cubeb.h: + // > "Optional vendor name, may be NULL." + // In practice, it seems some other fields might be NULL as well. + static constexpr auto fmt_str = [](const char* ptr) constexpr -> const char* { + return (ptr == nullptr) ? "(null)" : ptr; + }; + + INFO_LOG_FMT(AUDIO, + "[{}] Device ID: {}\n" + "\tName: {}\n" + "\tGroup ID: {}\n" + "\tVendor: {}\n" + "\tState: {}", + i, fmt_str(info.device_id), fmt_str(info.friendly_name), fmt_str(info.group_id), + fmt_str(info.vendor_name), state_name); + + if (info.device_id == nullptr) + continue; // Shouldn't happen + + if (info.state == CUBEB_DEVICE_STATE_ENABLED) + { + devices.emplace_back(info.device_id, fmt_str(info.friendly_name)); + } + } + + cubeb_device_collection_destroy(cubeb_ctx.get(), &collection); + + return devices; +} + +cubeb_devid CubebUtils::GetInputDeviceById(std::string_view id) +{ + if (id.empty()) + return nullptr; + + cubeb_device_collection collection; + auto cubeb_ctx = CubebUtils::GetContext(); + const int r = cubeb_enumerate_devices(cubeb_ctx.get(), CUBEB_DEVICE_TYPE_INPUT, &collection); + + if (r != CUBEB_OK) + { + ERROR_LOG_FMT(AUDIO, "Error enumerating cubeb input devices"); + return nullptr; + } + + cubeb_devid device_id = nullptr; + for (uint32_t i = 0; i < collection.count; i++) + { + const auto& info = collection.device[i]; + if (id.compare(info.device_id) == 0) + { + device_id = info.devid; + break; + } + } + if (device_id == nullptr) + { + WARN_LOG_FMT(AUDIO, "Failed to find selected input device, defaulting to system preferences"); + } + + cubeb_device_collection_destroy(cubeb_ctx.get(), &collection); + + return device_id; +} -- cgit v1.2.3 From aea5054509905e659aa365f0693c5adbc34caec2 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Sun, 25 Aug 2024 00:06:50 +0400 Subject: CubebUtils: Add COM helper class --- Source/Core/AudioCommon/CubebUtils.cpp | 56 +++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) (limited to 'Source/Core/AudioCommon/CubebUtils.cpp') diff --git a/Source/Core/AudioCommon/CubebUtils.cpp b/Source/Core/AudioCommon/CubebUtils.cpp index e63f75c26e..73bfafb7fd 100644 --- a/Source/Core/AudioCommon/CubebUtils.cpp +++ b/Source/Core/AudioCommon/CubebUtils.cpp @@ -13,6 +13,10 @@ #include +#ifdef _WIN32 +#include +#endif + static void LogCallback(const char* format, ...) { auto* instance = Common::Log::LogManager::GetInstance(); @@ -47,7 +51,9 @@ static void DestroyContext(cubeb* ctx) } } -std::shared_ptr CubebUtils::GetContext() +namespace CubebUtils +{ +std::shared_ptr GetContext() { static std::weak_ptr weak; @@ -73,12 +79,12 @@ std::shared_ptr CubebUtils::GetContext() return shared; } -std::vector> CubebUtils::ListInputDevices() +std::vector> ListInputDevices() { std::vector> devices; cubeb_device_collection collection; - auto cubeb_ctx = CubebUtils::GetContext(); + auto cubeb_ctx = GetContext(); const int r = cubeb_enumerate_devices(cubeb_ctx.get(), CUBEB_DEVICE_TYPE_INPUT, &collection); if (r != CUBEB_OK) @@ -136,7 +142,7 @@ std::vector> CubebUtils::ListInputDevices() return devices; } -cubeb_devid CubebUtils::GetInputDeviceById(std::string_view id) +cubeb_devid GetInputDeviceById(std::string_view id) { if (id.empty()) return nullptr; @@ -170,3 +176,45 @@ cubeb_devid CubebUtils::GetInputDeviceById(std::string_view id) return device_id; } + +CoInitSyncWorker::CoInitSyncWorker([[maybe_unused]] std::string worker_name) +#ifdef _WIN32 + : m_work_queue{std::move(worker_name)} +#endif +{ +#ifdef _WIN32 + m_work_queue.PushBlocking([this] { + const auto result = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + m_coinit_success = result == S_OK; + m_should_couninit = m_coinit_success || result == S_FALSE; + }); +#endif +} + +CoInitSyncWorker::~CoInitSyncWorker() +{ +#ifdef _WIN32 + if (m_should_couninit) + { + m_work_queue.PushBlocking([this] { + m_should_couninit = false; + CoUninitialize(); + }); + } + m_coinit_success = false; +#endif +} + +bool CoInitSyncWorker::Execute(FunctionType f) +{ +#ifdef _WIN32 + if (!m_coinit_success) + return false; + + m_work_queue.PushBlocking(f); +#else + f(); +#endif + return true; +} +} // namespace CubebUtils -- cgit v1.2.3