Commit 90d97053 authored by Max Kellermann's avatar Max Kellermann

win32/ComWorker: make COMWorker a real class, no static members

parent e1fe9ebc
...@@ -44,7 +44,11 @@ public: ...@@ -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: ...@@ -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 @@ ...@@ -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 &
...@@ -34,6 +37,10 @@ bool ...@@ -34,6 +37,10 @@ bool
wasapi_is_exclusive(WasapiOutput &output) noexcept; wasapi_is_exclusive(WasapiOutput &output) noexcept;
[[gnu::pure]] [[gnu::pure]]
std::shared_ptr<COMWorker>
wasapi_output_get_com_worker(WasapiOutput &output) noexcept;
[[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 { ...@@ -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: ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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: ...@@ -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); ~COMWorker() noexcept {
--reference_count; thread.Finish();
if (reference_count == 0) { thread.Join();
thread->Finish();
thread->Join();
thread.reset();
}
} }
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: ...@@ -101,9 +92,7 @@ public:
} }
private: private:
static Mutex mutex; COMWorkerThread thread;
static unsigned int reference_count;
static std::optional<COMWorkerThread> thread;
}; };
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment