From d1b0143ba50ba8c3a09c68fd527f0c4a31eb58c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sun, 25 Jul 2021 20:54:09 +0200 Subject: [PATCH] AudioServer: Persist audio settings with a config file AudioServer loads its settings, currently volume and mute state, from a user config file "Audio.ini". Additionally, the current settings are stored every ten seconds, if necessary. This allows for persistent audio settings in between boots. --- Userland/Services/AudioServer/Mixer.cpp | 31 ++++++++++++++++++++++++- Userland/Services/AudioServer/Mixer.h | 13 ++++++++++- Userland/Services/AudioServer/main.cpp | 18 ++++++++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Userland/Services/AudioServer/Mixer.cpp b/Userland/Services/AudioServer/Mixer.cpp index 514ad6cfb5..66d978c62f 100644 --- a/Userland/Services/AudioServer/Mixer.cpp +++ b/Userland/Services/AudioServer/Mixer.cpp @@ -1,21 +1,25 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ +#include "Mixer.h" #include #include #include #include #include +#include +#include #include namespace AudioServer { u8 Mixer::m_zero_filled_buffer[4096]; -Mixer::Mixer() +Mixer::Mixer(NonnullRefPtr config) : m_device(Core::File::construct("/dev/audio", this)) , m_sound_thread(Threading::Thread::construct( [this] { @@ -23,6 +27,7 @@ Mixer::Mixer() return 0; }, "AudioServer[mixer]")) + , m_config(move(config)) { if (!m_device->open(Core::OpenMode::WriteOnly)) { dbgln("Can't open audio device: {}", m_device->error_string()); @@ -32,6 +37,9 @@ Mixer::Mixer() pthread_mutex_init(&m_pending_mutex, nullptr); pthread_cond_init(&m_pending_cond, nullptr); + m_muted = m_config->read_bool_entry("Master", "Mute", false); + m_main_volume = m_config->read_num_entry("Master", "Volume", 100); + m_sound_thread->start(); } @@ -119,6 +127,10 @@ void Mixer::set_main_volume(int volume) m_main_volume = 200; else m_main_volume = volume; + + m_config->write_num_entry("Master", "Volume", volume); + request_setting_sync(); + ClientConnection::for_each([&](ClientConnection& client) { client.did_change_main_mix_volume({}, m_main_volume); }); @@ -129,11 +141,28 @@ void Mixer::set_muted(bool muted) if (m_muted == muted) return; m_muted = muted; + + m_config->write_bool_entry("Master", "Mute", m_muted); + request_setting_sync(); + ClientConnection::for_each([muted](ClientConnection& client) { client.did_change_muted_state({}, muted); }); } +void Mixer::request_setting_sync() +{ + if (m_config_write_timer.is_null() || !m_config_write_timer->is_active()) { + m_config_write_timer = Core::Timer::create_single_shot( + AUDIO_CONFIG_WRITE_INTERVAL, + [this] { + m_config->sync(); + }, + this); + m_config_write_timer->start(); + } +} + BufferQueue::BufferQueue(ClientConnection& client) : m_client(client) { diff --git a/Userland/Services/AudioServer/Mixer.h b/Userland/Services/AudioServer/Mixer.h index 74ff92ee2a..4465760062 100644 --- a/Userland/Services/AudioServer/Mixer.h +++ b/Userland/Services/AudioServer/Mixer.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -93,7 +95,7 @@ private: class Mixer : public Core::Object { C_OBJECT(Mixer) public: - Mixer(); + Mixer(NonnullRefPtr config); virtual ~Mixer() override; NonnullRefPtr create_queue(ClientConnection&); @@ -105,6 +107,8 @@ public: void set_muted(bool); private: + void request_setting_sync(); + Vector> m_pending_mixing; Atomic m_added_queue { false }; pthread_mutex_t m_pending_mutex; @@ -117,8 +121,15 @@ private: bool m_muted { false }; int m_main_volume { 100 }; + NonnullRefPtr m_config; + RefPtr m_config_write_timer; + static u8 m_zero_filled_buffer[4096]; void mix(); }; + +// Interval in ms when the server tries to save its configuration to disk. +constexpr unsigned AUDIO_CONFIG_WRITE_INTERVAL = 2000; + } diff --git a/Userland/Services/AudioServer/main.cpp b/Userland/Services/AudioServer/main.cpp index 10ccce2e7b..e2f38f7652 100644 --- a/Userland/Services/AudioServer/main.cpp +++ b/Userland/Services/AudioServer/main.cpp @@ -1,10 +1,13 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ #include "Mixer.h" +#include +#include #include int main(int, char**) @@ -14,8 +17,19 @@ int main(int, char**) return 1; } + auto config = Core::ConfigFile::get_for_app("Audio"); + if (unveil(config->filename().characters(), "rwc") < 0) { + perror("unveil"); + return 1; + } + if (unveil("/dev/audio", "wc") < 0) { + perror("unveil"); + return 1; + } + unveil(nullptr, nullptr); + Core::EventLoop event_loop; - AudioServer::Mixer mixer; + AudioServer::Mixer mixer { config }; auto server = Core::LocalServer::construct(); bool ok = server->take_over_from_system_server(); @@ -31,7 +45,7 @@ int main(int, char**) IPC::new_client_connection(client_socket.release_nonnull(), client_id, mixer); }; - if (pledge("stdio recvfd thread accept", nullptr) < 0) { + if (pledge("stdio recvfd thread accept cpath rpath wpath", nullptr) < 0) { perror("pledge"); return 1; }