win32/ComWorker: make COMWorker a real class, no static members
This commit is contained in:
@@ -44,7 +44,11 @@ public:
|
|||||||
void Close() noexcept override {}
|
void Close() noexcept override {}
|
||||||
|
|
||||||
int GetVolume() override {
|
int GetVolume() override {
|
||||||
auto future = COMWorker::Async([&]() -> int {
|
auto com_worker = wasapi_output_get_com_worker(output);
|
||||||
|
if (!com_worker)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
auto future = com_worker->Async([&]() -> int {
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
float volume_level;
|
float volume_level;
|
||||||
|
|
||||||
@@ -76,7 +80,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetVolume(unsigned volume) override {
|
void SetVolume(unsigned volume) override {
|
||||||
COMWorker::Async([&]() {
|
auto com_worker = wasapi_output_get_com_worker(output);
|
||||||
|
if (!com_worker)
|
||||||
|
throw std::runtime_error("Cannot set WASAPI volume");
|
||||||
|
|
||||||
|
com_worker->Async([&]() {
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
const float volume_level = volume / 100.0f;
|
const float volume_level = volume / 100.0f;
|
||||||
|
|
||||||
|
@@ -20,10 +20,13 @@
|
|||||||
#ifndef MPD_WASAPI_OUTPUT_FOR_MIXER_HXX
|
#ifndef MPD_WASAPI_OUTPUT_FOR_MIXER_HXX
|
||||||
#define MPD_WASAPI_OUTPUT_FOR_MIXER_HXX
|
#define MPD_WASAPI_OUTPUT_FOR_MIXER_HXX
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
struct IMMDevice;
|
struct IMMDevice;
|
||||||
struct IAudioClient;
|
struct IAudioClient;
|
||||||
class AudioOutput;
|
class AudioOutput;
|
||||||
class WasapiOutput;
|
class WasapiOutput;
|
||||||
|
class COMWorker;
|
||||||
|
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
WasapiOutput &
|
WasapiOutput &
|
||||||
@@ -33,6 +36,10 @@ wasapi_output_downcast(AudioOutput &output) noexcept;
|
|||||||
bool
|
bool
|
||||||
wasapi_is_exclusive(WasapiOutput &output) noexcept;
|
wasapi_is_exclusive(WasapiOutput &output) noexcept;
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
|
std::shared_ptr<COMWorker>
|
||||||
|
wasapi_output_get_com_worker(WasapiOutput &output) noexcept;
|
||||||
|
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
IMMDevice *
|
IMMDevice *
|
||||||
wasapi_output_get_device(WasapiOutput &output) noexcept;
|
wasapi_output_get_device(WasapiOutput &output) noexcept;
|
||||||
|
@@ -214,22 +214,28 @@ class WasapiOutput final : public AudioOutput {
|
|||||||
public:
|
public:
|
||||||
static AudioOutput *Create(EventLoop &, const ConfigBlock &block);
|
static AudioOutput *Create(EventLoop &, const ConfigBlock &block);
|
||||||
WasapiOutput(const ConfigBlock &block);
|
WasapiOutput(const ConfigBlock &block);
|
||||||
|
|
||||||
|
auto GetComWorker() noexcept {
|
||||||
|
// TODO: protect access to the shard_ptr
|
||||||
|
return com_worker;
|
||||||
|
}
|
||||||
|
|
||||||
void Enable() override {
|
void Enable() override {
|
||||||
COMWorker::Aquire();
|
com_worker = std::make_shared<COMWorker>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
COMWorker::Async([&]() { OpenDevice(); }).get();
|
com_worker->Async([&]() { OpenDevice(); }).get();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
COMWorker::Release();
|
com_worker.reset();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Disable() noexcept override {
|
void Disable() noexcept override {
|
||||||
COMWorker::Async([&]() { DoDisable(); }).get();
|
com_worker->Async([&]() { DoDisable(); }).get();
|
||||||
COMWorker::Release();
|
com_worker.reset();
|
||||||
}
|
}
|
||||||
void Open(AudioFormat &audio_format) override {
|
void Open(AudioFormat &audio_format) override {
|
||||||
COMWorker::Async([&]() { DoOpen(audio_format); }).get();
|
com_worker->Async([&]() { DoOpen(audio_format); }).get();
|
||||||
}
|
}
|
||||||
void Close() noexcept override;
|
void Close() noexcept override;
|
||||||
std::chrono::steady_clock::duration Delay() const noexcept override;
|
std::chrono::steady_clock::duration Delay() const noexcept override;
|
||||||
@@ -253,6 +259,7 @@ private:
|
|||||||
bool dop_setting;
|
bool dop_setting;
|
||||||
#endif
|
#endif
|
||||||
std::string device_config;
|
std::string device_config;
|
||||||
|
std::shared_ptr<COMWorker> com_worker;
|
||||||
ComPtr<IMMDeviceEnumerator> enumerator;
|
ComPtr<IMMDeviceEnumerator> enumerator;
|
||||||
ComPtr<IMMDevice> device;
|
ComPtr<IMMDevice> device;
|
||||||
ComPtr<IAudioClient> client;
|
ComPtr<IAudioClient> client;
|
||||||
@@ -283,6 +290,12 @@ WasapiOutput &wasapi_output_downcast(AudioOutput &output) noexcept {
|
|||||||
|
|
||||||
bool wasapi_is_exclusive(WasapiOutput &output) noexcept { return output.is_exclusive; }
|
bool wasapi_is_exclusive(WasapiOutput &output) noexcept { return output.is_exclusive; }
|
||||||
|
|
||||||
|
std::shared_ptr<COMWorker>
|
||||||
|
wasapi_output_get_com_worker(WasapiOutput &output) noexcept
|
||||||
|
{
|
||||||
|
return output.GetComWorker();
|
||||||
|
}
|
||||||
|
|
||||||
IMMDevice *wasapi_output_get_device(WasapiOutput &output) noexcept {
|
IMMDevice *wasapi_output_get_device(WasapiOutput &output) noexcept {
|
||||||
return output.device.get();
|
return output.device.get();
|
||||||
}
|
}
|
||||||
@@ -524,7 +537,7 @@ void WasapiOutput::Close() noexcept {
|
|||||||
assert(thread);
|
assert(thread);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
COMWorker::Async([&]() {
|
com_worker->Async([&]() {
|
||||||
Stop(*client);
|
Stop(*client);
|
||||||
}).get();
|
}).get();
|
||||||
thread->CheckException();
|
thread->CheckException();
|
||||||
@@ -535,7 +548,7 @@ void WasapiOutput::Close() noexcept {
|
|||||||
is_started = false;
|
is_started = false;
|
||||||
thread->Finish();
|
thread->Finish();
|
||||||
thread->Join();
|
thread->Join();
|
||||||
COMWorker::Async([&]() {
|
com_worker->Async([&]() {
|
||||||
thread.reset();
|
thread.reset();
|
||||||
client.reset();
|
client.reset();
|
||||||
}).get();
|
}).get();
|
||||||
@@ -586,7 +599,7 @@ size_t WasapiOutput::Play(const void *chunk, size_t size) {
|
|||||||
if (!is_started) {
|
if (!is_started) {
|
||||||
is_started = true;
|
is_started = true;
|
||||||
thread->Play();
|
thread->Play();
|
||||||
COMWorker::Async([&]() {
|
com_worker->Async([&]() {
|
||||||
Start(*client);
|
Start(*client);
|
||||||
}).wait();
|
}).wait();
|
||||||
}
|
}
|
||||||
|
@@ -21,10 +21,6 @@
|
|||||||
#include "Com.hxx"
|
#include "Com.hxx"
|
||||||
#include "thread/Name.hxx"
|
#include "thread/Name.hxx"
|
||||||
|
|
||||||
Mutex COMWorker::mutex;
|
|
||||||
unsigned int COMWorker::reference_count = 0;
|
|
||||||
std::optional<COMWorker::COMWorkerThread> COMWorker::thread;
|
|
||||||
|
|
||||||
void COMWorker::COMWorkerThread::Work() noexcept {
|
void COMWorker::COMWorkerThread::Work() noexcept {
|
||||||
SetThreadName("COM Worker");
|
SetThreadName("COM Worker");
|
||||||
COM com{true};
|
COM com{true};
|
||||||
|
@@ -22,12 +22,9 @@
|
|||||||
|
|
||||||
#include "WinEvent.hxx"
|
#include "WinEvent.hxx"
|
||||||
#include "thread/Future.hxx"
|
#include "thread/Future.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
|
||||||
#include "thread/Thread.hxx"
|
#include "thread/Thread.hxx"
|
||||||
|
|
||||||
#include <boost/lockfree/spsc_queue.hpp>
|
#include <boost/lockfree/spsc_queue.hpp>
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -56,31 +53,25 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void Aquire() {
|
COMWorker() {
|
||||||
std::unique_lock locker(mutex);
|
thread.Start();
|
||||||
if (reference_count == 0) {
|
|
||||||
thread.emplace();
|
|
||||||
thread->Start();
|
|
||||||
}
|
|
||||||
++reference_count;
|
|
||||||
}
|
|
||||||
static void Release() noexcept {
|
|
||||||
std::unique_lock locker(mutex);
|
|
||||||
--reference_count;
|
|
||||||
if (reference_count == 0) {
|
|
||||||
thread->Finish();
|
|
||||||
thread->Join();
|
|
||||||
thread.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~COMWorker() noexcept {
|
||||||
|
thread.Finish();
|
||||||
|
thread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
|
COMWorker(const COMWorker &) = delete;
|
||||||
|
COMWorker &operator=(const COMWorker &) = delete;
|
||||||
|
|
||||||
template <typename Function, typename... Args>
|
template <typename Function, typename... Args>
|
||||||
static auto Async(Function &&function, Args &&...args) {
|
auto Async(Function &&function, Args &&...args) {
|
||||||
using R = std::invoke_result_t<std::decay_t<Function>,
|
using R = std::invoke_result_t<std::decay_t<Function>,
|
||||||
std::decay_t<Args>...>;
|
std::decay_t<Args>...>;
|
||||||
auto promise = std::make_shared<Promise<R>>();
|
auto promise = std::make_shared<Promise<R>>();
|
||||||
auto future = promise->get_future();
|
auto future = promise->get_future();
|
||||||
thread->Push([function = std::forward<Function>(function),
|
thread.Push([function = std::forward<Function>(function),
|
||||||
args = std::make_tuple(std::forward<Args>(args)...),
|
args = std::make_tuple(std::forward<Args>(args)...),
|
||||||
promise = std::move(promise)]() mutable {
|
promise = std::move(promise)]() mutable {
|
||||||
try {
|
try {
|
||||||
@@ -101,9 +92,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Mutex mutex;
|
COMWorkerThread thread;
|
||||||
static unsigned int reference_count;
|
|
||||||
static std::optional<COMWorkerThread> thread;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user