From 2f13517a1adb262dbda8e12cb0aeb7383bf0c812 Mon Sep 17 00:00:00 2001 From: Till Mayer Date: Mon, 4 Nov 2019 19:39:17 +0100 Subject: [PATCH] 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 --- Libraries/LibAudio/AClientConnection.cpp | 20 ++++++++++++++ Libraries/LibAudio/AClientConnection.h | 5 ++++ Libraries/LibAudio/AWavLoader.cpp | 25 +++++++++++++---- Libraries/LibAudio/AWavLoader.h | 3 ++ Servers/AudioServer/ASClientConnection.cpp | 32 +++++++++++++++++++++- Servers/AudioServer/ASClientConnection.h | 4 +++ Servers/AudioServer/ASMixer.h | 24 ++++++++++++++-- Servers/AudioServer/AudioServer.ipc | 5 ++++ 8 files changed, 109 insertions(+), 9 deletions(-) diff --git a/Libraries/LibAudio/AClientConnection.cpp b/Libraries/LibAudio/AClientConnection.cpp index de1e368657..66f107b933 100644 --- a/Libraries/LibAudio/AClientConnection.cpp +++ b/Libraries/LibAudio/AClientConnection.cpp @@ -46,3 +46,23 @@ int AClientConnection::get_remaining_samples() { return send_sync()->remaining_samples(); } + +int AClientConnection::get_played_samples() +{ + return send_sync()->played_samples(); +} + +void AClientConnection::set_paused(bool paused) +{ + send_sync(paused); +} + +void AClientConnection::clear_buffer(bool paused) +{ + send_sync(paused); +} + +int AClientConnection::get_playing_buffer() +{ + return send_sync()->buffer_id(); +} diff --git a/Libraries/LibAudio/AClientConnection.h b/Libraries/LibAudio/AClientConnection.h index c1d2523340..ff0e6f59b2 100644 --- a/Libraries/LibAudio/AClientConnection.h +++ b/Libraries/LibAudio/AClientConnection.h @@ -18,4 +18,9 @@ public: void set_main_mix_volume(int); int get_remaining_samples(); + int get_played_samples(); + int get_playing_buffer(); + + void set_paused(bool paused); + void clear_buffer(bool paused = false); }; diff --git a/Libraries/LibAudio/AWavLoader.cpp b/Libraries/LibAudio/AWavLoader.cpp index d64a65ddc6..eb8403ef0f 100644 --- a/Libraries/LibAudio/AWavLoader.cpp +++ b/Libraries/LibAudio/AWavLoader.cpp @@ -31,6 +31,20 @@ RefPtr AWavLoader::get_more_samples(size_t max_bytes_to_read_from_input 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() { CIODeviceStreamReader stream(*m_file); @@ -80,7 +94,7 @@ bool AWavLoader::parse_header() u16 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 ASSERT(audio_format == 1); CHECK_OK("Audio format"); // value check @@ -161,7 +175,7 @@ bool AResampleHelper::read_sample(float& next_l, float& next_r) return false; } -template +template static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector& samples, AResampleHelper& resampler, int num_channels) { float norm_l = 0; @@ -169,7 +183,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam switch (num_channels) { case 1: - for(;;) { + for (;;) { while (resampler.read_sample(norm_l, norm_r)) { samples.append(ASample(norm_l)); } @@ -182,7 +196,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam } break; case 2: - for(;;) { + for (;;) { while (resampler.read_sample(norm_l, norm_r)) { samples.append(ASample(norm_l, norm_r)); } @@ -238,8 +252,7 @@ RefPtr ABuffer::from_pcm_data(ByteBuffer& data, AResampleHelper& resamp { BufferStream stream(data); Vector fdata; - fdata.ensure_capacity(data.size() * 2); - + fdata.ensure_capacity(data.size() / (bits_per_sample / 8)); #ifdef AWAVLOADER_DEBUG dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size(); #endif diff --git a/Libraries/LibAudio/AWavLoader.h b/Libraries/LibAudio/AWavLoader.h index 34fb0a0305..bd53b2ff15 100644 --- a/Libraries/LibAudio/AWavLoader.h +++ b/Libraries/LibAudio/AWavLoader.h @@ -22,6 +22,9 @@ public: RefPtr 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 total_samples() const { return m_total_samples; } u32 sample_rate() const { return m_sample_rate; } diff --git a/Servers/AudioServer/ASClientConnection.cpp b/Servers/AudioServer/ASClientConnection.cpp index 43e2e5e813..7bfe1df067 100644 --- a/Servers/AudioServer/ASClientConnection.cpp +++ b/Servers/AudioServer/ASClientConnection.cpp @@ -75,8 +75,38 @@ OwnPtr ASClientConnection::handle(const Audi OwnPtr ASClientConnection::handle(const AudioServer::GetRemainingSamples&) { int remaining = 0; - if(m_queue) + if (m_queue) remaining = m_queue->get_remaining_samples(); return make(remaining); } + +OwnPtr ASClientConnection::handle(const AudioServer::GetPlayedSamples&) +{ + int played = 0; + if (m_queue) + played = m_queue->get_played_samples(); + + return make(played); +} + +OwnPtr ASClientConnection::handle(const AudioServer::SetPaused& message) +{ + if (m_queue) + m_queue->set_paused(message.paused()); + return make(); +} + +OwnPtr ASClientConnection::handle(const AudioServer::ClearBuffer& message) +{ + if (m_queue) + m_queue->clear(message.paused()); + return make(); +} + +OwnPtr ASClientConnection::handle(const AudioServer::GetPlayingBuffer&){ + int id = -1; + if(m_queue) + id = m_queue->get_playing_buffer(); + return make(id); +} diff --git a/Servers/AudioServer/ASClientConnection.h b/Servers/AudioServer/ASClientConnection.h index a50fbd270e..d3946a834f 100644 --- a/Servers/AudioServer/ASClientConnection.h +++ b/Servers/AudioServer/ASClientConnection.h @@ -23,6 +23,10 @@ private: virtual OwnPtr handle(const AudioServer::SetMainMixVolume&) override; virtual OwnPtr handle(const AudioServer::EnqueueBuffer&) override; virtual OwnPtr handle(const AudioServer::GetRemainingSamples&) override; + virtual OwnPtr handle(const AudioServer::GetPlayedSamples&) override; + virtual OwnPtr handle(const AudioServer::SetPaused&) override; + virtual OwnPtr handle(const AudioServer::ClearBuffer&) override; + virtual OwnPtr handle(const AudioServer::GetPlayingBuffer&) override; ASMixer& m_mixer; RefPtr m_queue; diff --git a/Servers/AudioServer/ASMixer.h b/Servers/AudioServer/ASMixer.h index cd086d0da7..e2a823b029 100644 --- a/Servers/AudioServer/ASMixer.h +++ b/Servers/AudioServer/ASMixer.h @@ -22,6 +22,9 @@ public: bool get_next_sample(ASample& sample) { + if (m_paused) + return false; + while (!m_current && !m_queue.is_empty()) m_current = m_queue.dequeue(); @@ -29,7 +32,8 @@ public: return false; sample = m_current->samples()[m_position++]; - m_remaining_samples--; + --m_remaining_samples; + ++m_played_samples; if (m_position >= m_current->sample_count()) { m_current = nullptr; @@ -40,19 +44,35 @@ public: ASClientConnection* client() { return m_client.ptr(); } - void clear() + void clear(bool paused = false) { m_queue.clear(); 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_played_samples() const { return m_played_samples; } + int get_playing_buffer() const { + if(m_current) return m_current->shared_buffer_id(); + return -1; + } private: RefPtr m_current; Queue> m_queue; int m_position { 0 }; int m_remaining_samples { 0 }; + int m_played_samples { 0 }; + bool m_paused { false }; WeakPtr m_client; }; diff --git a/Servers/AudioServer/AudioServer.ipc b/Servers/AudioServer/AudioServer.ipc index a68beef39a..469e226eef 100644 --- a/Servers/AudioServer/AudioServer.ipc +++ b/Servers/AudioServer/AudioServer.ipc @@ -9,6 +9,11 @@ endpoint AudioServer // Buffer playback EnqueueBuffer(i32 buffer_id, int sample_count) => (bool success) + SetPaused(bool paused) => () + ClearBuffer(bool paused) => () + //Buffer information GetRemainingSamples() => (int remaining_samples) + GetPlayedSamples() => (int played_samples) + GetPlayingBuffer() => (i32 buffer_id) }