From 107011f1190004b3a18f395c145ee6211301622c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 22 Nov 2019 21:44:02 +0100 Subject: [PATCH] AudioServer: Allow muting the system audio This patch adds muting to ASMixer, which works by substituting what we would normally send to the sound card with zero-filled memory instead. We do it this way to ensure that the queued sample buffers keep getting played (silently.) This is obviously not the perfect way of doing this, and in the future we should improve on this, and also find a way to utilize any hardware mixing functions in the sound card. --- Libraries/LibAudio/AClientConnection.cpp | 10 ++++++ Libraries/LibAudio/AClientConnection.h | 3 ++ Servers/AudioServer/ASClientConnection.cpp | 16 ++++++++-- Servers/AudioServer/ASClientConnection.h | 2 ++ Servers/AudioServer/ASMixer.cpp | 37 ++++++++++++++-------- Servers/AudioServer/ASMixer.h | 6 ++++ Servers/AudioServer/AudioServer.ipc | 2 ++ Userland/avol.cpp | 11 +++++++ 8 files changed, 72 insertions(+), 15 deletions(-) diff --git a/Libraries/LibAudio/AClientConnection.cpp b/Libraries/LibAudio/AClientConnection.cpp index 66f107b933d..6ca9c2e2c04 100644 --- a/Libraries/LibAudio/AClientConnection.cpp +++ b/Libraries/LibAudio/AClientConnection.cpp @@ -32,6 +32,16 @@ bool AClientConnection::try_enqueue(const ABuffer& buffer) return response->success(); } +bool AClientConnection::get_muted() +{ + return send_sync()->muted(); +} + +void AClientConnection::set_muted(bool muted) +{ + send_sync(muted); +} + int AClientConnection::get_main_mix_volume() { return send_sync()->volume(); diff --git a/Libraries/LibAudio/AClientConnection.h b/Libraries/LibAudio/AClientConnection.h index ff0e6f59b2a..3d2089a57d2 100644 --- a/Libraries/LibAudio/AClientConnection.h +++ b/Libraries/LibAudio/AClientConnection.h @@ -14,6 +14,9 @@ public: void enqueue(const ABuffer&); bool try_enqueue(const ABuffer&); + bool get_muted(); + void set_muted(bool); + int get_main_mix_volume(); void set_main_mix_volume(int); diff --git a/Servers/AudioServer/ASClientConnection.cpp b/Servers/AudioServer/ASClientConnection.cpp index 7bfe1df067f..47595c458df 100644 --- a/Servers/AudioServer/ASClientConnection.cpp +++ b/Servers/AudioServer/ASClientConnection.cpp @@ -104,9 +104,21 @@ OwnPtr ASClientConnection::handle(const AudioS return make(); } -OwnPtr ASClientConnection::handle(const AudioServer::GetPlayingBuffer&){ +OwnPtr ASClientConnection::handle(const AudioServer::GetPlayingBuffer&) +{ int id = -1; - if(m_queue) + if (m_queue) id = m_queue->get_playing_buffer(); return make(id); } + +OwnPtr ASClientConnection::handle(const AudioServer::GetMuted&) +{ + return make(m_mixer.is_muted()); +} + +OwnPtr ASClientConnection::handle(const AudioServer::SetMuted& message) +{ + m_mixer.set_muted(message.muted()); + return make(); +} diff --git a/Servers/AudioServer/ASClientConnection.h b/Servers/AudioServer/ASClientConnection.h index d3946a834f3..b23886dcbad 100644 --- a/Servers/AudioServer/ASClientConnection.h +++ b/Servers/AudioServer/ASClientConnection.h @@ -27,6 +27,8 @@ private: virtual OwnPtr handle(const AudioServer::SetPaused&) override; virtual OwnPtr handle(const AudioServer::ClearBuffer&) override; virtual OwnPtr handle(const AudioServer::GetPlayingBuffer&) override; + virtual OwnPtr handle(const AudioServer::GetMuted&) override; + virtual OwnPtr handle(const AudioServer::SetMuted&) override; ASMixer& m_mixer; RefPtr m_queue; diff --git a/Servers/AudioServer/ASMixer.cpp b/Servers/AudioServer/ASMixer.cpp index 15a317e4a44..2cd71e8bec2 100644 --- a/Servers/AudioServer/ASMixer.cpp +++ b/Servers/AudioServer/ASMixer.cpp @@ -15,6 +15,8 @@ ASMixer::ASMixer() return; } + m_zero_filled_buffer = (u8*)malloc(4096); + bzero(m_zero_filled_buffer, 4096); m_sound_thread.start(); } @@ -66,33 +68,42 @@ void ASMixer::mix() } } + bool muted = m_muted; + // output the mixed stuff to the device u8 raw_buffer[4096]; - auto buffer = ByteBuffer::wrap(raw_buffer, sizeof(raw_buffer)); + auto buffer = ByteBuffer::wrap(muted ? m_zero_filled_buffer : raw_buffer, sizeof(raw_buffer)); + BufferStream stream(buffer); + if (!muted) { + for (int i = 0; i < mixed_buffer_length; ++i) { + auto& mixed_sample = mixed_buffer[i]; - for (int i = 0; i < mixed_buffer_length; ++i) { - auto& mixed_sample = mixed_buffer[i]; + mixed_sample.scale(m_main_volume); + mixed_sample.clip(); - mixed_sample.scale(m_main_volume); - mixed_sample.clip(); + i16 out_sample; + out_sample = mixed_sample.left * std::numeric_limits::max(); + stream << out_sample; - i16 out_sample; - out_sample = mixed_sample.left * std::numeric_limits::max(); - stream << out_sample; - - ASSERT(!stream.at_end()); // we should have enough space for both channels in one buffer! - out_sample = mixed_sample.right * std::numeric_limits::max(); - stream << out_sample; + ASSERT(!stream.at_end()); // we should have enough space for both channels in one buffer! + out_sample = mixed_sample.right * std::numeric_limits::max(); + stream << out_sample; + } } if (stream.offset() != 0) { buffer.trim(stream.offset()); - m_device->write(buffer); } + m_device->write(buffer); } } +void ASMixer::set_muted(bool muted) +{ + m_muted = muted; +} + ASBufferQueue::ASBufferQueue(ASClientConnection& client) : m_client(client.make_weak_ptr()) { diff --git a/Servers/AudioServer/ASMixer.h b/Servers/AudioServer/ASMixer.h index e2a823b029d..960dce9996d 100644 --- a/Servers/AudioServer/ASMixer.h +++ b/Servers/AudioServer/ASMixer.h @@ -87,6 +87,9 @@ public: int main_volume() const { return m_main_volume; } void set_main_volume(int volume) { m_main_volume = volume; } + bool is_muted() const { return m_muted; } + void set_muted(bool); + private: Vector> m_pending_mixing; @@ -95,7 +98,10 @@ private: LibThread::Thread m_sound_thread; + bool m_muted { false }; int m_main_volume { 100 }; + u8* m_zero_filled_buffer { nullptr }; + void mix(); }; diff --git a/Servers/AudioServer/AudioServer.ipc b/Servers/AudioServer/AudioServer.ipc index 469e226eef0..1bdc7c80918 100644 --- a/Servers/AudioServer/AudioServer.ipc +++ b/Servers/AudioServer/AudioServer.ipc @@ -4,6 +4,8 @@ endpoint AudioServer Greet(i32 client_pid) => (i32 server_pid, i32 client_id) // Mixer functions + SetMuted(bool muted) => () + GetMuted() => (bool muted) GetMainMixVolume() => (i32 volume) SetMainMixVolume(i32 volume) => () diff --git a/Userland/avol.cpp b/Userland/avol.cpp index 5fd89dfd9b9..e907672c435 100644 --- a/Userland/avol.cpp +++ b/Userland/avol.cpp @@ -9,6 +9,17 @@ int main(int argc, char** argv) audio_client->handshake(); if (argc > 1) { + if (String(argv[1]) == "-m") { + audio_client->set_muted(true); + printf("Muted.\n"); + return 0; + } + if (String(argv[1]) == "-M") { + audio_client->set_muted(false); + printf("Unmuted.\n"); + return 0; + } + int new_volume = atoi(argv[1]); audio_client->set_main_mix_volume(new_volume); }