mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-28 01:49:33 -06:00
CubebUtils: Add COM helper class
This commit is contained in:
@ -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;
|
||||
|
||||
@ -73,12 +79,12 @@ std::shared_ptr<cubeb> CubebUtils::GetContext()
|
||||
return shared;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> CubebUtils::ListInputDevices()
|
||||
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 = 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<std::pair<std::string, std::string>> 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
|
||||
|
@ -3,12 +3,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/WorkQueueThread.h"
|
||||
#endif
|
||||
|
||||
struct cubeb;
|
||||
|
||||
namespace CubebUtils
|
||||
@ -16,4 +21,23 @@ namespace CubebUtils
|
||||
std::shared_ptr<cubeb> GetContext();
|
||||
std::vector<std::pair<std::string, std::string>> ListInputDevices();
|
||||
const void* GetInputDeviceById(std::string_view id);
|
||||
|
||||
// Helper used to handle Windows COM library for cubeb WASAPI backend
|
||||
class CoInitSyncWorker
|
||||
{
|
||||
public:
|
||||
using FunctionType = std::function<void()>;
|
||||
|
||||
CoInitSyncWorker(std::string worker_name);
|
||||
~CoInitSyncWorker();
|
||||
|
||||
bool Execute(FunctionType f);
|
||||
|
||||
#ifdef _WIN32
|
||||
private:
|
||||
Common::AsyncWorkThread m_work_queue;
|
||||
bool m_coinit_success = false;
|
||||
bool m_should_couninit = false;
|
||||
#endif
|
||||
};
|
||||
} // namespace CubebUtils
|
||||
|
@ -12,7 +12,6 @@
|
||||
#endif
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "Common/Swap.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
@ -31,31 +30,12 @@ namespace IOS::HLE::USB
|
||||
{
|
||||
Microphone::Microphone(const WiiSpeakState& sampler) : m_sampler(sampler)
|
||||
{
|
||||
#if defined(_WIN32) && defined(HAVE_CUBEB)
|
||||
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
|
||||
|
||||
StreamInit();
|
||||
}
|
||||
|
||||
Microphone::~Microphone()
|
||||
{
|
||||
StreamTerminate();
|
||||
|
||||
#if defined(_WIN32) && defined(HAVE_CUBEB)
|
||||
if (m_should_couninit)
|
||||
{
|
||||
m_work_queue.PushBlocking([this] {
|
||||
m_should_couninit = false;
|
||||
CoUninitialize();
|
||||
});
|
||||
}
|
||||
m_coinit_success = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_CUBEB
|
||||
@ -77,18 +57,11 @@ void Microphone::StreamTerminate()
|
||||
#else
|
||||
void Microphone::StreamInit()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!m_coinit_success)
|
||||
if (!m_worker.Execute([this] { m_cubeb_ctx = CubebUtils::GetContext(); }))
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_USB, "Failed to init Wii Speak stream");
|
||||
return;
|
||||
}
|
||||
m_work_queue.PushBlocking([this] {
|
||||
#endif
|
||||
m_cubeb_ctx = CubebUtils::GetContext();
|
||||
#ifdef _WIN32
|
||||
});
|
||||
#endif
|
||||
|
||||
// TODO: Not here but rather inside the WiiSpeak device if possible?
|
||||
StreamStart();
|
||||
@ -99,17 +72,7 @@ void Microphone::StreamTerminate()
|
||||
StreamStop();
|
||||
|
||||
if (m_cubeb_ctx)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!m_coinit_success)
|
||||
return;
|
||||
m_work_queue.PushBlocking([this] {
|
||||
#endif
|
||||
m_cubeb_ctx.reset();
|
||||
#ifdef _WIN32
|
||||
});
|
||||
#endif
|
||||
}
|
||||
m_worker.Execute([this] { m_cubeb_ctx.reset(); });
|
||||
}
|
||||
|
||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state)
|
||||
@ -121,12 +84,7 @@ void Microphone::StreamStart()
|
||||
if (!m_cubeb_ctx)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!m_coinit_success)
|
||||
return;
|
||||
m_work_queue.PushBlocking([this] {
|
||||
#endif
|
||||
|
||||
m_worker.Execute([this] {
|
||||
#ifdef ANDROID
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
if (jboolean result = env->CallStaticBooleanMethod(
|
||||
@ -171,26 +129,20 @@ void Microphone::StreamStart()
|
||||
}
|
||||
|
||||
INFO_LOG_FMT(IOS_USB, "started cubeb stream");
|
||||
#ifdef _WIN32
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void Microphone::StreamStop()
|
||||
{
|
||||
if (m_cubeb_stream)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_work_queue.PushBlocking([this] {
|
||||
#endif
|
||||
if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK)
|
||||
ERROR_LOG_FMT(IOS_USB, "Error stopping cubeb stream");
|
||||
cubeb_stream_destroy(m_cubeb_stream);
|
||||
m_cubeb_stream = nullptr;
|
||||
#ifdef _WIN32
|
||||
});
|
||||
#endif
|
||||
}
|
||||
if (!m_cubeb_stream)
|
||||
return;
|
||||
|
||||
m_worker.Execute([this] {
|
||||
if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK)
|
||||
ERROR_LOG_FMT(IOS_USB, "Error stopping cubeb stream");
|
||||
cubeb_stream_destroy(m_cubeb_stream);
|
||||
m_cubeb_stream = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
long Microphone::CubebDataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "AudioCommon/CubebUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
|
||||
#ifdef HAVE_CUBEB
|
||||
#include "AudioCommon/CubebUtils.h"
|
||||
@ -60,12 +60,7 @@ private:
|
||||
#ifdef HAVE_CUBEB
|
||||
std::shared_ptr<cubeb> m_cubeb_ctx = nullptr;
|
||||
cubeb_stream* m_cubeb_stream = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
Common::AsyncWorkThread m_work_queue{"Wii Speak Worker"};
|
||||
bool m_coinit_success = false;
|
||||
bool m_should_couninit = false;
|
||||
#endif
|
||||
CubebUtils::CoInitSyncWorker m_worker{"Wii Speak Worker"};
|
||||
#endif
|
||||
};
|
||||
} // namespace IOS::HLE::USB
|
||||
|
Reference in New Issue
Block a user