This commit is contained in:
Julian Ospald 2017-10-10 08:43:08 +02:00
parent 0f3652a6b2
commit 9e4653fbd1
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
13 changed files with 420 additions and 199 deletions

View File

@ -2,6 +2,7 @@
use audio::alsa::backend::*; use audio::alsa::backend::*;
use audio::pulseaudio::*;
use audio::frontend::*; use audio::frontend::*;
use errors::*; use errors::*;
use gtk; use gtk;
@ -52,6 +53,19 @@ pub fn new_alsa_appstate() -> AppS<AlsaBackend> {
return AppS::new(prefs, audio); return AppS::new(prefs, audio);
} }
/// Create a new application state using the `PABackend`.
pub fn new_pa_appstate() -> AppS<PABackend> {
let prefs = RefCell::new(unwrap_error!(Prefs::new(), None));
let card_name = prefs.borrow().device_prefs.card.clone();
let chan_name = prefs.borrow().device_prefs.channel.clone();
let audio = Rc::new(unwrap_error!(
PABackend::new(Some(card_name), Some(chan_name)),
None
));
return AppS::new(prefs, audio);
}
impl<T> AppS<T> impl<T> AppS<T>
where where

View File

@ -136,8 +136,20 @@ impl AudioFrontend for AlsaBackend {
return Ok(n); return Ok(n);
} }
fn playable_chan_names(&self) -> Vec<String> { fn playable_chan_names(&self, cardname: Option<String>) -> Vec<String> {
return get_playable_selem_names(&self.acard.borrow().mixer); match cardname {
Some(name) => {
let card = try_r!(get_alsa_card_by_name(name), Vec::default());
let mixer = try_r!(get_mixer(&card), Vec::default());
return get_playable_selem_names(&mixer);
},
None => self.acard.borrow().playable_chan_names(),
}
}
fn playable_card_names(&self) -> Vec<String> {
return get_playable_alsa_card_names();
} }
fn get_vol(&self) -> Result<f64> { fn get_vol(&self) -> Result<f64> {
@ -286,29 +298,6 @@ impl AudioFrontend for AlsaBackend {
} }
/// Invokes the registered handlers.
fn invoke_handlers(
handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
signal: AudioSignal,
user: AudioUser,
) {
debug!(
"Invoking handlers for signal {:?} by user {:?}",
signal,
user
);
if handlers.is_empty() {
debug!("No handler found");
} else {
debug!("Executing handlers")
}
for handler in handlers {
let unboxed = handler.as_ref();
unboxed(signal, user);
}
}
/// The callback for alsa events that is passed to the alsa subsystem. /// The callback for alsa events that is passed to the alsa subsystem.
/// This is the bridge between low-level alsa events and "high-level" /// This is the bridge between low-level alsa events and "high-level"
/// audio system signals. /// audio system signals.

View File

@ -184,6 +184,11 @@ impl AlsaCard {
} }
} }
} }
// Get playable channel names of the given card.
pub fn playable_chan_names(&self) -> Vec<String> {
return get_playable_selem_names(&self.mixer);
}
} }

View File

@ -153,8 +153,11 @@ pub trait AudioFrontend {
/// Get the current card name. /// Get the current card name.
fn card_name(&self) -> Result<String>; fn card_name(&self) -> Result<String>;
/// Get the currently playable card names.
fn playable_card_names(&self) -> Vec<String>;
/// Get the currently playable channel names. /// Get the currently playable channel names.
fn playable_chan_names(&self) -> Vec<String>; fn playable_chan_names(&self, cardname: Option<String>) -> Vec<String>;
/// Get the current active channel name. /// Get the current active channel name.
fn chan_name(&self) -> Result<String>; fn chan_name(&self) -> Result<String>;

View File

@ -1,18 +1,25 @@
#![allow(missing_docs)]
//! Pulseaudio backend subsystem. //! Pulseaudio backend subsystem.
use audio::frontend::*; use audio::frontend::*;
use errors::*; use errors::*;
use libc; use libc;
use libpulse_sys::*; use libpulse_sys::*;
use std::cell::Cell;
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::{CString, CStr}; use std::ffi::{CString};
use std::mem;
use std::os::raw::c_char;
use std::ptr; use std::ptr;
use support::pulseaudio::*; use support::pulseaudio::*;
use support::audio::*; use support::audio::*;
pub const PA_VOLUME_MUTED: i64 = 0x0;
pub const PA_VOLUME_NORM: i64 = 0x10000;
// TODO: get info based on index, not descr. // TODO: get info based on index, not descr.
// //
// TODO: how to hook pulseaudio events? port change? // TODO: how to hook pulseaudio events? port change?
@ -28,17 +35,47 @@ pub struct Sink {
pub channels: u8, pub channels: u8,
} }
impl Sink {
pub fn new(sink_desc: Option<String>,
chan_name: Option<String>,
mainloop: *mut pa_threaded_mainloop,
context: *mut pa_context) -> Result<Self> {
let sink = {
match sink_desc.as_ref().map(|s| s.as_str()) {
Some("(default)") => get_first_sink(mainloop, context)?,
Some(sd) => {
let mysink = get_sink_by_desc(mainloop, context, sd);
match mysink {
Ok(s) => s,
Err(_) => {
warn!("Could not find sink with name {}, trying others", sd);
get_first_sink(mainloop, context)?
}
}
}
None => get_first_sink(mainloop, context)?
}
};
return Ok(sink);
}
}
pub struct PABackend { pub struct PABackend {
_cannot_construct: (), _cannot_construct: (),
m: *mut pa_threaded_mainloop, m: *mut pa_threaded_mainloop,
c: *mut pa_context, c: *mut pa_context,
pub sink: RefCell<Sink>, pub sink: RefCell<Sink>,
pub scroll_step: Cell<u32>,
pub handlers: Handlers,
} }
impl PABackend { impl PABackend {
pub fn new(sink_desc: Option<String>) -> Result<Self> { pub fn new(sink_desc: Option<String>, chan_name: Option<String>) -> Result<Self> {
unsafe { unsafe {
let mainloop: *mut pa_threaded_mainloop = pa_threaded_mainloop_new(); let mainloop: *mut pa_threaded_mainloop = pa_threaded_mainloop_new();
@ -86,35 +123,74 @@ impl PABackend {
pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_unlock(mainloop);
CONTEXT_READY = false; CONTEXT_READY = false;
let sink = { let sink = Sink::new(sink_desc, chan_name, mainloop, context)?;
match sink_desc.as_ref().map(|s| s.as_str()) {
Some("(default)") => get_first_sink(mainloop, context)?,
Some(sd) => {
let mysink = get_sink_by_desc(mainloop, context, sd); pa_threaded_mainloop_lock(mainloop);
match mysink {
Ok(s) => s, let mut success: bool = false;
Err(_) => { let data = &mut(mainloop, &mut success);
warn!("Could not find sink with name {}, trying others", sd); let o = pa_context_subscribe(context,
get_first_sink(mainloop, context)? PA_SUBSCRIPTION_MASK_SINK,
} Some(context_subscribe_cb),
data as *mut _ as *mut libc::c_void);
if o.is_null() {
pa_threaded_mainloop_unlock(mainloop);
bail!("Failed to initialize PA operation!");
} }
while pa_operation_get_state(o) == PA_OPERATION_RUNNING {
pa_threaded_mainloop_wait(mainloop);
} }
None => get_first_sink(mainloop, context)? pa_operation_unref(o);
} pa_threaded_mainloop_unlock(mainloop);
let handlers = Handlers::new();
let cb_box = {
let h_ref: &Vec<Box<Fn(AudioSignal, AudioUser)>> = &handlers.borrow();
Box::new((mainloop, h_ref as *const Vec<Box<Fn(AudioSignal, AudioUser)>>))
}; };
{
pa_context_set_subscribe_callback(context,
Some(sub_callback),
Box::into_raw(cb_box) as *mut libc::c_void);
}
return Ok(PABackend { return Ok(PABackend {
_cannot_construct: (), _cannot_construct: (),
m: mainloop, m: mainloop,
c: context, c: context,
sink: RefCell::new(sink), sink: RefCell::new(sink),
scroll_step: Cell::new(5),
handlers,
}) })
} }
} }
}
pub fn get_vol(&self) -> Result<f64> {
impl AudioFrontend for PABackend {
// TODO
fn switch_card(
&self,
card_name: Option<String>,
elem_name: Option<String>,
user: AudioUser,
) -> Result<()> {
{
let mut ac = self.sink.borrow_mut();
*ac = Sink::new(card_name, elem_name, self.m, self.c)?;
}
return Ok(())
}
fn get_vol(&self) -> Result<f64> {
let mut vol: u32 = 0; let mut vol: u32 = 0;
unsafe { unsafe {
@ -140,19 +216,21 @@ impl PABackend {
let _ = CString::from_raw(sink_name); let _ = CString::from_raw(sink_name);
} }
unsafe {
return Ok(pa_sw_volume_to_linear(vol) * 100.0); return vol_to_percent(vol as i64, (PA_VOLUME_MUTED,
} PA_VOLUME_NORM))
} }
pub fn set_vol(&self, new_vol: f64, dir: VolDir) -> Result<()> {
fn set_vol(&self, new_vol: f64, user: AudioUser, dir: VolDir, auto_unmute: bool) -> Result<()> {
let mut res: Result<()> = Err("No value".into()); let mut res: Result<()> = Err("No value".into());
let new_vol = percent_to_vol(new_vol, (PA_VOLUME_MUTED,
PA_VOLUME_NORM), dir)?;
unsafe { unsafe {
pa_threaded_mainloop_lock(self.m); pa_threaded_mainloop_lock(self.m);
let data = &mut(self, &mut res); let data = &mut(self, &mut res);
let sink_name = CString::new(self.sink.borrow().name.clone()).unwrap().into_raw(); let sink_name = CString::new(self.sink.borrow().name.clone()).unwrap().into_raw();
let new_vol = pa_sw_volume_from_linear(new_vol / 100.0);
let mut vol_arr: [u32; 32] = [0; 32]; let mut vol_arr: [u32; 32] = [0; 32];
for c in 0..(self.sink.borrow().channels) { for c in 0..(self.sink.borrow().channels) {
vol_arr[c as usize] = new_vol as u32; vol_arr[c as usize] = new_vol as u32;
@ -185,11 +263,44 @@ impl PABackend {
return res; return res;
} }
pub fn has_mute(&self) -> bool {
fn vol_level(&self) -> VolLevel {
let muted = self.get_mute().unwrap_or(false);
if muted {
return VolLevel::Muted;
}
let cur_vol = try_r!(self.get_vol(), VolLevel::Muted);
match cur_vol {
0. => return VolLevel::Off,
0.0...33.0 => return VolLevel::Low,
0.0...66.0 => return VolLevel::Medium,
0.0...100.0 => return VolLevel::High,
_ => return VolLevel::Off,
}
}
fn increase_vol(&self, user: AudioUser, auto_unmute: bool) -> Result<()> {
let old_vol = self.get_vol()?;
let new_vol = old_vol + (self.scroll_step.get() as f64);
return self.set_vol(new_vol, user, VolDir::Up, auto_unmute);
}
fn decrease_vol(&self, user: AudioUser, auto_unmute: bool) -> Result<()> {
let old_vol = self.get_vol()?;
let new_vol = old_vol - (self.scroll_step.get() as f64);
return self.set_vol(new_vol, user, VolDir::Down, auto_unmute);
}
fn has_mute(&self) -> bool {
return true; return true;
} }
pub fn get_mute(&self) -> Result<bool> {
fn get_mute(&self) -> Result<bool> {
let mut mute: bool = false; let mut mute: bool = false;
unsafe { unsafe {
@ -216,7 +327,8 @@ impl PABackend {
return Ok(mute); return Ok(mute);
} }
pub fn set_mute(&self, mute: bool) -> Result<()> {
fn set_mute(&self, mute: bool, user: AudioUser) -> Result<()> {
let mut res: Result<()> = Err("No value".into()); let mut res: Result<()> = Err("No value".into());
unsafe { unsafe {
pa_threaded_mainloop_lock(self.m); pa_threaded_mainloop_lock(self.m);
@ -243,6 +355,45 @@ impl PABackend {
return res; return res;
} }
fn toggle_mute(&self, user: AudioUser) -> Result<()> {
let muted = self.get_mute()?;
return self.set_mute(!muted, user);
}
// TODO
fn connect_handler(&self, cb: Box<Fn(AudioSignal, AudioUser)>) {
self.handlers.add_handler(cb);
}
// TODO: name or desc?
fn card_name(&self) -> Result<String> {
return Ok(self.sink.borrow().description.clone())
}
fn playable_card_names(&self) -> Vec<String> {
let sinks = try_r!(get_sinks(self.m, self.c), vec![]);
return sinks.iter().map(|s| s.description.clone()).collect();
}
// TODO
fn playable_chan_names(&self, cardname: Option<String>) -> Vec<String> {
return vec![]
}
// TODO
fn chan_name(&self) -> Result<String> {
return Ok(String::from("Blah"))
}
fn set_scroll_step(&self, scroll_step: u32) {
self.scroll_step.set(scroll_step);
}
fn get_scroll_step(&self) -> u32 {
return self.scroll_step.get();
}
} }
@ -284,13 +435,14 @@ unsafe extern "C" fn context_state_cb(
// TODO: Better error handling. // TODO: Better error handling.
unsafe extern "C" fn get_sink_vol( unsafe extern "C" fn get_sink_vol(
ctx: *mut pa_context, _: *mut pa_context,
i: *const pa_sink_info, i: *const pa_sink_info,
eol: i32, _: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let (_self, res) = *(data as *mut (*mut PABackend, let (_self, res) = *(data as *mut (*mut PABackend,
*mut u32)); *mut u32));
assert!(!(*_self).m.is_null(), "Mainloop is null"); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!res.is_null(), "res is null");
if i.is_null() { if i.is_null() {
return return
@ -303,13 +455,14 @@ unsafe extern "C" fn get_sink_vol(
// TODO: Better error handling. // TODO: Better error handling.
unsafe extern "C" fn get_sink_mute( unsafe extern "C" fn get_sink_mute(
ctx: *mut pa_context, _: *mut pa_context,
i: *const pa_sink_info, i: *const pa_sink_info,
eol: i32, _: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let (_self, res) = *(data as *mut (*mut PABackend, let (_self, res) = *(data as *mut (*mut PABackend,
*mut bool)); *mut bool));
assert!(!(*_self).m.is_null(), "Mainloop is null"); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!res.is_null(), "res is null");
if i.is_null() { if i.is_null() {
return return
@ -322,12 +475,13 @@ unsafe extern "C" fn get_sink_mute(
// TODO: Missing error handling. // TODO: Missing error handling.
unsafe extern "C" fn set_sink_vol( unsafe extern "C" fn set_sink_vol(
ctx: *mut pa_context, _: *mut pa_context,
success: i32, success: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let (_self, res) = *(data as *mut (*mut PABackend, let (_self, res) = *(data as *mut (*mut PABackend,
*mut Result<()>)); *mut Result<()>));
assert!(!(*_self).m.is_null(), "Mainloop is null"); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!res.is_null(), "res is null");
if success > 0 { if success > 0 {
*res = Ok(()); *res = Ok(());
@ -342,12 +496,13 @@ unsafe extern "C" fn set_sink_vol(
// TODO: Missing error handling. // TODO: Missing error handling.
// TODO: same as 'set_sink_vol' // TODO: same as 'set_sink_vol'
unsafe extern "C" fn set_sink_mute( unsafe extern "C" fn set_sink_mute(
ctx: *mut pa_context, _: *mut pa_context,
success: i32, success: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let (_self, res) = *(data as *mut (*mut PABackend, let (_self, res) = *(data as *mut (*mut PABackend,
*mut Result<()>)); *mut Result<()>));
assert!(!(*_self).m.is_null(), "Mainloop is null"); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!res.is_null(), "res is null");
if success > 0 { if success > 0 {
*res = Ok(()); *res = Ok(());
@ -357,3 +512,51 @@ unsafe extern "C" fn set_sink_mute(
pa_threaded_mainloop_signal((*_self).m, 0); pa_threaded_mainloop_signal((*_self).m, 0);
} }
unsafe extern "C" fn context_subscribe_cb(c: *mut pa_context,
success: i32,
data: *mut libc::c_void) {
let (mainloop, res) = *(data as *mut (*mut pa_threaded_mainloop,
*mut bool));
assert!(!mainloop.is_null(), "Mainloop is null");
assert!(!res.is_null(), "res is null");
if success > 0 {
*res = true;
} else {
*res = false;
}
pa_threaded_mainloop_signal(mainloop, 0);
}
unsafe extern "C" fn sub_callback(c: *mut pa_context,
t: u32,
idx: u32,
data: *mut libc::c_void) {
let (mainloop, p_handlers) = *(data as *mut (*mut pa_threaded_mainloop,
*mut Vec<Box<Fn(AudioSignal, AudioUser)>>));
assert!(!mainloop.is_null(), "Mainloop is null");
assert!(!p_handlers.is_null(), "Handlers are null");
let handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>> = &*p_handlers;
if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) ==
PA_SUBSCRIPTION_EVENT_SINK {
if (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE {
// invoke_handlers(
// handlers,
// AudioSignal::ValuesChanged,
// AudioUser::Unknown,
// );
}
}
}

View File

@ -22,6 +22,7 @@ use support::audio::VolDir;
fn main() { fn main() {
@ -73,22 +74,22 @@ fn main() {
.unwrap_or_else(|e|{panic!("Logger initialization failed with {}",e)}); .unwrap_or_else(|e|{panic!("Logger initialization failed with {}",e)});
let pa = PABackend::new(Some(String::from("Built-in Audio Analog Stereo"))).unwrap(); // let pa = PABackend::new(Some(String::from("Built-in Audio Analog Stereo"))).unwrap();
println!("Sink: {:?}", pa.sink); // println!("Sink: {:?}", pa.sink);
println!("Volume before: {:?}", pa.get_vol()); // println!("Volume before: {:?}", pa.get_vol());
pa.set_vol(80.0, VolDir::Up); // pa.set_vol(80.0, VolDir::Up);
println!("Volume after: {:?}", pa.get_vol()); // println!("Volume after: {:?}", pa.get_vol());
println!("Mute before: {:?}", pa.get_mute()); // println!("Mute before: {:?}", pa.get_mute());
println!("PA_VOLUME_NORM: {:?}", PA_VOLUME_NORM); // println!("PA_VOLUME_NORM: {:?}", PA_VOLUME_NORM);
// pa.set_mute(true); // pa.set_mute(true);
// println!("Mute after: {:?}", pa.get_mute()); // println!("Mute after: {:?}", pa.get_mute());
return; // return;
gtk::init() gtk::init()
.unwrap_or_else(|e| panic!("Gtk initialization failed with {}", e)); .unwrap_or_else(|e| panic!("Gtk initialization failed with {}", e));
let apps = Rc::new(new_alsa_appstate()); let apps = Rc::new(new_pa_appstate());
ui::entry::init(apps); ui::entry::init(apps);

View File

@ -144,37 +144,37 @@ where
{ {
{ {
/* connect handler */ /* connect handler */
let apps = appstate.clone(); // let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| { // appstate.audio.connect_handler(Box::new(move |s, u| {
let notif = &apps.notif; // let notif = &apps.notif;
if notif.is_none() || !notif.as_ref().unwrap().enabled.get() { // if notif.is_none() || !notif.as_ref().unwrap().enabled.get() {
return; // return;
} // }
let notif = notif.as_ref().unwrap(); // let notif = notif.as_ref().unwrap();
match (s, // match (s,
u, // u,
(notif.from_popup.get(), // (notif.from_popup.get(),
notif.from_tray.get(), // notif.from_tray.get(),
notif.from_external.get(), // notif.from_external.get(),
notif.from_hotkeys.get())) { // notif.from_hotkeys.get())) {
(AudioSignal::NoCard, _, _) => try_w!(notif.show_text_notif("No sound card", "No playable soundcard found")), // (AudioSignal::NoCard, _, _) => try_w!(notif.show_text_notif("No sound card", "No playable soundcard found")),
(AudioSignal::CardDisconnected, _, _) => try_w!(notif.show_text_notif("Soundcard disconnected", "Soundcard has been disconnected, reloading sound system...")), // (AudioSignal::CardDisconnected, _, _) => try_w!(notif.show_text_notif("Soundcard disconnected", "Soundcard has been disconnected, reloading sound system...")),
(AudioSignal::CardError, _, _) => (), // (AudioSignal::CardError, _, _) => (),
(AudioSignal::ValuesChanged, // (AudioSignal::ValuesChanged,
AudioUser::TrayIcon, // AudioUser::TrayIcon,
(_, true, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())), // (_, true, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
(AudioSignal::ValuesChanged, // (AudioSignal::ValuesChanged,
AudioUser::Popup, // AudioUser::Popup,
(true, _, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())), // (true, _, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
(AudioSignal::ValuesChanged, // (AudioSignal::ValuesChanged,
AudioUser::Unknown, // AudioUser::Unknown,
(_, _, true, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())), // (_, _, true, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
(AudioSignal::ValuesChanged, // (AudioSignal::ValuesChanged,
AudioUser::Hotkeys, // AudioUser::Hotkeys,
(_, _, _, true)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())), // (_, _, _, true)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
_ => (), // _ => (),
} // }
})); // }));
} }
} }

View File

@ -10,8 +10,6 @@ use audio::frontend::*;
use errors::*; use errors::*;
use prefs::*; use prefs::*;
// TODO: rm alsa
use support::alsa::*;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -100,16 +98,25 @@ pub fn percent_to_vol(vol: f64, range: (i64, i64), dir: VolDir) -> Result<i64> {
} }
/// Get all playable card names. /// Invokes the registered handlers.
pub fn get_playable_card_names() -> Vec<String> { pub fn invoke_handlers(
return get_playable_alsa_card_names(); handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
signal: AudioSignal,
user: AudioUser,
) {
debug!(
"Invoking handlers for signal {:?} by user {:?}",
signal,
user
);
if handlers.is_empty() {
debug!("No handler found");
} else {
debug!("Executing handlers")
}
for handler in handlers {
debug!("Handler executing");
let unboxed = handler.as_ref();
unboxed(signal, user);
} }
/// Get all playable channel names.
pub fn get_playable_chan_names(card_name: String) -> Vec<String> {
let card = try_r!(get_alsa_card_by_name(card_name), Vec::default());
let mixer = try_r!(get_mixer(&card), Vec::default());
return get_playable_selem_names(&mixer);
} }

View File

@ -63,31 +63,31 @@ where
{ {
{ {
/* "global" audio signal handler */ /* "global" audio signal handler */
let apps = appstate.clone(); // let apps = appstate.clone();
appstate.audio.connect_handler( // appstate.audio.connect_handler(
Box::new(move |s, u| match (s, u) { // Box::new(move |s, u| match (s, u) {
(AudioSignal::CardDisconnected, _) => { // (AudioSignal::CardDisconnected, _) => {
try_w!(audio_reload( // try_w!(audio_reload(
apps.audio.as_ref(), // apps.audio.as_ref(),
&apps.prefs.borrow(), // &apps.prefs.borrow(),
AudioUser::Unknown, // AudioUser::Unknown,
)); // ));
} // }
(AudioSignal::CardError, _) => { // (AudioSignal::CardError, _) => {
if run_audio_error_dialog( // if run_audio_error_dialog(
&apps.gui.popup_menu.menu_window, // &apps.gui.popup_menu.menu_window,
) == (GTK_RESPONSE_YES as i32) // ) == (GTK_RESPONSE_YES as i32)
{ // {
try_w!(audio_reload( // try_w!(audio_reload(
apps.audio.as_ref(), // apps.audio.as_ref(),
&apps.prefs.borrow(), // &apps.prefs.borrow(),
AudioUser::Unknown, // AudioUser::Unknown,
)); // ));
} // }
} // }
_ => (), // _ => (),
}), // }),
); // );
} }

View File

@ -48,16 +48,16 @@ where
{ {
/* audio.connect_handler */ /* audio.connect_handler */
{ {
let apps = appstate.clone(); // let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| { // appstate.audio.connect_handler(Box::new(move |s, u| {
/* skip if window is hidden */ // /* skip if window is hidden */
if !apps.gui.popup_menu.menu.get_visible() { // if !apps.gui.popup_menu.menu.get_visible() {
return; // return;
} // }
match (s, u) { // match (s, u) {
(_, _) => set_mute_check(&apps), // (_, _) => set_mute_check(&apps),
} // }
})); // }));
} }

View File

@ -125,31 +125,31 @@ where
{ {
/* audio.connect_handler */ /* audio.connect_handler */
{ {
let apps = appstate.clone(); // let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| { // appstate.audio.connect_handler(Box::new(move |s, u| {
/* skip if window is hidden */ // /* skip if window is hidden */
if !apps.gui.popup_window.popup_window.get_visible() { // if !apps.gui.popup_window.popup_window.get_visible() {
return; // return;
} // }
match (s, u) { // match (s, u) {
/* Update only mute check here // /* Update only mute check here
* If the user changes the volume through the popup window, // * If the user changes the volume through the popup window,
* we MUST NOT update the slider value, it's been done already. // * we MUST NOT update the slider value, it's been done already.
* It means that, as long as the popup window is visible, // * It means that, as long as the popup window is visible,
* the slider value reflects the value set by user, // * the slider value reflects the value set by user,
* and not the real value reported by the audio system. // * and not the real value reported by the audio system.
*/ // */
(_, AudioUser::Popup) => { // (_, AudioUser::Popup) => {
apps.gui.popup_window.update_mute_check( // apps.gui.popup_window.update_mute_check(
apps.audio.as_ref(), // apps.audio.as_ref(),
); // );
} // }
/* external change, safe to update slider too */ // /* external change, safe to update slider too */
(_, _) => { // (_, _) => {
try_w!(apps.gui.popup_window.update(apps.audio.as_ref())); // try_w!(apps.gui.popup_window.update(apps.audio.as_ref()));
} // }
} // }
})); // }));
} }
/* mute_check.connect_toggled */ /* mute_check.connect_toggled */

View File

@ -13,7 +13,6 @@ use prefs::*;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use support::audio::*;
use ui::hotkey_dialog::HotkeyDialog; use ui::hotkey_dialog::HotkeyDialog;
@ -434,21 +433,21 @@ where
T: AudioFrontend + 'static, T: AudioFrontend + 'static,
{ {
let apps = appstate.clone(); let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| { // appstate.audio.connect_handler(Box::new(move |s, u| {
/* skip if prefs window is not present */ // /* skip if prefs window is not present */
if apps.gui.prefs_dialog.borrow().is_none() { // if apps.gui.prefs_dialog.borrow().is_none() {
return; // return;
} // }
match (s, u) { // match (s, u) {
(AudioSignal::CardInitialized, _) => (), // (AudioSignal::CardInitialized, _) => (),
(AudioSignal::CardCleanedUp, _) => { // (AudioSignal::CardCleanedUp, _) => {
fill_card_combo(&apps); // fill_card_combo(&apps);
fill_chan_combo(&apps, None); // fill_chan_combo(&apps, None);
} // }
_ => (), // _ => (),
} // }
})); // }));
} }
@ -586,7 +585,7 @@ where
/* set card combo */ /* set card combo */
let cur_card_name = let cur_card_name =
try_w!(audio.card_name(), "Can't get current card name!"); try_w!(audio.card_name(), "Can't get current card name!");
let available_card_names = get_playable_card_names(); let available_card_names = audio.playable_card_names();
/* set_active_id doesn't work, so save the index */ /* set_active_id doesn't work, so save the index */
let mut c_index: i32 = -1; let mut c_index: i32 = -1;
@ -613,10 +612,7 @@ where
chan_combo.remove_all(); chan_combo.remove_all();
let audio = &appstate.audio; let audio = &appstate.audio;
let available_chan_names = match cardname { let available_chan_names = audio.playable_chan_names(cardname);
Some(name) => get_playable_chan_names(name),
None => audio.playable_chan_names(),
};
/* set chan combo */ /* set chan combo */
let cur_chan_name = try_w!(audio.chan_name()); let cur_chan_name = try_w!(audio.chan_name());

View File

@ -422,11 +422,14 @@ where
appstate.audio.connect_handler( appstate.audio.connect_handler(
Box::new(move |s, u| match (s, u) { Box::new(move |s, u| match (s, u) {
(_, _) => { (_, _) => {
apps.gui.tray_icon.update_tooltip(apps.audio.as_ref()); // apps.gui.tray_icon.update_tooltip(apps.audio.as_ref());
try_w!(apps.gui.tray_icon.update_vol_meter( // try_w!(apps.gui.tray_icon.update_vol_meter(
try_w!(apps.audio.get_vol()), // try_w!(apps.audio.get_vol()),
apps.audio.vol_level(), // apps.audio.vol_level(),
)); // ));
let vol = apps.audio.get_vol();
println!("Vol: {:?}", vol)
// println!("Gaga");
} }
}), }),
); );