mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
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
This commit is contained in:
parent
e7ccbdbe30
commit
2f13517a1a
Notes:
sideshowbarker
2024-07-19 11:22:35 +09:00
Author: https://github.com/tlmrgvf Commit: https://github.com/SerenityOS/serenity/commit/2f13517a1ad Pull-request: https://github.com/SerenityOS/serenity/pull/733
8 changed files with 109 additions and 9 deletions
|
@ -46,3 +46,23 @@ int AClientConnection::get_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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -31,6 +31,20 @@ RefPtr<ABuffer> 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 <typename SampleReader>
|
||||
template<typename SampleReader>
|
||||
static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<ASample>& 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> ABuffer::from_pcm_data(ByteBuffer& data, AResampleHelper& resamp
|
|||
{
|
||||
BufferStream stream(data);
|
||||
Vector<ASample> 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
|
||||
|
|
|
@ -22,6 +22,9 @@ public:
|
|||
|
||||
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 total_samples() const { return m_total_samples; }
|
||||
u32 sample_rate() const { return m_sample_rate; }
|
||||
|
|
|
@ -75,8 +75,38 @@ OwnPtr<AudioServer::EnqueueBufferResponse> ASClientConnection::handle(const Audi
|
|||
OwnPtr<AudioServer::GetRemainingSamplesResponse> ASClientConnection::handle(const AudioServer::GetRemainingSamples&)
|
||||
{
|
||||
int remaining = 0;
|
||||
if(m_queue)
|
||||
if (m_queue)
|
||||
remaining = m_queue->get_remaining_samples();
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ private:
|
|||
virtual OwnPtr<AudioServer::SetMainMixVolumeResponse> handle(const AudioServer::SetMainMixVolume&) override;
|
||||
virtual OwnPtr<AudioServer::EnqueueBufferResponse> handle(const AudioServer::EnqueueBuffer&) 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;
|
||||
RefPtr<ASBufferQueue> m_queue;
|
||||
|
|
|
@ -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<ABuffer> m_current;
|
||||
Queue<NonnullRefPtr<ABuffer>> m_queue;
|
||||
int m_position { 0 };
|
||||
int m_remaining_samples { 0 };
|
||||
int m_played_samples { 0 };
|
||||
bool m_paused { false };
|
||||
WeakPtr<ASClientConnection> m_client;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue