mirror of
https://github.com/Xetibo/ReSet.git
synced 2025-07-01 15:57:46 +02:00
feat: Add basic functionality to all audio usecases
This commit is contained in:
parent
2f1099267a
commit
c1984b5b79
32 changed files with 368 additions and 201 deletions
|
@ -1,5 +1,15 @@
|
|||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use adw::glib;
|
||||
use adw::glib::Object;
|
||||
use adw::prelude::RangeExt;
|
||||
use dbus::blocking::Connection;
|
||||
use dbus::Error;
|
||||
use ReSet_Lib::audio::audio::OutputStream;
|
||||
use glib::{clone, Propagation};
|
||||
use glib::subclass::types::ObjectSubclassIsExt;
|
||||
|
||||
use super::outputStreamEntryImpl;
|
||||
|
||||
|
@ -10,7 +20,51 @@ glib::wrapper! {
|
|||
}
|
||||
|
||||
impl OutputStreamEntry {
|
||||
pub fn new() -> Self {
|
||||
Object::builder().build()
|
||||
pub fn new(stream: OutputStream) -> Self {
|
||||
let obj: Self = Object::builder().build();
|
||||
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
||||
// TODO map mute to callback
|
||||
// TODO map dropdown
|
||||
{
|
||||
let imp = obj.imp();
|
||||
let name = stream.application_name.clone() + ": " + stream.name.as_str();
|
||||
imp.resetSourceName.set_text(name.as_str());
|
||||
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||
let fraction = (*volume as f64 / 655.36).round();
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
imp.resetVolumePercentage.set_text(&percentage);
|
||||
imp.resetVolumeSlider.set_value(*volume as f64);
|
||||
imp.stream.replace(stream);
|
||||
imp.resetVolumeSlider.connect_change_value(
|
||||
clone!(@weak imp => @default-return Propagation::Stop, move |_, _, value| {
|
||||
let fraction = (value / 655.36).round();
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
imp.resetVolumePercentage.set_text(&percentage);
|
||||
set_outputstream_volume(value, imp.stream.clone());
|
||||
Propagation::Proceed
|
||||
}),
|
||||
);
|
||||
}
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
||||
fn set_outputstream_volume(value: f64, stream: Arc<RefCell<OutputStream>>) -> bool {
|
||||
let mut stream = stream.borrow_mut().clone();
|
||||
// let x = stream.volume.iter_mut().map(|_| value as u32);
|
||||
stream.volume = vec![value as u32; stream.channels as usize];
|
||||
dbg!(stream.volume.clone());
|
||||
|
||||
let conn = Connection::new_session().unwrap();
|
||||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(bool,), Error> =
|
||||
proxy.method_call("org.xetibo.ReSet", "SetOutputStreamVolume", (stream,));
|
||||
if res.is_err() {
|
||||
return false;
|
||||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::components::input::outputStreamEntry;
|
||||
use ReSet_Lib::audio::audio::OutputStream;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, DropDown};
|
||||
|
||||
|
@ -18,6 +22,7 @@ pub struct OutputStreamEntry {
|
|||
pub resetVolumePercentage: TemplateChild<Label>,
|
||||
#[template_child]
|
||||
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
||||
pub stream: Arc<RefCell<OutputStream>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
|
|
@ -1,9 +1,23 @@
|
|||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::components::base::listEntry::ListEntry;
|
||||
use crate::components::base::utils::Listeners;
|
||||
use crate::components::input::sourceBoxImpl;
|
||||
use crate::components::input::sourceEntry::set_source_volume;
|
||||
use adw::glib;
|
||||
use adw::glib::Object;
|
||||
use adw::prelude::{BoxExt, ListBoxRowExt, RangeExt};
|
||||
use dbus::blocking::Connection;
|
||||
use dbus::Error;
|
||||
use glib::subclass::prelude::ObjectSubclassIsExt;
|
||||
use glib::Variant;
|
||||
use glib::{Propagation, Variant};
|
||||
use gtk::gio;
|
||||
use gtk::prelude::ActionableExt;
|
||||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||
|
||||
use super::outputStreamEntry::OutputStreamEntry;
|
||||
use super::sourceEntry::SourceEntry;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct SourceBox(ObjectSubclass<sourceBoxImpl::SourceBox>)
|
||||
|
@ -11,6 +25,9 @@ glib::wrapper! {
|
|||
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
|
||||
}
|
||||
|
||||
unsafe impl Send for SourceBox {}
|
||||
unsafe impl Sync for SourceBox {}
|
||||
|
||||
impl SourceBox {
|
||||
pub fn new() -> Self {
|
||||
Object::builder().build()
|
||||
|
@ -18,9 +35,124 @@ impl SourceBox {
|
|||
|
||||
pub fn setupCallbacks(&self) {
|
||||
let selfImp = self.imp();
|
||||
selfImp.resetSourceRow.set_action_name(Some("navigation.push"));
|
||||
selfImp.resetSourceRow.set_action_target_value(Some(&Variant::from("sources")));
|
||||
selfImp
|
||||
.resetSourceRow
|
||||
.set_action_name(Some("navigation.push"));
|
||||
selfImp
|
||||
.resetSourceRow
|
||||
.set_action_target_value(Some(&Variant::from("sources")));
|
||||
|
||||
selfImp.resetOutputStreamButton.set_action_name(Some("navigation.pop"));
|
||||
selfImp
|
||||
.resetOutputStreamButton
|
||||
.set_action_name(Some("navigation.pop"));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||
gio::spawn_blocking(move || {
|
||||
let output_box_imp = output_box.imp();
|
||||
let sinks = get_sources();
|
||||
output_box_imp
|
||||
.resetDefaultSource
|
||||
.replace(get_default_source());
|
||||
glib::spawn_future(async move {
|
||||
glib::idle_add_once(move || {
|
||||
// TODO handle default mapping
|
||||
let output_box_ref_slider = output_box.clone();
|
||||
let output_box_ref = output_box.clone();
|
||||
{
|
||||
let output_box_imp = output_box_ref.imp();
|
||||
let default_sink = output_box_imp.resetDefaultSource.clone(); // Clone outside closure
|
||||
let source = default_sink.borrow(); //
|
||||
|
||||
let volume = source.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||
let fraction = (*volume as f64 / 655.36).round();
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
output_box_imp.resetVolumePercentage.set_text(&percentage);
|
||||
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
||||
for stream in sinks {
|
||||
let entry = ListEntry::new(&SourceEntry::new(stream));
|
||||
entry.set_activatable(false);
|
||||
output_box_imp.resetSources.append(&entry);
|
||||
}
|
||||
}
|
||||
output_box_ref
|
||||
.imp()
|
||||
.resetVolumeSlider
|
||||
.connect_change_value(move |_, _, value| {
|
||||
let imp = output_box_ref_slider.imp();
|
||||
let fraction = (value / 655.36).round();
|
||||
println!("{fraction}");
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
imp.resetVolumePercentage.set_text(&percentage);
|
||||
set_source_volume(value, imp.resetDefaultSource.clone());
|
||||
Propagation::Proceed
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn populate_outputstreams(listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
|
||||
// TODO add listener
|
||||
let output_box_ref = output_box.clone();
|
||||
|
||||
gio::spawn_blocking(move || {
|
||||
let streams = get_output_streams();
|
||||
glib::spawn_future(async move {
|
||||
glib::idle_add_once(move || {
|
||||
let output_box_imp = output_box_ref.imp();
|
||||
for stream in streams {
|
||||
let entry = ListEntry::new(&OutputStreamEntry::new(stream));
|
||||
entry.set_activatable(false);
|
||||
output_box_imp.resetOutputStreams.append(&entry);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn get_output_streams() -> Vec<OutputStream> {
|
||||
let conn = Connection::new_session().unwrap();
|
||||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(Vec<OutputStream>,), Error> =
|
||||
proxy.method_call("org.xetibo.ReSet", "ListOutputStreams", ());
|
||||
if res.is_err() {
|
||||
return Vec::new();
|
||||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
||||
fn get_sources() -> Vec<Source> {
|
||||
let conn = Connection::new_session().unwrap();
|
||||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(Vec<Source>,), Error> =
|
||||
proxy.method_call("org.xetibo.ReSet", "ListSources", ());
|
||||
if res.is_err() {
|
||||
return Vec::new();
|
||||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
||||
fn get_default_source() -> Source {
|
||||
let conn = Connection::new_session().unwrap();
|
||||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(Source,), Error> =
|
||||
proxy.method_call("org.xetibo.ReSet", "GetDefaultSource", ());
|
||||
if res.is_err() {
|
||||
return Source::default();
|
||||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use gtk::{prelude::*, Button, Label, ProgressBar, Scale};
|
|||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||
|
||||
use super::outputStreamEntry::OutputStreamEntry;
|
||||
use super::sourceEntry::SourceEntry;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Default, CompositeTemplate)]
|
||||
|
@ -32,7 +33,7 @@ pub struct SourceBox {
|
|||
pub resetOutputStreamButton: TemplateChild<ListEntry>,
|
||||
#[template_child]
|
||||
pub resetOutputStreams: TemplateChild<gtk::Box>,
|
||||
pub resetDefaultSource: RefCell<Option<Source>>,
|
||||
pub resetDefaultSource: Arc<RefCell<Source>>,
|
||||
pub resetSourceList: Arc<Mutex<Vec<Source>>>,
|
||||
pub resetOutputStreamList: Arc<Mutex<Vec<OutputStream>>>,
|
||||
}
|
||||
|
@ -45,6 +46,7 @@ impl ObjectSubclass for SourceBox {
|
|||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
OutputStreamEntry::ensure_type();
|
||||
SourceEntry::ensure_type();
|
||||
ListEntry::ensure_type();
|
||||
klass.bind_template();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ impl SourceEntry {
|
|||
println!("{fraction}");
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
imp.resetVolumePercentage.set_text(&percentage);
|
||||
set_inputstream_volume(value, imp.stream.clone());
|
||||
set_source_volume(value, imp.stream.clone());
|
||||
Propagation::Proceed
|
||||
}),
|
||||
);
|
||||
|
@ -51,7 +51,7 @@ impl SourceEntry {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_inputstream_volume(value: f64, stream: Arc<RefCell<Source>>) -> bool {
|
||||
pub fn set_source_volume(value: f64, stream: Arc<RefCell<Source>>) -> bool {
|
||||
let mut stream = stream.borrow_mut().clone();
|
||||
// let x = stream.volume.iter_mut().map(|_| value as u32);
|
||||
stream.volume = vec![value as u32; stream.channels as usize];
|
||||
|
@ -61,7 +61,7 @@ fn set_inputstream_volume(value: f64, stream: Arc<RefCell<Source>>) -> bool {
|
|||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(100),
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(bool,), Error> =
|
||||
proxy.method_call("org.xetibo.ReSet", "SetSourceVolume", (stream,));
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|||
use std::sync::Arc;
|
||||
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale, CheckButton};
|
||||
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, CheckButton};
|
||||
use ReSet_Lib::audio::audio::Source;
|
||||
|
||||
use super::sourceEntry;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue