fix(audio): debounce volume updates by 128ms
This commit is contained in:
parent
a1d4be5d10
commit
73d727814c
1 changed files with 62 additions and 31 deletions
|
|
@ -33,10 +33,15 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use cosmic_settings_audio_client::{self as audio_client, CosmicAudioProxy};
|
use cosmic_settings_audio_client::{self as audio_client, CosmicAudioProxy};
|
||||||
use futures::SinkExt;
|
use futures::SinkExt;
|
||||||
use iced::platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup};
|
|
||||||
use mpris_subscription::{MprisRequest, MprisUpdate};
|
use mpris_subscription::{MprisRequest, MprisUpdate};
|
||||||
use mpris2_zbus::player::PlaybackStatus;
|
use mpris2_zbus::player::PlaybackStatus;
|
||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
use std::{
|
||||||
|
sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{self, AtomicU32},
|
||||||
|
},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod mpris_subscription;
|
mod mpris_subscription;
|
||||||
|
|
@ -58,11 +63,15 @@ pub struct Audio {
|
||||||
/// Track the applet's popup window.
|
/// Track the applet's popup window.
|
||||||
popup: Option<window::Id>,
|
popup: Option<window::Id>,
|
||||||
/// Varlink connection to `com.system76.CosmicSettings.Audio`.
|
/// Varlink connection to `com.system76.CosmicSettings.Audio`.
|
||||||
audio_client: Option<Rc<RefCell<audio_client::Client>>>,
|
audio_client: Option<audio_client::Client>,
|
||||||
/// Known audio device state
|
/// Known audio device state
|
||||||
model: model::Model,
|
model: model::Model,
|
||||||
/// Whether to expand the revealer of a source or sink device.
|
/// Whether to expand the revealer of a source or sink device.
|
||||||
is_open: IsOpen,
|
is_open: IsOpen,
|
||||||
|
/// Used to debounce sink volume updates.
|
||||||
|
applied_sink_volume: Arc<AtomicU32>,
|
||||||
|
/// Used to deboune source volume updates.
|
||||||
|
applied_source_volume: Arc<AtomicU32>,
|
||||||
/// Max slider volume for the sink device, as determined by the amplification property.
|
/// Max slider volume for the sink device, as determined by the amplification property.
|
||||||
max_sink_volume: u32,
|
max_sink_volume: u32,
|
||||||
/// Max slider volume for the source device, as determined by the amplification property.
|
/// Max slider volume for the source device, as determined by the amplification property.
|
||||||
|
|
@ -125,26 +134,27 @@ enum IsOpen {
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
/// Connection to `com.system76.CosmicSettings`.
|
/// Connection to `com.system76.CosmicSettings`.
|
||||||
Client(Arc<audio_client::Client>),
|
Client(Arc<audio_client::Client>),
|
||||||
Ignore,
|
|
||||||
SetSinkVolume(u32),
|
|
||||||
SetSourceVolume(u32),
|
|
||||||
ToggleSinkMute,
|
|
||||||
ToggleSourceMute,
|
|
||||||
SetDefaultSink(usize),
|
|
||||||
SetDefaultSource(usize),
|
|
||||||
OutputToggle,
|
|
||||||
InputToggle,
|
|
||||||
TogglePopup,
|
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
ToggleMediaControlsInTopPanel(bool),
|
|
||||||
ConfigChanged(AudioAppletConfig),
|
ConfigChanged(AudioAppletConfig),
|
||||||
|
Ignore,
|
||||||
|
InputToggle,
|
||||||
Mpris(mpris_subscription::MprisUpdate),
|
Mpris(mpris_subscription::MprisUpdate),
|
||||||
MprisRequest(MprisRequest),
|
MprisRequest(MprisRequest),
|
||||||
Token(TokenUpdate),
|
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
OutputToggle,
|
||||||
|
ReattachClient(Arc<audio_client::Client>),
|
||||||
|
Rectangle(RectangleUpdate<u32>),
|
||||||
|
SetDefaultSink(usize),
|
||||||
|
SetDefaultSource(usize),
|
||||||
|
SetSinkVolume(u32),
|
||||||
|
SetSourceVolume(u32),
|
||||||
Subscription(audio_client::Event),
|
Subscription(audio_client::Event),
|
||||||
Surface(surface::Action),
|
Surface(surface::Action),
|
||||||
Rectangle(RectangleUpdate<u32>),
|
ToggleMediaControlsInTopPanel(bool),
|
||||||
|
TogglePopup,
|
||||||
|
ToggleSinkMute,
|
||||||
|
ToggleSourceMute,
|
||||||
|
Token(TokenUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -287,6 +297,11 @@ impl cosmic::Application for Audio {
|
||||||
self.rectangle_tracker.replace(tracker);
|
self.rectangle_tracker.replace(tracker);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Message::ReattachClient(client) => {
|
||||||
|
if let Some(client) = Arc::into_inner(client) {
|
||||||
|
self.audio_client = Some(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::Ignore => {}
|
Message::Ignore => {}
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
|
|
@ -359,7 +374,7 @@ impl cosmic::Application for Audio {
|
||||||
&& let Some(client) = self.audio_client.as_mut()
|
&& let Some(client) = self.audio_client.as_mut()
|
||||||
{
|
{
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
_ = client.borrow_mut().conn.set_default(node_id, true).await;
|
_ = client.conn.set_default(node_id, true).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +385,7 @@ impl cosmic::Application for Audio {
|
||||||
&& let Some(client) = self.audio_client.as_mut()
|
&& let Some(client) = self.audio_client.as_mut()
|
||||||
{
|
{
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
_ = client.borrow_mut().conn.set_default(node_id, true).await;
|
_ = client.conn.set_default(node_id, true).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -378,7 +393,7 @@ impl cosmic::Application for Audio {
|
||||||
Message::ToggleSinkMute => {
|
Message::ToggleSinkMute => {
|
||||||
if let Some(ref mut client) = self.audio_client {
|
if let Some(ref mut client) = self.audio_client {
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
_ = client.borrow_mut().conn.sink_mute_toggle().await;
|
_ = client.conn.sink_mute_toggle().await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -386,27 +401,43 @@ impl cosmic::Application for Audio {
|
||||||
Message::ToggleSourceMute => {
|
Message::ToggleSourceMute => {
|
||||||
if let Some(ref mut client) = self.audio_client {
|
if let Some(ref mut client) = self.audio_client {
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
_ = client.borrow_mut().conn.source_mute_toggle().await;
|
_ = client.conn.source_mute_toggle().await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::SetSinkVolume(volume) => {
|
Message::SetSinkVolume(volume) => {
|
||||||
if let Some(ref mut client) = self.audio_client {
|
self.applied_sink_volume
|
||||||
self.model.active_sink.volume = volume;
|
.store(volume, atomic::Ordering::Relaxed);
|
||||||
self.model.active_sink.volume_text = volume.to_string();
|
self.model.active_sink.volume = volume;
|
||||||
futures::executor::block_on(async {
|
self.model.active_sink.volume_text = volume.to_string();
|
||||||
_ = client.borrow_mut().conn.set_sink_volume(volume).await;
|
if let Some(mut client) = self.audio_client.take() {
|
||||||
|
let volume = Arc::clone(&self.applied_sink_volume);
|
||||||
|
return cosmic::Task::future(async move {
|
||||||
|
tokio::time::sleep(Duration::from_millis(128)).await;
|
||||||
|
_ = client
|
||||||
|
.conn
|
||||||
|
.set_sink_volume(volume.load(atomic::Ordering::Relaxed))
|
||||||
|
.await;
|
||||||
|
Message::ReattachClient(Arc::new(client)).into()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::SetSourceVolume(volume) => {
|
Message::SetSourceVolume(volume) => {
|
||||||
if let Some(ref mut client) = self.audio_client {
|
self.applied_source_volume
|
||||||
self.model.active_source.volume = volume;
|
.store(volume, atomic::Ordering::Relaxed);
|
||||||
self.model.active_source.volume_text = volume.to_string();
|
self.model.active_source.volume = volume;
|
||||||
futures::executor::block_on(async {
|
self.model.active_source.volume_text = volume.to_string();
|
||||||
_ = client.borrow_mut().conn.set_source_volume(volume).await;
|
if let Some(mut client) = self.audio_client.take() {
|
||||||
|
let volume = Arc::clone(&self.applied_source_volume);
|
||||||
|
return cosmic::Task::future(async move {
|
||||||
|
tokio::time::sleep(Duration::from_millis(128)).await;
|
||||||
|
_ = client
|
||||||
|
.conn
|
||||||
|
.set_sink_volume(volume.load(atomic::Ordering::Relaxed))
|
||||||
|
.await;
|
||||||
|
Message::ReattachClient(Arc::new(client)).into()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +548,7 @@ impl cosmic::Application for Audio {
|
||||||
}
|
}
|
||||||
Message::Client(client) => {
|
Message::Client(client) => {
|
||||||
if let Some(client) = Arc::into_inner(client) {
|
if let Some(client) = Arc::into_inner(client) {
|
||||||
self.audio_client = Some(Rc::new(RefCell::new(client)));
|
self.audio_client = Some(client);
|
||||||
self.model = model::Model::default();
|
self.model = model::Model::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue