audio: Use custom, cancellable, single threaded future type
This commit is contained in:
parent
35a2d6905b
commit
0aaa0dd74d
2 changed files with 152 additions and 107 deletions
63
applets/cosmic-applet-audio/src/pa/future.rs
Normal file
63
applets/cosmic-applet-audio/src/pa/future.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
use libpulse_binding::operation::Operation;
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
future::{self, Future},
|
||||||
|
pin::Pin,
|
||||||
|
rc::Rc,
|
||||||
|
task::{self, Poll, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PAFutInner<T> {
|
||||||
|
res: Option<T>,
|
||||||
|
waker: Option<Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PAFutWaker<T>(Rc<RefCell<PAFutInner<T>>>);
|
||||||
|
|
||||||
|
impl<T> PAFutWaker<T> {
|
||||||
|
pub fn wake(&self, res: T) {
|
||||||
|
let mut inner = self.0.borrow_mut();
|
||||||
|
inner.res = Some(res);
|
||||||
|
if let Some(waker) = inner.waker.take() {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PAFut<T, F: ?Sized> {
|
||||||
|
inner: Rc<RefCell<PAFutInner<T>>>,
|
||||||
|
operation: Operation<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: ?Sized> PAFut<T, F> {
|
||||||
|
pub fn new(cb: impl FnOnce(PAFutWaker<T>) -> Operation<F>) -> Self {
|
||||||
|
let inner = Rc::new(RefCell::new(PAFutInner {
|
||||||
|
res: None,
|
||||||
|
waker: None,
|
||||||
|
}));
|
||||||
|
let operation = cb(PAFutWaker(inner.clone()));
|
||||||
|
Self { inner, operation }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: ?Sized> Future for PAFut<T, F> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
if let Some(res) = inner.res.take() {
|
||||||
|
Poll::Ready(res)
|
||||||
|
} else {
|
||||||
|
inner.waker = Some(cx.waker().clone());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: ?Sized> Drop for PAFut<T, F> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.operation.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use futures::{channel::oneshot, future::poll_fn, task::Poll};
|
|
||||||
use gtk4::glib;
|
use gtk4::glib;
|
||||||
use libpulse_binding::{
|
use libpulse_binding::{
|
||||||
callbacks::ListResult,
|
callbacks::ListResult,
|
||||||
|
|
@ -12,10 +11,13 @@ use libpulse_binding::{
|
||||||
};
|
};
|
||||||
use libpulse_glib_binding::Mainloop;
|
use libpulse_glib_binding::Mainloop;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::RefCell,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod future;
|
||||||
|
use future::{PAFut, PAFutWaker};
|
||||||
|
|
||||||
pub struct DeviceInfo {
|
pub struct DeviceInfo {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
|
@ -90,37 +92,33 @@ impl PA {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_server_info(&self) -> ServerInfo {
|
pub async fn get_server_info(&self) -> ServerInfo {
|
||||||
let (sender, receiver) = oneshot::channel();
|
PAFut::new(|waker| {
|
||||||
let mut sender = Some(sender);
|
self.introspect().get_server_info(move |info| {
|
||||||
self.introspect().get_server_info(move |info| {
|
waker.wake(ServerInfo {
|
||||||
sender.take().unwrap().send(ServerInfo {
|
default_sink_name: info.default_sink_name.clone().map(|x| x.into_owned()),
|
||||||
default_sink_name: info.default_sink_name.clone().map(|x| x.into_owned()),
|
default_source_name: info.default_source_name.clone().map(|x| x.into_owned()),
|
||||||
default_source_name: info.default_source_name.clone().map(|x| x.into_owned()),
|
});
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
receiver.await.unwrap()
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_sink_info_list(&self) -> Result<Vec<DeviceInfo>, ()> {
|
pub async fn get_sink_info_list(&self) -> Result<Vec<DeviceInfo>, ()> {
|
||||||
let (sender, receiver) = oneshot::channel();
|
|
||||||
let mut sender = Some(sender);
|
|
||||||
let mut items = Some(Vec::new());
|
let mut items = Some(Vec::new());
|
||||||
self.introspect()
|
PAFut::new(|waker| {
|
||||||
.get_sink_info_list(move |result| match result {
|
self.introspect()
|
||||||
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
.get_sink_info_list(move |result| match result {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
volume: item.volume,
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
index: item.index,
|
volume: item.volume,
|
||||||
}),
|
index: item.index,
|
||||||
ListResult::End => {
|
}),
|
||||||
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
||||||
}
|
ListResult::Error => waker.wake(Err(())),
|
||||||
ListResult::Error => {
|
})
|
||||||
sender.take().unwrap().send(Err(()));
|
})
|
||||||
}
|
.await
|
||||||
});
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_default_sink(&self) -> Result<DeviceInfo, ()> {
|
pub async fn get_default_sink(&self) -> Result<DeviceInfo, ()> {
|
||||||
|
|
@ -130,27 +128,23 @@ impl PA {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (sender, receiver) = oneshot::channel();
|
|
||||||
let mut sender = Some(sender);
|
|
||||||
let mut sink = None;
|
let mut sink = None;
|
||||||
self.introspect()
|
PAFut::new(|waker| {
|
||||||
.get_sink_info_by_name(&name, move |result| match result {
|
self.introspect()
|
||||||
ListResult::Item(item) => {
|
.get_sink_info_by_name(&name, move |result| match result {
|
||||||
sink = Some(DeviceInfo {
|
ListResult::Item(item) => {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
sink = Some(DeviceInfo {
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
volume: item.volume,
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
index: item.index,
|
volume: item.volume,
|
||||||
});
|
index: item.index,
|
||||||
}
|
});
|
||||||
ListResult::End => {
|
}
|
||||||
sender.take().unwrap().send(sink.take().ok_or(()));
|
ListResult::End => waker.wake(sink.take().ok_or(())),
|
||||||
}
|
ListResult::Error => waker.wake(Err(())),
|
||||||
ListResult::Error => {
|
})
|
||||||
sender.take().unwrap().send(Err(()));
|
})
|
||||||
}
|
.await
|
||||||
});
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX async wait and handle error
|
// XXX async wait and handle error
|
||||||
|
|
@ -163,25 +157,21 @@ impl PA {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_source_info_list(&self) -> Result<Vec<DeviceInfo>, ()> {
|
pub async fn get_source_info_list(&self) -> Result<Vec<DeviceInfo>, ()> {
|
||||||
let (sender, receiver) = oneshot::channel();
|
|
||||||
let mut sender = Some(sender);
|
|
||||||
let mut items = Some(Vec::new());
|
let mut items = Some(Vec::new());
|
||||||
self.introspect()
|
PAFut::new(|waker| {
|
||||||
.get_source_info_list(move |result| match result {
|
self.introspect()
|
||||||
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
.get_source_info_list(move |result| match result {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
volume: item.volume,
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
index: item.index,
|
volume: item.volume,
|
||||||
}),
|
index: item.index,
|
||||||
ListResult::End => {
|
}),
|
||||||
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
ListResult::End => waker.wake(Ok(items.take().unwrap())),
|
||||||
}
|
ListResult::Error => waker.wake(Err(())),
|
||||||
ListResult::Error => {
|
})
|
||||||
sender.take().unwrap().send(Err(()));
|
})
|
||||||
}
|
.await
|
||||||
});
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_default_source(&self) -> Result<DeviceInfo, ()> {
|
pub async fn get_default_source(&self) -> Result<DeviceInfo, ()> {
|
||||||
|
|
@ -191,52 +181,44 @@ impl PA {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (sender, receiver) = oneshot::channel();
|
|
||||||
let mut sender = Some(sender);
|
|
||||||
let mut source = None;
|
let mut source = None;
|
||||||
self.introspect()
|
PAFut::new(|waker| {
|
||||||
.get_source_info_by_name(&name, move |result| match result {
|
self.introspect()
|
||||||
ListResult::Item(item) => {
|
.get_source_info_by_name(&name, move |result| match result {
|
||||||
source = Some(DeviceInfo {
|
ListResult::Item(item) => {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
source = Some(DeviceInfo {
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
volume: item.volume,
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
index: item.index,
|
volume: item.volume,
|
||||||
});
|
index: item.index,
|
||||||
}
|
});
|
||||||
ListResult::End => {
|
}
|
||||||
sender.take().unwrap().send(source.take().ok_or(()));
|
ListResult::End => waker.wake(source.take().ok_or(())),
|
||||||
}
|
ListResult::Error => waker.wake(Err(())),
|
||||||
ListResult::Error => {
|
})
|
||||||
sender.take().unwrap().send(Err(()));
|
})
|
||||||
}
|
.await
|
||||||
});
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_sink_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool {
|
pub async fn set_sink_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool {
|
||||||
let (sender, receiver) = oneshot::channel();
|
PAFut::new(|waker| {
|
||||||
let mut sender = Some(sender);
|
self.introspect().set_sink_volume_by_name(
|
||||||
self.introspect().set_sink_volume_by_name(
|
name,
|
||||||
name,
|
volume,
|
||||||
volume,
|
Some(Box::new(move |success| waker.wake(success))),
|
||||||
Some(Box::new(move |success| {
|
)
|
||||||
sender.take().unwrap().send(success);
|
})
|
||||||
})),
|
.await
|
||||||
);
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_source_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool {
|
pub async fn set_source_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool {
|
||||||
let (sender, receiver) = oneshot::channel();
|
PAFut::new(|waker| {
|
||||||
let mut sender = Some(sender);
|
self.introspect().set_source_volume_by_name(
|
||||||
self.introspect().set_source_volume_by_name(
|
name,
|
||||||
name,
|
volume,
|
||||||
volume,
|
Some(Box::new(move |success| waker.wake(success))),
|
||||||
Some(Box::new(move |success| {
|
)
|
||||||
sender.take().unwrap().send(success);
|
})
|
||||||
})),
|
.await
|
||||||
);
|
|
||||||
receiver.await.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue