From 0a663e97f2c0da5a39332b538800742f6b010566 Mon Sep 17 00:00:00 2001 From: GHOSCHT <31184695+GHOSCHT@users.noreply.github.com> Date: Tue, 30 Apr 2024 23:44:39 +0200 Subject: [PATCH] Add sink input volume manipulation --- src/pulse_client.rs | 100 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 19 deletions(-) diff --git a/src/pulse_client.rs b/src/pulse_client.rs index 273e96a..42b1a3f 100644 --- a/src/pulse_client.rs +++ b/src/pulse_client.rs @@ -3,10 +3,11 @@ extern crate libpulse_binding as pulse; use pulse::context::{Context, FlagSet as ContextFlagSet}; use pulse::mainloop::threaded::Mainloop; use pulse::proplist::Proplist; +use pulse::volume; use regex::Regex; use std::cell::RefCell; use std::ops::Deref; -use std::rc::Rc; +use std::sync::Arc; use std::time; pub fn run() { @@ -18,11 +19,11 @@ pub fn run() { ) .unwrap(); - let mainloop = Rc::new(RefCell::new( + let mainloop = Arc::new(RefCell::new( Mainloop::new().expect("Failed to create mainloop"), )); - let context = Rc::new(RefCell::new( + let context = Arc::new(RefCell::new( Context::new_with_proplist( mainloop.borrow().deref(), "picoKontrollerContext", @@ -33,8 +34,8 @@ pub fn run() { // Context state change callback { - let ml_ref = Rc::clone(&mainloop); - let context_ref = Rc::clone(&context); + let ml_ref = Arc::clone(&mainloop); + let context_ref = Arc::clone(&context); context .borrow_mut() .set_state_callback(Some(Box::new(move || { @@ -82,19 +83,21 @@ pub fn run() { mainloop.borrow_mut().unlock(); //--------------------- - let ml = Rc::clone(&mainloop); - let ctx = Rc::clone(&context); - mute_sink_input(ml, ctx, "Firefox", false); + let ml = Arc::clone(&mainloop); + let ctx = Arc::clone(&context); + + set_volume_sink_input(ml, ctx, "Firefox", 100); //--------------------- loop { + //TODO: react to incoming commands here instead of infinite sleep std::thread::sleep(time::Duration::from_secs(u64::MAX)); } } pub fn set_default_sink( - mainloop: Rc>, - context: Rc>, + mainloop: Arc>, + context: Arc>, name: &str, ) { mainloop.borrow_mut().lock(); @@ -117,11 +120,11 @@ pub fn set_default_sink( mainloop.borrow_mut().unlock(); } -pub fn mute_sink_input( - mainloop: Rc>, - context: Rc>, +fn for_all_sink_inputs( + mainloop: Arc>, + context: Arc>, name: &str, - state: bool, + function: Arc>, u32, &mut volume::ChannelVolumes)>, ) { mainloop.borrow_mut().lock(); let sink_filter = Regex::new(name).expect("Creating RegEx failed"); @@ -139,14 +142,73 @@ pub fn mute_sink_input( println!("{:?}", application_name); if matches_regex { - println!("Setting default sink to: {}", application_name); - callback_context - .borrow_mut() - .introspect() - .set_sink_input_mute(item.index, state, Option::None); + function( + callback_context.clone(), + item.index, + &mut item.volume.clone(), + ); } } _ => {} }); mainloop.borrow_mut().unlock(); } + +pub fn mute_sink_input( + mainloop: Arc>, + context: Arc>, + name: &str, + state: bool, +) { + for_all_sink_inputs( + mainloop, + context, + name, + Arc::new(move |ctx, index, _| { + ctx.borrow_mut() + .introspect() + .set_sink_input_mute(index, state, Option::None); + }), + ) +} + +pub fn set_volume_sink_input( + mainloop: Arc>, + context: Arc>, + name: &str, + volume: i16, +) { + for_all_sink_inputs( + mainloop, + context, + name, + Arc::new(move |ctx, index, vols| { + let target = percent_to_volume(volume); + + for v in vols.get_mut() { + v.0 = target; + } + + ctx.borrow_mut() + .introspect() + .set_sink_input_volume(index, vols, Option::None); + }), + ) +} + +//taken from https://github.com/jantap/rsmixer +pub fn percent_to_volume(target_percent: i16) -> u32 { + let base_delta = (volume::Volume::NORMAL.0 as f32 - volume::Volume::MUTED.0 as f32) / 100.0; + + if target_percent < 0 { + volume::Volume::MUTED.0 + } else if target_percent == 100 { + volume::Volume::NORMAL.0 + } else if target_percent >= 150 { + (volume::Volume::NORMAL.0 as f32 * 1.5) as u32 + } else if target_percent < 100 { + volume::Volume::MUTED.0 + target_percent as u32 * base_delta as u32 + } else { + volume::Volume::NORMAL.0 + (target_percent - 100) as u32 * base_delta as u32 + } +}