This commit is contained in:
Julian Ospald 2017-10-04 17:23:46 +02:00
parent 6a37ba7f7f
commit 0f3652a6b2
3 changed files with 141 additions and 51 deletions

View File

@ -19,14 +19,13 @@ use support::audio::*;
// TODO: how to handle channels // TODO: how to handle channels
// TODO: update when sink changes // TODO: update when sink changes, only name and description are const
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Sink { pub struct Sink {
pub name: String, pub name: String,
pub index: u32, pub index: u32,
pub description: String, pub description: String,
pub channels: u8, pub channels: u8,
pub base_vol: u32,
} }
@ -117,19 +116,90 @@ impl PABackend {
pub fn get_vol(&self) -> Result<f64> { pub fn get_vol(&self) -> Result<f64> {
let mut vol: Result<f64> = Err("No value".into()); let mut vol: u32 = 0;
unsafe { unsafe {
pa_threaded_mainloop_lock(self.m); pa_threaded_mainloop_lock(self.m);
let _data = &mut(self.m, &mut vol); let data = &mut(self, &mut vol);
let data = mem::transmute::<&mut(*mut pa_threaded_mainloop,
&mut Result<f64>),
*mut libc::c_void>(_data);
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 o = pa_context_get_sink_info_by_name(self.c, let o = pa_context_get_sink_info_by_name(self.c,
sink_name, sink_name,
Some(get_sink_vol), Some(get_sink_vol),
data); data as *mut _ as *mut libc::c_void);
if o.is_null() {
pa_threaded_mainloop_unlock(self.m);
bail!("Failed to initialize PA operation!");
}
while pa_operation_get_state(o) == PA_OPERATION_RUNNING {
pa_threaded_mainloop_wait(self.m);
}
pa_operation_unref(o);
pa_threaded_mainloop_unlock(self.m);
let _ = CString::from_raw(sink_name);
}
unsafe {
return Ok(pa_sw_volume_to_linear(vol) * 100.0);
}
}
pub fn set_vol(&self, new_vol: f64, dir: VolDir) -> Result<()> {
let mut res: Result<()> = Err("No value".into());
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;
}
let mut new_cvol = Struct_pa_cvolume {
channels: self.sink.borrow().channels,
values: vol_arr,
};
assert!(pa_cvolume_valid(&mut new_cvol as *mut pa_cvolume) != 0, "Invalid cvolume");
let o = pa_context_set_sink_volume_by_name(self.c,
sink_name,
&new_cvol as *const pa_cvolume,
Some(set_sink_vol),
data as *mut _ as *mut libc::c_void);
if o.is_null() {
pa_threaded_mainloop_unlock(self.m);
bail!("Failed to initialize PA operation!");
}
while pa_operation_get_state(o) == PA_OPERATION_RUNNING {
pa_threaded_mainloop_wait(self.m);
}
pa_operation_unref(o);
pa_threaded_mainloop_unlock(self.m);
}
return res;
}
pub fn has_mute(&self) -> bool {
return true;
}
pub fn get_mute(&self) -> Result<bool> {
let mut mute: bool = false;
unsafe {
pa_threaded_mainloop_lock(self.m);
let data = &mut(self, &mut mute);
let sink_name = CString::new(self.sink.borrow().name.clone()).unwrap().into_raw();
let o = pa_context_get_sink_info_by_name(self.c,
sink_name,
Some(get_sink_mute),
data as *mut _ as *mut libc::c_void);
if o.is_null() { if o.is_null() {
pa_threaded_mainloop_unlock(self.m); pa_threaded_mainloop_unlock(self.m);
bail!("Failed to initialize PA operation!"); bail!("Failed to initialize PA operation!");
@ -143,37 +213,21 @@ impl PABackend {
let _ = CString::from_raw(sink_name); let _ = CString::from_raw(sink_name);
} }
return vol; return Ok(mute);
} }
pub fn set_vol(&self, new_vol: f64, dir: VolDir) -> Result<()> { pub fn set_mute(&self, mute: bool) -> 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);
let _data = &mut(self, &mut res); let data = &mut(self, &mut res);
let data = mem::transmute::<&mut(&PABackend,
&mut Result<()>),
*mut libc::c_void>(_data);
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 = percent_to_vol(new_vol, let o = pa_context_set_sink_mute_by_name(self.c,
(0, self.sink.borrow().base_vol as i64), sink_name,
dir)?; mute as i32,
let mut vol_arr: [u32; 32] = [0; 32]; Some(set_sink_mute),
for c in 0..(self.sink.borrow().channels - 1) { data as *mut _ as *mut libc::c_void);
vol_arr[c as usize] = new_vol as u32;
}
let new_cvol = Struct_pa_cvolume {
channels: self.sink.borrow().channels,
values: vol_arr,
};
let o = pa_context_set_sink_volume_by_name(self.c,
sink_name,
&new_cvol as *const pa_cvolume,
Some(set_sink_vol),
data);
if o.is_null() { if o.is_null() {
pa_threaded_mainloop_unlock(self.m); pa_threaded_mainloop_unlock(self.m);
@ -220,7 +274,6 @@ unsafe extern "C" fn context_state_cb(
match state { match state {
PA_CONTEXT_READY => { PA_CONTEXT_READY => {
println!("Context ready");
CONTEXT_READY = true; CONTEXT_READY = true;
pa_threaded_mainloop_signal(mainloop, 1); pa_threaded_mainloop_signal(mainloop, 1);
}, },
@ -235,19 +288,36 @@ unsafe extern "C" fn get_sink_vol(
i: *const pa_sink_info, i: *const pa_sink_info,
eol: i32, eol: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let &mut(mainloop, res) = mem::transmute::<*mut libc::c_void, let (_self, res) = *(data as *mut (*mut PABackend,
&mut(*mut pa_threaded_mainloop, *mut u32));
*mut Result<f64>)>(data); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!mainloop.is_null(), "Mainloop is null");
if i.is_null() { if i.is_null() {
return return
} }
*res = vol_to_percent((*i).volume.values[0] as i64, *res = (*i).volume.values[0];
(0, (*i).base_volume as i64));
pa_threaded_mainloop_signal(mainloop, 0); pa_threaded_mainloop_signal((*_self).m, 0);
}
// TODO: Better error handling.
unsafe extern "C" fn get_sink_mute(
ctx: *mut pa_context,
i: *const pa_sink_info,
eol: i32,
data: *mut libc::c_void) {
let (_self, res) = *(data as *mut (*mut PABackend,
*mut bool));
assert!(!(*_self).m.is_null(), "Mainloop is null");
if i.is_null() {
return
}
*res = (*i).mute != 0;
pa_threaded_mainloop_signal((*_self).m, 0);
} }
// TODO: Missing error handling. // TODO: Missing error handling.
@ -255,10 +325,9 @@ unsafe extern "C" fn set_sink_vol(
ctx: *mut pa_context, ctx: *mut pa_context,
success: i32, success: i32,
data: *mut libc::c_void) { data: *mut libc::c_void) {
let &mut(mainloop, res) = mem::transmute::<*mut libc::c_void, let (_self, res) = *(data as *mut (*mut PABackend,
&mut(*mut pa_threaded_mainloop, *mut Result<()>));
*mut Result<()>)>(data); assert!(!(*_self).m.is_null(), "Mainloop is null");
assert!(!mainloop.is_null(), "Mainloop is null");
if success > 0 { if success > 0 {
*res = Ok(()); *res = Ok(());
@ -266,6 +335,25 @@ unsafe extern "C" fn set_sink_vol(
*res = Err("Failed to set volume".into()); *res = Err("Failed to set volume".into());
} }
pa_threaded_mainloop_signal(mainloop, 0); pa_threaded_mainloop_signal((*_self).m, 0);
} }
// TODO: Missing error handling.
// TODO: same as 'set_sink_vol'
unsafe extern "C" fn set_sink_mute(
ctx: *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");
if success > 0 {
*res = Ok(());
} else {
*res = Err("Failed to set volume".into());
}
pa_threaded_mainloop_signal((*_self).m, 0);
}

View File

@ -75,9 +75,13 @@ fn main() {
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: {:?}", pa.get_vol()); println!("Volume before: {:?}", pa.get_vol());
pa.set_vol(80.0, VolDir::Up).unwrap(); pa.set_vol(80.0, VolDir::Up);
println!("Volume: {:?}", pa.get_vol()); 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;

View File

@ -52,14 +52,12 @@ unsafe extern "C" fn get_all_sinks(
let index = (*i).index; let index = (*i).index;
let description = CStr::from_ptr((*i).description).to_str().unwrap().to_owned(); let description = CStr::from_ptr((*i).description).to_str().unwrap().to_owned();
let channels = (*i).channel_map.channels; let channels = (*i).channel_map.channels;
let base_vol = (*i).base_volume;
(*vec).push(Sink { (*vec).push(Sink {
name, name,
index, index,
description, description,
channels, channels,
base_vol,
}); });
pa_threaded_mainloop_signal(mainloop, 0); pa_threaded_mainloop_signal(mainloop, 0);
} }