diff options
author | Shen-Ta Hsieh <ibmibmibm.tw@gmail.com> | 2020-12-02 07:33:40 +0800 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2021-03-04 18:45:56 +0100 |
commit | db7caa2dac03ec114b99ec7d49d10d6f81b73115 (patch) | |
tree | 8466a512761a3e297939e34f846bf84a11044ff6 /src/output | |
parent | 29747377467168ac8928081d3d37aa5016acd778 (diff) |
src/output: Move event and spsc_queue into thread object
Diffstat (limited to 'src/output')
-rw-r--r-- | src/output/plugins/WasapiOutputPlugin.cxx | 72 |
1 files changed, 33 insertions, 39 deletions
diff --git a/src/output/plugins/WasapiOutputPlugin.cxx b/src/output/plugins/WasapiOutputPlugin.cxx index 8c52bf15f..30eeb2c75 100644 --- a/src/output/plugins/WasapiOutputPlugin.cxx +++ b/src/output/plugins/WasapiOutputPlugin.cxx @@ -118,15 +118,14 @@ inline constexpr const unsigned int kErrorId = -1; class WasapiOutputThread : public Thread { public: enum class Status : uint32_t { FINISH, PLAY, PAUSE }; - WasapiOutputThread(std::shared_ptr<WinEvent> _event, ComPtr<IAudioClient> _client, + WasapiOutputThread(IAudioClient *_client, ComPtr<IAudioRenderClient> &&_render_client, const UINT32 _frame_size, const UINT32 _buffer_size_in_frames, - bool _is_exclusive, - boost::lockfree::spsc_queue<BYTE> &_spsc_buffer) - : Thread(BIND_THIS_METHOD(Work)), event(std::move(_event)), - client(std::move(_client)), render_client(std::move(_render_client)), - frame_size(_frame_size), buffer_size_in_frames(_buffer_size_in_frames), - is_exclusive(_is_exclusive), spsc_buffer(_spsc_buffer) {} + bool _is_exclusive) + : Thread(BIND_THIS_METHOD(Work)), client(_client), + render_client(std::move(_render_client)), frame_size(_frame_size), + buffer_size_in_frames(_buffer_size_in_frames), is_exclusive(_is_exclusive), + spsc_buffer(_buffer_size_in_frames * 4 * _frame_size) {} void Finish() noexcept { return SetStatus(Status::FINISH); } void Play() noexcept { return SetStatus(Status::PLAY); } void Pause() noexcept { return SetStatus(Status::PAUSE); } @@ -144,13 +143,13 @@ public: } private: - std::shared_ptr<WinEvent> event; - ComPtr<IAudioClient> client; + friend class WasapiOutput; + WinEvent event; + IAudioClient *client; ComPtr<IAudioRenderClient> render_client; const UINT32 frame_size; const UINT32 buffer_size_in_frames; bool is_exclusive; - boost::lockfree::spsc_queue<BYTE> &spsc_buffer; alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status = Status::PAUSE; alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct { @@ -162,10 +161,11 @@ private: Cond cond; std::exception_ptr error_ptr = nullptr; } error{}; + boost::lockfree::spsc_queue<BYTE> spsc_buffer; void SetStatus(Status s) noexcept { status.store(s); - event->Set(); + event.Set(); } void Work() noexcept; }; @@ -203,13 +203,11 @@ private: bool enumerate_devices; std::string device_config; std::vector<std::pair<unsigned int, AllocatedString>> device_desc; - std::shared_ptr<WinEvent> event; ComPtr<IMMDeviceEnumerator> enumerator; ComPtr<IMMDevice> device; ComPtr<IAudioClient> client; WAVEFORMATEXTENSIBLE device_format; - std::unique_ptr<WasapiOutputThread> thread; - std::unique_ptr<boost::lockfree::spsc_queue<BYTE>> spsc_buffer; + std::optional<WasapiOutputThread> thread; std::size_t watermark; friend bool wasapi_is_exclusive(WasapiOutput &output) noexcept; @@ -248,7 +246,7 @@ void WasapiOutputThread::Work() noexcept { COM com{true}; while (true) { try { - event->Wait(INFINITE); + event.Wait(INFINITE); Status current_state = status.load(); if (current_state == Status::FINISH) { @@ -330,13 +328,10 @@ void WasapiOutput::DoDisable() noexcept { err.what()); } thread.reset(); - spsc_buffer.reset(); client.reset(); } device.reset(); enumerator.reset(); - com.reset(); - event.reset(); } /// run inside COMWorkerThread @@ -442,11 +437,6 @@ void WasapiOutput::DoOpen(AudioFormat &audio_format) { throw FormatHResultError(result, "Unable to get new render client"); } - result = client->SetEventHandle(event->handle()); - if (FAILED(result)) { - throw FormatHResultError(result, "Unable to set event handler"); - } - UINT32 buffer_size_in_frames; result = client->GetBufferSize(&buffer_size_in_frames); if (FAILED(result)) { @@ -455,11 +445,14 @@ void WasapiOutput::DoOpen(AudioFormat &audio_format) { } watermark = buffer_size_in_frames * 3 * FrameSize(); - spsc_buffer = std::make_unique<boost::lockfree::spsc_queue<BYTE>>( - buffer_size_in_frames * 4 * FrameSize()); - thread = std::make_unique<WasapiOutputThread>( - event, client, std::move(render_client), FrameSize(), - buffer_size_in_frames, is_exclusive, *spsc_buffer); + thread.emplace(client.get(), std::move(render_client), FrameSize(), + buffer_size_in_frames, is_exclusive); + + result = client->SetEventHandle(thread->event.handle()); + if (FAILED(result)) { + throw FormatHResultError(result, "Unable to set event handler"); + } + thread->Start(); } @@ -472,7 +465,6 @@ void WasapiOutput::Close() noexcept { thread.reset(); client.reset(); }).get(); - spsc_buffer.reset(); } std::chrono::steady_clock::duration WasapiOutput::Delay() const noexcept { @@ -480,7 +472,9 @@ std::chrono::steady_clock::duration WasapiOutput::Delay() const noexcept { return std::chrono::steady_clock::duration::zero(); } - const size_t data_size = spsc_buffer->read_available(); + assert(thread); + + const size_t data_size = thread->spsc_buffer.read_available(); const size_t delay_size = std::max(data_size, watermark) - watermark; using s = std::chrono::seconds; @@ -490,13 +484,11 @@ std::chrono::steady_clock::duration WasapiOutput::Delay() const noexcept { } size_t WasapiOutput::Play(const void *chunk, size_t size) { - if (!client || !thread) { - return 0; - } + assert(thread); do { const size_t consumed_size = - spsc_buffer->push(static_cast<const BYTE *>(chunk), size); + thread->spsc_buffer.push(static_cast<const BYTE *>(chunk), size); if (consumed_size == 0) { assert(is_started); thread->WaitWrite(); @@ -523,11 +515,6 @@ size_t WasapiOutput::Play(const void *chunk, size_t size) { } while (true); } -void WasapiOutput::Drain() { - spsc_buffer->consume_all([](auto &&) {}); - thread->CheckException(); -} - bool WasapiOutput::Pause() { if (!client || !thread) { return false; @@ -549,6 +536,13 @@ bool WasapiOutput::Pause() { return true; } +void WasapiOutput::Drain() { + assert(thread); + + thread->spsc_buffer.consume_all([](auto &&) {}); + thread->CheckException(); +} + /// run inside COMWorkerThread void WasapiOutput::OpenDevice() { enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, |