From f8939ec58101a9c835b72545b802df96d47b2b00 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 8 Jul 2017 01:35:13 +0200 Subject: [PATCH] Update --- src/alsa_card.rs | 31 +++++++++++++------ src/app_state.rs | 7 ++++- src/support_alsa.rs | 68 ++++++++++++++++++++++++++++++++++-------- src/ui_popup_menu.rs | 49 ++++++++++++++++++++---------- src/ui_popup_window.rs | 5 ++-- src/ui_prefs_dialog.rs | 4 +-- src/ui_tray_icon.rs | 4 ++- 7 files changed, 126 insertions(+), 42 deletions(-) diff --git a/src/alsa_card.rs b/src/alsa_card.rs index 65e6113c4..f40c7c5e8 100644 --- a/src/alsa_card.rs +++ b/src/alsa_card.rs @@ -44,24 +44,36 @@ impl AlsaCard { match card_name { Some(name) => { if name == "(default)" { - get_default_alsa_card() + let default = get_default_alsa_card(); + if alsa_card_has_playable_selem(&default) { + default + } else { + warn!("Default alsa card not playabla, trying others"); + get_first_playable_alsa_card()? + } } else { - get_alsa_card_by_name(name)? + let mycard = get_alsa_card_by_name(name.clone()); + match mycard { + Ok(card) => card, + Err(_) => { + warn!("Card {} not playable, trying others", name); + get_first_playable_alsa_card()? + } + } } }, - None => get_default_alsa_card(), + None => get_first_playable_alsa_card()?, } }; let mixer = get_mixer(&card)?; - let vec_pollfd = PollDescriptors::get(&mixer)?; - let selem_id = - get_selem_by_name(&mixer, - elem_name.unwrap_or(String::from("Master"))) - .unwrap() + get_playable_selem_by_name(&mixer, + elem_name.unwrap_or(String::from("Master")))? .get_id(); + let vec_pollfd = PollDescriptors::get(&mixer)?; + let acard = Box::new(AlsaCard { _cannot_construct: (), card: card, @@ -114,7 +126,7 @@ impl AlsaCard { pub fn set_vol(&self, new_vol: f64) -> Result<()> { let selem = self.selem(); /* auto-unmute */ - if self.get_mute()? { + if self.has_mute() && self.get_mute()? { self.set_mute(false)?; } @@ -241,6 +253,7 @@ extern "C" fn watch_cb(chan: *mut glib_sys::GIOChannel, debug!("G_IO_STATUS_AGAIN"); continue; } + // TODO: handle these failure cases glib_sys::G_IO_STATUS_NORMAL => debug!("G_IO_STATUS_NORMAL"), glib_sys::G_IO_STATUS_ERROR => debug!("G_IO_STATUS_ERROR"), glib_sys::G_IO_STATUS_EOF => debug!("G_IO_STATUS_EOF"), diff --git a/src/app_state.rs b/src/app_state.rs index 74aac0a6f..b1ef1cf46 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -30,10 +30,14 @@ impl AppS { let gui = Gui::new(builder_popup_window, builder_popup_menu, &prefs.borrow()); + let card_name = prefs.borrow().device_prefs.card.clone(); + let chan_name = prefs.borrow().device_prefs.channel.clone(); + return AppS { _cant_construct: (), gui: gui, - audio: Audio::new(None, Some(String::from("Master"))) + audio: Audio::new(Some(card_name), + Some(chan_name)) .unwrap(), prefs: prefs, }; @@ -54,6 +58,7 @@ impl AppS { return self.gui.popup_window.update(&self.audio); } + // TODO pub fn show_preferences(&self) { // show_prefs_dialog(self); } diff --git a/src/support_alsa.rs b/src/support_alsa.rs index 2e2a40549..0ce860e19 100644 --- a/src/support_alsa.rs +++ b/src/support_alsa.rs @@ -1,9 +1,10 @@ use alsa::card::Card; -use alsa::mixer::{Mixer, Selem, Elem}; +use alsa::mixer::{Mixer, Selem, SelemId, Elem}; use alsa; use errors::*; use libc::c_int; use std::iter::Map; +use std::iter::Filter; @@ -22,11 +23,34 @@ pub fn get_alsa_cards() -> alsa::card::Iter { } -pub fn get_alsa_card_names() -> Vec { +pub fn get_first_playable_alsa_card() -> Result { + for m_card in get_alsa_cards() { + match m_card { + Ok(card) => { + if alsa_card_has_playable_selem(&card) { + return Ok(card); + } + }, + _ => (), + } + } + + bail!("No playable alsa card found!") +} + + +pub fn get_playable_alsa_card_names() -> Vec { let mut vec = vec![]; - for card in get_alsa_cards() { - match card.and_then(|c| c.get_name()) { - Ok(name) => vec.push(name), + for m_card in get_alsa_cards() { + match m_card { + Ok(card) => { + if alsa_card_has_playable_selem(&card) { + let m_name = card.get_name(); + if m_name.is_ok() { + vec.push(m_name.unwrap()) + } + } + }, _ => (), } } @@ -47,6 +71,17 @@ pub fn get_alsa_card_by_name(name: String) -> Result { } +pub fn alsa_card_has_playable_selem(card: &Card) -> bool { + let mixer = try_wr!(get_mixer(&card), false); + for selem in get_playable_selems(&mixer) { + if selem_is_playable(&selem) { + return true; + } + } + return false; +} + + pub fn get_mixer(card: &Card) -> Result { return Mixer::new(&format!("hw:{}", card.get_index()), false).from_err(); } @@ -60,14 +95,18 @@ pub fn get_selem(elem: Elem) -> Selem { } -pub fn get_selems(mixer: &Mixer) -> Map Selem> { - return mixer.iter().map(get_selem); +pub fn get_playable_selems(mixer: &Mixer) -> Vec { + let mut v = vec![]; + for s in mixer.iter().map(get_selem).filter(selem_is_playable) { + v.push(s); + } + return v; } -pub fn get_selem_names(mixer: &Mixer) -> Vec { +pub fn get_playable_selem_names(mixer: &Mixer) -> Vec { let mut vec = vec![]; - for selem in get_selems(mixer) { + for selem in get_playable_selems(mixer) { let n = selem.get_id().get_name().map(|y| String::from(y)); match n { Ok(name) => vec.push(name), @@ -79,8 +118,8 @@ pub fn get_selem_names(mixer: &Mixer) -> Vec { } -pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result { - for selem in get_selems(mixer) { +pub fn get_playable_selem_by_name(mixer: &Mixer, name: String) -> Result { + for selem in get_playable_selems(mixer) { let n = selem.get_id() .get_name() .map(|y| String::from(y))?; @@ -89,7 +128,12 @@ pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result { return Ok(selem); } } - bail!("Not found a matching selem named {}", name); + bail!("Not found a matching playable selem named {}", name); +} + + +pub fn selem_is_playable(selem: &Selem) -> bool { + return selem.has_playback_volume(); } diff --git a/src/ui_popup_menu.rs b/src/ui_popup_menu.rs index 7313d9839..3eaa9fa00 100644 --- a/src/ui_popup_menu.rs +++ b/src/ui_popup_menu.rs @@ -38,13 +38,7 @@ pub fn init_popup_menu(appstate: Rc) { return; } match (s, u) { - (_, _) => { - let muted = try_w!(apps.audio.get_mute()); - apps.gui - .popup_menu - .mute_check - .set_active(muted); - } + (_, _) => set_mute_check(&apps) } })); @@ -57,11 +51,7 @@ pub fn init_popup_menu(appstate: Rc) { .popup_menu .menu .connect_show(move |_| { - let muted = try_w!(apps.audio.get_mute()); - apps.gui - .popup_menu - .mute_check - .set_active(muted); + set_mute_check(&apps) }); } @@ -75,12 +65,14 @@ pub fn init_popup_menu(appstate: Rc) { }); } - /* about_item.connect_activate_link */ + /* mute_item.connect_activate_link */ { let apps = appstate.clone(); let mute_item = &appstate.gui.popup_menu.mute_item; mute_item.connect_activate(move |_| { - try_w!(apps.audio.toggle_mute(AudioUser::Popup)); + if apps.audio.has_mute() { + try_w!(apps.audio.toggle_mute(AudioUser::Popup)); + } }); } @@ -93,7 +85,7 @@ pub fn init_popup_menu(appstate: Rc) { }); } - /* about_item.connect_activate_link */ + /* prefs_item.connect_activate_link */ { let apps = appstate.clone(); let prefs_item = &appstate.gui.popup_menu.prefs_item; @@ -157,3 +149,30 @@ fn on_prefs_item_activate(appstate: &Rc) { /* TODO: only create if needed */ show_prefs_dialog(appstate); } + + +fn set_mute_check(apps: &Rc) { + let mute_check = &apps.gui + .popup_menu + .mute_check; + let m_muted = apps.audio.get_mute(); + match m_muted { + Ok(muted) => { + mute_check + .set_sensitive(false); + mute_check + .set_active(muted); + mute_check.set_tooltip_text( + ""); + }, + Err(_) => { + mute_check + .set_active(true); + mute_check + .set_sensitive(false); + mute_check.set_tooltip_text( + "Soundcard has no mute switch", + ); + } + } +} diff --git a/src/ui_popup_window.rs b/src/ui_popup_window.rs index f7423fbd2..ec9ec89ba 100644 --- a/src/ui_popup_window.rs +++ b/src/ui_popup_window.rs @@ -48,12 +48,13 @@ impl PopupWindow { } pub fn update_mute_check(&self, audio: &Audio) { - let muted = audio.get_mute(); + let m_muted = audio.get_mute(); glib::signal_handler_block(&self.mute_check, self.toggle_signal.get()); - match muted { + match m_muted { Ok(val) => { + self.mute_check.set_sensitive(true); self.mute_check.set_active(val); self.mute_check.set_tooltip_text(""); } diff --git a/src/ui_prefs_dialog.rs b/src/ui_prefs_dialog.rs index 191bf1d98..6da6cf7f4 100644 --- a/src/ui_prefs_dialog.rs +++ b/src/ui_prefs_dialog.rs @@ -329,7 +329,7 @@ fn fill_card_combo(appstate: &AppS) { /* set card combo */ let cur_card_name = try_w!(acard.card_name(), "Can't get current card name!"); - let available_card_names = get_alsa_card_names(); + let available_card_names = get_playable_alsa_card_names(); /* set_active_id doesn't work, so save the index */ let mut c_index: i32 = -1; @@ -362,7 +362,7 @@ fn fill_chan_combo(appstate: &AppS, cardname: Option) { /* set chan combo */ let cur_chan_name = try_w!(cur_acard.chan_name()); let mixer = try_w!(get_mixer(&card)); - let available_chan_names = get_selem_names(&mixer); + let available_chan_names = get_playable_selem_names(&mixer); /* set_active_id doesn't work, so save the index */ let mut c_index: i32 = -1; diff --git a/src/ui_tray_icon.rs b/src/ui_tray_icon.rs index 8935177f2..65dafad63 100644 --- a/src/ui_tray_icon.rs +++ b/src/ui_tray_icon.rs @@ -415,7 +415,9 @@ fn on_tray_button_release_event(appstate: &AppS, match middle_click_action { &MiddleClickAction::ToggleMute => { - try_wr!(audio.toggle_mute(AudioUser::Popup), false); + if audio.has_mute() { + try_wr!(audio.toggle_mute(AudioUser::Popup), false); + } } &MiddleClickAction::ShowPreferences => (), &MiddleClickAction::VolumeControl => {