src/output: Use WinEvent for as a condition_variable without lock
This commit is contained in:
parent
db7caa2dac
commit
844dbd2ec5
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user