From a3355f3b72e087c1b10f53a2a8c5f345346c8c9b Mon Sep 17 00:00:00 2001 From: "Ospald, Julian" Date: Thu, 29 Jun 2017 14:25:40 +0200 Subject: [PATCH] Restructure modules --- src/app_state.rs | 94 ---------------------- src/audio.rs | 188 ++++++++++++++++++++----------------------- src/errors.rs | 6 +- src/gui.rs | 13 +-- src/gui_callbacks.rs | 20 ++--- src/main.rs | 19 ++--- src/myalsa.rs | 111 +++++++++++++++++++++++++ 7 files changed, 220 insertions(+), 231 deletions(-) create mode 100644 src/myalsa.rs diff --git a/src/app_state.rs b/src/app_state.rs index fd70b8966..63c6fd9aa 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -1,16 +1,5 @@ use gtk; -use alsa::poll::PollDescriptors; -use alsa::card::Card; -use alsa::mixer::{Mixer, SelemId, Selem}; -use audio; -use errors::*; -use std::rc::Rc; -use std::cell::RefCell; - - -// TODO: fix import -use libc::pollfd; pub struct AppS { /* we keep this to ensure the lifetime is across the whole application */ @@ -19,86 +8,3 @@ pub struct AppS { pub builder_popup: gtk::Builder, } -// TODO: implement free/destructor -pub struct AlsaCard { - _cannot_construct: (), - pub card: Card, - pub mixer: Mixer, - pub selem_id: SelemId, - pub watch_ids: Vec, -} - -impl AlsaCard { - pub fn new( - card_name: Option, - elem_name: Option, - ) -> Result { - let card = { - match card_name { - Some(name) => audio::get_alsa_card_by_name(name)?, - None => audio::get_default_alsa_card(), - } - }; - let mixer = audio::get_mixer(&card)?; - let selem_id = audio::get_selem_by_name( - &mixer, - elem_name.unwrap_or(String::from("Master")), - ).unwrap() - .get_id(); - let vec_pollfd = PollDescriptors::get(&mixer)?; - - /* TODO: callback is registered here, which must be unregistered - * when the mixer is destroyed!! */ - let watch_ids = audio::watch_poll_descriptors(vec_pollfd, &mixer); - - return Ok(AlsaCard { - _cannot_construct: (), - card: card, - mixer: mixer, - selem_id: selem_id, - watch_ids: watch_ids, - }); - } - - pub fn selem(&self) -> Selem { - return audio::get_selems(&self.mixer) - .nth(self.selem_id.get_index() as usize) - .unwrap(); - } - - pub fn vol(&self) -> Result { - return audio::get_vol(&self.selem()); - } - - pub fn set_vol(&self, new_vol: f64) -> Result<()> { - return audio::set_vol(&self.selem(), new_vol); - } - - pub fn has_mute(&self) -> bool { - return audio::has_mute(&self.selem()); - } - - pub fn get_mute(&self) -> Result { - return audio::get_mute(&self.selem()); - } - - pub fn set_mute(&self, mute: bool) -> Result<()> { - return audio::set_mute(&self.selem(), mute); - } -} - -pub enum AudioUser { - AudioUserUnknown, - AudioUserPopup, - AudioUserTrayIcon, - AudioUserHotkeys, -} - -enum AudioSignal { - AudioNoCard, - AudioCardInitialized, - AudioCardCleanedUp, - AudioCardDisconnected, - AudioCardError, - AudioValuesChanged, -} diff --git a/src/audio.rs b/src/audio.rs index 9f5ef05ee..3d8d3740c 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -1,131 +1,115 @@ -extern crate alsa; -extern crate alsa_sys; -extern crate glib_sys; - -use self::alsa::card::Card; -use self::alsa::mixer::{Mixer, Selem, Elem}; -use alsa::mixer::SelemChannelId::*; -use std::iter::Map; +use alsa::card::Card; +use alsa::mixer::{Mixer, Selem, Elem, SelemId}; +use alsa::poll::PollDescriptors; +use alsa_sys; +use errors::*; +use glib_sys; use libc::c_int; use libc::c_uint; use libc::c_void; -use libc::size_t; -use errors::*; -use std::convert::From; use libc::pollfd; -use app_state; +use libc::size_t; +use myalsa::*; use std::cell::RefCell; -use std::rc::Rc; use std::mem; use std::ptr; +use std::rc::Rc; use std::u8; - -pub fn get_default_alsa_card() -> Card { - return get_alsa_card_by_id(0); +// TODO: implement free/destructor +pub struct AlsaCard { + _cannot_construct: (), + pub card: Card, + pub mixer: Mixer, + pub selem_id: SelemId, + pub watch_ids: Vec, } -pub fn get_alsa_card_by_id(index: c_int) -> Card { - return alsa::Card::new(index); -} +impl AlsaCard { + pub fn new( + card_name: Option, + elem_name: Option, + ) -> Result { + let card = { + match card_name { + Some(name) => get_alsa_card_by_name(name)?, + None => get_default_alsa_card(), + } + }; + let mixer = get_mixer(&card)?; + let selem_id = get_selem_by_name( + &mixer, + elem_name.unwrap_or(String::from("Master")), + ).unwrap() + .get_id(); + let vec_pollfd = PollDescriptors::get(&mixer)?; -pub fn get_alsa_cards() -> alsa::card::Iter { - return alsa::card::Iter::new(); -} + /* TODO: callback is registered here, which must be unregistered + * when the mixer is destroyed!! */ + let watch_ids = watch_poll_descriptors(vec_pollfd, &mixer); -pub fn get_alsa_card_by_name(name: String) -> Result { - for r_card in get_alsa_cards() { - let card = r_card?; - let card_name = card.get_name()?; - if name == card_name { - return Ok(card); - } - } - bail!("Not found a matching card named {}", name); -} - -pub fn get_mixer(card: &Card) -> Result { - return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr(); -} - -pub fn get_selem(elem: Elem) -> Selem { - /* in the ALSA API, there are currently only simple elements, - * so this unwrap() should be safe. - *http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html#enum-members */ - return Selem::new(elem).unwrap(); -} - -pub fn get_selems(mixer: &Mixer) -> Map Selem> { - return mixer.iter().map(get_selem); -} - -pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result { - for selem in get_selems(mixer) { - let n = selem.get_id().get_name().map(|y| String::from(y))?; - - if n == name { - return Ok(selem); - } - } - bail!("Not found a matching selem named {}", name); -} - -pub fn vol_to_percent(vol: i64, range: (i64, i64)) -> f64 { - let (min, max) = range; - return ((vol - min) as f64) / ((max - min) as f64) * 100.0; -} - -pub fn percent_to_vol(vol: f64, range: (i64, i64)) -> i64 { - let (min, max) = range; - let _v = vol / 100.0 * ((max - min) as f64) + (min as f64); - /* TODO: precision? Use direction. */ - return _v as i64; -} - -pub fn get_vol(selem: &Selem) -> Result { - let range = selem.get_playback_volume_range(); - let volume = selem.get_playback_volume(FrontRight).map(|v| { - return vol_to_percent(v, range); - }); - - return volume.cherr(); -} - -pub fn set_vol(selem: &Selem, new_vol: f64) -> Result<()> { - /* auto-unmute */ - if get_mute(selem)? { - set_mute(selem, false)?; + return Ok(AlsaCard { + _cannot_construct: (), + card: card, + mixer: mixer, + selem_id: selem_id, + watch_ids: watch_ids, + }); } - let range = selem.get_playback_volume_range(); - selem.set_playback_volume_all( - percent_to_vol(new_vol, range), - )?; + pub fn selem(&self) -> Selem { + return get_selems(&self.mixer) + .nth(self.selem_id.get_index() as usize) + .unwrap(); + } + + pub fn vol(&self) -> Result { + return get_vol(&self.selem()); + } + + pub fn set_vol(&self, new_vol: f64) -> Result<()> { + return set_vol(&self.selem(), new_vol); + } + + pub fn has_mute(&self) -> bool { + return has_mute(&self.selem()); + } + + pub fn get_mute(&self) -> Result { + return get_mute(&self.selem()); + } + + pub fn set_mute(&self, mute: bool) -> Result<()> { + return set_mute(&self.selem(), mute); + } + + - return Ok(()); } -pub fn has_mute(selem: &Selem) -> bool { - return selem.has_playback_switch(); +pub enum AudioUser { + AudioUserUnknown, + AudioUserPopup, + AudioUserTrayIcon, + AudioUserHotkeys, } -pub fn get_mute(selem: &Selem) -> Result { - let val = selem.get_playback_switch(FrontRight)?; - return Ok(val == 0); -} - -pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> { - /* true -> mute, false -> unmute */ - let _ = selem.set_playback_switch_all(!mute as i32)?; - return Ok(()); +enum AudioSignal { + AudioNoCard, + AudioCardInitialized, + AudioCardCleanedUp, + AudioCardDisconnected, + AudioCardError, + AudioValuesChanged, } -/* GIO */ -pub fn watch_poll_descriptors( + + +fn watch_poll_descriptors( polls: Vec, mixer: &Mixer, ) -> Vec { diff --git a/src/errors.rs b/src/errors.rs index 126a0b673..1fc76ee9d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,6 @@ use alsa; -use std; use std::convert::From; +use std; error_chain! { foreign_links { @@ -40,8 +40,8 @@ macro_rules! try_w { #[macro_export] macro_rules! try_wr { ($expr:expr, $ret:expr) => (match $expr { - std::result::Result::Ok(val) => val, - std::result::Result::Err(err) => { + ::std::result::Result::Ok(val) => val, + ::std::result::Result::Err(err) => { warn!("{:?}", err); return $ret; }, diff --git a/src/gui.rs b/src/gui.rs index 8faa90b1f..548d4a390 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,17 +1,10 @@ -extern crate gtk; -extern crate gtk_sys; -extern crate gdk; -extern crate gdk_sys; -extern crate glib; -extern crate ffi; -extern crate libc; - - use errors::*; -use gtk::prelude::*; use gdk::DeviceExt; use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK}; use gdk_sys::GDK_CURRENT_TIME; +use gtk::prelude::*; +use gtk; + pub fn set_slider(vol_scale_adj: >k::Adjustment, scale: f64) { vol_scale_adj.set_value(scale); diff --git a/src/gui_callbacks.rs b/src/gui_callbacks.rs index ac07c0b59..1f09d49e1 100644 --- a/src/gui_callbacks.rs +++ b/src/gui_callbacks.rs @@ -1,19 +1,13 @@ -extern crate gtk; -extern crate gtk_sys; -extern crate gdk; -extern crate gdk_sys; -extern crate alsa; -extern crate std; - -use gtk::prelude::*; -use gdk_sys::GDK_KEY_Escape; - -use gui; use app_state::*; +use audio::AlsaCard; use errors::*; +use gdk; +use gdk_sys::GDK_KEY_Escape; +use gtk::prelude::*; +use gtk; +use gui; use std::cell::RefCell; use std::rc::Rc; -use audio; pub fn init<'a>(appstate: &'a AppS, rc_acard: Rc>) { @@ -56,7 +50,7 @@ fn init_popup_window(appstate: &AppS, rc_acard: Rc>) { popup_window.connect_show(move |_| { let acard = card.borrow(); - let cur_vol = try_w!(audio::get_vol(&acard.selem())); + let cur_vol = try_w!(acard.vol()); println!("Cur vol: {}", cur_vol); gui::set_slider(&vol_scale_adj, cur_vol); diff --git a/src/main.rs b/src/main.rs index baf09eec9..a236bd160 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,29 +8,31 @@ extern crate log; #[macro_use] extern crate error_chain; -extern crate gtk; -extern crate gtk_sys; +extern crate alsa; +extern crate alsa_sys; +extern crate ffi; extern crate gdk; extern crate gdk_sys; -extern crate alsa; +extern crate glib_sys; +extern crate gtk; +extern crate gtk_sys; extern crate libc; -use gtk::prelude::*; -use gdk_sys::GDK_KEY_Escape; use app_state::*; +use gtk::prelude::*; use std::cell::RefCell; use std::rc::Rc; -use std::boxed::Box; - #[macro_use] mod errors; +mod app_state; mod audio; mod gui; mod gui_callbacks; -mod app_state; +mod myalsa; +use audio::AlsaCard; fn main() { @@ -53,7 +55,6 @@ fn main() { .init(Some("info".to_string())) .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e)); - gui_callbacks::init(apps, acard); gtk::main(); diff --git a/src/myalsa.rs b/src/myalsa.rs new file mode 100644 index 000000000..3cb324f24 --- /dev/null +++ b/src/myalsa.rs @@ -0,0 +1,111 @@ +use alsa; +use alsa::card::Card; +use alsa::mixer::{Mixer, Selem, Elem}; +use alsa::mixer::SelemChannelId::*; +use std::iter::Map; +use libc::c_int; +use errors::*; +use app_state; + + + +pub fn get_default_alsa_card() -> Card { + return get_alsa_card_by_id(0); +} + +pub fn get_alsa_card_by_id(index: c_int) -> Card { + return Card::new(index); +} + +pub fn get_alsa_cards() -> alsa::card::Iter { + return alsa::card::Iter::new(); +} + +pub fn get_alsa_card_by_name(name: String) -> Result { + for r_card in get_alsa_cards() { + let card = r_card?; + let card_name = card.get_name()?; + if name == card_name { + return Ok(card); + } + } + bail!("Not found a matching card named {}", name); +} + +pub fn get_mixer(card: &Card) -> Result { + return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr(); +} + +pub fn get_selem(elem: Elem) -> Selem { + /* in the ALSA API, there are currently only simple elements, + * so this unwrap() should be safe. + *http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html#enum-members */ + return Selem::new(elem).unwrap(); +} + +pub fn get_selems(mixer: &Mixer) -> Map Selem> { + return mixer.iter().map(get_selem); +} + +pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result { + for selem in get_selems(mixer) { + let n = selem.get_id().get_name().map(|y| String::from(y))?; + + if n == name { + return Ok(selem); + } + } + bail!("Not found a matching selem named {}", name); +} + +pub fn vol_to_percent(vol: i64, range: (i64, i64)) -> f64 { + let (min, max) = range; + return ((vol - min) as f64) / ((max - min) as f64) * 100.0; +} + +pub fn percent_to_vol(vol: f64, range: (i64, i64)) -> i64 { + let (min, max) = range; + let _v = vol / 100.0 * ((max - min) as f64) + (min as f64); + /* TODO: precision? Use direction. */ + return _v as i64; +} + +pub fn get_vol(selem: &Selem) -> Result { + let range = selem.get_playback_volume_range(); + let volume = selem.get_playback_volume(FrontRight).map(|v| { + return vol_to_percent(v, range); + }); + + return volume.cherr(); +} + +pub fn set_vol(selem: &Selem, new_vol: f64) -> Result<()> { + /* auto-unmute */ + if get_mute(selem)? { + set_mute(selem, false)?; + } + + let range = selem.get_playback_volume_range(); + selem.set_playback_volume_all( + percent_to_vol(new_vol, range), + )?; + + return Ok(()); +} + +pub fn has_mute(selem: &Selem) -> bool { + return selem.has_playback_switch(); +} + +pub fn get_mute(selem: &Selem) -> Result { + let val = selem.get_playback_switch(FrontRight)?; + return Ok(val == 0); +} + +pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> { + /* true -> mute, false -> unmute */ + let _ = selem.set_playback_switch_all(!mute as i32)?; + return Ok(()); +} + +