mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
CubebUtils: Add COM helper class
This commit is contained in:
@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
#include <cubeb/cubeb.h>
|
#include <cubeb/cubeb.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Objbase.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static void LogCallback(const char* format, ...)
|
static void LogCallback(const char* format, ...)
|
||||||
{
|
{
|
||||||
auto* instance = Common::Log::LogManager::GetInstance();
|
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;
|
static std::weak_ptr<cubeb> weak;
|
||||||
|
|
||||||
@ -73,12 +79,12 @@ std::shared_ptr<cubeb> CubebUtils::GetContext()
|
|||||||
return shared;
|
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;
|
std::vector<std::pair<std::string, std::string>> devices;
|
||||||
|
|
||||||
cubeb_device_collection collection;
|
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);
|
const int r = cubeb_enumerate_devices(cubeb_ctx.get(), CUBEB_DEVICE_TYPE_INPUT, &collection);
|
||||||
|
|
||||||
if (r != CUBEB_OK)
|
if (r != CUBEB_OK)
|
||||||
@ -136,7 +142,7 @@ std::vector<std::pair<std::string, std::string>> CubebUtils::ListInputDevices()
|
|||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
cubeb_devid CubebUtils::GetInputDeviceById(std::string_view id)
|
cubeb_devid GetInputDeviceById(std::string_view id)
|
||||||
{
|
{
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -170,3 +176,45 @@ cubeb_devid CubebUtils::GetInputDeviceById(std::string_view id)
|
|||||||
|
|
||||||
return device_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
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "Common/WorkQueueThread.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct cubeb;
|
struct cubeb;
|
||||||
|
|
||||||
namespace CubebUtils
|
namespace CubebUtils
|
||||||
@ -16,4 +21,23 @@ namespace CubebUtils
|
|||||||
std::shared_ptr<cubeb> GetContext();
|
std::shared_ptr<cubeb> GetContext();
|
||||||
std::vector<std::pair<std::string, std::string>> ListInputDevices();
|
std::vector<std::pair<std::string, std::string>> ListInputDevices();
|
||||||
const void* GetInputDeviceById(std::string_view id);
|
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
|
} // namespace CubebUtils
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/ScopeGuard.h"
|
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
@ -31,31 +30,12 @@ namespace IOS::HLE::USB
|
|||||||
{
|
{
|
||||||
Microphone::Microphone(const WiiSpeakState& sampler) : m_sampler(sampler)
|
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();
|
StreamInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Microphone::~Microphone()
|
Microphone::~Microphone()
|
||||||
{
|
{
|
||||||
StreamTerminate();
|
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
|
#ifndef HAVE_CUBEB
|
||||||
@ -77,18 +57,11 @@ void Microphone::StreamTerminate()
|
|||||||
#else
|
#else
|
||||||
void Microphone::StreamInit()
|
void Microphone::StreamInit()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
if (!m_worker.Execute([this] { m_cubeb_ctx = CubebUtils::GetContext(); }))
|
||||||
if (!m_coinit_success)
|
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_USB, "Failed to init Wii Speak stream");
|
ERROR_LOG_FMT(IOS_USB, "Failed to init Wii Speak stream");
|
||||||
return;
|
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?
|
// TODO: Not here but rather inside the WiiSpeak device if possible?
|
||||||
StreamStart();
|
StreamStart();
|
||||||
@ -99,17 +72,7 @@ void Microphone::StreamTerminate()
|
|||||||
StreamStop();
|
StreamStop();
|
||||||
|
|
||||||
if (m_cubeb_ctx)
|
if (m_cubeb_ctx)
|
||||||
{
|
m_worker.Execute([this] { m_cubeb_ctx.reset(); });
|
||||||
#ifdef _WIN32
|
|
||||||
if (!m_coinit_success)
|
|
||||||
return;
|
|
||||||
m_work_queue.PushBlocking([this] {
|
|
||||||
#endif
|
|
||||||
m_cubeb_ctx.reset();
|
|
||||||
#ifdef _WIN32
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state)
|
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state)
|
||||||
@ -121,12 +84,7 @@ void Microphone::StreamStart()
|
|||||||
if (!m_cubeb_ctx)
|
if (!m_cubeb_ctx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef _WIN32
|
m_worker.Execute([this] {
|
||||||
if (!m_coinit_success)
|
|
||||||
return;
|
|
||||||
m_work_queue.PushBlocking([this] {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
if (jboolean result = env->CallStaticBooleanMethod(
|
if (jboolean result = env->CallStaticBooleanMethod(
|
||||||
@ -171,26 +129,20 @@ void Microphone::StreamStart()
|
|||||||
}
|
}
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_USB, "started cubeb stream");
|
INFO_LOG_FMT(IOS_USB, "started cubeb stream");
|
||||||
#ifdef _WIN32
|
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Microphone::StreamStop()
|
void Microphone::StreamStop()
|
||||||
{
|
{
|
||||||
if (m_cubeb_stream)
|
if (!m_cubeb_stream)
|
||||||
{
|
return;
|
||||||
#ifdef _WIN32
|
|
||||||
m_work_queue.PushBlocking([this] {
|
m_worker.Execute([this] {
|
||||||
#endif
|
if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK)
|
||||||
if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK)
|
ERROR_LOG_FMT(IOS_USB, "Error stopping cubeb stream");
|
||||||
ERROR_LOG_FMT(IOS_USB, "Error stopping cubeb stream");
|
cubeb_stream_destroy(m_cubeb_stream);
|
||||||
cubeb_stream_destroy(m_cubeb_stream);
|
m_cubeb_stream = nullptr;
|
||||||
m_cubeb_stream = nullptr;
|
});
|
||||||
#ifdef _WIN32
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long Microphone::CubebDataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
long Microphone::CubebDataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "AudioCommon/CubebUtils.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/WorkQueueThread.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
#include "AudioCommon/CubebUtils.h"
|
#include "AudioCommon/CubebUtils.h"
|
||||||
@ -60,12 +60,7 @@ private:
|
|||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
std::shared_ptr<cubeb> m_cubeb_ctx = nullptr;
|
std::shared_ptr<cubeb> m_cubeb_ctx = nullptr;
|
||||||
cubeb_stream* m_cubeb_stream = nullptr;
|
cubeb_stream* m_cubeb_stream = nullptr;
|
||||||
|
CubebUtils::CoInitSyncWorker m_worker{"Wii Speak Worker"};
|
||||||
#ifdef _WIN32
|
|
||||||
Common::AsyncWorkThread m_work_queue{"Wii Speak Worker"};
|
|
||||||
bool m_coinit_success = false;
|
|
||||||
bool m_should_couninit = false;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::USB
|
} // namespace IOS::HLE::USB
|
||||||
|
Reference in New Issue
Block a user