summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon/CubebUtils.cpp
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-05-21 13:54:56 -0400
committerGitHub <noreply@github.com>2025-05-21 13:54:56 -0400
commita62449711fe1c18aa8ce47b792914e01177e1b7a (patch)
tree96482db05dce20b4596bbdb4bb013072131530b1 /Source/Core/AudioCommon/CubebUtils.cpp
parent1dc4dc6b6d660f29226bdff29d0b1bae122dda7e (diff)
parenteff334524a6825d78a888dc85f6d97aded1691fe (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.cpp148
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