adad
This commit is contained in:
parent
0f3652a6b2
commit
9e4653fbd1
@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
use audio::alsa::backend::*;
|
||||
use audio::pulseaudio::*;
|
||||
use audio::frontend::*;
|
||||
use errors::*;
|
||||
use gtk;
|
||||
@ -52,6 +53,19 @@ pub fn new_alsa_appstate() -> AppS<AlsaBackend> {
|
||||
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>
|
||||
where
|
||||
|
@ -136,8 +136,20 @@ impl AudioFrontend for AlsaBackend {
|
||||
return Ok(n);
|
||||
}
|
||||
|
||||
fn playable_chan_names(&self) -> Vec<String> {
|
||||
return get_playable_selem_names(&self.acard.borrow().mixer);
|
||||
fn playable_chan_names(&self, cardname: Option<String>) -> Vec<String> {
|
||||
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> {
|
||||
@ -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.
|
||||
/// This is the bridge between low-level alsa events and "high-level"
|
||||
/// audio system signals.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -153,8 +153,11 @@ pub trait AudioFrontend {
|
||||
/// Get the current card name.
|
||||
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.
|
||||
fn playable_chan_names(&self) -> Vec<String>;
|
||||
fn playable_chan_names(&self, cardname: Option<String>) -> Vec<String>;
|
||||
|
||||
/// Get the current active channel name.
|
||||
fn chan_name(&self) -> Result<String>;
|
||||
|
@ -1,18 +1,25 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
|
||||
//! Pulseaudio backend subsystem.
|
||||
|
||||
use audio::frontend::*;
|
||||
use errors::*;
|
||||
use libc;
|
||||
use libpulse_sys::*;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{CString, CStr};
|
||||
use std::mem;
|
||||
use std::os::raw::c_char;
|
||||
use std::ffi::{CString};
|
||||
use std::ptr;
|
||||
use support::pulseaudio::*;
|
||||
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: how to hook pulseaudio events? port change?
|
||||
@ -28,17 +35,47 @@ pub struct Sink {
|
||||
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 {
|
||||
_cannot_construct: (),
|
||||
m: *mut pa_threaded_mainloop,
|
||||
c: *mut pa_context,
|
||||
pub sink: RefCell<Sink>,
|
||||
pub scroll_step: Cell<u32>,
|
||||
pub handlers: Handlers,
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
let mainloop: *mut pa_threaded_mainloop = pa_threaded_mainloop_new();
|
||||
|
||||
@ -86,35 +123,74 @@ impl PABackend {
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
CONTEXT_READY = false;
|
||||
|
||||
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)?
|
||||
}
|
||||
}
|
||||
let sink = Sink::new(sink_desc, chan_name, mainloop, context)?;
|
||||
|
||||
}
|
||||
None => get_first_sink(mainloop, context)?
|
||||
}
|
||||
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
|
||||
let mut success: bool = false;
|
||||
let data = &mut(mainloop, &mut success);
|
||||
let o = pa_context_subscribe(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);
|
||||
}
|
||||
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 {
|
||||
_cannot_construct: (),
|
||||
m: mainloop,
|
||||
c: context,
|
||||
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;
|
||||
unsafe {
|
||||
@ -140,19 +216,21 @@ impl PABackend {
|
||||
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 new_vol = percent_to_vol(new_vol, (PA_VOLUME_MUTED,
|
||||
PA_VOLUME_NORM), dir)?;
|
||||
unsafe {
|
||||
pa_threaded_mainloop_lock(self.m);
|
||||
let data = &mut(self, &mut res);
|
||||
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];
|
||||
for c in 0..(self.sink.borrow().channels) {
|
||||
vol_arr[c as usize] = new_vol as u32;
|
||||
@ -185,11 +263,44 @@ impl PABackend {
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn get_mute(&self) -> Result<bool> {
|
||||
|
||||
fn get_mute(&self) -> Result<bool> {
|
||||
let mut mute: bool = false;
|
||||
unsafe {
|
||||
|
||||
@ -216,7 +327,8 @@ impl PABackend {
|
||||
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());
|
||||
unsafe {
|
||||
pa_threaded_mainloop_lock(self.m);
|
||||
@ -243,6 +355,45 @@ impl PABackend {
|
||||
|
||||
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.
|
||||
unsafe extern "C" fn get_sink_vol(
|
||||
ctx: *mut pa_context,
|
||||
_: *mut pa_context,
|
||||
i: *const pa_sink_info,
|
||||
eol: i32,
|
||||
_: i32,
|
||||
data: *mut libc::c_void) {
|
||||
let (_self, res) = *(data as *mut (*mut PABackend,
|
||||
*mut u32));
|
||||
assert!(!(*_self).m.is_null(), "Mainloop is null");
|
||||
assert!(!res.is_null(), "res is null");
|
||||
|
||||
if i.is_null() {
|
||||
return
|
||||
@ -303,13 +455,14 @@ unsafe extern "C" fn get_sink_vol(
|
||||
|
||||
// TODO: Better error handling.
|
||||
unsafe extern "C" fn get_sink_mute(
|
||||
ctx: *mut pa_context,
|
||||
_: *mut pa_context,
|
||||
i: *const pa_sink_info,
|
||||
eol: i32,
|
||||
_: i32,
|
||||
data: *mut libc::c_void) {
|
||||
let (_self, res) = *(data as *mut (*mut PABackend,
|
||||
*mut bool));
|
||||
assert!(!(*_self).m.is_null(), "Mainloop is null");
|
||||
assert!(!res.is_null(), "res is null");
|
||||
|
||||
if i.is_null() {
|
||||
return
|
||||
@ -322,12 +475,13 @@ unsafe extern "C" fn get_sink_mute(
|
||||
|
||||
// TODO: Missing error handling.
|
||||
unsafe extern "C" fn set_sink_vol(
|
||||
ctx: *mut pa_context,
|
||||
_: *mut pa_context,
|
||||
success: i32,
|
||||
data: *mut libc::c_void) {
|
||||
let (_self, res) = *(data as *mut (*mut PABackend,
|
||||
*mut Result<()>));
|
||||
assert!(!(*_self).m.is_null(), "Mainloop is null");
|
||||
assert!(!res.is_null(), "res is null");
|
||||
|
||||
if success > 0 {
|
||||
*res = Ok(());
|
||||
@ -342,12 +496,13 @@ unsafe extern "C" fn set_sink_vol(
|
||||
// TODO: Missing error handling.
|
||||
// TODO: same as 'set_sink_vol'
|
||||
unsafe extern "C" fn set_sink_mute(
|
||||
ctx: *mut pa_context,
|
||||
_: *mut pa_context,
|
||||
success: i32,
|
||||
data: *mut libc::c_void) {
|
||||
let (_self, res) = *(data as *mut (*mut PABackend,
|
||||
*mut Result<()>));
|
||||
assert!(!(*_self).m.is_null(), "Mainloop is null");
|
||||
assert!(!res.is_null(), "res is null");
|
||||
|
||||
if success > 0 {
|
||||
*res = Ok(());
|
||||
@ -357,3 +512,51 @@ unsafe extern "C" fn set_sink_mute(
|
||||
|
||||
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,
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
19
src/bin.rs
19
src/bin.rs
@ -22,6 +22,7 @@ use support::audio::VolDir;
|
||||
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
|
||||
|
||||
@ -73,22 +74,22 @@ fn main() {
|
||||
.unwrap_or_else(|e|{panic!("Logger initialization failed with {}",e)});
|
||||
|
||||
|
||||
let pa = PABackend::new(Some(String::from("Built-in Audio Analog Stereo"))).unwrap();
|
||||
println!("Sink: {:?}", pa.sink);
|
||||
println!("Volume before: {:?}", pa.get_vol());
|
||||
pa.set_vol(80.0, VolDir::Up);
|
||||
println!("Volume after: {:?}", pa.get_vol());
|
||||
println!("Mute before: {:?}", pa.get_mute());
|
||||
println!("PA_VOLUME_NORM: {:?}", PA_VOLUME_NORM);
|
||||
// let pa = PABackend::new(Some(String::from("Built-in Audio Analog Stereo"))).unwrap();
|
||||
// println!("Sink: {:?}", pa.sink);
|
||||
// println!("Volume before: {:?}", pa.get_vol());
|
||||
// pa.set_vol(80.0, VolDir::Up);
|
||||
// println!("Volume after: {:?}", pa.get_vol());
|
||||
// println!("Mute before: {:?}", pa.get_mute());
|
||||
// println!("PA_VOLUME_NORM: {:?}", PA_VOLUME_NORM);
|
||||
// pa.set_mute(true);
|
||||
// println!("Mute after: {:?}", pa.get_mute());
|
||||
|
||||
return;
|
||||
// return;
|
||||
|
||||
gtk::init()
|
||||
.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);
|
||||
|
||||
|
62
src/notif.rs
62
src/notif.rs
@ -144,37 +144,37 @@ where
|
||||
{
|
||||
{
|
||||
/* connect handler */
|
||||
let apps = appstate.clone();
|
||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
let notif = &apps.notif;
|
||||
if notif.is_none() || !notif.as_ref().unwrap().enabled.get() {
|
||||
return;
|
||||
}
|
||||
let notif = notif.as_ref().unwrap();
|
||||
match (s,
|
||||
u,
|
||||
(notif.from_popup.get(),
|
||||
notif.from_tray.get(),
|
||||
notif.from_external.get(),
|
||||
notif.from_hotkeys.get())) {
|
||||
(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::CardError, _, _) => (),
|
||||
(AudioSignal::ValuesChanged,
|
||||
AudioUser::TrayIcon,
|
||||
(_, true, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
(AudioSignal::ValuesChanged,
|
||||
AudioUser::Popup,
|
||||
(true, _, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
(AudioSignal::ValuesChanged,
|
||||
AudioUser::Unknown,
|
||||
(_, _, true, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
(AudioSignal::ValuesChanged,
|
||||
AudioUser::Hotkeys,
|
||||
(_, _, _, true)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
_ => (),
|
||||
}
|
||||
}));
|
||||
// let apps = appstate.clone();
|
||||
// appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
// let notif = &apps.notif;
|
||||
// if notif.is_none() || !notif.as_ref().unwrap().enabled.get() {
|
||||
// return;
|
||||
// }
|
||||
// let notif = notif.as_ref().unwrap();
|
||||
// match (s,
|
||||
// u,
|
||||
// (notif.from_popup.get(),
|
||||
// notif.from_tray.get(),
|
||||
// notif.from_external.get(),
|
||||
// notif.from_hotkeys.get())) {
|
||||
// (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::CardError, _, _) => (),
|
||||
// (AudioSignal::ValuesChanged,
|
||||
// AudioUser::TrayIcon,
|
||||
// (_, true, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
// (AudioSignal::ValuesChanged,
|
||||
// AudioUser::Popup,
|
||||
// (true, _, _, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
// (AudioSignal::ValuesChanged,
|
||||
// AudioUser::Unknown,
|
||||
// (_, _, true, _)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
// (AudioSignal::ValuesChanged,
|
||||
// AudioUser::Hotkeys,
|
||||
// (_, _, _, true)) => try_w!(notif.show_volume_notif(apps.audio.as_ref())),
|
||||
// _ => (),
|
||||
// }
|
||||
// }));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ use audio::frontend::*;
|
||||
use errors::*;
|
||||
use prefs::*;
|
||||
|
||||
// TODO: rm alsa
|
||||
use support::alsa::*;
|
||||
|
||||
|
||||
#[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.
|
||||
pub fn get_playable_card_names() -> Vec<String> {
|
||||
return get_playable_alsa_card_names();
|
||||
}
|
||||
|
||||
|
||||
/// 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);
|
||||
/// Invokes the registered handlers.
|
||||
pub 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 {
|
||||
debug!("Handler executing");
|
||||
let unboxed = handler.as_ref();
|
||||
unboxed(signal, user);
|
||||
}
|
||||
}
|
||||
|
@ -63,31 +63,31 @@ where
|
||||
{
|
||||
{
|
||||
/* "global" audio signal handler */
|
||||
let apps = appstate.clone();
|
||||
appstate.audio.connect_handler(
|
||||
Box::new(move |s, u| match (s, u) {
|
||||
(AudioSignal::CardDisconnected, _) => {
|
||||
try_w!(audio_reload(
|
||||
apps.audio.as_ref(),
|
||||
&apps.prefs.borrow(),
|
||||
AudioUser::Unknown,
|
||||
));
|
||||
}
|
||||
(AudioSignal::CardError, _) => {
|
||||
if run_audio_error_dialog(
|
||||
&apps.gui.popup_menu.menu_window,
|
||||
) == (GTK_RESPONSE_YES as i32)
|
||||
{
|
||||
try_w!(audio_reload(
|
||||
apps.audio.as_ref(),
|
||||
&apps.prefs.borrow(),
|
||||
AudioUser::Unknown,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}),
|
||||
);
|
||||
// let apps = appstate.clone();
|
||||
// appstate.audio.connect_handler(
|
||||
// Box::new(move |s, u| match (s, u) {
|
||||
// (AudioSignal::CardDisconnected, _) => {
|
||||
// try_w!(audio_reload(
|
||||
// apps.audio.as_ref(),
|
||||
// &apps.prefs.borrow(),
|
||||
// AudioUser::Unknown,
|
||||
// ));
|
||||
// }
|
||||
// (AudioSignal::CardError, _) => {
|
||||
// if run_audio_error_dialog(
|
||||
// &apps.gui.popup_menu.menu_window,
|
||||
// ) == (GTK_RESPONSE_YES as i32)
|
||||
// {
|
||||
// try_w!(audio_reload(
|
||||
// apps.audio.as_ref(),
|
||||
// &apps.prefs.borrow(),
|
||||
// AudioUser::Unknown,
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
// _ => (),
|
||||
// }),
|
||||
// );
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,16 +48,16 @@ where
|
||||
{
|
||||
/* audio.connect_handler */
|
||||
{
|
||||
let apps = appstate.clone();
|
||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
/* skip if window is hidden */
|
||||
if !apps.gui.popup_menu.menu.get_visible() {
|
||||
return;
|
||||
}
|
||||
match (s, u) {
|
||||
(_, _) => set_mute_check(&apps),
|
||||
}
|
||||
}));
|
||||
// let apps = appstate.clone();
|
||||
// appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
// /* skip if window is hidden */
|
||||
// if !apps.gui.popup_menu.menu.get_visible() {
|
||||
// return;
|
||||
// }
|
||||
// match (s, u) {
|
||||
// (_, _) => set_mute_check(&apps),
|
||||
// }
|
||||
// }));
|
||||
|
||||
}
|
||||
|
||||
|
@ -125,31 +125,31 @@ where
|
||||
{
|
||||
/* audio.connect_handler */
|
||||
{
|
||||
let apps = appstate.clone();
|
||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
/* skip if window is hidden */
|
||||
if !apps.gui.popup_window.popup_window.get_visible() {
|
||||
return;
|
||||
}
|
||||
match (s, u) {
|
||||
/* Update only mute check here
|
||||
* If the user changes the volume through the popup window,
|
||||
* we MUST NOT update the slider value, it's been done already.
|
||||
* It means that, as long as the popup window is visible,
|
||||
* the slider value reflects the value set by user,
|
||||
* and not the real value reported by the audio system.
|
||||
*/
|
||||
(_, AudioUser::Popup) => {
|
||||
apps.gui.popup_window.update_mute_check(
|
||||
apps.audio.as_ref(),
|
||||
);
|
||||
}
|
||||
/* external change, safe to update slider too */
|
||||
(_, _) => {
|
||||
try_w!(apps.gui.popup_window.update(apps.audio.as_ref()));
|
||||
}
|
||||
}
|
||||
}));
|
||||
// let apps = appstate.clone();
|
||||
// appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
// /* skip if window is hidden */
|
||||
// if !apps.gui.popup_window.popup_window.get_visible() {
|
||||
// return;
|
||||
// }
|
||||
// match (s, u) {
|
||||
// /* Update only mute check here
|
||||
// * If the user changes the volume through the popup window,
|
||||
// * we MUST NOT update the slider value, it's been done already.
|
||||
// * It means that, as long as the popup window is visible,
|
||||
// * the slider value reflects the value set by user,
|
||||
// * and not the real value reported by the audio system.
|
||||
// */
|
||||
// (_, AudioUser::Popup) => {
|
||||
// apps.gui.popup_window.update_mute_check(
|
||||
// apps.audio.as_ref(),
|
||||
// );
|
||||
// }
|
||||
// /* external change, safe to update slider too */
|
||||
// (_, _) => {
|
||||
// try_w!(apps.gui.popup_window.update(apps.audio.as_ref()));
|
||||
// }
|
||||
// }
|
||||
// }));
|
||||
}
|
||||
|
||||
/* mute_check.connect_toggled */
|
||||
|
@ -13,7 +13,6 @@ use prefs::*;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use support::audio::*;
|
||||
use ui::hotkey_dialog::HotkeyDialog;
|
||||
|
||||
|
||||
@ -434,21 +433,21 @@ where
|
||||
T: AudioFrontend + 'static,
|
||||
{
|
||||
let apps = appstate.clone();
|
||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
/* skip if prefs window is not present */
|
||||
if apps.gui.prefs_dialog.borrow().is_none() {
|
||||
return;
|
||||
}
|
||||
// appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||
// /* skip if prefs window is not present */
|
||||
// if apps.gui.prefs_dialog.borrow().is_none() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
match (s, u) {
|
||||
(AudioSignal::CardInitialized, _) => (),
|
||||
(AudioSignal::CardCleanedUp, _) => {
|
||||
fill_card_combo(&apps);
|
||||
fill_chan_combo(&apps, None);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}));
|
||||
// match (s, u) {
|
||||
// (AudioSignal::CardInitialized, _) => (),
|
||||
// (AudioSignal::CardCleanedUp, _) => {
|
||||
// fill_card_combo(&apps);
|
||||
// fill_chan_combo(&apps, None);
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
// }));
|
||||
}
|
||||
|
||||
|
||||
@ -586,7 +585,7 @@ where
|
||||
/* set card combo */
|
||||
let cur_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 */
|
||||
let mut c_index: i32 = -1;
|
||||
@ -613,10 +612,7 @@ where
|
||||
chan_combo.remove_all();
|
||||
|
||||
let audio = &appstate.audio;
|
||||
let available_chan_names = match cardname {
|
||||
Some(name) => get_playable_chan_names(name),
|
||||
None => audio.playable_chan_names(),
|
||||
};
|
||||
let available_chan_names = audio.playable_chan_names(cardname);
|
||||
|
||||
/* set chan combo */
|
||||
let cur_chan_name = try_w!(audio.chan_name());
|
||||
|
@ -422,11 +422,14 @@ where
|
||||
appstate.audio.connect_handler(
|
||||
Box::new(move |s, u| match (s, u) {
|
||||
(_, _) => {
|
||||
apps.gui.tray_icon.update_tooltip(apps.audio.as_ref());
|
||||
try_w!(apps.gui.tray_icon.update_vol_meter(
|
||||
try_w!(apps.audio.get_vol()),
|
||||
apps.audio.vol_level(),
|
||||
));
|
||||
// apps.gui.tray_icon.update_tooltip(apps.audio.as_ref());
|
||||
// try_w!(apps.gui.tray_icon.update_vol_meter(
|
||||
// try_w!(apps.audio.get_vol()),
|
||||
// apps.audio.vol_level(),
|
||||
// ));
|
||||
let vol = apps.audio.get_vol();
|
||||
println!("Vol: {:?}", vol)
|
||||
// println!("Gaga");
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user