/// Source = microphone etc. something that takes in audio /// Source Output = application consuming that audio /// /// Sink = headphones etc. something that plays out audio /// Sink Input = application producing that audio /// When you create a `SinkController`, you are working with audio playback devices and applications /// if you want to manipulate recording devices such as microphone volume, /// you'll need to use a `SourceController`. Both of these implement the same api, defined by /// the traits DeviceControl and AppControl use std::cell::RefCell; use std::clone::Clone; use std::rc::Rc; use pulse::{ callbacks::ListResult, context::introspect, volume::{ChannelVolumes, Volume}, }; use errors::{ControllerError, ControllerErrorType::*}; use types::{ApplicationInfo, DeviceInfo, ServerInfo}; use crate::Handler; pub(crate) mod errors; pub mod types; pub trait DeviceControl { fn get_default_device(&mut self) -> Result; fn set_default_device(&mut self, name: &str) -> Result; fn list_devices(&mut self) -> Result, ControllerError>; fn get_device_by_index(&mut self, index: u32) -> Result; fn get_device_by_name(&mut self, name: &str) -> Result; fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes); fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes); fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64); fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64); } pub trait AppControl { fn list_applications(&mut self) -> Result, ControllerError>; fn get_app_by_index(&mut self, index: u32) -> Result; fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64); fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64); fn move_app_by_index( &mut self, stream_index: u32, device_index: u32, ) -> Result; fn move_app_by_name( &mut self, stream_index: u32, device_name: &str, ) -> Result; fn set_app_mute(&mut self, index: u32, mute: bool) -> Result; } fn volume_from_percent(volume: f64) -> f64 { (volume * 100.0) * (f64::from(pulse::volume::VOLUME_NORM.0) / 100.0) } pub struct SinkController { pub handler: Handler, } impl SinkController { pub fn create() -> Result { let handler = Handler::connect("SinkController")?; Ok(SinkController { handler }) } pub fn get_server_info(&mut self) -> Result { let server = Rc::new(RefCell::new(Some(None))); let server_ref = server.clone(); let op = self.handler.introspect.get_server_info(move |res| { server_ref .borrow_mut() .as_mut() .unwrap() .replace(res.into()); }); self.handler.wait_for_operation(op)?; let mut result = server.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting information about the server", )) } } impl DeviceControl for SinkController { fn get_default_device(&mut self) -> Result { let server_info = self.get_server_info(); match server_info { Ok(info) => self.get_device_by_name(info.default_sink_name.unwrap().as_ref()), Err(e) => Err(e), } } fn set_default_device(&mut self, name: &str) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self .handler .context .borrow_mut() .set_default_sink(name, move |res| success_ref.borrow_mut().clone_from(&res)); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn list_devices(&mut self) -> Result, ControllerError> { let list = Rc::new(RefCell::new(Some(Vec::new()))); let list_ref = list.clone(); let op = self.handler.introspect.get_sink_info_list( move |sink_list: ListResult<&introspect::SinkInfo>| { if let ListResult::Item(item) = sink_list { list_ref.borrow_mut().as_mut().unwrap().push(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = list.borrow_mut(); result.take().ok_or(ControllerError::new( GetInfoError, "Error getting device list", )) } fn get_device_by_index(&mut self, index: u32) -> Result { let device = Rc::new(RefCell::new(Some(None))); let dev_ref = device.clone(); let op = self.handler.introspect.get_sink_info_by_index( index, move |sink_list: ListResult<&introspect::SinkInfo>| { if let ListResult::Item(item) = sink_list { dev_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = device.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting requested device", )) } fn get_device_by_name(&mut self, name: &str) -> Result { let device = Rc::new(RefCell::new(Some(None))); let dev_ref = device.clone(); let op = self.handler.introspect.get_sink_info_by_name( name, move |sink_list: ListResult<&introspect::SinkInfo>| { if let ListResult::Item(item) = sink_list { dev_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = device.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting requested device", )) } fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes) { let op = self .handler .introspect .set_sink_volume_by_index(index, volume, None); self.handler.wait_for_operation(op).ok(); } fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes) { let op = self .handler .introspect .set_sink_volume_by_name(name, volume, None); self.handler.wait_for_operation(op).ok(); } fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut dev_ref) = self.get_device_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = dev_ref.volume.increase(new_vol) { let op = self .handler .introspect .set_sink_volume_by_index(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut dev_ref) = self.get_device_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = dev_ref.volume.decrease(new_vol) { let op = self .handler .introspect .set_sink_volume_by_index(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } } impl AppControl for SinkController { fn list_applications(&mut self) -> Result, ControllerError> { let list = Rc::new(RefCell::new(Some(Vec::new()))); let list_ref = list.clone(); let op = self.handler.introspect.get_sink_input_info_list( move |sink_list: ListResult<&introspect::SinkInputInfo>| { if let ListResult::Item(item) = sink_list { list_ref.borrow_mut().as_mut().unwrap().push(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = list.borrow_mut(); result.take().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn get_app_by_index(&mut self, index: u32) -> Result { let app = Rc::new(RefCell::new(Some(None))); let app_ref = app.clone(); let op = self.handler.introspect.get_sink_input_info( index, move |sink_list: ListResult<&introspect::SinkInputInfo>| { if let ListResult::Item(item) = sink_list { app_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = app.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting requested app", )) } fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut app_ref) = self.get_app_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = app_ref.volume.increase(new_vol) { let op = self .handler .introspect .set_sink_input_volume(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut app_ref) = self.get_app_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = app_ref.volume.decrease(new_vol) { let op = self .handler .introspect .set_sink_input_volume(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn move_app_by_index( &mut self, stream_index: u32, device_index: u32, ) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.move_sink_input_by_index( stream_index, device_index, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn move_app_by_name( &mut self, stream_index: u32, device_name: &str, ) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.move_sink_input_by_name( stream_index, device_name, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn set_app_mute(&mut self, index: u32, mute: bool) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.set_sink_input_mute( index, mute, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } } pub struct SourceController { pub handler: Handler, } impl SourceController { pub fn create() -> Result { let handler = Handler::connect("SourceController")?; Ok(SourceController { handler }) } pub fn get_server_info(&mut self) -> Result { let server = Rc::new(RefCell::new(Some(None))); let server_ref = server.clone(); let op = self.handler.introspect.get_server_info(move |res| { server_ref .borrow_mut() .as_mut() .unwrap() .replace(res.into()); }); self.handler.wait_for_operation(op)?; let mut result = server.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } } impl DeviceControl for SourceController { fn get_default_device(&mut self) -> Result { let server_info = self.get_server_info(); match server_info { Ok(info) => self.get_device_by_name(info.default_sink_name.unwrap().as_ref()), Err(e) => Err(e), } } fn set_default_device(&mut self, name: &str) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self .handler .context .borrow_mut() .set_default_source(name, move |res| success_ref.borrow_mut().clone_from(&res)); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn list_devices(&mut self) -> Result, ControllerError> { let list = Rc::new(RefCell::new(Some(Vec::new()))); let list_ref = list.clone(); let op = self.handler.introspect.get_source_info_list( move |sink_list: ListResult<&introspect::SourceInfo>| { if let ListResult::Item(item) = sink_list { list_ref.borrow_mut().as_mut().unwrap().push(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = list.borrow_mut(); result.take().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn get_device_by_index(&mut self, index: u32) -> Result { let device = Rc::new(RefCell::new(Some(None))); let dev_ref = device.clone(); let op = self.handler.introspect.get_source_info_by_index( index, move |sink_list: ListResult<&introspect::SourceInfo>| { if let ListResult::Item(item) = sink_list { dev_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = device.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn get_device_by_name(&mut self, name: &str) -> Result { let device = Rc::new(RefCell::new(Some(None))); let dev_ref = device.clone(); let op = self.handler.introspect.get_source_info_by_name( name, move |sink_list: ListResult<&introspect::SourceInfo>| { if let ListResult::Item(item) = sink_list { dev_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = device.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes) { let op = self .handler .introspect .set_source_volume_by_index(index, volume, None); self.handler.wait_for_operation(op).ok(); } fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes) { let op = self .handler .introspect .set_source_volume_by_name(name, volume, None); self.handler.wait_for_operation(op).ok(); } fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut dev_ref) = self.get_device_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = dev_ref.volume.increase(new_vol) { let op = self .handler .introspect .set_source_volume_by_index(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut dev_ref) = self.get_device_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = dev_ref.volume.decrease(new_vol) { let op = self .handler .introspect .set_source_volume_by_index(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } } impl AppControl for SourceController { fn list_applications(&mut self) -> Result, ControllerError> { let list = Rc::new(RefCell::new(Some(Vec::new()))); let list_ref = list.clone(); let op = self.handler.introspect.get_source_output_info_list( move |sink_list: ListResult<&introspect::SourceOutputInfo>| { if let ListResult::Item(item) = sink_list { list_ref.borrow_mut().as_mut().unwrap().push(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = list.borrow_mut(); result.take().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn get_app_by_index(&mut self, index: u32) -> Result { let app = Rc::new(RefCell::new(Some(None))); let app_ref = app.clone(); let op = self.handler.introspect.get_source_output_info( index, move |sink_list: ListResult<&introspect::SourceOutputInfo>| { if let ListResult::Item(item) = sink_list { app_ref.borrow_mut().as_mut().unwrap().replace(item.into()); } }, ); self.handler.wait_for_operation(op)?; let mut result = app.borrow_mut(); result.take().unwrap().ok_or(ControllerError::new( GetInfoError, "Error getting application list", )) } fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut app_ref) = self.get_app_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = app_ref.volume.increase(new_vol) { let op = self .handler .introspect .set_source_output_volume(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64) { if let Ok(mut app_ref) = self.get_app_by_index(index) { let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32)); if let Some(volumes) = app_ref.volume.decrease(new_vol) { let op = self .handler .introspect .set_source_output_volume(index, &volumes, None); self.handler.wait_for_operation(op).ok(); } } } fn move_app_by_index( &mut self, stream_index: u32, device_index: u32, ) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.move_source_output_by_index( stream_index, device_index, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn move_app_by_name( &mut self, stream_index: u32, device_name: &str, ) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.move_source_output_by_name( stream_index, device_name, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } fn set_app_mute(&mut self, index: u32, mute: bool) -> Result { let success = Rc::new(RefCell::new(false)); let success_ref = success.clone(); let op = self.handler.introspect.set_source_mute_by_index( index, mute, Some(Box::new(move |res| { success_ref.borrow_mut().clone_from(&res) })), ); self.handler.wait_for_operation(op)?; let result = success.borrow_mut().clone(); Ok(result) } }