diff --git a/Libraries/LibAudio/AClientConnection.cpp b/Libraries/LibAudio/AClientConnection.cpp index 0cb64578b2..abe9a307c4 100644 --- a/Libraries/LibAudio/AClientConnection.cpp +++ b/Libraries/LibAudio/AClientConnection.cpp @@ -25,3 +25,18 @@ void AClientConnection::play(const ABuffer& buffer, bool block) request.play_buffer.buffer_id = buffer.shared_buffer_id(); sync_request(request, block ? ASAPI_ServerMessage::Type::FinishedPlayingBuffer : ASAPI_ServerMessage::Type::PlayingBuffer); } + +void AClientConnection::enqueue(const ABuffer& buffer) +{ + for (;;) { + const_cast(buffer).shared_buffer().share_with(server_pid()); + ASAPI_ClientMessage request; + request.type = ASAPI_ClientMessage::Type::EnqueueBuffer; + request.play_buffer.buffer_id = buffer.shared_buffer_id(); + auto response = sync_request(request, ASAPI_ServerMessage::Type::EnqueueBufferResponse); + if (response.success) + break; + dbg() << "EnqueueBuffer failed, retrying..."; + sleep(1); + } +} diff --git a/Libraries/LibAudio/AClientConnection.h b/Libraries/LibAudio/AClientConnection.h index 214af48bc0..2cc224353d 100644 --- a/Libraries/LibAudio/AClientConnection.h +++ b/Libraries/LibAudio/AClientConnection.h @@ -12,4 +12,5 @@ public: virtual void handshake() override; void play(const ABuffer&, bool block); + void enqueue(const ABuffer&); }; diff --git a/Libraries/LibAudio/ASAPI.h b/Libraries/LibAudio/ASAPI.h index 227aee1027..0dabd28c86 100644 --- a/Libraries/LibAudio/ASAPI.h +++ b/Libraries/LibAudio/ASAPI.h @@ -6,10 +6,12 @@ struct ASAPI_ServerMessage { Greeting, PlayingBuffer, FinishedPlayingBuffer, + EnqueueBufferResponse, }; Type type { Type::Invalid }; unsigned extra_size { 0 }; + bool success { true }; union { struct { @@ -27,6 +29,7 @@ struct ASAPI_ClientMessage { Invalid, Greeting, PlayBuffer, + EnqueueBuffer, }; Type type { Type::Invalid }; diff --git a/Servers/AudioServer/ASClientConnection.cpp b/Servers/AudioServer/ASClientConnection.cpp index 96cf328fcc..2e22dab008 100644 --- a/Servers/AudioServer/ASClientConnection.cpp +++ b/Servers/AudioServer/ASClientConnection.cpp @@ -54,6 +54,30 @@ bool ASClientConnection::handle_message(const ASAPI_ClientMessage& message, cons m_mixer.queue(*this, ABuffer::create_with_shared_buffer(*shared_buffer)); break; } + case ASAPI_ClientMessage::Type::EnqueueBuffer: { + auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.play_buffer.buffer_id); + if (!shared_buffer) { + did_misbehave(); + return false; + } + + static const int max_in_queue = 2; + + ASAPI_ServerMessage reply; + reply.type = ASAPI_ServerMessage::Type::EnqueueBufferResponse; + reply.playing_buffer.buffer_id = message.play_buffer.buffer_id; + if (m_buffer_queue.size() >= max_in_queue) { + reply.success = false; + } else { + m_buffer_queue.enqueue(ABuffer::create_with_shared_buffer(*shared_buffer)); + } + post_message(reply); + + if (m_playing_queued_buffer_id == -1) + play_next_in_queue(); + + break; + } case ASAPI_ClientMessage::Type::Invalid: default: dbgprintf("ASClientConnection: Unexpected message ID %d\n", int(message.type)); @@ -65,8 +89,19 @@ bool ASClientConnection::handle_message(const ASAPI_ClientMessage& message, cons void ASClientConnection::did_finish_playing_buffer(Badge, int buffer_id) { + if (m_playing_queued_buffer_id == buffer_id) + play_next_in_queue(); + ASAPI_ServerMessage reply; reply.type = ASAPI_ServerMessage::Type::FinishedPlayingBuffer; reply.playing_buffer.buffer_id = buffer_id; post_message(reply); } + +void ASClientConnection::play_next_in_queue() +{ + dbg() << "Playing next in queue (" << m_buffer_queue.size() << " queued)"; + auto buffer = m_buffer_queue.dequeue(); + m_playing_queued_buffer_id = buffer->shared_buffer_id(); + m_mixer.queue(*this, move(buffer)); +} diff --git a/Servers/AudioServer/ASClientConnection.h b/Servers/AudioServer/ASClientConnection.h index 295adfc221..ee89c4fab5 100644 --- a/Servers/AudioServer/ASClientConnection.h +++ b/Servers/AudioServer/ASClientConnection.h @@ -1,8 +1,10 @@ #pragma once +#include #include #include +class ABuffer; class ASMixer; class ASClientConnection final : public IPC::Server::Connection { @@ -16,5 +18,9 @@ public: void did_finish_playing_buffer(Badge, int buffer_id); private: + void play_next_in_queue(); + ASMixer& m_mixer; + Queue> m_buffer_queue; + int m_playing_queued_buffer_id { -1 }; }; diff --git a/Userland/aplay.cpp b/Userland/aplay.cpp index 158121534c..9d2fba736b 100644 --- a/Userland/aplay.cpp +++ b/Userland/aplay.cpp @@ -25,7 +25,7 @@ int main(int argc, char **argv) break; } printf("Playing %d sample(s)\n", samples->sample_count()); - a_conn.play(*samples, true); + a_conn.enqueue(*samples); } printf("Exiting! :)\n");