Restructure modules
This commit is contained in:
parent
537ab6bafe
commit
a3355f3b72
@ -1,16 +1,5 @@
|
|||||||
use gtk;
|
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 {
|
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 */
|
||||||
@ -19,86 +8,3 @@ pub struct AppS {
|
|||||||
pub builder_popup: gtk::Builder,
|
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,
|
|
||||||
}
|
|
||||||
|
178
src/audio.rs
178
src/audio.rs
@ -1,131 +1,115 @@
|
|||||||
extern crate alsa;
|
use alsa::card::Card;
|
||||||
extern crate alsa_sys;
|
use alsa::mixer::{Mixer, Selem, Elem, SelemId};
|
||||||
extern crate glib_sys;
|
use alsa::poll::PollDescriptors;
|
||||||
|
use alsa_sys;
|
||||||
use self::alsa::card::Card;
|
use errors::*;
|
||||||
use self::alsa::mixer::{Mixer, Selem, Elem};
|
use glib_sys;
|
||||||
use alsa::mixer::SelemChannelId::*;
|
|
||||||
use std::iter::Map;
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use libc::size_t;
|
|
||||||
use errors::*;
|
|
||||||
use std::convert::From;
|
|
||||||
use libc::pollfd;
|
use libc::pollfd;
|
||||||
use app_state;
|
use libc::size_t;
|
||||||
|
use myalsa::*;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::u8;
|
use std::u8;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: implement free/destructor
|
||||||
pub fn get_default_alsa_card() -> Card {
|
pub struct AlsaCard {
|
||||||
return get_alsa_card_by_id(0);
|
_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 {
|
impl AlsaCard {
|
||||||
return alsa::Card::new(index);
|
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 {
|
/* TODO: callback is registered here, which must be unregistered
|
||||||
return alsa::card::Iter::new();
|
* 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> {
|
return Ok(AlsaCard {
|
||||||
for r_card in get_alsa_cards() {
|
_cannot_construct: (),
|
||||||
let card = r_card?;
|
card: card,
|
||||||
let card_name = card.get_name()?;
|
mixer: mixer,
|
||||||
if name == card_name {
|
selem_id: selem_id,
|
||||||
return Ok(card);
|
watch_ids: watch_ids,
|
||||||
}
|
|
||||||
}
|
|
||||||
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<()> {
|
pub fn selem(&self) -> Selem {
|
||||||
/* auto-unmute */
|
return get_selems(&self.mixer)
|
||||||
if get_mute(selem)? {
|
.nth(self.selem_id.get_index() as usize)
|
||||||
set_mute(selem, false)?;
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let range = selem.get_playback_volume_range();
|
pub fn vol(&self) -> Result<f64> {
|
||||||
selem.set_playback_volume_all(
|
return get_vol(&self.selem());
|
||||||
percent_to_vol(new_vol, range),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_mute(selem: &Selem) -> bool {
|
pub fn set_vol(&self, new_vol: f64) -> Result<()> {
|
||||||
return selem.has_playback_switch();
|
return set_vol(&self.selem(), new_vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mute(selem: &Selem) -> Result<bool> {
|
pub fn has_mute(&self) -> bool {
|
||||||
let val = selem.get_playback_switch(FrontRight)?;
|
return has_mute(&self.selem());
|
||||||
return Ok(val == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> {
|
pub fn get_mute(&self) -> Result<bool> {
|
||||||
/* true -> mute, false -> unmute */
|
return get_mute(&self.selem());
|
||||||
let _ = selem.set_playback_switch_all(!mute as i32)?;
|
}
|
||||||
return Ok(());
|
|
||||||
|
pub fn set_mute(&self, mute: bool) -> Result<()> {
|
||||||
|
return set_mute(&self.selem(), mute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* GIO */
|
}
|
||||||
|
|
||||||
pub fn watch_poll_descriptors(
|
pub enum AudioUser {
|
||||||
|
AudioUserUnknown,
|
||||||
|
AudioUserPopup,
|
||||||
|
AudioUserTrayIcon,
|
||||||
|
AudioUserHotkeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AudioSignal {
|
||||||
|
AudioNoCard,
|
||||||
|
AudioCardInitialized,
|
||||||
|
AudioCardCleanedUp,
|
||||||
|
AudioCardDisconnected,
|
||||||
|
AudioCardError,
|
||||||
|
AudioValuesChanged,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn watch_poll_descriptors(
|
||||||
polls: Vec<pollfd>,
|
polls: Vec<pollfd>,
|
||||||
mixer: &Mixer,
|
mixer: &Mixer,
|
||||||
) -> Vec<c_uint> {
|
) -> Vec<c_uint> {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use alsa;
|
use alsa;
|
||||||
use std;
|
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
use std;
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
foreign_links {
|
foreign_links {
|
||||||
@ -40,8 +40,8 @@ macro_rules! try_w {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! try_wr {
|
macro_rules! try_wr {
|
||||||
($expr:expr, $ret:expr) => (match $expr {
|
($expr:expr, $ret:expr) => (match $expr {
|
||||||
std::result::Result::Ok(val) => val,
|
::std::result::Result::Ok(val) => val,
|
||||||
std::result::Result::Err(err) => {
|
::std::result::Result::Err(err) => {
|
||||||
warn!("{:?}", err);
|
warn!("{:?}", err);
|
||||||
return $ret;
|
return $ret;
|
||||||
},
|
},
|
||||||
|
13
src/gui.rs
13
src/gui.rs
@ -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 errors::*;
|
||||||
use gtk::prelude::*;
|
|
||||||
use gdk::DeviceExt;
|
use gdk::DeviceExt;
|
||||||
use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK};
|
use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK};
|
||||||
use gdk_sys::GDK_CURRENT_TIME;
|
use gdk_sys::GDK_CURRENT_TIME;
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk;
|
||||||
|
|
||||||
|
|
||||||
pub fn set_slider(vol_scale_adj: >k::Adjustment, scale: f64) {
|
pub fn set_slider(vol_scale_adj: >k::Adjustment, scale: f64) {
|
||||||
vol_scale_adj.set_value(scale);
|
vol_scale_adj.set_value(scale);
|
||||||
|
@ -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 app_state::*;
|
||||||
|
use audio::AlsaCard;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
use gdk;
|
||||||
|
use gdk_sys::GDK_KEY_Escape;
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk;
|
||||||
|
use gui;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use audio;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn init<'a>(appstate: &'a AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
|
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 |_| {
|
popup_window.connect_show(move |_| {
|
||||||
let acard = card.borrow();
|
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);
|
println!("Cur vol: {}", cur_vol);
|
||||||
gui::set_slider(&vol_scale_adj, cur_vol);
|
gui::set_slider(&vol_scale_adj, cur_vol);
|
||||||
|
|
||||||
|
19
src/main.rs
19
src/main.rs
@ -8,29 +8,31 @@ extern crate log;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate error_chain;
|
extern crate error_chain;
|
||||||
|
|
||||||
extern crate gtk;
|
extern crate alsa;
|
||||||
extern crate gtk_sys;
|
extern crate alsa_sys;
|
||||||
|
extern crate ffi;
|
||||||
extern crate gdk;
|
extern crate gdk;
|
||||||
extern crate gdk_sys;
|
extern crate gdk_sys;
|
||||||
extern crate alsa;
|
extern crate glib_sys;
|
||||||
|
extern crate gtk;
|
||||||
|
extern crate gtk_sys;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use gdk_sys::GDK_KEY_Escape;
|
|
||||||
use app_state::*;
|
use app_state::*;
|
||||||
|
use gtk::prelude::*;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::boxed::Box;
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod errors;
|
mod errors;
|
||||||
|
|
||||||
|
mod app_state;
|
||||||
mod audio;
|
mod audio;
|
||||||
mod gui;
|
mod gui;
|
||||||
mod gui_callbacks;
|
mod gui_callbacks;
|
||||||
mod app_state;
|
mod myalsa;
|
||||||
|
|
||||||
|
use audio::AlsaCard;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -53,7 +55,6 @@ fn main() {
|
|||||||
.init(Some("info".to_string()))
|
.init(Some("info".to_string()))
|
||||||
.unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));
|
.unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));
|
||||||
|
|
||||||
|
|
||||||
gui_callbacks::init(apps, acard);
|
gui_callbacks::init(apps, acard);
|
||||||
|
|
||||||
gtk::main();
|
gtk::main();
|
||||||
|
111
src/myalsa.rs
Normal file
111
src/myalsa.rs
Normal 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(());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user