Просмотр исходного кода

AudioServer: Add a buffer queue so we can buffer some sound.

The idea here is to keep a small number of sample buffers queued in the
AudioServer so we don't get caught without something to play.
Andreas Kling 6 лет назад
Родитель
Сommit
7cabe6433e

+ 15 - 0
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<ABuffer&>(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);
+    }
+}

+ 1 - 0
Libraries/LibAudio/AClientConnection.h

@@ -12,4 +12,5 @@ public:
 
     virtual void handshake() override;
     void play(const ABuffer&, bool block);
+    void enqueue(const ABuffer&);
 };

+ 3 - 0
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 };

+ 35 - 0
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<ASMixer>, 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));
+}

+ 6 - 0
Servers/AudioServer/ASClientConnection.h

@@ -1,8 +1,10 @@
 #pragma once
 
+#include <AK/Queue.h>
 #include <LibAudio/ASAPI.h>
 #include <LibCore/CoreIPCServer.h>
 
+class ABuffer;
 class ASMixer;
 
 class ASClientConnection final : public IPC::Server::Connection<ASAPI_ServerMessage, ASAPI_ClientMessage> {
@@ -16,5 +18,9 @@ public:
     void did_finish_playing_buffer(Badge<ASMixer>, int buffer_id);
 
 private:
+    void play_next_in_queue();
+
     ASMixer& m_mixer;
+    Queue<NonnullRefPtr<ABuffer>> m_buffer_queue;
+    int m_playing_queued_buffer_id { -1 };
 };

+ 1 - 1
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");