Restructure modules

This commit is contained in:
Ospald, Julian 2017-06-29 14:25:40 +02:00
parent 537ab6bafe
commit a3355f3b72
7 changed files with 220 additions and 231 deletions

View File

@ -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<u32>,
}
impl AlsaCard {
pub fn new(
card_name: Option<String>,
elem_name: Option<String>,
) -> Result<AlsaCard> {
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<f64> {
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<bool> {
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,
}

View File

@ -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<u32>,
}
pub fn get_alsa_card_by_id(index: c_int) -> Card {
return alsa::Card::new(index);
}
impl AlsaCard {
pub fn new(
card_name: Option<String>,
elem_name: Option<String>,
) -> Result<AlsaCard> {
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<Card> {
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<Mixer> {
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<alsa::mixer::Iter, fn(Elem) -> Selem> {
return mixer.iter().map(get_selem);
}
pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result<Selem> {
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<f64> {
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<f64> {
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<bool> {
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<bool> {
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<pollfd>,
mixer: &Mixer,
) -> Vec<c_uint> {

View File

@ -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;
},

View File

@ -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: &gtk::Adjustment, scale: f64) {
vol_scale_adj.set_value(scale);

View File

@ -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<RefCell<AlsaCard>>) {
@ -56,7 +50,7 @@ fn init_popup_window(appstate: &AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
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);

View File

@ -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();

111
src/myalsa.rs Normal file
View File

@ -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<Card> {
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<Mixer> {
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<alsa::mixer::Iter, fn(Elem) -> Selem> {
return mixer.iter().map(get_selem);
}
pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result<Selem> {
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<f64> {
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<bool> {
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(());
}