Update
This commit is contained in:
parent
6504c5c5ab
commit
4760355ef1
@ -9,6 +9,7 @@ libc = "^0.2.23"
|
|||||||
gdk-sys = { git = "https://github.com/gtk-rs/sys" }
|
gdk-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||||
gtk-sys = { git = "https://github.com/gtk-rs/sys" }
|
gtk-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||||
glib = { git = "https://github.com/gtk-rs/glib.git" }
|
glib = { git = "https://github.com/gtk-rs/glib.git" }
|
||||||
|
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||||
ffi = "^0.0.2"
|
ffi = "^0.0.2"
|
||||||
flexi_logger = "^0.5.1"
|
flexi_logger = "^0.5.1"
|
||||||
log = "^0.3.8"
|
log = "^0.3.8"
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
use gtk;
|
use gtk;
|
||||||
|
|
||||||
|
use alsa::poll::PollDescriptors;
|
||||||
use alsa::card::Card;
|
use alsa::card::Card;
|
||||||
use alsa::mixer::{Mixer, SelemId, Selem};
|
use alsa::mixer::{Mixer, SelemId, Selem};
|
||||||
use audio;
|
use audio;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
|
||||||
|
// TODO: fix import
|
||||||
|
use libc::pollfd;
|
||||||
|
|
||||||
pub struct AppS {
|
pub struct AppS {
|
||||||
/* we keep this to ensure the lifetime is across the whole application */
|
/* we keep this to ensure the lifetime is across the whole application */
|
||||||
pub status_icon: gtk::StatusIcon,
|
pub status_icon: gtk::StatusIcon,
|
||||||
@ -12,10 +16,13 @@ pub struct AppS {
|
|||||||
pub builder_popup: gtk::Builder,
|
pub builder_popup: gtk::Builder,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: implement free/destructor
|
||||||
pub struct AlsaCard {
|
pub struct AlsaCard {
|
||||||
card: Card,
|
_cannot_construct: (),
|
||||||
mixer: Mixer,
|
pub card: Card,
|
||||||
selem_id: SelemId,
|
pub mixer: Mixer,
|
||||||
|
pub selem_id: SelemId,
|
||||||
|
pub watch_ids: Vec<pollfd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlsaCard {
|
impl AlsaCard {
|
||||||
@ -35,11 +42,15 @@ impl AlsaCard {
|
|||||||
elem_name.unwrap_or(String::from("Master")),
|
elem_name.unwrap_or(String::from("Master")),
|
||||||
).unwrap()
|
).unwrap()
|
||||||
.get_id();
|
.get_id();
|
||||||
|
let vec_pollfd = PollDescriptors::get(&mixer)?;
|
||||||
|
// let watch_ids =
|
||||||
|
|
||||||
return Ok(AlsaCard {
|
return Ok(AlsaCard {
|
||||||
|
_cannot_construct: (),
|
||||||
card: card,
|
card: card,
|
||||||
mixer: mixer,
|
mixer: mixer,
|
||||||
selem_id: selem_id,
|
selem_id: selem_id,
|
||||||
|
watch_ids: vec![],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +64,10 @@ impl AlsaCard {
|
|||||||
return audio::get_vol(&self.selem());
|
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 {
|
pub fn has_mute(&self) -> bool {
|
||||||
return audio::has_mute(&self.selem());
|
return audio::has_mute(&self.selem());
|
||||||
}
|
}
|
||||||
@ -65,3 +80,19 @@ impl AlsaCard {
|
|||||||
return audio::set_mute(&self.selem(), mute);
|
return audio::set_mute(&self.selem(), mute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum AudioUser {
|
||||||
|
AudioUserUnknown,
|
||||||
|
AudioUserPopup,
|
||||||
|
AudioUserTrayIcon,
|
||||||
|
AudioUserHotkeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AudioSignal {
|
||||||
|
AudioNoCard,
|
||||||
|
AudioCardInitialized,
|
||||||
|
AudioCardCleanedUp,
|
||||||
|
AudioCardDisconnected,
|
||||||
|
AudioCardError,
|
||||||
|
AudioValuesChanged,
|
||||||
|
}
|
||||||
|
73
src/audio.rs
73
src/audio.rs
@ -1,13 +1,18 @@
|
|||||||
extern crate alsa;
|
extern crate alsa;
|
||||||
extern crate libc;
|
extern crate glib_sys;
|
||||||
|
|
||||||
use self::alsa::card::Card;
|
use self::alsa::card::Card;
|
||||||
use self::alsa::mixer::{Mixer, Selem, Elem};
|
use self::alsa::mixer::{Mixer, Selem, Elem};
|
||||||
use alsa::mixer::SelemChannelId::*;
|
use alsa::mixer::SelemChannelId::*;
|
||||||
use std::iter::Map;
|
use std::iter::Map;
|
||||||
use self::libc::c_int;
|
use libc::c_int;
|
||||||
|
use libc::c_uint;
|
||||||
|
use libc::c_void;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
use libc::pollfd;
|
||||||
|
use app_state;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -60,15 +65,41 @@ pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result<Selem> {
|
|||||||
bail!("Not found a matching selem named {}", name);
|
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<f64> {
|
pub fn get_vol(selem: &Selem) -> Result<f64> {
|
||||||
let (min, max) = selem.get_playback_volume_range();
|
let range = selem.get_playback_volume_range();
|
||||||
let volume = selem.get_playback_volume(FrontRight).map(|v| {
|
let volume = selem.get_playback_volume(FrontRight).map(|v| {
|
||||||
return ((v - min) as f64) / ((max - min) as f64) * 100.0;
|
return vol_to_percent(v, range);
|
||||||
});
|
});
|
||||||
|
|
||||||
return volume.cherr();
|
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 {
|
pub fn has_mute(selem: &Selem) -> bool {
|
||||||
return selem.has_playback_switch();
|
return selem.has_playback_switch();
|
||||||
}
|
}
|
||||||
@ -83,3 +114,37 @@ pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> {
|
|||||||
let _ = selem.set_playback_switch_all(!mute as i32)?;
|
let _ = selem.set_playback_switch_all(!mute as i32)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* GIO */
|
||||||
|
|
||||||
|
pub fn watch_poll_descriptors(
|
||||||
|
polls: Vec<pollfd>,
|
||||||
|
acard: RefCell<app_state::AlsaCard>,
|
||||||
|
) -> Vec<c_uint> {
|
||||||
|
let mut watch_ids: Vec<c_uint> = vec![];
|
||||||
|
for poll in polls {
|
||||||
|
unsafe {
|
||||||
|
let gioc = glib_sys::g_io_channel_unix_new(poll.fd);
|
||||||
|
watch_ids.push(glib_sys::g_io_add_watch(
|
||||||
|
gioc,
|
||||||
|
glib_sys::GIOCondition::from_bits_truncate(
|
||||||
|
glib_sys::G_IO_IN.bits() | glib_sys::G_IO_ERR.bits(),
|
||||||
|
),
|
||||||
|
Some(watch_cb),
|
||||||
|
acard.as_ptr() as glib_sys::gpointer,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn watch_cb(
|
||||||
|
chan: *mut glib_sys::GIOChannel,
|
||||||
|
cond: glib_sys::GIOCondition,
|
||||||
|
data: glib_sys::gpointer,
|
||||||
|
) -> glib_sys::gboolean {
|
||||||
|
return true as glib_sys::gboolean;
|
||||||
|
}
|
||||||
|
@ -63,6 +63,23 @@ fn init_popup_window(appstate: &AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* vol_scale_adj.connect_value_changed */
|
||||||
|
{
|
||||||
|
let vol_scale_adj: Rc<gtk::Adjustment> =
|
||||||
|
Rc::new(
|
||||||
|
appstate.builder_popup.get_object("vol_scale_adj").unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let card = rc_acard.clone();
|
||||||
|
let vol_scale = vol_scale_adj.clone();
|
||||||
|
vol_scale_adj.connect_value_changed(move |_| {
|
||||||
|
let acard = card.borrow();
|
||||||
|
let val = vol_scale.get_value();
|
||||||
|
|
||||||
|
try_w!(acard.set_vol(val));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* mute_check.connect_toggled */
|
/* mute_check.connect_toggled */
|
||||||
{
|
{
|
||||||
let mute_check: gtk::CheckButton =
|
let mute_check: gtk::CheckButton =
|
||||||
|
@ -10,6 +10,7 @@ extern crate gtk_sys;
|
|||||||
extern crate gdk;
|
extern crate gdk;
|
||||||
extern crate gdk_sys;
|
extern crate gdk_sys;
|
||||||
extern crate alsa;
|
extern crate alsa;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gdk_sys::GDK_KEY_Escape;
|
use gdk_sys::GDK_KEY_Escape;
|
||||||
|
Loading…
Reference in New Issue
Block a user