src/output: Use WinEvent for as a condition_variable without lock

This commit is contained in:
Shen-Ta Hsieh 2020-12-02 07:41:44 +08:00 committed by Max Kellermann
parent db7caa2dac
commit 844dbd2ec5

View File

@ -129,15 +129,11 @@ public:
void Finish() noexcept { return SetStatus(Status::FINISH); } void Finish() noexcept { return SetStatus(Status::FINISH); }
void Play() noexcept { return SetStatus(Status::PLAY); } void Play() noexcept { return SetStatus(Status::PLAY); }
void Pause() noexcept { return SetStatus(Status::PAUSE); } void Pause() noexcept { return SetStatus(Status::PAUSE); }
void WaitWrite() noexcept { void WaitDataPoped() noexcept { data_poped.Wait(200); }
std::unique_lock<Mutex> lock(write.mutex);
write.cond.wait(lock);
}
void CheckException() { void CheckException() {
std::unique_lock<Mutex> lock(error.mutex); if (error.occur.load()) {
if (error.error_ptr) { auto err = std::exchange(error.ptr, nullptr);
std::exception_ptr err = std::exchange(error.error_ptr, nullptr); error.thrown.Set();
error.cond.notify_all();
std::rethrow_exception(err); std::rethrow_exception(err);
} }
} }
@ -145,6 +141,7 @@ public:
private: private:
friend class WasapiOutput; friend class WasapiOutput;
WinEvent event; WinEvent event;
WinEvent data_poped;
IAudioClient *client; IAudioClient *client;
ComPtr<IAudioRenderClient> render_client; ComPtr<IAudioRenderClient> render_client;
const UINT32 frame_size; const UINT32 frame_size;
@ -153,14 +150,10 @@ private:
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status = alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status =
Status::PAUSE; Status::PAUSE;
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct { alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct {
Mutex mutex; std::atomic_bool occur = false;
Cond cond; std::exception_ptr ptr = nullptr;
} write{}; WinEvent thrown;
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct { } error;
Mutex mutex;
Cond cond;
std::exception_ptr error_ptr = nullptr;
} error{};
boost::lockfree::spsc_queue<BYTE> spsc_buffer; boost::lockfree::spsc_queue<BYTE> spsc_buffer;
void SetStatus(Status s) noexcept { void SetStatus(Status s) noexcept {
@ -255,8 +248,6 @@ void WasapiOutputThread::Work() noexcept {
return; return;
} }
AtScopeExit(&) { write.cond.notify_all(); };
HRESULT result; HRESULT result;
UINT32 data_in_frames; UINT32 data_in_frames;
result = client->GetCurrentPadding(&data_in_frames); result = client->GetCurrentPadding(&data_in_frames);
@ -293,16 +284,16 @@ void WasapiOutputThread::Work() noexcept {
new_data_size = spsc_buffer.pop(data, write_size); new_data_size = spsc_buffer.pop(data, write_size);
std::fill_n(data + new_data_size, std::fill_n(data + new_data_size,
write_size - new_data_size, 0); write_size - new_data_size, 0);
data_poped.Set();
} else { } else {
mode = AUDCLNT_BUFFERFLAGS_SILENT; mode = AUDCLNT_BUFFERFLAGS_SILENT;
FormatDebug(wasapi_output_domain, FormatDebug(wasapi_output_domain,
"Working thread paused"); "Working thread paused");
} }
} catch (...) { } catch (...) {
std::unique_lock<Mutex> lock(error.mutex); error.ptr = std::current_exception();
error.error_ptr = std::current_exception(); error.occur.store(true);
error.cond.wait(lock); error.thrown.Wait(INFINITE);
assert(error.error_ptr == nullptr);
} }
} }
} }
@ -491,7 +482,7 @@ size_t WasapiOutput::Play(const void *chunk, size_t size) {
thread->spsc_buffer.push(static_cast<const BYTE *>(chunk), size); thread->spsc_buffer.push(static_cast<const BYTE *>(chunk), size);
if (consumed_size == 0) { if (consumed_size == 0) {
assert(is_started); assert(is_started);
thread->WaitWrite(); thread->WaitDataPoped();
continue; continue;
} }