sound: Remove a thread

This commit is contained in:
Kenny Levinsen
2019-08-28 18:04:31 +02:00
parent 3dd09ca589
commit bbfdb56d70
+207 -165
View File
@@ -1,8 +1,8 @@
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::cmd::Cmd;
use crate::color::Color; use crate::color::Color;
use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR}; use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR};
use crate::modules::module::{Input, ModuleImpl}; use crate::modules::module::{Input, ModuleImpl};
use crate::cmd::Cmd;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::{max, min}; use std::cmp::{max, min};
@@ -40,7 +40,6 @@ struct PulseAudioClient {
sender: Sender<PulseAudioClientRequest>, sender: Sender<PulseAudioClientRequest>,
default_sink: String, default_sink: String,
sinks: HashMap<String, PulseAudioSinkInfo>, sinks: HashMap<String, PulseAudioSinkInfo>,
listener: Sender<bool>,
} }
enum PulseAudioClientRequest { enum PulseAudioClientRequest {
@@ -51,12 +50,18 @@ enum PulseAudioClientRequest {
SetSinkMuteByName(Option<Sender<bool>>, String, bool), SetSinkMuteByName(Option<Sender<bool>>, String, bool),
} }
struct PulseAudioSoundDevice { #[derive(Debug)]
client: Arc<Mutex<PulseAudioClient>>, struct PulseAudioSoundDeviceInner {
name: Option<String>, name: Option<String>,
volume: Option<ChannelVolumes>, volume: Option<ChannelVolumes>,
volume_avg: f32, volume_avg: f32,
muted: bool, muted: bool,
default_sink: String,
}
struct PulseAudioSoundDevice {
client: Arc<Mutex<PulseAudioClient>>,
inner: Arc<Mutex<PulseAudioSoundDeviceInner>>,
} }
impl PulseAudioConnection { impl PulseAudioConnection {
@@ -112,120 +117,138 @@ impl PulseAudioConnection {
} }
impl PulseAudioClient { impl PulseAudioClient {
fn new(listener: Sender<bool>) -> Result<Arc<Mutex<Self>>, ::std::io::Error> { fn new<F>(listener: F) -> Result<Arc<Mutex<Self>>, ::std::io::Error>
where
F: Fn(Arc<Mutex<Self>>) -> (),
F: Send + 'static + Clone,
{
let (tx, rx) = channel(); let (tx, rx) = channel();
let client = Arc::new(Mutex::new(PulseAudioClient { let client = Arc::new(Mutex::new(PulseAudioClient {
sender: tx, sender: tx,
default_sink: "@DEFAULT_SINK@".to_string(), default_sink: "@DEFAULT_SINK@".to_string(),
sinks: HashMap::new(), sinks: HashMap::new(),
listener: listener,
})); }));
let cl1 = client.clone(); let loop_client = client.clone();
let (tx1, rx1) = channel(); let (tx1, rx1) = channel();
thread::spawn(move || { let _ = thread::Builder::new()
let mut conn = match PulseAudioConnection::new() { .name("pa_writer".to_string())
Ok(v) => { .spawn(move || {
tx1.send(true).unwrap(); let mut conn = match PulseAudioConnection::new() {
v Ok(v) => {
tx1.send(true).unwrap();
v
}
Err(_) => {
tx1.send(false).unwrap();
return;
}
};
// make sure mainloop dispatched everything
for _ in 0..10 {
conn.iterate(false).unwrap();
} }
Err(_) => {
tx1.send(false).unwrap();
return;
}
};
// make sure mainloop dispatched everything loop {
for _ in 0..10 { let cl = loop_client.clone();
conn.iterate(false).unwrap(); let l = listener.clone();
} match rx.recv() {
Err(_) => return,
Ok(req) => {
let mut introspector = conn.context.borrow_mut().introspect();
loop { match req {
let cl11 = cl1.clone(); PulseAudioClientRequest::GetDefaultDevice(s) => {
let cl12 = cl1.clone(); introspector.get_server_info(move |info| {
let cl13 = cl1.clone(); let _res = PulseAudioClient::server_info_callback(
match rx.recv() { cl.clone(),
Err(_) => return, l.clone(),
Ok(req) => { info,
let mut introspector = conn.context.borrow_mut().introspect(); );
if let Some(s) = &s {
match req { let _ = s.send(true);
PulseAudioClientRequest::GetDefaultDevice(s) => { }
introspector.get_server_info(move |info| { });
let _res = cl11.lock().unwrap().server_info_callback(info);
if let Some(s) = &s {
let _ = s.send(true);
}
});
}
PulseAudioClientRequest::GetSinkInfoByIndex(s, index) => {
introspector.get_sink_info_by_index(index, move |res| {
cl12.lock().unwrap().sink_info_callback(res);
if let Some(s) = &s {
let _ = s.send(true);
}
});
}
PulseAudioClientRequest::GetSinkInfoByName(s, name) => {
introspector.get_sink_info_by_name(&name, move |res| {
cl13.lock().unwrap().sink_info_callback(res);
if let Some(s) = &s {
let _ = s.send(true);
}
});
}
PulseAudioClientRequest::SetSinkVolumeByName(s, name, volumes) => {
introspector.set_sink_volume_by_name(&name, &volumes, None);
if let Some(s) = &s {
let _ = s.send(true);
} }
} PulseAudioClientRequest::GetSinkInfoByIndex(s, index) => {
PulseAudioClientRequest::SetSinkMuteByName(s, name, mute) => { introspector.get_sink_info_by_index(index, move |res| {
introspector.set_sink_mute_by_name(&name, mute, None); PulseAudioClient::sink_info_callback(
if let Some(s) = &s { cl.clone(),
let _ = s.send(true); l.clone(),
res,
);
if let Some(s) = &s {
let _ = s.send(true);
}
});
} }
} PulseAudioClientRequest::GetSinkInfoByName(s, name) => {
}; introspector.get_sink_info_by_name(&name, move |res| {
PulseAudioClient::sink_info_callback(
cl.clone(),
l.clone(),
res,
);
if let Some(s) = &s {
let _ = s.send(true);
}
});
}
PulseAudioClientRequest::SetSinkVolumeByName(s, name, volumes) => {
introspector.set_sink_volume_by_name(&name, &volumes, None);
if let Some(s) = &s {
let _ = s.send(true);
}
}
PulseAudioClientRequest::SetSinkMuteByName(s, name, mute) => {
introspector.set_sink_mute_by_name(&name, mute, None);
if let Some(s) = &s {
let _ = s.send(true);
}
}
};
// send request and receive response // send request and receive response
conn.iterate(true).unwrap(); conn.iterate(true).unwrap();
conn.iterate(true).unwrap(); conn.iterate(true).unwrap();
}
} }
} }
} });
});
// subscribe // subscribe
let cl2 = client.clone(); let cl2 = client.clone();
let (tx2, rx2) = channel(); let (tx2, rx2) = channel();
thread::spawn(move || { let _ = thread::Builder::new()
let conn = match PulseAudioConnection::new() { .name("pa_reader".to_string())
Ok(v) => { .spawn(move || {
tx2.send(true).unwrap(); let conn = match PulseAudioConnection::new() {
v Ok(v) => {
} tx2.send(true).unwrap();
Err(_) => { v
tx2.send(false).unwrap(); }
return; Err(_) => {
} tx2.send(false).unwrap();
}; return;
// subcribe for events }
conn.context };
.borrow_mut() // subcribe for events
.set_subscribe_callback(Some(Box::new(move |facility, operation, index| { conn.context
cl2.lock() .borrow_mut()
.unwrap() .set_subscribe_callback(Some(Box::new(move |facility, operation, index| {
.subscribe_callback(facility, operation, index) cl2.lock()
}))); .unwrap()
conn.context.borrow_mut().subscribe( .subscribe_callback(facility, operation, index)
subscription_masks::SERVER | subscription_masks::SINK, })));
|_| {}, conn.context.borrow_mut().subscribe(
); subscription_masks::SERVER | subscription_masks::SINK,
|_| {},
);
conn.mainloop.borrow_mut().run().unwrap(); conn.mainloop.borrow_mut().run().unwrap();
}); });
if !rx1.recv().unwrap() || !rx2.recv().unwrap() { if !rx1.recv().unwrap() || !rx2.recv().unwrap() {
return Err(::std::io::Error::new( return Err(::std::io::Error::new(
@@ -247,16 +270,25 @@ impl PulseAudioClient {
res res
} }
fn server_info_callback(&mut self, server_info: &ServerInfo) { fn server_info_callback<F>(s: Arc<Mutex<Self>>, listener: F, server_info: &ServerInfo)
where
F: Fn(Arc<Mutex<Self>>) -> (),
F: Send + 'static,
{
match server_info.default_sink_name.clone() { match server_info.default_sink_name.clone() {
None => {} None => {}
Some(default_sink) => { Some(default_sink) => {
self.default_sink = default_sink.into(); (*s.lock().unwrap()).default_sink = default_sink.into();
listener(s);
} }
} }
} }
fn sink_info_callback(&mut self, result: ListResult<&SinkInfo>) { fn sink_info_callback<F>(s: Arc<Mutex<Self>>, listener: F, result: ListResult<&SinkInfo>)
where
F: Fn(Arc<Mutex<Self>>) -> (),
F: Send + 'static,
{
match result { match result {
ListResult::End | ListResult::Error => {} ListResult::End | ListResult::Error => {}
ListResult::Item(sink_info) => match sink_info.name.clone() { ListResult::Item(sink_info) => match sink_info.name.clone() {
@@ -266,8 +298,8 @@ impl PulseAudioClient {
volume: sink_info.volume, volume: sink_info.volume,
mute: sink_info.mute, mute: sink_info.mute,
}; };
self.sinks.insert(name.into(), info); s.lock().unwrap().sinks.insert(name.into(), info);
self.listener.send(true).unwrap(); listener(s);
} }
}, },
} }
@@ -295,8 +327,39 @@ impl PulseAudioClient {
} }
impl PulseAudioSoundDevice { impl PulseAudioSoundDevice {
fn new(listener: Sender<bool>) -> Result<Arc<Mutex<Self>>, ::std::io::Error> { fn new<F>(listener: F) -> Result<Self, ::std::io::Error>
let client = PulseAudioClient::new(listener)?; where
F: Fn() -> (),
F: Send + 'static + Clone,
{
let inner = Arc::new(Mutex::new(PulseAudioSoundDeviceInner {
name: None,
volume: None,
volume_avg: 0.0,
muted: false,
default_sink: "@DEFAULT_SINK@".to_string(),
}));
let cb_inner = inner.clone();
let client = PulseAudioClient::new(move |client| {
let mut inner = cb_inner.lock().unwrap();
inner.default_sink = client.lock().unwrap().default_sink.clone();
let name = inner
.name
.clone()
.unwrap_or_else(|| inner.default_sink.clone());
let sink_info = match client.lock().unwrap().sinks.get(&name) {
None => return,
Some(sink_info) => (*sink_info).clone(),
};
inner.volume = Some(sink_info.volume);
inner.volume_avg = sink_info.volume.avg().0 as f32 / VOLUME_NORM.0 as f32;
inner.muted = sink_info.mute;
listener();
})?;
let cl = client.clone(); let cl = client.clone();
let (tx, rx) = channel(); let (tx, rx) = channel();
{ {
@@ -308,52 +371,29 @@ impl PulseAudioSoundDevice {
let cl = client.lock().unwrap(); let cl = client.lock().unwrap();
cl.default_sink.to_string() cl.default_sink.to_string()
}; };
let device = Arc::new(Mutex::new(PulseAudioSoundDevice { (*inner.lock().unwrap()).name = Some(name.clone());
let device = PulseAudioSoundDevice {
client: cl, client: cl,
name: Some(name.to_string()), inner: inner,
volume: None, };
volume_avg: 0.0,
muted: false,
}));
let (tx, rx) = channel(); let (tx, rx) = channel();
{ {
let cl = client.lock().unwrap(); let cl = client.lock().unwrap();
cl.send(PulseAudioClientRequest::GetSinkInfoByName(Some(tx), name))?; cl.send(PulseAudioClientRequest::GetSinkInfoByName(Some(tx), name))?;
} }
rx.recv().unwrap(); rx.recv().unwrap();
device.lock().unwrap().get_info()?;
Ok(device) Ok(device)
} }
fn name(&self) -> String {
self.name
.clone()
.unwrap_or_else(|| self.client.lock().unwrap().default_sink.clone())
}
fn update_volume(&mut self, volume: ChannelVolumes) {
self.volume = Some(volume);
self.volume_avg = volume.avg().0 as f32 / VOLUME_NORM.0 as f32;
}
fn volume(&self) -> f32 { fn volume(&self) -> f32 {
self.volume_avg let inner = self.inner.lock().unwrap();
} inner.volume_avg
fn get_info(&mut self) -> Result<(), ::std::io::Error> {
let sink_info = match self.client.lock().unwrap().sinks.get(&self.name()) {
None => return Ok(()),
Some(sink_info) => (*sink_info).clone(),
};
self.update_volume(sink_info.volume);
self.muted = sink_info.mute;
Ok(())
} }
fn set_volume(&mut self, step: f32) -> Result<(), ::std::io::Error> { fn set_volume(&mut self, step: f32) -> Result<(), ::std::io::Error> {
let mut volume = match self.volume { let mut inner = self.inner.lock().unwrap();
let mut volume = match inner.volume {
Some(volume) => volume, Some(volume) => volume,
None => { None => {
return Err(::std::io::Error::new( return Err(::std::io::Error::new(
@@ -369,59 +409,63 @@ impl PulseAudioSoundDevice {
vol.0 = min(max(0, vol.0 as i32 + step) as u32, VOLUME_MAX.0); vol.0 = min(max(0, vol.0 as i32 + step) as u32, VOLUME_MAX.0);
} }
let name = inner
.name
.clone()
.unwrap_or_else(|| inner.default_sink.clone());
// update volumes // update volumes
self.update_volume(volume); inner.volume = Some(volume);
inner.volume_avg = volume.avg().0 as f32 / VOLUME_NORM.0 as f32;
self.client self.client
.lock() .lock()
.unwrap() .unwrap()
.send(PulseAudioClientRequest::SetSinkVolumeByName( .send(PulseAudioClientRequest::SetSinkVolumeByName(
None, None, name, volume,
self.name(),
volume,
))?; ))?;
Ok(()) Ok(())
} }
fn toggle(&mut self) -> Result<(), ::std::io::Error> { fn toggle(&mut self) -> Result<(), ::std::io::Error> {
self.muted = !self.muted; let mut inner = self.inner.lock().unwrap();
inner.muted = !inner.muted;
self.client self.client
.lock() .lock()
.unwrap() .unwrap()
.send(PulseAudioClientRequest::SetSinkMuteByName( .send(PulseAudioClientRequest::SetSinkMuteByName(
None, None,
self.name(), inner
self.muted, .name
.clone()
.unwrap_or_else(|| inner.default_sink.clone()),
inner.muted,
))?; ))?;
Ok(()) Ok(())
} }
} }
pub struct PulseAudio { pub struct PulseAudio {
device: Arc<Mutex<PulseAudioSoundDevice>>, device: PulseAudioSoundDevice,
font: Font, font: Font,
dirty: Arc<Mutex<bool>>, dirty: Arc<Mutex<bool>>,
} }
impl PulseAudio { impl PulseAudio {
pub fn new(listener: Sender<Cmd>) -> Result<PulseAudio, ::std::io::Error> { pub fn new(listener: Sender<Cmd>) -> Result<PulseAudio, ::std::io::Error> {
let (tx, rx) = channel();
let mut font = Font::new(&ROBOTO_REGULAR, 24.0); let mut font = Font::new(&ROBOTO_REGULAR, 24.0);
font.add_str_to_cache("volume"); font.add_str_to_cache("volume");
let pa = PulseAudio { let dirty = Arc::new(Mutex::new(true));
device: PulseAudioSoundDevice::new(tx)?, let dev_dirty = dirty.clone();
font: font, let device = PulseAudioSoundDevice::new(move || {
dirty: Arc::new(Mutex::new(true)), *dev_dirty.lock().unwrap() = true;
};
let device = pa.device.clone();
let dirty = pa.dirty.clone();
std::thread::spawn(move || loop {
rx.recv().unwrap();
device.lock().unwrap().get_info().unwrap();
*(dirty.lock().unwrap()) = true;
listener.send(Cmd::Draw).unwrap(); listener.send(Cmd::Draw).unwrap();
}); })?;
let pa = PulseAudio {
device: device,
font: font,
dirty: dirty,
};
Ok(pa) Ok(pa)
} }
} }
@@ -433,8 +477,8 @@ impl ModuleImpl for PulseAudio {
bg: &Color, bg: &Color,
_time: &DateTime<Local>, _time: &DateTime<Local>,
) -> Result<Vec<(i32, i32, i32, i32)>, ::std::io::Error> { ) -> Result<Vec<(i32, i32, i32, i32)>, ::std::io::Error> {
let muted = self.device.lock().unwrap().muted; let muted = self.device.inner.lock().unwrap().muted;
let mut vol = self.device.lock().unwrap().volume(); let mut vol = self.device.volume();
buf.memset(bg); buf.memset(bg);
let c = if muted { let c = if muted {
Color::new(1.0, 1.0, 0.0, 1.0) Color::new(1.0, 1.0, 0.0, 1.0)
@@ -476,15 +520,13 @@ impl ModuleImpl for PulseAudio {
x: _x, x: _x,
y, y,
} => { } => {
self.device self.device.set_volume(y as f32 / -800.0).unwrap();
.lock() *self.dirty.lock().unwrap() = true;
.unwrap()
.set_volume(y as f32 / -800.0)
.unwrap();
} }
Input::Click { pos: _pos, button } => match button { Input::Click { pos: _pos, button } => match button {
273 => { 273 => {
self.device.lock().unwrap().toggle().unwrap(); self.device.toggle().unwrap();
*self.dirty.lock().unwrap() = true;
} }
_ => {} _ => {}
}, },