From aacb4fc59089ce72ee70742656259c6b4787141e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Mon, 10 Jul 2023 23:41:08 +0200 Subject: [PATCH] AudioServer: Move ClientAudioStream to own files This class will only grow, and it should really have its own files. --- Userland/Services/AudioServer/CMakeLists.txt | 1 + .../AudioServer/ClientAudioStream.cpp | 121 ++++++++++++++++++ .../Services/AudioServer/ClientAudioStream.h | 57 +++++++++ .../Services/AudioServer/FadingProperty.h | 1 - Userland/Services/AudioServer/Mixer.cpp | 5 - Userland/Services/AudioServer/Mixer.h | 91 +------------ 6 files changed, 181 insertions(+), 95 deletions(-) create mode 100644 Userland/Services/AudioServer/ClientAudioStream.cpp create mode 100644 Userland/Services/AudioServer/ClientAudioStream.h diff --git a/Userland/Services/AudioServer/CMakeLists.txt b/Userland/Services/AudioServer/CMakeLists.txt index 1aaa2f0b38..1590b766f5 100644 --- a/Userland/Services/AudioServer/CMakeLists.txt +++ b/Userland/Services/AudioServer/CMakeLists.txt @@ -10,6 +10,7 @@ compile_ipc(AudioManagerClient.ipc AudioManagerClientEndpoint.h) compile_ipc(AudioManagerServer.ipc AudioManagerServerEndpoint.h) set(SOURCES + ClientAudioStream.cpp ConnectionFromClient.cpp ConnectionFromManagerClient.cpp Mixer.cpp diff --git a/Userland/Services/AudioServer/ClientAudioStream.cpp b/Userland/Services/AudioServer/ClientAudioStream.cpp new file mode 100644 index 0000000000..040f2f9dd4 --- /dev/null +++ b/Userland/Services/AudioServer/ClientAudioStream.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018-2022, the SerenityOS developers. + * Copyright (c) 2021-2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ClientAudioStream.h" +#include + +namespace AudioServer { + +ClientAudioStream::ClientAudioStream(ConnectionFromClient& client) + : m_client(client) +{ +} + +ConnectionFromClient* ClientAudioStream::client() +{ + return m_client.ptr(); +} + +bool ClientAudioStream::is_connected() const +{ + return m_client && m_client->is_open(); +} + +bool ClientAudioStream::get_next_sample(Audio::Sample& sample, u32 audiodevice_sample_rate) +{ + // Note: Even though we only check client state here, we will probably close the client much earlier. + if (!is_connected()) + return false; + + if (m_paused) + return false; + + if (m_in_chunk_location >= m_current_audio_chunk.size()) { + auto result = m_buffer->dequeue(); + if (result.is_error()) { + if (result.error() == Audio::AudioQueue::QueueStatus::Empty) { + dbgln_if(AUDIO_DEBUG, "Audio client {} can't keep up!", m_client->client_id()); + } + + return false; + } + // FIXME: Our resampler and the way we resample here are bad. + // Ideally, we should both do perfect band-corrected resampling, + // as well as carry resampling state over between buffers. + auto attempted_resample = Audio::ResampleHelper { + m_sample_rate == 0 ? audiodevice_sample_rate : m_sample_rate, audiodevice_sample_rate + } + .try_resample(result.release_value()); + if (attempted_resample.is_error()) + return false; + + // If the sample rate changes underneath us, we will still play the existing buffer unchanged until we're done. + // This is not a significant problem since the buffers are very small (~100 samples or less). + m_current_audio_chunk = attempted_resample.release_value(); + m_in_chunk_location = 0; + } + + sample = m_current_audio_chunk[m_in_chunk_location++]; + + return true; +} + +void ClientAudioStream::set_buffer(OwnPtr buffer) +{ + m_buffer = move(buffer); +} + +void ClientAudioStream::clear() +{ + ErrorOr, Audio::AudioQueue::QueueStatus> result = Audio::AudioQueue::QueueStatus::Invalid; + do { + result = m_buffer->dequeue(); + } while (!result.is_error() || result.error() != Audio::AudioQueue::QueueStatus::Empty); +} + +void ClientAudioStream::set_paused(bool paused) +{ + m_paused = paused; +} + +FadingProperty& ClientAudioStream::volume() +{ + return m_volume; +} + +double ClientAudioStream::volume() const +{ + return m_volume; +} + +void ClientAudioStream::set_volume(double const volume) +{ + m_volume = volume; +} + +bool ClientAudioStream::is_muted() const +{ + return m_muted; +} + +void ClientAudioStream::set_muted(bool muted) +{ + m_muted = muted; +} + +u32 ClientAudioStream::sample_rate() const +{ + return m_sample_rate; +} + +void ClientAudioStream::set_sample_rate(u32 sample_rate) +{ + dbgln_if(AUDIO_DEBUG, "queue {} got sample rate {} Hz", m_client->client_id(), sample_rate); + m_sample_rate = sample_rate; +} + +} diff --git a/Userland/Services/AudioServer/ClientAudioStream.h b/Userland/Services/AudioServer/ClientAudioStream.h new file mode 100644 index 0000000000..06e61f2d3e --- /dev/null +++ b/Userland/Services/AudioServer/ClientAudioStream.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018-2022, the SerenityOS developers. + * Copyright (c) 2021-2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "ConnectionFromClient.h" +#include "FadingProperty.h" +#include +#include +#include +#include +#include +#include + +namespace AudioServer { + +class ClientAudioStream : public RefCounted { +public: + explicit ClientAudioStream(ConnectionFromClient&); + ~ClientAudioStream() = default; + + bool get_next_sample(Audio::Sample& sample, u32 audiodevice_sample_rate); + void clear(); + + bool is_connected() const; + + ConnectionFromClient* client(); + + void set_buffer(OwnPtr buffer); + + void set_paused(bool paused); + FadingProperty& volume(); + double volume() const; + void set_volume(double const volume); + bool is_muted() const; + void set_muted(bool muted); + u32 sample_rate() const; + void set_sample_rate(u32 sample_rate); + +private: + OwnPtr m_buffer; + Vector m_current_audio_chunk; + size_t m_in_chunk_location; + + bool m_paused { true }; + bool m_muted { false }; + u32 m_sample_rate; + + WeakPtr m_client; + FadingProperty m_volume { 1 }; +}; + +} diff --git a/Userland/Services/AudioServer/FadingProperty.h b/Userland/Services/AudioServer/FadingProperty.h index fb37dffd3d..bdee2231db 100644 --- a/Userland/Services/AudioServer/FadingProperty.h +++ b/Userland/Services/AudioServer/FadingProperty.h @@ -6,7 +6,6 @@ #pragma once -#include "Mixer.h" namespace AudioServer { // This is in buffer counts. diff --git a/Userland/Services/AudioServer/Mixer.cpp b/Userland/Services/AudioServer/Mixer.cpp index d3f34d8be8..79a3d10ad6 100644 --- a/Userland/Services/AudioServer/Mixer.cpp +++ b/Userland/Services/AudioServer/Mixer.cpp @@ -187,9 +187,4 @@ void Mixer::request_setting_sync() } } -ClientAudioStream::ClientAudioStream(ConnectionFromClient& client) - : m_client(client) -{ -} - } diff --git a/Userland/Services/AudioServer/Mixer.h b/Userland/Services/AudioServer/Mixer.h index d31b3b2cf9..af80f6da6d 100644 --- a/Userland/Services/AudioServer/Mixer.h +++ b/Userland/Services/AudioServer/Mixer.h @@ -1,12 +1,13 @@ /* * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2021-2022, kleines Filmröllchen + * Copyright (c) 2021-2023, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include "ClientAudioStream.h" #include "ConnectionFromClient.h" #include "FadingProperty.h" #include @@ -24,7 +25,6 @@ #include #include #include -#include namespace AudioServer { @@ -36,93 +36,6 @@ constexpr size_t HARDWARE_BUFFER_SIZE = 512; // The hardware buffer size in bytes; there's two channels of 16-bit samples. constexpr size_t HARDWARE_BUFFER_SIZE_BYTES = HARDWARE_BUFFER_SIZE * 2 * sizeof(i16); -class ConnectionFromClient; - -class ClientAudioStream : public RefCounted { -public: - explicit ClientAudioStream(ConnectionFromClient&); - ~ClientAudioStream() = default; - - bool get_next_sample(Audio::Sample& sample, u32 audiodevice_sample_rate) - { - // Note: Even though we only check client state here, we will probably close the client much earlier. - if (!is_connected()) - return false; - - if (m_paused) - return false; - - if (m_in_chunk_location >= m_current_audio_chunk.size()) { - auto result = m_buffer->dequeue(); - if (result.is_error()) { - if (result.error() == Audio::AudioQueue::QueueStatus::Empty) { - dbgln_if(AUDIO_DEBUG, "Audio client {} can't keep up!", m_client->client_id()); - } - - return false; - } - // FIXME: Our resampler and the way we resample here are bad. - // Ideally, we should both do perfect band-corrected resampling, - // as well as carry resampling state over between buffers. - auto attempted_resample = Audio::ResampleHelper { - m_sample_rate == 0 ? audiodevice_sample_rate : m_sample_rate, audiodevice_sample_rate - } - .try_resample(result.release_value()); - if (attempted_resample.is_error()) - return false; - - // If the sample rate changes underneath us, we will still play the existing buffer unchanged until we're done. - // This is not a significant problem since the buffers are very small (~100 samples or less). - m_current_audio_chunk = attempted_resample.release_value(); - m_in_chunk_location = 0; - } - - sample = m_current_audio_chunk[m_in_chunk_location++]; - - return true; - } - - bool is_connected() const { return m_client && m_client->is_open(); } - - ConnectionFromClient* client() { return m_client.ptr(); } - - void set_buffer(OwnPtr buffer) { m_buffer = move(buffer); } - - void clear() - { - ErrorOr, Audio::AudioQueue::QueueStatus> result = Audio::AudioQueue::QueueStatus::Invalid; - do { - result = m_buffer->dequeue(); - } while (!result.is_error() || result.error() != Audio::AudioQueue::QueueStatus::Empty); - } - - void set_paused(bool paused) { m_paused = paused; } - - FadingProperty& volume() { return m_volume; } - double volume() const { return m_volume; } - void set_volume(double const volume) { m_volume = volume; } - bool is_muted() const { return m_muted; } - void set_muted(bool muted) { m_muted = muted; } - u32 sample_rate() const { return m_sample_rate; } - void set_sample_rate(u32 sample_rate) - { - dbgln_if(AUDIO_DEBUG, "queue {} got sample rate {} Hz", m_client->client_id(), sample_rate); - m_sample_rate = sample_rate; - } - -private: - OwnPtr m_buffer; - Vector m_current_audio_chunk; - size_t m_in_chunk_location; - - bool m_paused { true }; - bool m_muted { false }; - u32 m_sample_rate; - - WeakPtr m_client; - FadingProperty m_volume { 1 }; -}; - class Mixer : public Core::EventReceiver { C_OBJECT_ABSTRACT(Mixer) public: