Commit 25b01940 authored by Max Kellermann's avatar Max Kellermann

output/wasapi: implement Drain()

parent 77fe727e
...@@ -181,6 +181,8 @@ class WasapiOutputThread { ...@@ -181,6 +181,8 @@ class WasapiOutputThread {
std::atomic_bool cancel = false; std::atomic_bool cancel = false;
std::atomic_bool empty = true;
enum class Status : uint32_t { FINISH, PLAY, PAUSE }; enum class Status : uint32_t { FINISH, PLAY, PAUSE };
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status = alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status =
...@@ -224,6 +226,8 @@ public: ...@@ -224,6 +226,8 @@ public:
} }
std::size_t Push(ConstBuffer<void> input) noexcept { std::size_t Push(ConstBuffer<void> input) noexcept {
empty.store(false);
std::size_t consumed = std::size_t consumed =
spsc_buffer.push(static_cast<const BYTE *>(input.data), spsc_buffer.push(static_cast<const BYTE *>(input.data),
input.size); input.size);
...@@ -237,6 +241,24 @@ public: ...@@ -237,6 +241,24 @@ public:
} }
/** /**
* Check if the buffer is empty, and if not, wait a bit.
*
* Throws on error.
*
* @return true if the buffer is now empty
*/
bool Drain() {
if (empty)
return true;
CheckException();
Wait();
CheckException();
return empty;
}
/**
* Instruct the thread to discard the buffer (and wait for * Instruct the thread to discard the buffer (and wait for
* completion). This needs to be done inside this thread, * completion). This needs to be done inside this thread,
* because only the consumer thread is allowed to do that. * because only the consumer thread is allowed to do that.
...@@ -417,6 +439,7 @@ try { ...@@ -417,6 +439,7 @@ try {
if (cancel.load()) { if (cancel.load()) {
spsc_buffer.consume_all([](auto &&) {}); spsc_buffer.consume_all([](auto &&) {});
cancel.store(false); cancel.store(false);
empty.store(true);
InterruptWaiter(); InterruptWaiter();
} }
...@@ -475,6 +498,9 @@ try { ...@@ -475,6 +498,9 @@ try {
const UINT32 write_size = write_in_frames * frame_size; const UINT32 write_size = write_in_frames * frame_size;
UINT32 new_data_size = 0; UINT32 new_data_size = 0;
new_data_size = spsc_buffer.pop(data, write_size); new_data_size = spsc_buffer.pop(data, write_size);
if (new_data_size == 0)
empty.store(true);
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);
InterruptWaiter(); InterruptWaiter();
...@@ -741,9 +767,15 @@ WasapiOutput::Drain() ...@@ -741,9 +767,15 @@ WasapiOutput::Drain()
{ {
assert(thread); assert(thread);
// TODO implement not_interrupted.test_and_set();
thread->CheckException(); while (!thread->Drain()) {
if (!not_interrupted.test_and_set())
throw AudioOutputInterrupted{};
}
/* TODO: this needs to wait until the hardware has really
finished playing */
} }
void void
......
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