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
1 changed files with 14 additions and 23 deletions

View File

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