Compare commits
2 commits
d1eec7399a
...
0a663e97f2
Author | SHA1 | Date | |
---|---|---|---|
0a663e97f2 | |||
12b8a4c93b |
1 changed files with 85 additions and 20 deletions
|
@ -3,10 +3,11 @@ extern crate libpulse_binding as pulse;
|
||||||
use pulse::context::{Context, FlagSet as ContextFlagSet};
|
use pulse::context::{Context, FlagSet as ContextFlagSet};
|
||||||
use pulse::mainloop::threaded::Mainloop;
|
use pulse::mainloop::threaded::Mainloop;
|
||||||
use pulse::proplist::Proplist;
|
use pulse::proplist::Proplist;
|
||||||
|
use pulse::volume;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
|
@ -18,11 +19,11 @@ pub fn run() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mainloop = Rc::new(RefCell::new(
|
let mainloop = Arc::new(RefCell::new(
|
||||||
Mainloop::new().expect("Failed to create mainloop"),
|
Mainloop::new().expect("Failed to create mainloop"),
|
||||||
));
|
));
|
||||||
|
|
||||||
let context = Rc::new(RefCell::new(
|
let context = Arc::new(RefCell::new(
|
||||||
Context::new_with_proplist(
|
Context::new_with_proplist(
|
||||||
mainloop.borrow().deref(),
|
mainloop.borrow().deref(),
|
||||||
"picoKontrollerContext",
|
"picoKontrollerContext",
|
||||||
|
@ -33,8 +34,8 @@ pub fn run() {
|
||||||
|
|
||||||
// Context state change callback
|
// Context state change callback
|
||||||
{
|
{
|
||||||
let ml_ref = Rc::clone(&mainloop);
|
let ml_ref = Arc::clone(&mainloop);
|
||||||
let context_ref = Rc::clone(&context);
|
let context_ref = Arc::clone(&context);
|
||||||
context
|
context
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_state_callback(Some(Box::new(move || {
|
.set_state_callback(Some(Box::new(move || {
|
||||||
|
@ -82,19 +83,21 @@ pub fn run() {
|
||||||
mainloop.borrow_mut().unlock();
|
mainloop.borrow_mut().unlock();
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
let ml = Rc::clone(&mainloop);
|
let ml = Arc::clone(&mainloop);
|
||||||
let ctx = Rc::clone(&context);
|
let ctx = Arc::clone(&context);
|
||||||
mute_sink_input(ml, ctx, "Firefox", false);
|
|
||||||
|
set_volume_sink_input(ml, ctx, "Firefox", 100);
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
//TODO: react to incoming commands here instead of infinite sleep
|
||||||
std::thread::sleep(time::Duration::from_secs(u64::MAX));
|
std::thread::sleep(time::Duration::from_secs(u64::MAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default_sink(
|
pub fn set_default_sink(
|
||||||
mainloop: Rc<RefCell<Mainloop>>,
|
mainloop: Arc<RefCell<Mainloop>>,
|
||||||
context: Rc<RefCell<Context>>,
|
context: Arc<RefCell<Context>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) {
|
) {
|
||||||
mainloop.borrow_mut().lock();
|
mainloop.borrow_mut().lock();
|
||||||
|
@ -117,11 +120,11 @@ pub fn set_default_sink(
|
||||||
mainloop.borrow_mut().unlock();
|
mainloop.borrow_mut().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mute_sink_input(
|
fn for_all_sink_inputs(
|
||||||
mainloop: Rc<RefCell<Mainloop>>,
|
mainloop: Arc<RefCell<Mainloop>>,
|
||||||
context: Rc<RefCell<Context>>,
|
context: Arc<RefCell<Context>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
state: bool,
|
function: Arc<dyn Fn(Arc<RefCell<Context>>, u32, &mut volume::ChannelVolumes)>,
|
||||||
) {
|
) {
|
||||||
mainloop.borrow_mut().lock();
|
mainloop.borrow_mut().lock();
|
||||||
let sink_filter = Regex::new(name).expect("Creating RegEx failed");
|
let sink_filter = Regex::new(name).expect("Creating RegEx failed");
|
||||||
|
@ -131,19 +134,81 @@ pub fn mute_sink_input(
|
||||||
.introspect()
|
.introspect()
|
||||||
.get_sink_input_info_list(move |items_result| match items_result {
|
.get_sink_input_info_list(move |items_result| match items_result {
|
||||||
pulse::callbacks::ListResult::Item(item) => {
|
pulse::callbacks::ListResult::Item(item) => {
|
||||||
let application_name = item.proplist.get_str("application.name").unwrap();
|
let application_name = item
|
||||||
|
.proplist
|
||||||
|
.get_str(pulse::proplist::properties::APPLICATION_NAME)
|
||||||
|
.unwrap();
|
||||||
let matches_regex = sink_filter.is_match(&application_name);
|
let matches_regex = sink_filter.is_match(&application_name);
|
||||||
|
|
||||||
println!("{:?}", application_name);
|
println!("{:?}", application_name);
|
||||||
if matches_regex {
|
if matches_regex {
|
||||||
println!("Setting default sink to: {}", application_name);
|
function(
|
||||||
callback_context
|
callback_context.clone(),
|
||||||
.borrow_mut()
|
item.index,
|
||||||
.introspect()
|
&mut item.volume.clone(),
|
||||||
.set_sink_input_mute(item.index, state, Option::None);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
});
|
||||||
mainloop.borrow_mut().unlock();
|
mainloop.borrow_mut().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mute_sink_input(
|
||||||
|
mainloop: Arc<RefCell<Mainloop>>,
|
||||||
|
context: Arc<RefCell<Context>>,
|
||||||
|
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<RefCell<Mainloop>>,
|
||||||
|
context: Arc<RefCell<Context>>,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue