diff --git a/Base/home/anon/.config/SystemServer.ini b/Base/home/anon/.config/SystemServer.ini index 8eed0436da..7f6c3e7cb2 100644 --- a/Base/home/anon/.config/SystemServer.ini +++ b/Base/home/anon/.config/SystemServer.ini @@ -58,7 +58,7 @@ Priority=low KeepAlive=true [AudioServer] -Socket=/tmp/session/%sid/portal/audio +Socket=/tmp/session/%sid/portal/audio,/tmp/session/%sid/portal/audiomanager Priority=high KeepAlive=true SystemModes=text,graphical diff --git a/Userland/Applets/Audio/main.cpp b/Userland/Applets/Audio/main.cpp index 0d3a402be6..52938f28c3 100644 --- a/Userland/Applets/Audio/main.cpp +++ b/Userland/Applets/Audio/main.cpp @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include @@ -45,14 +45,14 @@ public: { 0, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/audio-volume-zero.png"sv)) }, { 0, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/audio-volume-muted.png"sv)) } } }; - auto audio_client = TRY(Audio::ConnectionToServer::try_create()); + auto audio_client = TRY(Audio::ConnectionToManagerServer::try_create()); NonnullRefPtr audio_widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AudioWidget(move(audio_client), move(volume_level_bitmaps)))); TRY(audio_widget->try_initialize_graphical_elements()); return audio_widget; } private: - AudioWidget(NonnullRefPtr audio_client, Array volume_level_bitmaps) + AudioWidget(NonnullRefPtr audio_client, Array volume_level_bitmaps) : m_audio_client(move(audio_client)) , m_volume_level_bitmaps(move(volume_level_bitmaps)) { @@ -217,7 +217,7 @@ private: height); } - NonnullRefPtr m_audio_client; + NonnullRefPtr m_audio_client; Array m_volume_level_bitmaps; bool m_show_percent { false }; bool m_audio_muted { false }; @@ -236,7 +236,7 @@ ErrorOr serenity_main(Main::Arguments arguments) auto app = TRY(GUI::Application::create(arguments)); Config::pledge_domain("AudioApplet"); - TRY(Core::System::unveil("/tmp/session/%sid/portal/audio", "rw")); + TRY(Core::System::unveil("/tmp/session/%sid/portal/audiomanager", "rw")); TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil(nullptr, nullptr)); diff --git a/Userland/Libraries/LibAudio/CMakeLists.txt b/Userland/Libraries/LibAudio/CMakeLists.txt index b15be38990..d41ce36db0 100644 --- a/Userland/Libraries/LibAudio/CMakeLists.txt +++ b/Userland/Libraries/LibAudio/CMakeLists.txt @@ -16,9 +16,12 @@ set(SOURCES if (SERENITYOS) list(APPEND SOURCES ConnectionToServer.cpp) + list(APPEND SOURCES ConnectionToManagerServer.cpp) set(GENERATED_SOURCES ../../Services/AudioServer/AudioClientEndpoint.h ../../Services/AudioServer/AudioServerEndpoint.h + ../../Services/AudioServer/AudioManagerClientEndpoint.h + ../../Services/AudioServer/AudioManagerServerEndpoint.h ) endif() diff --git a/Userland/Libraries/LibAudio/ConnectionToManagerServer.cpp b/Userland/Libraries/LibAudio/ConnectionToManagerServer.cpp new file mode 100644 index 0000000000..01b3cf2e27 --- /dev/null +++ b/Userland/Libraries/LibAudio/ConnectionToManagerServer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ConnectionToManagerServer.h" + +namespace Audio { + +ConnectionToManagerServer::ConnectionToManagerServer(NonnullOwnPtr socket) + : IPC::ConnectionToServer(*this, move(socket)) +{ +} + +ConnectionToManagerServer::~ConnectionToManagerServer() +{ + die(); +} + +void ConnectionToManagerServer::die() { } + +void ConnectionToManagerServer::main_mix_muted_state_changed(bool muted) +{ + if (on_main_mix_muted_state_change) + on_main_mix_muted_state_change(muted); +} + +void ConnectionToManagerServer::main_mix_volume_changed(double volume) +{ + if (on_main_mix_volume_change) + on_main_mix_volume_change(volume); +} + +void ConnectionToManagerServer::device_sample_rate_changed(u32 sample_rate) +{ + if (on_device_sample_rate_change) + on_device_sample_rate_change(sample_rate); +} + +} diff --git a/Userland/Libraries/LibAudio/ConnectionToManagerServer.h b/Userland/Libraries/LibAudio/ConnectionToManagerServer.h new file mode 100644 index 0000000000..d9c4786f15 --- /dev/null +++ b/Userland/Libraries/LibAudio/ConnectionToManagerServer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Audio { + +class ConnectionToManagerServer final + : public IPC::ConnectionToServer + , public AudioManagerClientEndpoint { + IPC_CLIENT_CONNECTION(ConnectionToManagerServer, "/tmp/session/%sid/portal/audiomanager"sv) +public: + virtual ~ConnectionToManagerServer() override; + virtual void die() override; + + virtual void main_mix_volume_changed(double volume) override; + virtual void main_mix_muted_state_changed(bool muted) override; + virtual void device_sample_rate_changed(u32 sample_rate) override; + + Function on_main_mix_muted_state_change; + Function on_main_mix_volume_change; + Function on_device_sample_rate_change; + +private: + ConnectionToManagerServer(NonnullOwnPtr); +}; + +} diff --git a/Userland/Libraries/LibAudio/ConnectionToServer.cpp b/Userland/Libraries/LibAudio/ConnectionToServer.cpp index 8ca968a144..c055b5c0ab 100644 --- a/Userland/Libraries/LibAudio/ConnectionToServer.cpp +++ b/Userland/Libraries/LibAudio/ConnectionToServer.cpp @@ -142,18 +142,6 @@ size_t ConnectionToServer::remaining_buffers() const return m_buffer->size() - m_buffer->weak_remaining_capacity(); } -void ConnectionToServer::main_mix_muted_state_changed(bool muted) -{ - if (on_main_mix_muted_state_change) - on_main_mix_muted_state_change(muted); -} - -void ConnectionToServer::main_mix_volume_changed(double volume) -{ - if (on_main_mix_volume_change) - on_main_mix_volume_change(volume); -} - void ConnectionToServer::client_volume_changed(double volume) { if (on_client_volume_change) diff --git a/Userland/Libraries/LibAudio/ConnectionToServer.h b/Userland/Libraries/LibAudio/ConnectionToServer.h index 7bab23c407..d7757765d8 100644 --- a/Userland/Libraries/LibAudio/ConnectionToServer.h +++ b/Userland/Libraries/LibAudio/ConnectionToServer.h @@ -57,15 +57,11 @@ public: virtual void die() override; - Function on_main_mix_muted_state_change; - Function on_main_mix_volume_change; Function on_client_volume_change; private: ConnectionToServer(NonnullOwnPtr); - virtual void main_mix_muted_state_changed(bool) override; - virtual void main_mix_volume_changed(double) override; virtual void client_volume_changed(double) override; // We use this to perform the audio enqueuing on the background thread's event loop diff --git a/Userland/Services/AudioServer/AudioClient.ipc b/Userland/Services/AudioServer/AudioClient.ipc index df97c95709..8f0188fbb9 100644 --- a/Userland/Services/AudioServer/AudioClient.ipc +++ b/Userland/Services/AudioServer/AudioClient.ipc @@ -2,7 +2,5 @@ endpoint AudioClient { - main_mix_muted_state_changed(bool muted) =| - main_mix_volume_changed(double volume) =| client_volume_changed(double volume) =| } diff --git a/Userland/Services/AudioServer/AudioManagerClient.ipc b/Userland/Services/AudioServer/AudioManagerClient.ipc new file mode 100644 index 0000000000..34e752982e --- /dev/null +++ b/Userland/Services/AudioServer/AudioManagerClient.ipc @@ -0,0 +1,6 @@ +endpoint AudioManagerClient +{ + main_mix_muted_state_changed(bool muted) =| + main_mix_volume_changed(double volume) =| + device_sample_rate_changed(u32 sample_rate) =| +} diff --git a/Userland/Services/AudioServer/AudioManagerServer.ipc b/Userland/Services/AudioServer/AudioManagerServer.ipc new file mode 100644 index 0000000000..d1fd62b8fa --- /dev/null +++ b/Userland/Services/AudioServer/AudioManagerServer.ipc @@ -0,0 +1,11 @@ +endpoint AudioManagerServer +{ + set_main_mix_muted(bool muted) => () + is_main_mix_muted() => (bool muted) + get_main_mix_volume() => (double volume) + set_main_mix_volume(double volume) => () + + // Audio device + set_device_sample_rate(u32 sample_rate) => () + get_device_sample_rate() => (u32 sample_rate) +} diff --git a/Userland/Services/AudioServer/AudioServer.ipc b/Userland/Services/AudioServer/AudioServer.ipc index 9d612a56b5..e52694de55 100644 --- a/Userland/Services/AudioServer/AudioServer.ipc +++ b/Userland/Services/AudioServer/AudioServer.ipc @@ -3,18 +3,12 @@ endpoint AudioServer { - // Mixer functions - set_main_mix_muted(bool muted) => () - is_main_mix_muted() => (bool muted) set_self_muted(bool muted) => () is_self_muted() => (bool muted) - get_main_mix_volume() => (double volume) - set_main_mix_volume(double volume) => () get_self_volume() => (double volume) set_self_volume(double volume) => () - // Audio device - set_sample_rate(u32 sample_rate) => () + // FIXME: Decouple client sample rate from device sample rate, then remove this API get_sample_rate() => (u32 sample_rate) // Buffer playback diff --git a/Userland/Services/AudioServer/CMakeLists.txt b/Userland/Services/AudioServer/CMakeLists.txt index 827ddaaf1d..1aaa2f0b38 100644 --- a/Userland/Services/AudioServer/CMakeLists.txt +++ b/Userland/Services/AudioServer/CMakeLists.txt @@ -6,9 +6,12 @@ serenity_component( compile_ipc(AudioServer.ipc AudioServerEndpoint.h) compile_ipc(AudioClient.ipc AudioClientEndpoint.h) +compile_ipc(AudioManagerClient.ipc AudioManagerClientEndpoint.h) +compile_ipc(AudioManagerServer.ipc AudioManagerServerEndpoint.h) set(SOURCES ConnectionFromClient.cpp + ConnectionFromManagerClient.cpp Mixer.cpp main.cpp ) @@ -16,6 +19,8 @@ set(SOURCES set(GENERATED_SOURCES AudioServerEndpoint.h AudioClientEndpoint.h + AudioManagerClientEndpoint.h + AudioManagerServerEndpoint.h ) serenity_bin(AudioServer) diff --git a/Userland/Services/AudioServer/ConnectionFromClient.cpp b/Userland/Services/AudioServer/ConnectionFromClient.cpp index 9afaa8bf9d..15d7014d34 100644 --- a/Userland/Services/AudioServer/ConnectionFromClient.cpp +++ b/Userland/Services/AudioServer/ConnectionFromClient.cpp @@ -47,41 +47,16 @@ void ConnectionFromClient::set_buffer(Audio::AudioQueue const& buffer) m_queue->set_buffer(make(move(const_cast(buffer)))); } -void ConnectionFromClient::did_change_main_mix_muted_state(Badge, bool muted) -{ - async_main_mix_muted_state_changed(muted); -} - -void ConnectionFromClient::did_change_main_mix_volume(Badge, double volume) -{ - async_main_mix_volume_changed(volume); -} - void ConnectionFromClient::did_change_client_volume(Badge, double volume) { async_client_volume_changed(volume); } -Messages::AudioServer::GetMainMixVolumeResponse ConnectionFromClient::get_main_mix_volume() -{ - return m_mixer.main_volume(); -} - -void ConnectionFromClient::set_main_mix_volume(double volume) -{ - m_mixer.set_main_volume(volume); -} - Messages::AudioServer::GetSampleRateResponse ConnectionFromClient::get_sample_rate() { return { m_mixer.audiodevice_get_sample_rate() }; } -void ConnectionFromClient::set_sample_rate(u32 sample_rate) -{ - m_mixer.audiodevice_set_sample_rate(sample_rate); -} - Messages::AudioServer::GetSelfVolumeResponse ConnectionFromClient::get_self_volume() { return m_queue->volume().target(); @@ -111,16 +86,6 @@ void ConnectionFromClient::clear_buffer() m_queue->clear(); } -Messages::AudioServer::IsMainMixMutedResponse ConnectionFromClient::is_main_mix_muted() -{ - return m_mixer.is_muted(); -} - -void ConnectionFromClient::set_main_mix_muted(bool muted) -{ - m_mixer.set_muted(muted); -} - Messages::AudioServer::IsSelfMutedResponse ConnectionFromClient::is_self_muted() { if (m_queue) diff --git a/Userland/Services/AudioServer/ConnectionFromClient.h b/Userland/Services/AudioServer/ConnectionFromClient.h index 4bc85c83e3..148b0cd1a8 100644 --- a/Userland/Services/AudioServer/ConnectionFromClient.h +++ b/Userland/Services/AudioServer/ConnectionFromClient.h @@ -24,8 +24,6 @@ public: ~ConnectionFromClient() override = default; void did_change_client_volume(Badge, double volume); - void did_change_main_mix_muted_state(Badge, bool muted); - void did_change_main_mix_volume(Badge, double volume); virtual void die() override; @@ -34,19 +32,15 @@ public: private: explicit ConnectionFromClient(NonnullOwnPtr, int client_id, Mixer& mixer); - virtual Messages::AudioServer::GetMainMixVolumeResponse get_main_mix_volume() override; - virtual void set_main_mix_volume(double) override; virtual Messages::AudioServer::GetSelfVolumeResponse get_self_volume() override; virtual void set_self_volume(double) override; virtual void set_buffer(Audio::AudioQueue const&) override; virtual void clear_buffer() override; virtual void start_playback() override; virtual void pause_playback() override; - virtual Messages::AudioServer::IsMainMixMutedResponse is_main_mix_muted() override; - virtual void set_main_mix_muted(bool) override; virtual Messages::AudioServer::IsSelfMutedResponse is_self_muted() override; virtual void set_self_muted(bool) override; - virtual void set_sample_rate(u32 sample_rate) override; + // FIXME: Decouple client sample rate from device sample rate, then remove this endpoint virtual Messages::AudioServer::GetSampleRateResponse get_sample_rate() override; Mixer& m_mixer; diff --git a/Userland/Services/AudioServer/ConnectionFromManagerClient.cpp b/Userland/Services/AudioServer/ConnectionFromManagerClient.cpp new file mode 100644 index 0000000000..c43d520f79 --- /dev/null +++ b/Userland/Services/AudioServer/ConnectionFromManagerClient.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ConnectionFromManagerClient.h" + +namespace AudioServer { + +static HashMap> s_connections; + +ConnectionFromManagerClient::ConnectionFromManagerClient(NonnullOwnPtr client_socket, int client_id, Mixer& mixer) + : IPC::ConnectionFromClient(*this, move(client_socket), client_id) + , m_mixer(mixer) +{ + s_connections.set(client_id, *this); +} + +void ConnectionFromManagerClient::die() +{ + s_connections.remove(client_id()); +} + +void ConnectionFromManagerClient::for_each(Function callback) +{ + Vector> connections; + for (auto& it : s_connections) + connections.append(*it.value); + for (auto& connection : connections) + callback(connection); +} + +void ConnectionFromManagerClient::did_change_main_mix_muted_state(Badge, bool muted) +{ + async_main_mix_muted_state_changed(muted); +} + +void ConnectionFromManagerClient::did_change_main_mix_volume(Badge, double volume) +{ + async_main_mix_volume_changed(volume); +} + +Messages::AudioManagerServer::GetMainMixVolumeResponse ConnectionFromManagerClient::get_main_mix_volume() +{ + return m_mixer.main_volume(); +} + +void ConnectionFromManagerClient::set_main_mix_volume(double volume) +{ + m_mixer.set_main_volume(volume); +} + +Messages::AudioManagerServer::GetDeviceSampleRateResponse ConnectionFromManagerClient::get_device_sample_rate() +{ + return { m_mixer.audiodevice_get_sample_rate() }; +} + +void ConnectionFromManagerClient::set_device_sample_rate(u32 sample_rate) +{ + m_mixer.audiodevice_set_sample_rate(sample_rate); +} + +Messages::AudioManagerServer::IsMainMixMutedResponse ConnectionFromManagerClient::is_main_mix_muted() +{ + return m_mixer.is_muted(); +} + +void ConnectionFromManagerClient::set_main_mix_muted(bool muted) +{ + m_mixer.set_muted(muted); +} + +} diff --git a/Userland/Services/AudioServer/ConnectionFromManagerClient.h b/Userland/Services/AudioServer/ConnectionFromManagerClient.h new file mode 100644 index 0000000000..05841ab387 --- /dev/null +++ b/Userland/Services/AudioServer/ConnectionFromManagerClient.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AudioServer { + +class ConnectionFromManagerClient final : public IPC::ConnectionFromClient { + C_OBJECT(ConnectionFromManagerClient) + +public: + ~ConnectionFromManagerClient() override = default; + + virtual void die() override; + + static void for_each(Function); + + void did_change_main_mix_muted_state(Badge, bool muted); + void did_change_main_mix_volume(Badge, double volume); + +private: + ConnectionFromManagerClient(NonnullOwnPtr client_socket, int client_id, Mixer& mixer); + + virtual Messages::AudioManagerServer::GetMainMixVolumeResponse get_main_mix_volume() override; + virtual void set_main_mix_volume(double) override; + virtual Messages::AudioManagerServer::IsMainMixMutedResponse is_main_mix_muted() override; + virtual void set_main_mix_muted(bool) override; + virtual void set_device_sample_rate(u32 sample_rate) override; + virtual Messages::AudioManagerServer::GetDeviceSampleRateResponse get_device_sample_rate() override; + + Mixer& m_mixer; +}; + +} diff --git a/Userland/Services/AudioServer/Mixer.cpp b/Userland/Services/AudioServer/Mixer.cpp index 2047a59de8..d30593dbb0 100644 --- a/Userland/Services/AudioServer/Mixer.cpp +++ b/Userland/Services/AudioServer/Mixer.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -127,7 +128,7 @@ void Mixer::set_main_volume(double volume) m_config->write_num_entry("Master", "Volume", static_cast(volume * 100)); request_setting_sync(); - ConnectionFromClient::for_each([&](ConnectionFromClient& client) { + ConnectionFromManagerClient::for_each([&](auto& client) { client.did_change_main_mix_volume({}, main_volume()); }); } @@ -141,7 +142,7 @@ void Mixer::set_muted(bool muted) m_config->write_bool_entry("Master", "Mute", m_muted); request_setting_sync(); - ConnectionFromClient::for_each([muted](ConnectionFromClient& client) { + ConnectionFromManagerClient::for_each([muted](auto& client) { client.did_change_main_mix_muted_state({}, muted); }); } diff --git a/Userland/Services/AudioServer/Mixer.h b/Userland/Services/AudioServer/Mixer.h index a3aa8ea996..8c00fd3678 100644 --- a/Userland/Services/AudioServer/Mixer.h +++ b/Userland/Services/AudioServer/Mixer.h @@ -44,6 +44,10 @@ public: bool get_next_sample(Audio::Sample& sample) { + // 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; @@ -52,11 +56,6 @@ public: 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()); - // Note: Even though we only check client state here, we will probably close the client much earlier. - if (!m_client->is_open()) { - dbgln("Client socket {} has closed, closing audio server connection.", m_client->client_id()); - m_client->shutdown(); - } } return false; diff --git a/Userland/Services/AudioServer/main.cpp b/Userland/Services/AudioServer/main.cpp index b2d11fdeb5..186fd5cfd7 100644 --- a/Userland/Services/AudioServer/main.cpp +++ b/Userland/Services/AudioServer/main.cpp @@ -5,6 +5,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "ConnectionFromClient.h" +#include "ConnectionFromManagerClient.h" #include "Mixer.h" #include #include @@ -23,7 +25,7 @@ ErrorOr serenity_main(Main::Arguments) Core::EventLoop event_loop; auto mixer = TRY(AudioServer::Mixer::try_create(config)); auto server = TRY(Core::LocalServer::try_create()); - TRY(server->take_over_from_system_server()); + TRY(server->take_over_from_system_server("/tmp/session/%sid/portal/audio")); server->on_accept = [&](NonnullOwnPtr client_socket) { static int s_next_client_id = 0; @@ -31,8 +33,16 @@ ErrorOr serenity_main(Main::Arguments) (void)IPC::new_client_connection(move(client_socket), client_id, *mixer); }; + auto manager_server = TRY(Core::LocalServer::try_create()); + TRY(manager_server->take_over_from_system_server("/tmp/session/%sid/portal/audiomanager")); + + manager_server->on_accept = [&](NonnullOwnPtr client_socket) { + static int s_next_client_id = 0; + int client_id = ++s_next_client_id; + (void)IPC::new_client_connection(move(client_socket), client_id, *mixer); + }; + TRY(Core::System::pledge("stdio recvfd thread accept cpath rpath wpath")); - TRY(Core::System::unveil(nullptr, nullptr)); return event_loop.exec(); } diff --git a/Userland/Utilities/asctl.cpp b/Userland/Utilities/asctl.cpp index 4184683fd9..4707772e09 100644 --- a/Userland/Utilities/asctl.cpp +++ b/Userland/Utilities/asctl.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -27,8 +27,7 @@ enum AudioVariable : u32 { ErrorOr serenity_main(Main::Arguments arguments) { Core::EventLoop loop; - auto audio_client = TRY(Audio::ConnectionToServer::try_create()); - audio_client->async_pause_playback(); + auto audio_client = TRY(Audio::ConnectionToManagerServer::try_create()); StringView command; Vector command_arguments; @@ -85,7 +84,7 @@ ErrorOr serenity_main(Main::Arguments arguments) break; } case AudioVariable::SampleRate: { - u32 sample_rate = audio_client->get_sample_rate(); + u32 sample_rate = audio_client->get_device_sample_rate(); if (human_mode) outln("Sample rate: {:5d} Hz", sample_rate); else @@ -155,7 +154,7 @@ ErrorOr serenity_main(Main::Arguments arguments) } case AudioVariable::SampleRate: { int& sample_rate = to_set.value.get(); - audio_client->set_sample_rate(sample_rate); + audio_client->set_device_sample_rate(sample_rate); break; } }