Browse Source

LibAudio: Added playback control features to audio server

LibAudio now supports pausing playback, clearing the buffer queue,
retrieving the played samples since the last clear and retrieving
the currently playing shared buffer id
Till Mayer 5 years ago
parent
commit
2f13517a1a

+ 20 - 0
Libraries/LibAudio/AClientConnection.cpp

@@ -46,3 +46,23 @@ int AClientConnection::get_remaining_samples()
 {
 {
     return send_sync<AudioServer::GetRemainingSamples>()->remaining_samples();
     return send_sync<AudioServer::GetRemainingSamples>()->remaining_samples();
 }
 }
+
+int AClientConnection::get_played_samples()
+{
+    return send_sync<AudioServer::GetPlayedSamples>()->played_samples();
+}
+
+void AClientConnection::set_paused(bool paused)
+{
+    send_sync<AudioServer::SetPaused>(paused);
+}
+
+void AClientConnection::clear_buffer(bool paused)
+{
+    send_sync<AudioServer::ClearBuffer>(paused);
+}
+
+int AClientConnection::get_playing_buffer()
+{
+    return send_sync<AudioServer::GetPlayingBuffer>()->buffer_id();
+}

+ 5 - 0
Libraries/LibAudio/AClientConnection.h

@@ -18,4 +18,9 @@ public:
     void set_main_mix_volume(int);
     void set_main_mix_volume(int);
 
 
     int get_remaining_samples();
     int get_remaining_samples();
+    int get_played_samples();
+    int get_playing_buffer();
+
+    void set_paused(bool paused);
+    void clear_buffer(bool paused = false);
 };
 };

+ 19 - 6
Libraries/LibAudio/AWavLoader.cpp

@@ -31,6 +31,20 @@ RefPtr<ABuffer> AWavLoader::get_more_samples(size_t max_bytes_to_read_from_input
     return buffer;
     return buffer;
 }
 }
 
 
+void AWavLoader::seek(const int position)
+{
+    if (position < 0 || position > m_total_samples)
+        return;
+
+    m_loaded_samples = position;
+    m_file->seek(position * m_num_channels * (m_bits_per_sample / 8));
+}
+
+void AWavLoader::reset()
+{
+    seek(0);
+}
+
 bool AWavLoader::parse_header()
 bool AWavLoader::parse_header()
 {
 {
     CIODeviceStreamReader stream(*m_file);
     CIODeviceStreamReader stream(*m_file);
@@ -80,7 +94,7 @@ bool AWavLoader::parse_header()
 
 
     u16 audio_format;
     u16 audio_format;
     stream >> audio_format;
     stream >> audio_format;
-    CHECK_OK("Audio format"); // incomplete read check
+    CHECK_OK("Audio format");     // incomplete read check
     ok = ok && audio_format == 1; // WAVE_FORMAT_PCM
     ok = ok && audio_format == 1; // WAVE_FORMAT_PCM
     ASSERT(audio_format == 1);
     ASSERT(audio_format == 1);
     CHECK_OK("Audio format"); // value check
     CHECK_OK("Audio format"); // value check
@@ -161,7 +175,7 @@ bool AResampleHelper::read_sample(float& next_l, float& next_r)
     return false;
     return false;
 }
 }
 
 
-template <typename SampleReader>
+template<typename SampleReader>
 static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<ASample>& samples, AResampleHelper& resampler, int num_channels)
 static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<ASample>& samples, AResampleHelper& resampler, int num_channels)
 {
 {
     float norm_l = 0;
     float norm_l = 0;
@@ -169,7 +183,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam
 
 
     switch (num_channels) {
     switch (num_channels) {
     case 1:
     case 1:
-        for(;;) {
+        for (;;) {
             while (resampler.read_sample(norm_l, norm_r)) {
             while (resampler.read_sample(norm_l, norm_r)) {
                 samples.append(ASample(norm_l));
                 samples.append(ASample(norm_l));
             }
             }
@@ -182,7 +196,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam
         }
         }
         break;
         break;
     case 2:
     case 2:
-        for(;;) {
+        for (;;) {
             while (resampler.read_sample(norm_l, norm_r)) {
             while (resampler.read_sample(norm_l, norm_r)) {
                 samples.append(ASample(norm_l, norm_r));
                 samples.append(ASample(norm_l, norm_r));
             }
             }
@@ -238,8 +252,7 @@ RefPtr<ABuffer> ABuffer::from_pcm_data(ByteBuffer& data, AResampleHelper& resamp
 {
 {
     BufferStream stream(data);
     BufferStream stream(data);
     Vector<ASample> fdata;
     Vector<ASample> fdata;
-    fdata.ensure_capacity(data.size() * 2);
-
+    fdata.ensure_capacity(data.size() / (bits_per_sample / 8));
 #ifdef AWAVLOADER_DEBUG
 #ifdef AWAVLOADER_DEBUG
     dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size();
     dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size();
 #endif
 #endif

+ 3 - 0
Libraries/LibAudio/AWavLoader.h

@@ -22,6 +22,9 @@ public:
 
 
     RefPtr<ABuffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KB);
     RefPtr<ABuffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KB);
 
 
+    void reset();
+    void seek(const int position);
+
     int loaded_samples() const { return m_loaded_samples; }
     int loaded_samples() const { return m_loaded_samples; }
     int total_samples() const { return m_total_samples; }
     int total_samples() const { return m_total_samples; }
     u32 sample_rate() const { return m_sample_rate; }
     u32 sample_rate() const { return m_sample_rate; }

+ 31 - 1
Servers/AudioServer/ASClientConnection.cpp

@@ -75,8 +75,38 @@ OwnPtr<AudioServer::EnqueueBufferResponse> ASClientConnection::handle(const Audi
 OwnPtr<AudioServer::GetRemainingSamplesResponse> ASClientConnection::handle(const AudioServer::GetRemainingSamples&)
 OwnPtr<AudioServer::GetRemainingSamplesResponse> ASClientConnection::handle(const AudioServer::GetRemainingSamples&)
 {
 {
     int remaining = 0;
     int remaining = 0;
-    if(m_queue)
+    if (m_queue)
         remaining = m_queue->get_remaining_samples();
         remaining = m_queue->get_remaining_samples();
 
 
     return make<AudioServer::GetRemainingSamplesResponse>(remaining);
     return make<AudioServer::GetRemainingSamplesResponse>(remaining);
 }
 }
+
+OwnPtr<AudioServer::GetPlayedSamplesResponse> ASClientConnection::handle(const AudioServer::GetPlayedSamples&)
+{
+    int played = 0;
+    if (m_queue)
+        played = m_queue->get_played_samples();
+
+    return make<AudioServer::GetPlayedSamplesResponse>(played);
+}
+
+OwnPtr<AudioServer::SetPausedResponse> ASClientConnection::handle(const AudioServer::SetPaused& message)
+{
+    if (m_queue)
+        m_queue->set_paused(message.paused());
+    return make<AudioServer::SetPausedResponse>();
+}
+
+OwnPtr<AudioServer::ClearBufferResponse> ASClientConnection::handle(const AudioServer::ClearBuffer& message)
+{
+    if (m_queue)
+        m_queue->clear(message.paused());
+    return make<AudioServer::ClearBufferResponse>();
+}
+
+OwnPtr<AudioServer::GetPlayingBufferResponse> ASClientConnection::handle(const AudioServer::GetPlayingBuffer&){
+    int id = -1;
+    if(m_queue)
+        id = m_queue->get_playing_buffer();
+    return make<AudioServer::GetPlayingBufferResponse>(id);
+}

+ 4 - 0
Servers/AudioServer/ASClientConnection.h

@@ -23,6 +23,10 @@ private:
     virtual OwnPtr<AudioServer::SetMainMixVolumeResponse> handle(const AudioServer::SetMainMixVolume&) override;
     virtual OwnPtr<AudioServer::SetMainMixVolumeResponse> handle(const AudioServer::SetMainMixVolume&) override;
     virtual OwnPtr<AudioServer::EnqueueBufferResponse> handle(const AudioServer::EnqueueBuffer&) override;
     virtual OwnPtr<AudioServer::EnqueueBufferResponse> handle(const AudioServer::EnqueueBuffer&) override;
     virtual OwnPtr<AudioServer::GetRemainingSamplesResponse> handle(const AudioServer::GetRemainingSamples&) override;
     virtual OwnPtr<AudioServer::GetRemainingSamplesResponse> handle(const AudioServer::GetRemainingSamples&) override;
+    virtual OwnPtr<AudioServer::GetPlayedSamplesResponse> handle(const AudioServer::GetPlayedSamples&) override;
+    virtual OwnPtr<AudioServer::SetPausedResponse> handle(const AudioServer::SetPaused&) override;
+    virtual OwnPtr<AudioServer::ClearBufferResponse> handle(const AudioServer::ClearBuffer&) override;
+    virtual OwnPtr<AudioServer::GetPlayingBufferResponse> handle(const AudioServer::GetPlayingBuffer&) override;
 
 
     ASMixer& m_mixer;
     ASMixer& m_mixer;
     RefPtr<ASBufferQueue> m_queue;
     RefPtr<ASBufferQueue> m_queue;

+ 22 - 2
Servers/AudioServer/ASMixer.h

@@ -22,6 +22,9 @@ public:
 
 
     bool get_next_sample(ASample& sample)
     bool get_next_sample(ASample& sample)
     {
     {
+        if (m_paused)
+            return false;
+
         while (!m_current && !m_queue.is_empty())
         while (!m_current && !m_queue.is_empty())
             m_current = m_queue.dequeue();
             m_current = m_queue.dequeue();
 
 
@@ -29,7 +32,8 @@ public:
             return false;
             return false;
 
 
         sample = m_current->samples()[m_position++];
         sample = m_current->samples()[m_position++];
-        m_remaining_samples--;
+        --m_remaining_samples;
+        ++m_played_samples;
 
 
         if (m_position >= m_current->sample_count()) {
         if (m_position >= m_current->sample_count()) {
             m_current = nullptr;
             m_current = nullptr;
@@ -40,19 +44,35 @@ public:
 
 
     ASClientConnection* client() { return m_client.ptr(); }
     ASClientConnection* client() { return m_client.ptr(); }
 
 
-    void clear()
+    void clear(bool paused = false)
     {
     {
         m_queue.clear();
         m_queue.clear();
         m_position = 0;
         m_position = 0;
+        m_remaining_samples = 0;
+        m_played_samples = 0;
+        m_current = nullptr;
+        m_paused = paused;
+    }
+
+    void set_paused(bool paused)
+    {
+        m_paused = paused;
     }
     }
 
 
     int get_remaining_samples() const { return m_remaining_samples; }
     int get_remaining_samples() const { return m_remaining_samples; }
+    int get_played_samples() const { return m_played_samples; }
+    int get_playing_buffer() const {
+        if(m_current) return m_current->shared_buffer_id();
+        return -1;
+    }
 
 
 private:
 private:
     RefPtr<ABuffer> m_current;
     RefPtr<ABuffer> m_current;
     Queue<NonnullRefPtr<ABuffer>> m_queue;
     Queue<NonnullRefPtr<ABuffer>> m_queue;
     int m_position { 0 };
     int m_position { 0 };
     int m_remaining_samples { 0 };
     int m_remaining_samples { 0 };
+    int m_played_samples { 0 };
+    bool m_paused { false };
     WeakPtr<ASClientConnection> m_client;
     WeakPtr<ASClientConnection> m_client;
 };
 };
 
 

+ 5 - 0
Servers/AudioServer/AudioServer.ipc

@@ -9,6 +9,11 @@ endpoint AudioServer
 
 
     // Buffer playback
     // Buffer playback
     EnqueueBuffer(i32 buffer_id, int sample_count) => (bool success)
     EnqueueBuffer(i32 buffer_id, int sample_count) => (bool success)
+    SetPaused(bool paused) => ()
+    ClearBuffer(bool paused) => ()
 
 
+    //Buffer information
     GetRemainingSamples() => (int remaining_samples)
     GetRemainingSamples() => (int remaining_samples)
+    GetPlayedSamples() => (int played_samples)
+    GetPlayingBuffer() => (i32 buffer_id)
 }
 }