Fix updating volume
This commit is contained in:
parent
786a980254
commit
7212fe545b
5 changed files with 49 additions and 32 deletions
|
|
@ -2,16 +2,16 @@ use gtk4::{prelude::*, Button, Label, ListBox};
|
||||||
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
|
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
|
||||||
use std::rc::Rc;
|
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
|
// XXX handle error
|
||||||
pa.get_source_info_list()
|
pa.get_source_info_list()
|
||||||
.await
|
.await
|
||||||
.expect("failed to list input devices")
|
.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
|
// XXX handle error
|
||||||
let default_input = pa
|
let default_input = pa
|
||||||
.get_default_source()
|
.get_default_source()
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,15 @@ use gtk4::{
|
||||||
Orientation, PositionType, Revealer, RevealerTransitionType, Scale, SelectionMode, Separator,
|
Orientation, PositionType, Revealer, RevealerTransitionType, Scale, SelectionMode, Separator,
|
||||||
};
|
};
|
||||||
use libpulse_binding::{
|
use libpulse_binding::{
|
||||||
context::subscribe::{Facility, InterestMaskSet, Operation},
|
context::{
|
||||||
|
subscribe::{Facility, InterestMaskSet, Operation},
|
||||||
|
FlagSet, State,
|
||||||
|
},
|
||||||
volume::Volume,
|
volume::Volume,
|
||||||
};
|
};
|
||||||
use mpris2_zbus::metadata::Metadata;
|
use mpris2_zbus::metadata::Metadata;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::rc::Rc;
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("failed to build tokio 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
|
let pa = Rc::new(RefCell::new(pa));
|
||||||
.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {});
|
pa.borrow_mut()
|
||||||
let pa = Rc::new(pa);
|
.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! {
|
view! {
|
||||||
window = ApplicationWindow {
|
window = ApplicationWindow {
|
||||||
set_application: Some(application),
|
set_application: Some(application),
|
||||||
|
|
@ -152,18 +166,20 @@ fn app(application: &Application) {
|
||||||
glib::MainContext::default().spawn_local(
|
glib::MainContext::default().spawn_local(
|
||||||
clone!(@weak inputs, @weak current_input, @weak input_volume, @strong pa => async move {
|
clone!(@weak inputs, @weak current_input, @weak input_volume, @strong pa => async move {
|
||||||
while let Some(()) = refresh_input_rx.next().await {
|
while let Some(()) = refresh_input_rx.next().await {
|
||||||
input::refresh_input_widgets(&pa, &inputs);
|
let pa = pa.borrow();
|
||||||
let default_input = input::refresh_default_input(&pa, ¤t_input);
|
input::refresh_input_widgets(&pa, &inputs).await;
|
||||||
// XXX volume::update_volume(&default_input, &input_volume);
|
let default_input = input::refresh_default_input(&pa, ¤t_input).await;
|
||||||
|
volume::update_volume(&default_input, &input_volume);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
glib::MainContext::default().spawn_local(
|
glib::MainContext::default().spawn_local(
|
||||||
clone!(@weak outputs, @weak current_output, @weak output_volume, @strong pa => async move {
|
clone!(@weak outputs, @weak current_output, @weak output_volume, @strong pa => async move {
|
||||||
while let Some(()) = refresh_output_rx.next().await {
|
while let Some(()) = refresh_output_rx.next().await {
|
||||||
|
let pa = pa.borrow();
|
||||||
output::refresh_output_widgets(&pa, &outputs);
|
output::refresh_output_widgets(&pa, &outputs);
|
||||||
let default_output = output::refresh_default_output(&pa, ¤t_output);
|
let default_output = output::refresh_default_output(&pa, ¤t_output).await;
|
||||||
// XXX volume::update_volume(&default_output, &output_volume);
|
volume::update_volume(&default_output, &output_volume);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@ use gtk4::{prelude::*, Button, Label, ListBox};
|
||||||
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
|
use libcosmic_widgets::{relm4::RelmContainerExt, LabeledItem};
|
||||||
use std::rc::Rc;
|
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
|
// XXX handle error
|
||||||
pa.get_sink_info_list()
|
pa.get_sink_info_list()
|
||||||
.await
|
.await
|
||||||
.expect("failed to list output devices")
|
.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
|
// XXX handle error
|
||||||
let default_output = pa
|
let default_output = pa
|
||||||
.get_default_sink()
|
.get_default_sink()
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,15 @@ use futures::{channel::oneshot, future::poll_fn, task::Poll};
|
||||||
use libpulse_binding::{
|
use libpulse_binding::{
|
||||||
callbacks::ListResult,
|
callbacks::ListResult,
|
||||||
context::{introspect::SinkInfo, Context},
|
context::{introspect::SinkInfo, Context},
|
||||||
|
volume::ChannelVolumes,
|
||||||
};
|
};
|
||||||
use libpulse_glib_binding::Mainloop;
|
use libpulse_glib_binding::Mainloop;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Sink {
|
pub struct DeviceInfo {
|
||||||
pub name: Option<String>,
|
|
||||||
pub description: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Source {
|
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
pub volume: ChannelVolumes,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerInfo {
|
pub struct ServerInfo {
|
||||||
|
|
@ -45,16 +42,17 @@ impl PA {
|
||||||
receiver.await.unwrap()
|
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 (sender, receiver) = oneshot::channel();
|
||||||
let mut sender = Some(sender);
|
let mut sender = Some(sender);
|
||||||
let mut items = Some(Vec::new());
|
let mut items = Some(Vec::new());
|
||||||
self.context
|
self.context
|
||||||
.introspect()
|
.introspect()
|
||||||
.get_sink_info_list(move |result| match result {
|
.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()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: item.volume,
|
||||||
}),
|
}),
|
||||||
ListResult::End => {
|
ListResult::End => {
|
||||||
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
||||||
|
|
@ -66,7 +64,7 @@ impl PA {
|
||||||
receiver.await.unwrap()
|
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 {
|
let name = match self.get_server_info().await.default_sink_name {
|
||||||
Some(name) => name,
|
Some(name) => name,
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -80,9 +78,10 @@ impl PA {
|
||||||
.introspect()
|
.introspect()
|
||||||
.get_sink_info_by_name(&name, move |result| match result {
|
.get_sink_info_by_name(&name, move |result| match result {
|
||||||
ListResult::Item(item) => {
|
ListResult::Item(item) => {
|
||||||
sink = Some(Sink {
|
sink = Some(DeviceInfo {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: item.volume,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ListResult::End => {
|
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 (sender, receiver) = oneshot::channel();
|
||||||
let mut sender = Some(sender);
|
let mut sender = Some(sender);
|
||||||
let mut items = Some(Vec::new());
|
let mut items = Some(Vec::new());
|
||||||
self.context
|
self.context
|
||||||
.introspect()
|
.introspect()
|
||||||
.get_source_info_list(move |result| match result {
|
.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()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: item.volume,
|
||||||
}),
|
}),
|
||||||
ListResult::End => {
|
ListResult::End => {
|
||||||
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
sender.take().unwrap().send(Ok(items.take().unwrap()));
|
||||||
|
|
@ -123,7 +123,7 @@ impl PA {
|
||||||
receiver.await.unwrap()
|
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 {
|
let name = match self.get_server_info().await.default_source_name {
|
||||||
Some(name) => name,
|
Some(name) => name,
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -137,9 +137,10 @@ impl PA {
|
||||||
.introspect()
|
.introspect()
|
||||||
.get_source_info_by_name(&name, move |result| match result {
|
.get_source_info_by_name(&name, move |result| match result {
|
||||||
ListResult::Item(item) => {
|
ListResult::Item(item) => {
|
||||||
source = Some(Source {
|
source = Some(DeviceInfo {
|
||||||
name: item.name.clone().map(|x| x.into_owned()),
|
name: item.name.clone().map(|x| x.into_owned()),
|
||||||
description: item.description.clone().map(|x| x.into_owned()),
|
description: item.description.clone().map(|x| x.into_owned()),
|
||||||
|
volume: item.volume,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ListResult::End => {
|
ListResult::End => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use gtk4::{prelude::*, Scale};
|
use gtk4::{prelude::*, Scale};
|
||||||
use libpulse_binding::volume::Volume;
|
use libpulse_binding::volume::Volume;
|
||||||
|
|
||||||
/*
|
use crate::pa::DeviceInfo;
|
||||||
|
|
||||||
pub fn update_volume(device: &DeviceInfo, scale: &Scale) {
|
pub fn update_volume(device: &DeviceInfo, scale: &Scale) {
|
||||||
scale.set_value((device.volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.);
|
scale.set_value((device.volume.avg().0 as f64 / Volume::NORMAL.0 as f64) * 100.);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue