Fix updating volume

This commit is contained in:
Ian Douglas Scott 2022-06-13 18:37:52 -07:00
parent 786a980254
commit 7212fe545b
5 changed files with 49 additions and 32 deletions

View file

@ -2,16 +2,16 @@ use gtk4::{prelude::*, Button, Label, ListBox};
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
use std::rc::Rc;
use crate::pa::{Source, PA};
use crate::pa::{DeviceInfo, PA};
pub async fn get_inputs(pa: &PA) -> Vec<Source> {
pub async fn get_inputs(pa: &PA) -> Vec<DeviceInfo> {
// XXX handle error
pa.get_source_info_list()
.await
.expect("failed to list input devices")
}
pub async fn refresh_default_input(pa: &PA, label: &Label) -> Source {
pub async fn refresh_default_input(pa: &PA, label: &Label) -> DeviceInfo {
// XXX handle error
let default_input = pa
.get_default_source()

View file

@ -21,12 +21,15 @@ use gtk4::{
Orientation, PositionType, Revealer, RevealerTransitionType, Scale, SelectionMode, Separator,
};
use libpulse_binding::{
context::subscribe::{Facility, InterestMaskSet, Operation},
context::{
subscribe::{Facility, InterestMaskSet, Operation},
FlagSet, State,
},
volume::Volume,
};
use mpris2_zbus::metadata::Metadata;
use once_cell::sync::Lazy;
use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};
use tokio::runtime::Runtime;
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime"));
@ -61,9 +64,20 @@ fn app(application: &Application) {
_ => {}
}
}))));
pa.context
.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {});
let pa = Rc::new(pa);
let pa = Rc::new(RefCell::new(pa));
pa.borrow_mut()
.context
.set_state_callback(Some(Box::new(clone!(@strong pa => move || {
let mut pa = pa.borrow_mut();
if pa.context.get_state() == State::Ready {
pa.context
.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {});
}
}))));
pa.borrow_mut()
.context
.connect(None, FlagSet::empty(), None)
.unwrap();
view! {
window = ApplicationWindow {
set_application: Some(application),
@ -152,18 +166,20 @@ fn app(application: &Application) {
glib::MainContext::default().spawn_local(
clone!(@weak inputs, @weak current_input, @weak input_volume, @strong pa => async move {
while let Some(()) = refresh_input_rx.next().await {
input::refresh_input_widgets(&pa, &inputs);
let default_input = input::refresh_default_input(&pa, &current_input);
// XXX volume::update_volume(&default_input, &input_volume);
let pa = pa.borrow();
input::refresh_input_widgets(&pa, &inputs).await;
let default_input = input::refresh_default_input(&pa, &current_input).await;
volume::update_volume(&default_input, &input_volume);
}
}),
);
glib::MainContext::default().spawn_local(
clone!(@weak outputs, @weak current_output, @weak output_volume, @strong pa => async move {
while let Some(()) = refresh_output_rx.next().await {
let pa = pa.borrow();
output::refresh_output_widgets(&pa, &outputs);
let default_output = output::refresh_default_output(&pa, &current_output);
// XXX volume::update_volume(&default_output, &output_volume);
let default_output = output::refresh_default_output(&pa, &current_output).await;
volume::update_volume(&default_output, &output_volume);
}
}),
);

View file

@ -2,16 +2,16 @@ use gtk4::{prelude::*, Button, Label, ListBox};
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
use std::rc::Rc;
use crate::pa::{Sink, PA};
use crate::pa::{DeviceInfo, PA};
pub async fn get_outputs(pa: &PA) -> Vec<Sink> {
pub async fn get_outputs(pa: &PA) -> Vec<DeviceInfo> {
// XXX handle error
pa.get_sink_info_list()
.await
.expect("failed to list output devices")
}
pub async fn refresh_default_output(pa: &PA, label: &Label) -> Sink {
pub async fn refresh_default_output(pa: &PA, label: &Label) -> DeviceInfo {
// XXX handle error
let default_output = pa
.get_default_sink()

View file

@ -2,18 +2,15 @@ use futures::{channel::oneshot, future::poll_fn, task::Poll};
use libpulse_binding::{
callbacks::ListResult,
context::{introspect::SinkInfo, Context},
volume::ChannelVolumes,
};
use libpulse_glib_binding::Mainloop;
use std::rc::Rc;
pub struct Sink {
pub name: Option<String>,
pub description: Option<String>,
}
pub struct Source {
pub struct DeviceInfo {
pub name: Option<String>,
pub description: Option<String>,
pub volume: ChannelVolumes,
}
pub struct ServerInfo {
@ -45,16 +42,17 @@ impl PA {
receiver.await.unwrap()
}
pub async fn get_sink_info_list(&self) -> Result<Vec<Sink>, ()> {
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());
self.context
.introspect()
.get_sink_info_list(move |result| match result {
ListResult::Item(item) => items.as_mut().unwrap().push(Sink {
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
name: item.name.clone().map(|x| x.into_owned()),
description: item.description.clone().map(|x| x.into_owned()),
volume: item.volume,
}),
ListResult::End => {
sender.take().unwrap().send(Ok(items.take().unwrap()));
@ -66,7 +64,7 @@ impl PA {
receiver.await.unwrap()
}
pub async fn get_default_sink(&self) -> Result<Sink, ()> {
pub async fn get_default_sink(&self) -> Result<DeviceInfo, ()> {
let name = match self.get_server_info().await.default_sink_name {
Some(name) => name,
None => {
@ -80,9 +78,10 @@ impl PA {
.introspect()
.get_sink_info_by_name(&name, move |result| match result {
ListResult::Item(item) => {
sink = Some(Sink {
sink = Some(DeviceInfo {
name: item.name.clone().map(|x| x.into_owned()),
description: item.description.clone().map(|x| x.into_owned()),
volume: item.volume,
});
}
ListResult::End => {
@ -102,16 +101,17 @@ impl PA {
}
*/
pub async fn get_source_info_list(&self) -> Result<Vec<Source>, ()> {
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());
self.context
.introspect()
.get_source_info_list(move |result| match result {
ListResult::Item(item) => items.as_mut().unwrap().push(Source {
ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo {
name: item.name.clone().map(|x| x.into_owned()),
description: item.description.clone().map(|x| x.into_owned()),
volume: item.volume,
}),
ListResult::End => {
sender.take().unwrap().send(Ok(items.take().unwrap()));
@ -123,7 +123,7 @@ impl PA {
receiver.await.unwrap()
}
pub async fn get_default_source(&self) -> Result<Source, ()> {
pub async fn get_default_source(&self) -> Result<DeviceInfo, ()> {
let name = match self.get_server_info().await.default_source_name {
Some(name) => name,
None => {
@ -137,9 +137,10 @@ impl PA {
.introspect()
.get_source_info_by_name(&name, move |result| match result {
ListResult::Item(item) => {
source = Some(Source {
source = Some(DeviceInfo {
name: item.name.clone().map(|x| x.into_owned()),
description: item.description.clone().map(|x| x.into_owned()),
volume: item.volume,
});
}
ListResult::End => {

View file

@ -1,8 +1,8 @@
use gtk4::{prelude::*, Scale};
use libpulse_binding::volume::Volume;
/*
use crate::pa::DeviceInfo;
pub fn update_volume(device: &DeviceInfo, scale: &Scale) {
scale.set_value((device.volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.);
}
*/