diff options
| author | JMC47 <JMC4789@gmail.com> | 2025-05-21 13:54:56 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-21 13:54:56 -0400 |
| commit | a62449711fe1c18aa8ce47b792914e01177e1b7a (patch) | |
| tree | 96482db05dce20b4596bbdb4bb013072131530b1 /Source/Core/AudioCommon/CubebUtils.cpp | |
| parent | 1dc4dc6b6d660f29226bdff29d0b1bae122dda7e (diff) | |
| parent | eff334524a6825d78a888dc85f6d97aded1691fe (diff) | |
Merge pull request #12769 from sepalani/wii-speak
IOS/USB: Emulate Wii Speak using cubeb
Diffstat (limited to 'Source/Core/AudioCommon/CubebUtils.cpp')
| -rw-r--r-- | Source/Core/AudioCommon/CubebUtils.cpp | 148 |
1 files changed, 147 insertions, 1 deletions
diff --git a/Source/Core/AudioCommon/CubebUtils.cpp b/Source/Core/AudioCommon/CubebUtils.cpp index 6ad94f612c..73bfafb7fd 100644 --- a/Source/Core/AudioCommon/CubebUtils.cpp +++ b/Source/Core/AudioCommon/CubebUtils.cpp @@ -13,6 +13,10 @@ #include <cubeb/cubeb.h> +#ifdef _WIN32 +#include <Objbase.h> +#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<cubeb> CubebUtils::GetContext() +namespace CubebUtils +{ +std::shared_ptr<cubeb> GetContext() { static std::weak_ptr<cubeb> weak; @@ -72,3 +78,143 @@ std::shared_ptr<cubeb> CubebUtils::GetContext() weak = shared = {ctx, DestroyContext}; return shared; } + +std::vector<std::pair<std::string, std::string>> ListInputDevices() +{ + std::vector<std::pair<std::string, std::string>> devices; + + cubeb_device_collection collection; + auto cubeb_ctx = 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 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; +} + +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 |
