feat(sound): volume amplification

This adds toggles that allow increasing volume to 150% for both the sink and source.
This commit is contained in:
Vukašin Vojinović 2025-09-12 13:37:52 +02:00 committed by Ashley Wulber
parent bd7fc2a2f2
commit 0e5054a4c5
4 changed files with 104 additions and 12 deletions

View file

@ -7,12 +7,17 @@ use cosmic::{
surface,
widget::{self, settings},
};
use cosmic_config::{Config, ConfigGet, ConfigSet};
use cosmic_settings_page::{self as page, Section, section};
use slab::Slab;
use slotmap::SlotMap;
use cosmic_settings_subscriptions::sound as subscription;
const AUDIO_CONFIG: &str = "com.system76.CosmicAudio";
const AMPLIFICATION_SINK: &str = "amplification_sink";
const AMPLIFICATION_SOURCE: &str = "amplification_source";
#[derive(Clone, Debug)]
pub enum Message {
/// Change the balance of the active sink.
@ -25,6 +30,8 @@ pub enum Message {
SinkProfileChanged(usize),
/// Request to change the default output volume.
SinkVolumeChanged(u32),
/// Toggle amplification for sink
ToggleOverAmplificationSink(bool),
/// Change the default input output.
SourceChanged(usize),
/// Toggle the mute status of the input output.
@ -33,6 +40,8 @@ pub enum Message {
SourceProfileChanged(usize),
/// Request to change the input volume.
SourceVolumeChanged(u32),
/// Toggle amplification for sink
ToggleOverAmplificationSource(bool),
/// Messages handled by the sound module in cosmic-settings-subscriptions
Subscription(subscription::Message),
/// Surface Action
@ -61,9 +70,29 @@ impl Into<Message> for subscription::Message {
pub struct Page {
entity: page::Entity,
model: subscription::Model,
sound_config: Option<Config>,
amplification_sink: bool,
amplification_source: bool,
}
impl page::Page<crate::pages::Message> for Page {
fn on_enter(&mut self) -> cosmic::Task<crate::pages::Message> {
match Config::new(AUDIO_CONFIG, 1) {
Ok(config) => {
self.amplification_sink = config.get::<bool>(AMPLIFICATION_SINK).unwrap_or(true);
self.amplification_source =
config.get::<bool>(AMPLIFICATION_SOURCE).unwrap_or(false);
self.sound_config = Some(config);
}
Err(why) => {
tracing::error!(?why, "Failed to load sound config");
self.amplification_sink = true;
self.amplification_source = false;
}
}
Task::none()
}
fn content(
&self,
sections: &mut SlotMap<section::Entity, Section<crate::pages::Message>>,
@ -131,6 +160,16 @@ impl Page {
.map(|message| Message::Subscription(message).into());
}
Message::ToggleOverAmplificationSink(enabled) => {
self.amplification_sink = enabled;
if let Some(config) = &self.sound_config {
if let Err(why) = config.set(AMPLIFICATION_SINK, enabled) {
tracing::error!(?why, "Failed to save over amplification setting");
}
}
}
Message::SourceChanged(pos) => {
return self
.model
@ -154,6 +193,16 @@ impl Page {
.map(|message| Message::Subscription(message).into());
}
Message::ToggleOverAmplificationSource(enabled) => {
self.amplification_source = enabled;
if let Some(config) = &self.sound_config {
if let Err(why) = config.set(AMPLIFICATION_SOURCE, enabled) {
tracing::error!(?why, "Failed to save over amplification setting");
}
}
}
Message::Subscription(message) => {
return self
.model
@ -175,6 +224,8 @@ fn input() -> Section<crate::pages::Message> {
let device = descriptions.insert(fl!("sound-input", "device"));
let _level = descriptions.insert(fl!("sound-input", "level"));
let profile = descriptions.insert(fl!("profile"));
let amplification = descriptions.insert(fl!("amplification"));
let amplification_desc = descriptions.insert(fl!("amplification", "desc"));
Section::default()
.title(fl!("sound-input"))
@ -184,6 +235,17 @@ fn input() -> Section<crate::pages::Message> {
return widget::row().into();
}
let slider = if page.amplification_source {
widget::slider(0..=150, page.model.source_volume, |change| {
Message::SourceVolumeChanged(change).into()
})
.breakpoints(&[100])
} else {
widget::slider(0..=100, page.model.source_volume, |change| {
Message::SourceVolumeChanged(change).into()
})
};
let volume_control = widget::row::with_capacity(4)
.align_y(Alignment::Center)
.push(
@ -200,12 +262,7 @@ fn input() -> Section<crate::pages::Message> {
.align_x(Alignment::Center),
)
.push(widget::horizontal_space().width(8))
.push(
widget::slider(0..=150, page.model.source_volume, |change| {
Message::SourceVolumeChanged(change).into()
})
.breakpoints(&[100]),
);
.push(slider);
let devices = widget::dropdown::popup_dropdown(
page.model.sources(),
Some(page.model.active_source().unwrap_or(0)),
@ -240,6 +297,15 @@ fn input() -> Section<crate::pages::Message> {
controls = controls.add(settings::item(&*section.descriptions[profile], dropdown));
}
controls = controls.add(
settings::item::builder(&*section.descriptions[amplification])
.description(&*section.descriptions[amplification_desc])
.control(
widget::toggler(page.amplification_source)
.on_toggle(|t| Message::ToggleOverAmplificationSource(t).into()),
),
);
Element::from(controls)
})
}
@ -255,11 +321,24 @@ fn output() -> Section<crate::pages::Message> {
let left = descriptions.insert(fl!("sound-output", "left"));
let right = descriptions.insert(fl!("sound-output", "right"));
// let balance = descriptions.insert(fl!("sound-output", "balance"));
let amplification = descriptions.insert(fl!("amplification"));
let amplification_desc = descriptions.insert(fl!("amplification", "desc"));
Section::default()
.title(fl!("sound-output"))
.descriptions(descriptions)
.view::<Page>(move |_binder, page, section| {
let slider = if page.amplification_sink {
widget::slider(0..=150, page.model.sink_volume, |change| {
Message::SinkVolumeChanged(change).into()
})
.breakpoints(&[100])
} else {
widget::slider(0..=100, page.model.sink_volume, |change| {
Message::SinkVolumeChanged(change).into()
})
};
let volume_control = widget::row::with_capacity(4)
.align_y(Alignment::Center)
.push(
@ -276,12 +355,7 @@ fn output() -> Section<crate::pages::Message> {
.align_x(Alignment::Center),
)
.push(widget::horizontal_space().width(8))
.push(
widget::slider(0..=150, page.model.sink_volume, |change| {
Message::SinkVolumeChanged(change).into()
})
.breakpoints(&[100]),
);
.push(slider);
let devices = widget::dropdown::popup_dropdown(
page.model.sinks(),
@ -344,6 +418,15 @@ fn output() -> Section<crate::pages::Message> {
));
}
controls = controls.add(
settings::item::builder(&*section.descriptions[amplification])
.description(&*section.descriptions[amplification_desc])
.control(
widget::toggler(page.amplification_sink)
.on_toggle(|t| Message::ToggleOverAmplificationSink(t).into()),
),
);
Element::from(controls)
})
}

View file

@ -473,6 +473,9 @@ sound-input = Input
.device = Input device
.level = Input level
amplification = Amplification
.desc = Allows raising the volume to 150%.
sound-alerts = Alerts
.volume = Alerts volume
.sound = Alerts sound

View file

@ -474,6 +474,9 @@ sound-input = Улаз
.device = Улазни уређај
.level = Ниво улаза
amplification = Појачавање
.desc = Омогућава повећање јачине звука до 150%.
sound-alerts = Упозорења
.volume = Јачина звука упозорења
.sound = Звук упозорења

View file

@ -474,6 +474,9 @@ sound-input = Ulaz
.device = Ulazni uređaj
.level = Nivo ulaza
amplification = Pojačavanje
.desc = Omogućava povećanje jačine zvuka do 150%.
sound-alerts = Upozorenja
.volume = Jačina zvuka upozorenja
.sound = Zvuk upozorenja