Merge pull request #58 from Xetibo/dashie

feat: Add audio events
This commit is contained in:
takotori 2023-11-16 10:23:07 +01:00 committed by GitHub
commit 70a8d3fdb8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1208 additions and 273 deletions

View file

@ -5,7 +5,7 @@ edition = "2021"
description = "A wip universal Linux settings application."
[dependencies]
reset_daemon = "0.1.3"
reset_daemon = "0.1.7"
ReSet-Lib = "0.2.8"
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
dbus = "0.9.7"

View file

@ -10,3 +10,8 @@
### instructions for installation:
`flatpak install --user reset.flatpak`
### permissions
currently ReSet uses permission on all devices, for some reason otherwise it can't access sound settings like volume changes etc.
This can likely be fixed by implementing portal integration later.

View file

@ -1042,14 +1042,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/reset_daemon/reset_daemon-0.1.3.crate",
"sha256": "1d7b1c575b773eadd0fc8991de8abb883cfb7bce9c5e8c4f9e10b85cb142efee",
"dest": "cargo/vendor/reset_daemon-0.1.3"
"url": "https://static.crates.io/crates/reset_daemon/reset_daemon-0.1.7.crate",
"sha256": "f7b48ba0698bdb4ead119140a557346907b40ae17cac324687a032b4d6ea9851",
"dest": "cargo/vendor/reset_daemon-0.1.7"
},
{
"type": "inline",
"contents": "{\"package\": \"1d7b1c575b773eadd0fc8991de8abb883cfb7bce9c5e8c4f9e10b85cb142efee\", \"files\": {}}",
"dest": "cargo/vendor/reset_daemon-0.1.3",
"contents": "{\"package\": \"f7b48ba0698bdb4ead119140a557346907b40ae17cac324687a032b4d6ea9851\", \"files\": {}}",
"dest": "cargo/vendor/reset_daemon-0.1.7",
"dest-filename": ".cargo-checksum.json"
},
{

View file

@ -3,15 +3,20 @@
"runtime": "org.gnome.Platform",
"runtime-version": "45",
"sdk": "org.gnome.Sdk",
"sdk-extensions": ["org.freedesktop.Sdk.Extension.rust-stable"],
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.rust-stable"
],
"command": "reset",
"finish-args": [
"--socket=session-bus",
"--socket=system-bus",
"--socket=pulseaudio",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--device=dri"
"--device=dri",
"--device=all",
"--allow=bluetooth"
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin"
@ -29,7 +34,7 @@
"cargo --offline fetch --manifest-path Cargo.toml --verbose",
"cargo --offline build --release --verbose",
"install -Dm755 ./target/release/reset -t /app/bin/",
"install -Dm644 ./src/resources/icons/ReSet.svg /app/share/icons/hicolor/scalable/apps/org.xetibo.ReSet.svg",
"install -Dm644 ./src/resources/icons/ReSet.svg /app/share/icons/hicolor/scalable/apps/org.xetibo.ReSet.svg",
"install -Dm644 ./flatpak/org.xetibo.ReSet.desktop /app/share/applications/org.xetibo.ReSet.desktop"
],
"sources": [

View file

@ -1,10 +1,21 @@
use std::{
sync::atomic::{AtomicBool, Ordering},
sync::{atomic::{AtomicBool, Ordering}, Arc},
thread,
time::Duration,
};
use dbus::{blocking::Connection, Error};
use dbus::{
arg::{self, Append},
blocking::Connection,
Error,
};
use gtk::gio;
use ReSet_Lib::{
audio::audio::{InputStream, OutputStream, Sink, Source},
signals::GetVal,
};
use crate::components::{input::sourceBox::{SourceBox, start_input_box_listener}, output::sinkBox::{SinkBox, start_output_box_listener}};
#[derive(Default)]
pub struct Listeners {
@ -31,3 +42,350 @@ impl Listeners {
});
}
}
#[derive(Debug)]
pub struct SinkAdded {
pub sink: Sink,
}
impl arg::AppendAll for SinkAdded {
fn append(&self, i: &mut arg::IterAppend) {
self.sink.append_by_ref(i);
}
}
impl arg::ReadAll for SinkAdded {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SinkAdded { sink: i.read()? })
}
}
impl dbus::message::SignalArgs for SinkAdded {
const NAME: &'static str = "SinkAdded";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(Sink,)> for SinkAdded {
fn get_value(&self) -> (Sink,) {
(self.sink.clone(),)
}
}
#[derive(Debug)]
pub struct SinkChanged {
pub sink: Sink,
}
impl arg::AppendAll for SinkChanged {
fn append(&self, i: &mut arg::IterAppend) {
self.sink.append_by_ref(i);
}
}
impl arg::ReadAll for SinkChanged {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SinkChanged { sink: i.read()? })
}
}
impl dbus::message::SignalArgs for SinkChanged {
const NAME: &'static str = "SinkChanged";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(Sink,)> for SinkChanged {
fn get_value(&self) -> (Sink,) {
(self.sink.clone(),)
}
}
#[derive(Debug)]
pub struct SinkRemoved {
pub index: u32,
}
impl arg::AppendAll for SinkRemoved {
fn append(&self, i: &mut arg::IterAppend) {
self.index.append_by_ref(i);
}
}
impl arg::ReadAll for SinkRemoved {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SinkRemoved { index: i.read()? })
}
}
impl dbus::message::SignalArgs for SinkRemoved {
const NAME: &'static str = "SinkRemoved";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(u32,)> for SinkRemoved {
fn get_value(&self) -> (u32,) {
(self.index.clone(),)
}
}
#[derive(Debug)]
pub struct InputStreamAdded {
pub stream: InputStream,
}
impl arg::AppendAll for InputStreamAdded {
fn append(&self, i: &mut arg::IterAppend) {
self.stream.append_by_ref(i);
}
}
impl arg::ReadAll for InputStreamAdded {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(InputStreamAdded { stream: i.read()? })
}
}
impl dbus::message::SignalArgs for InputStreamAdded {
const NAME: &'static str = "InputStreamAdded";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(InputStream,)> for InputStreamAdded {
fn get_value(&self) -> (InputStream,) {
(self.stream.clone(),)
}
}
#[derive(Debug)]
pub struct InputStreamChanged {
pub stream: InputStream,
}
impl arg::AppendAll for InputStreamChanged {
fn append(&self, i: &mut arg::IterAppend) {
self.stream.append_by_ref(i);
}
}
impl arg::ReadAll for InputStreamChanged {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(InputStreamChanged { stream: i.read()? })
}
}
impl dbus::message::SignalArgs for InputStreamChanged {
const NAME: &'static str = "InputStreamChanged";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
#[derive(Debug)]
pub struct InputStreamRemoved {
pub index: u32,
}
impl arg::AppendAll for InputStreamRemoved {
fn append(&self, i: &mut arg::IterAppend) {
self.index.append_by_ref(i);
}
}
impl arg::ReadAll for InputStreamRemoved {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(InputStreamRemoved { index: i.read()? })
}
}
impl dbus::message::SignalArgs for InputStreamRemoved {
const NAME: &'static str = "InputStreamRemoved";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(u32,)> for InputStreamRemoved {
fn get_value(&self) -> (u32,) {
(self.index.clone(),)
}
}
#[derive(Debug)]
pub struct SourceAdded {
pub source: Source,
}
impl arg::AppendAll for SourceAdded {
fn append(&self, i: &mut arg::IterAppend) {
self.source.append_by_ref(i);
}
}
impl arg::ReadAll for SourceAdded {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SourceAdded { source: i.read()? })
}
}
impl dbus::message::SignalArgs for SourceAdded {
const NAME: &'static str = "SourceAdded";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(Source,)> for SourceAdded {
fn get_value(&self) -> (Source,) {
(self.source.clone(),)
}
}
#[derive(Debug)]
pub struct SourceChanged {
pub source: Source,
}
impl arg::AppendAll for SourceChanged {
fn append(&self, i: &mut arg::IterAppend) {
self.source.append_by_ref(i);
}
}
impl arg::ReadAll for SourceChanged {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SourceChanged { source: i.read()? })
}
}
impl dbus::message::SignalArgs for SourceChanged {
const NAME: &'static str = "SourceChanged";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(Source,)> for SourceChanged {
fn get_value(&self) -> (Source,) {
(self.source.clone(),)
}
}
#[derive(Debug)]
pub struct SourceRemoved {
pub index: u32,
}
impl arg::AppendAll for SourceRemoved {
fn append(&self, i: &mut arg::IterAppend) {
self.index.append_by_ref(i);
}
}
impl arg::ReadAll for SourceRemoved {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(SourceRemoved { index: i.read()? })
}
}
impl dbus::message::SignalArgs for SourceRemoved {
const NAME: &'static str = "SourceRemoved";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(u32,)> for SourceRemoved {
fn get_value(&self) -> (u32,) {
(self.index.clone(),)
}
}
#[derive(Debug)]
pub struct OutputStreamAdded {
pub stream: OutputStream,
}
impl arg::AppendAll for OutputStreamAdded {
fn append(&self, i: &mut arg::IterAppend) {
self.stream.append_by_ref(i);
}
}
impl arg::ReadAll for OutputStreamAdded {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OutputStreamAdded { stream: i.read()? })
}
}
impl dbus::message::SignalArgs for OutputStreamAdded {
const NAME: &'static str = "OutputStreamAdded";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(OutputStream,)> for OutputStreamAdded {
fn get_value(&self) -> (OutputStream,) {
(self.stream.clone(),)
}
}
#[derive(Debug)]
pub struct OutputStreamChanged {
pub stream: OutputStream,
}
impl arg::AppendAll for OutputStreamChanged {
fn append(&self, i: &mut arg::IterAppend) {
self.stream.append_by_ref(i);
}
}
impl arg::ReadAll for OutputStreamChanged {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OutputStreamChanged { stream: i.read()? })
}
}
impl dbus::message::SignalArgs for OutputStreamChanged {
const NAME: &'static str = "OutputStreamChanged";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
#[derive(Debug)]
pub struct OutputStreamRemoved {
pub index: u32,
}
impl arg::AppendAll for OutputStreamRemoved {
fn append(&self, i: &mut arg::IterAppend) {
self.index.append_by_ref(i);
}
}
impl arg::ReadAll for OutputStreamRemoved {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OutputStreamRemoved { index: i.read()? })
}
}
impl dbus::message::SignalArgs for OutputStreamRemoved {
const NAME: &'static str = "OutputStreamRemoved";
const INTERFACE: &'static str = "org.xetibo.ReSet";
}
impl GetVal<(u32,)> for OutputStreamRemoved {
fn get_value(&self) -> (u32,) {
(self.index.clone(),)
}
}
pub fn start_event_listener(listeners: Arc<Listeners>, sink_box: Option<Arc<SinkBox>>,source_box: Option<Arc<SourceBox>>) {
gio::spawn_blocking(move || {
let mut conn = Connection::new_session().unwrap();
if sink_box.is_some() {
conn = start_output_box_listener(conn, listeners.clone(), sink_box.unwrap());
}
if source_box.is_some() {
conn = start_input_box_listener(conn, listeners.clone(), source_box.unwrap());
}
loop {
let _ = conn.process(Duration::from_millis(1000));
if !listeners.network_listener.load(Ordering::SeqCst) {
println!("stopping audio listener");
break;
}
// thread::sleep(Duration::from_millis(1000));
// TODO is this really how we should do this?
}
});
}

View file

@ -8,7 +8,7 @@ use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use gtk::StringObject;
use gtk::{gio, StringObject};
use ReSet_Lib::audio::audio::OutputStream;
use super::outputStreamEntryImpl;
@ -24,8 +24,6 @@ impl OutputStreamEntry {
pub fn new(source_box: Arc<SourceBox>, 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 box_imp = source_box.imp();
let imp = obj.imp();
@ -54,17 +52,17 @@ impl OutputStreamEntry {
}),
);
{
let mut list = box_imp.resetModelList.try_borrow();
while list.is_err() {
list = box_imp.resetModelList.try_borrow();
}
let list = list.unwrap();
let list = box_imp.resetModelList.read().unwrap();
// while list.is_err() {
// list = box_imp.resetModelList.try_borrow();
// }
// let list = list.unwrap();
imp.resetSelectedSource.set_model(Some(&*list));
let mut map = box_imp.resetSourceMap.try_borrow();
while map.is_err() {
map = box_imp.resetSourceMap.try_borrow();
}
let map = map.unwrap();
let map = box_imp.resetSourceMap.write().unwrap();
// while map.is_err() {
// map = box_imp.resetSourceMap.try_borrow();
// }
// let map = map.unwrap();
let mut name = box_imp.resetDefaultSource.try_borrow();
while name.is_err() {
name = box_imp.resetDefaultSource.try_borrow();
@ -85,11 +83,7 @@ impl OutputStreamEntry {
let selected = selected.unwrap();
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let mut source = box_imp.resetSourceMap.try_borrow();
while source.is_err() {
source = box_imp.resetSourceMap.try_borrow();
}
let source = source.unwrap();
let source = box_imp.resetSourceMap.write().unwrap();
let source = source.get(&selected);
if source.is_none() {
return;
@ -116,10 +110,10 @@ impl OutputStreamEntry {
let index = stream.index;
if muted {
imp.resetSourceMute
.set_icon_name("audio-volume-muted-symbolic");
.set_icon_name("microphone-disabled-symbolic");
} else {
imp.resetSourceMute
.set_icon_name("audio-volume-high-symbolic");
.set_icon_name("audio-input-microphone-symbolic");
}
toggle_output_stream_mute(index, muted);
}));
@ -129,52 +123,63 @@ impl OutputStreamEntry {
}
fn set_outputstream_volume(value: f64, index: u32, channels: u16) -> bool {
gio::spawn_blocking(move || {
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(
let _: Result<(), Error> = proxy.method_call(
"org.xetibo.ReSet",
"SetOutputStreamVolume",
(index, channels, value as u32),
);
if res.is_err() {
return false;
}
res.unwrap().0
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
fn toggle_output_stream_mute(index: u32, muted: bool) -> bool {
gio::spawn_blocking(move || {
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> =
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetOutputStreamMute", (index, muted));
if res.is_err() {
return false;
}
res.unwrap().0
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
fn set_source_of_output_stream(stream: u32, source: u32) -> bool {
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",
"SetSourceOfOutputStream",
(stream, source),
);
if res.is_err() {
return false;
}
res.unwrap().0
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(bool,), Error> = proxy.method_call(
"org.xetibo.ReSet",
"SetSourceOfOutputStream",
(stream, source),
);
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
// TODO propagate error from dbus

View file

@ -1,15 +1,20 @@
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use crate::components::base::listEntry::ListEntry;
use crate::components::base::utils::Listeners;
use crate::components::base::utils::{
Listeners, OutputStreamAdded, OutputStreamChanged, OutputStreamRemoved, SourceAdded,
SourceChanged, SourceRemoved,
};
use crate::components::input::sourceBoxImpl;
use crate::components::input::sourceEntry::set_source_volume;
use adw::glib;
use adw::glib::Object;
use adw::prelude::{BoxExt, ButtonExt, ListBoxRowExt, RangeExt};
use adw::prelude::{BoxExt, ButtonExt, CheckButtonExt, ListBoxRowExt, RangeExt};
use dbus::blocking::Connection;
use dbus::Error;
use dbus::message::SignalArgs;
use dbus::{Error, Path};
use glib::subclass::prelude::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation, Variant};
use gtk::prelude::ActionableExt;
@ -48,55 +53,65 @@ impl SourceBox {
}
}
pub fn populate_sources(output_box: Arc<SourceBox>) {
pub fn populate_sources(input_box: Arc<SourceBox>) {
gio::spawn_blocking(move || {
let output_box_imp = output_box.imp();
let output_box_imp = input_box.imp();
let sources = get_sources();
{
let list = output_box_imp.resetModelList.borrow_mut();
let mut map = output_box_imp.resetSourceMap.borrow_mut();
let list = output_box_imp.resetModelList.write().unwrap();
let mut map = output_box_imp.resetSourceMap.write().unwrap();
let mut model_index = output_box_imp.resetModelIndex.write().unwrap();
let mut i: u32 = 0;
for source in sources.iter() {
list.append(&source.alias);
map.insert(source.alias.clone(), (source.index, i, source.name.clone()));
i += 1;
*model_index += 1;
}
}
output_box_imp
.resetDefaultSource
.replace(get_default_source());
populate_outputstreams(input_box.clone());
glib::spawn_future(async move {
glib::idle_add_once(move || {
// TODO handle events
let output_box_ref_slider = output_box.clone();
let output_box_ref_mute = output_box.clone();
let output_box_ref = output_box.clone();
let output_box_ref_slider = input_box.clone();
let output_box_ref_mute = input_box.clone();
let output_box_ref = input_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 default_sink = output_box_imp.resetDefaultSource.clone();
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);
let mut list = output_box_imp.resetSourceList.write().unwrap();
for stream in sources {
let index = source.index;
let alias = source.alias.clone();
let mut is_default = false;
if output_box_imp.resetDefaultSource.borrow().name == stream.name {
is_default = true;
}
let entry = ListEntry::new(&SourceEntry::new(
let source_entry = Arc::new(SourceEntry::new(
is_default,
output_box_imp.resetDefaultCheckButton.clone(),
stream,
));
let source_clone = source_entry.clone();
let entry = Arc::new(ListEntry::new(&*source_entry));
entry.set_activatable(false);
output_box_imp.resetSources.append(&entry);
list.insert(index, (entry.clone(), source_clone, alias));
output_box_imp.resetSources.append(&*entry);
}
let list = output_box_imp.resetModelList.borrow();
let list = output_box_imp.resetModelList.read().unwrap();
output_box_imp.resetSourceDropdown.set_model(Some(&*list));
let map = output_box_imp.resetSourceMap.borrow();
let map = output_box_imp.resetSourceMap.read().unwrap();
let name = output_box_imp.resetDefaultSource.borrow();
let name = &name.alias;
let index = map.get(name);
@ -115,7 +130,7 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let source = output_box_imp.resetSourceMap.borrow();
let source = output_box_imp.resetSourceMap.read().unwrap();
let source = source.get(&selected);
if source.is_none() {
return;
@ -131,7 +146,6 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
.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);
let source = imp.resetDefaultSource.borrow();
@ -153,10 +167,10 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
let index = stream.index;
if muted {
imp.resetSourceMute
.set_icon_name("audio-volume-muted-symbolic");
.set_icon_name("microphone-disabled-symbolic");
} else {
imp.resetSourceMute
.set_icon_name("audio-volume-high-symbolic");
.set_icon_name("audio-input-microphone-symbolic");
}
toggle_source_mute(index, muted);
});
@ -165,19 +179,23 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
});
}
pub fn populate_outputstreams(_listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
pub fn populate_outputstreams(input_box: Arc<SourceBox>) {
// TODO add listener
let output_box_ref = output_box.clone();
let input_box_ref = input_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();
let input_box_imp = input_box_ref.imp();
let mut list = input_box_imp.resetOutputStreamList.write().unwrap();
for stream in streams {
let entry = ListEntry::new(&OutputStreamEntry::new(output_box.clone(), stream));
let index = stream.index;
let input_stream = Arc::new(OutputStreamEntry::new(input_box.clone(), stream));
let entry = Arc::new(ListEntry::new(&*input_stream));
entry.set_activatable(false);
output_box_imp.resetOutputStreams.append(&entry);
list.insert(index, (entry.clone(), input_stream.clone()));
input_box_imp.resetOutputStreams.append(&*entry);
}
});
});
@ -228,3 +246,262 @@ fn get_default_source() -> Source {
}
res.unwrap().0
}
pub fn start_input_box_listener(
conn: Connection,
listeners: Arc<Listeners>,
source_box: Arc<SourceBox>,
) -> Connection {
if listeners.network_listener.load(Ordering::SeqCst) {
return conn;
}
listeners.network_listener.store(true, Ordering::SeqCst);
let source_added = SourceAdded::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let source_removed = SourceRemoved::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let source_changed = SourceChanged::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let output_stream_added = OutputStreamAdded::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let output_stream_removed = OutputStreamRemoved::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let output_stream_changed = OutputStreamChanged::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let source_added_box = source_box.clone();
let source_removed_box = source_box.clone();
let source_changed_box = source_box.clone();
let output_stream_added_box = source_box.clone();
let output_stream_removed_box = source_box.clone();
let output_stream_changed_box = source_box.clone();
let res = conn.add_match(source_added, move |ir: SourceAdded, _, _| {
let source_box = source_added_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetSourceList.write().unwrap();
let index = ir.source.index;
let alias = ir.source.alias.clone();
let name = ir.source.name.clone();
let mut is_default = false;
if output_box_imp.resetDefaultSource.borrow().name == ir.source.name {
is_default = true;
}
let source_entry = Arc::new(SourceEntry::new(
is_default,
output_box_imp.resetDefaultCheckButton.clone(),
ir.source,
));
let source_clone = source_entry.clone();
let entry = Arc::new(ListEntry::new(&*source_entry));
entry.set_activatable(false);
list.insert(index, (entry.clone(), source_clone, alias.clone()));
output_box_imp.resetSources.append(&*entry);
let mut map = output_box_imp.resetSourceMap.write().unwrap();
let mut index = output_box_imp.resetModelIndex.write().unwrap();
map.insert(alias, (*index, *index, name));
*index += 1;
});
});
true
});
if res.is_err() {
println!("fail on source add");
return conn;
}
let res = conn.add_match(source_removed, move |ir: SourceRemoved, _, _| {
let source_box = source_removed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetSourceList.write().unwrap();
let entry = list.get(&ir.index);
if entry.is_none() {
return;
}
output_box_imp.resetSources.remove(&*entry.unwrap().0);
list.remove(&ir.index);
let alias = list.remove(&ir.index);
if alias.is_none() {
return;
}
let mut map = output_box_imp.resetSourceMap.write().unwrap();
map.remove(&alias.unwrap().2);
let mut index = output_box_imp.resetModelIndex.write().unwrap();
*index -= 1;
});
});
true
});
if res.is_err() {
println!("fail on source remove");
return conn;
}
let res = conn.add_match(source_changed, move |ir: SourceChanged, _, _| {
let source_box = source_changed_box.clone();
let default_source = get_default_source();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let list = output_box_imp.resetSourceList.read().unwrap();
let entry = list.get(&ir.source.index);
if entry.is_none() {
return;
}
let imp = entry.unwrap().1.imp();
let is_default = ir.source.name == default_source.name;
imp.resetSourceName
.set_text(ir.source.alias.clone().as_str());
let volume = ir.source.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);
if is_default {
imp.resetSelectedSource.set_active(true);
} else {
imp.resetSelectedSource.set_active(false);
}
});
});
true
});
if res.is_err() {
println!("fail on source remove");
return conn;
}
let res = conn.add_match(output_stream_added, move |ir: OutputStreamAdded, _, _| {
let source_box = output_stream_added_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetOutputStreamList.write().unwrap();
let index = ir.stream.index;
let output_stream = Arc::new(OutputStreamEntry::new(output_box.clone(), ir.stream));
let entry = Arc::new(ListEntry::new(&*output_stream));
entry.set_activatable(false);
list.insert(index, (entry.clone(), output_stream.clone()));
output_box_imp.resetOutputStreams.append(&*entry);
});
});
true
});
if res.is_err() {
println!("fail on stream add");
return conn;
}
let res = conn.add_match(
output_stream_changed,
move |ir: OutputStreamChanged, _, _| {
let imp = output_stream_changed_box.imp();
let alias: String;
{
let source_list = imp.resetSourceList.read().unwrap();
let alias_opt = source_list.get(&ir.stream.source_index);
if alias_opt.is_some() {
alias = alias_opt.unwrap().2.clone();
} else {
alias = String::from("");
}
}
let source_box = output_stream_changed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let entry: Arc<OutputStreamEntry>;
{
let list = output_box_imp.resetOutputStreamList.read().unwrap();
let entry_opt = list.get(&ir.stream.index);
if entry_opt.is_none() {
return;
}
entry = entry_opt.unwrap().1.clone();
}
let imp = entry.imp();
if ir.stream.muted {
imp.resetSourceMute
.set_icon_name("microphone-disabled-symbolic");
} else {
imp.resetSourceMute
.set_icon_name("audio-input-microphone-symbolic");
}
let name = ir.stream.application_name.clone() + ": " + ir.stream.name.as_str();
imp.resetSourceName.set_text(name.as_str());
let volume = ir.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);
let map = output_box_imp.resetSourceMap.read().unwrap();
let index = map.get(&alias);
if index.is_some() {
imp.resetSelectedSource.set_selected(index.unwrap().1);
}
});
});
true
},
);
if res.is_err() {
println!("fail on stream change");
return conn;
}
let res = conn.add_match(
output_stream_removed,
move |ir: OutputStreamRemoved, _, _| {
let source_box = output_stream_removed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = source_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetOutputStreamList.write().unwrap();
let entry = list.get(&ir.index);
if entry.is_none() {
return;
}
output_box_imp.resetOutputStreams.remove(&*entry.unwrap().0);
list.remove(&ir.index);
});
});
true
},
);
if res.is_err() {
println!("fail on stream remove");
return conn;
}
listeners.network_listener.store(true, Ordering::SeqCst);
conn
}

View file

@ -1,13 +1,13 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
use crate::components::base::listEntry::ListEntry;
use crate::components::input::sourceBox;
use gtk::subclass::prelude::*;
use gtk::{glib, CheckButton, CompositeTemplate, DropDown, StringList, TemplateChild};
use gtk::{prelude::*, Button, Label, ProgressBar, Scale};
use ReSet_Lib::audio::audio::{OutputStream, Source};
use ReSet_Lib::audio::audio::Source;
use super::outputStreamEntry::OutputStreamEntry;
use super::sourceEntry::SourceEntry;
@ -36,11 +36,13 @@ pub struct SourceBox {
pub resetOutputStreams: TemplateChild<gtk::Box>,
pub resetDefaultCheckButton: Arc<CheckButton>,
pub resetDefaultSource: Arc<RefCell<Source>>,
pub resetSourceList: Arc<Mutex<Vec<Source>>>,
pub resetOutputStreamList: Arc<Mutex<Vec<OutputStream>>>,
pub resetModelList: Arc<RefCell<StringList>>,
// first u32 is the index of the source, the second the index in the model list
pub resetSourceMap: Arc<RefCell<HashMap<String, (u32, u32, String)>>>,
pub resetSourceList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SourceEntry>, String)>>>,
pub resetOutputStreamList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<OutputStreamEntry>)>>>,
pub resetModelList: Arc<RwLock<StringList>>,
pub resetModelIndex: Arc<RwLock<u32>>,
// first u32 is the index of the source, the second the index in the model list and the third is
// the full name
pub resetSourceMap: Arc<RwLock<HashMap<String, (u32, u32, String)>>>,
}
#[glib::object_subclass]

View file

@ -1,16 +1,15 @@
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use adw::glib;
use adw::glib::Object;
use adw::prelude::{ButtonExt, RangeExt, CheckButtonExt};
use adw::prelude::{ButtonExt, CheckButtonExt, RangeExt};
use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Propagation};
use gtk::{gio, CheckButton};
use ReSet_Lib::audio::audio::Source;
use gtk::CheckButton;
use super::sourceEntryImpl;
@ -24,7 +23,6 @@ impl SourceEntry {
pub fn new(is_default: bool, check_group: Arc<CheckButton>, stream: Source) -> Self {
let obj: Self = Object::builder().build();
// TODO use event callback for progress bar -> this is the "im speaking" indicator
// TODO handle events
{
let imp = obj.imp();
imp.resetSourceName.set_text(stream.alias.clone().as_str());
@ -38,7 +36,6 @@ impl SourceEntry {
imp.resetVolumeSlider.connect_change_value(
clone!(@weak imp => @default-return Propagation::Stop, move |_, _, value| {
let fraction = (value / 655.36).round();
println!("{fraction}");
let percentage = (fraction).to_string() + "%";
imp.resetVolumePercentage.set_text(&percentage);
let source = imp.stream.borrow();
@ -69,10 +66,10 @@ impl SourceEntry {
let index = stream.index;
if muted {
imp.resetSourceMute
.set_icon_name("audio-volume-muted-symbolic");
.set_icon_name("microphone-disabled-symbolic");
} else {
imp.resetSourceMute
.set_icon_name("audio-volume-high-symbolic");
.set_icon_name("audio-input-microphone-symbolic");
}
toggle_source_mute(index, muted);
}));
@ -82,51 +79,60 @@ impl SourceEntry {
}
pub fn set_source_volume(value: f64, index: u32, channels: u16) -> bool {
gio::spawn_blocking(move || {
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(
let _: Result<(), Error> = proxy.method_call(
"org.xetibo.ReSet",
"SetSourceVolume",
(index, channels, value as u32),
);
if res.is_err() {
return false;
}
res.unwrap().0
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
pub fn toggle_source_mute(index: u32, muted: bool) -> bool {
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", "SetSourceMute", (index, muted));
if res.is_err() {
return false;
}
res.unwrap().0
}
pub fn set_default_source(name: Arc<String>) {
thread::spawn(move || {
gio::spawn_blocking(move || {
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> =
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetSourceMute", (index, muted));
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
pub fn set_default_source(name: Arc<String>) -> bool {
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),));
if res.is_err() {
return;
}
// if res.is_err() {
// return;
// }
// handle change
});
true
}
// TODO propagate error from dbus

View file

@ -8,7 +8,7 @@ use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use gtk::StringObject;
use gtk::{gio, StringObject};
use ReSet_Lib::audio::audio::InputStream;
use super::inputStreamEntryImpl;
@ -24,8 +24,8 @@ impl InputStreamEntry {
pub fn new(sink_box: Arc<SinkBox>, stream: InputStream) -> Self {
let obj: Self = Object::builder().build();
// TODO use event callback for progress bar -> this is the "im speaking" indicator
// TODO handle events
{
let index = stream.sink_index;
let box_imp = sink_box.imp();
let imp = obj.imp();
if stream.muted {
@ -64,26 +64,31 @@ impl InputStreamEntry {
}),
);
{
let mut list = box_imp.resetModelList.try_borrow();
while list.is_err() {
list = box_imp.resetModelList.try_borrow();
}
let list = list.unwrap();
let list = box_imp.resetModelList.read().unwrap();
// while list.is_err() {
// list = box_imp.resetModelList.try_borrow();
// }
// let list = list.unwrap();
imp.resetSelectedSink.set_model(Some(&*list));
let mut map = box_imp.resetSinkMap.try_borrow();
while map.is_err() {
map = box_imp.resetSinkMap.try_borrow();
}
let map = map.unwrap();
let mut name = box_imp.resetDefaultSink.try_borrow();
while name.is_err() {
name = box_imp.resetDefaultSink.try_borrow();
}
let name = name.unwrap();
let name = &name.alias;
let index = map.get(name);
if index.is_some() {
imp.resetSelectedSink.set_selected(index.unwrap().1);
let map = box_imp.resetSinkMap.read().unwrap();
let sink_list = box_imp.resetSinkList.read().unwrap();
let name = sink_list.get(&index);
if name.is_some() {
let name = &name.unwrap().2;
let index = map.get(name);
if index.is_some() {
imp.resetSelectedSink.set_selected(index.unwrap().1);
}
} else {
let mut name = box_imp.resetDefaultSink.try_borrow();
while name.is_err() {
name = box_imp.resetDefaultSink.try_borrow();
}
let name = &name.unwrap().alias;
let index = map.get(name);
if index.is_some() {
imp.resetSelectedSink.set_selected(index.unwrap().1);
}
}
}
imp.resetSelectedSink.connect_selected_notify(
@ -95,11 +100,11 @@ impl InputStreamEntry {
let selected = selected.unwrap();
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let mut sink = box_imp.resetSinkMap.try_borrow();
while sink.is_err() {
sink = box_imp.resetSinkMap.try_borrow();
}
let sink = sink.unwrap();
let sink = box_imp.resetSinkMap.read().unwrap();
// if sink.is_err() {
// return;
// }
// let sink = sink.unwrap();
let sink = sink.get(&selected);
if sink.is_none() {
return;
@ -139,49 +144,60 @@ impl InputStreamEntry {
}
fn set_inputstream_volume(value: f64, index: u32, channels: u16) -> bool {
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",
"SetInputStreamVolume",
(index, channels, value as u32),
);
if res.is_err() {
return false;
}
res.unwrap().0
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> = proxy.method_call(
"org.xetibo.ReSet",
"SetInputStreamVolume",
(index, channels, value as u32),
);
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
fn toggle_input_stream_mute(index: u32, muted: bool) -> bool {
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", "SetInputStreamMute", (index, muted));
if res.is_err() {
return false;
}
res.unwrap().0
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetInputStreamMute", (index, muted));
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
fn set_sink_of_input_stream(stream: u32, sink: u32) -> bool {
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", "SetSinkOfInputStream", (stream, sink));
if res.is_err() {
return false;
}
res.unwrap().0
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetSinkOfInputStream", (stream, sink));
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
// TODO propagate error from dbus

View file

@ -1,14 +1,19 @@
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use crate::components::base::listEntry::ListEntry;
use crate::components::base::utils::Listeners;
use crate::components::base::utils::{
InputStreamAdded, InputStreamChanged, InputStreamRemoved, Listeners, SinkAdded, SinkChanged,
SinkRemoved,
};
use crate::components::output::sinkEntry::set_sink_volume;
use adw::glib::Object;
use adw::prelude::{BoxExt, ButtonExt, RangeExt};
use adw::prelude::{BoxExt, ButtonExt, CheckButtonExt, RangeExt};
use adw::{glib, prelude::ListBoxRowExt};
use dbus::blocking::Connection;
use dbus::Error;
use dbus::message::SignalArgs;
use dbus::{Error, Path};
use glib::subclass::prelude::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation, Variant};
use gtk::prelude::ActionableExt;
@ -54,17 +59,19 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
let sinks = get_sinks();
{
let output_box_imp = output_box.imp();
let mut map = output_box_imp.resetSinkMap.write().unwrap();
let list = output_box_imp.resetModelList.write().unwrap();
let mut model_index = output_box_imp.resetModelIndex.write().unwrap();
output_box_imp.resetDefaultSink.replace(get_default_sink());
let list = output_box_imp.resetModelList.borrow_mut();
let mut map = output_box_imp.resetSinkMap.borrow_mut();
let mut i: u32 = 0;
for sink in sinks.iter() {
dbg!(sink.clone());
list.append(&sink.alias);
map.insert(sink.alias.clone(), (sink.index, i, sink.name.clone()));
i += 1;
*model_index += 1;
}
}
populate_inputstreams(output_box.clone());
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box_ref_slider = output_box.clone();
@ -79,22 +86,28 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
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 mut list = output_box_imp.resetSinkList.write().unwrap();
for sink in sinks {
let index = sink.index;
let alias = sink.alias.clone();
let mut is_default = false;
if output_box_imp.resetDefaultSink.borrow().name == stream.name {
if output_box_imp.resetDefaultSink.borrow().name == sink.name {
is_default = true;
}
let entry = ListEntry::new(&SinkEntry::new(
let sink_entry = Arc::new(SinkEntry::new(
is_default,
output_box_imp.resetDefaultCheckButton.clone(),
stream,
sink,
));
let sink_clone = sink_entry.clone();
let entry = Arc::new(ListEntry::new(&*sink_entry));
entry.set_activatable(false);
output_box_imp.resetSinks.append(&entry);
list.insert(index, (entry.clone(), sink_clone, alias));
output_box_imp.resetSinks.append(&*entry);
}
let list = output_box_imp.resetModelList.borrow();
let list = output_box_imp.resetModelList.read().unwrap();
output_box_imp.resetSinkDropdown.set_model(Some(&*list));
let map = output_box_imp.resetSinkMap.borrow();
let map = output_box_imp.resetSinkMap.read().unwrap();
let name = output_box_imp.resetDefaultSink.borrow();
let name = &name.alias;
let index = map.get(name);
@ -113,7 +126,7 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let sink = output_box_imp.resetSinkMap.borrow();
let sink = output_box_imp.resetSinkMap.read().unwrap();
let sink = sink.get(&selected);
if sink.is_none() {
return;
@ -129,7 +142,6 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
.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);
let sink = imp.resetDefaultSink.borrow();
@ -162,8 +174,7 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
});
}
pub fn populate_inputstreams(_listeners: Arc<Listeners>, output_box: Arc<SinkBox>) {
// TODO add listener
pub fn populate_inputstreams(output_box: Arc<SinkBox>) {
let output_box_ref = output_box.clone();
gio::spawn_blocking(move || {
@ -171,10 +182,14 @@ pub fn populate_inputstreams(_listeners: Arc<Listeners>, output_box: Arc<SinkBox
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box_imp = output_box_ref.imp();
let mut list = output_box_imp.resetInputStreamList.write().unwrap();
for stream in streams {
let entry = ListEntry::new(&InputStreamEntry::new(output_box.clone(), stream));
let index = stream.index;
let input_stream = Arc::new(InputStreamEntry::new(output_box.clone(), stream));
let entry = Arc::new(ListEntry::new(&*input_stream));
entry.set_activatable(false);
output_box_imp.resetInputStreams.append(&entry);
list.insert(index, (entry.clone(), input_stream.clone()));
output_box_imp.resetInputStreams.append(&*entry);
}
});
});
@ -223,3 +238,250 @@ fn get_default_sink() -> Sink {
}
res.unwrap().0
}
pub fn start_output_box_listener(conn: Connection, listeners: Arc<Listeners>, sink_box: Arc<SinkBox>) -> Connection {
if listeners.network_listener.load(Ordering::SeqCst) {
return conn;
}
listeners.network_listener.store(true, Ordering::SeqCst);
let sink_added = SinkAdded::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let sink_removed = SinkRemoved::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let sink_changed = SinkChanged::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let input_stream_added = InputStreamAdded::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let input_stream_removed = InputStreamRemoved::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let input_stream_changed = InputStreamChanged::match_rule(
Some(&"org.xetibo.ReSet".into()),
Some(&Path::from("/org/xetibo/ReSet")),
)
.static_clone();
let sink_added_box = sink_box.clone();
let sink_removed_box = sink_box.clone();
let sink_changed_box = sink_box.clone();
let input_stream_added_box = sink_box.clone();
let input_stream_removed_box = sink_box.clone();
let input_stream_changed_box = sink_box.clone();
let res = conn.add_match(sink_added, move |ir: SinkAdded, _, _| {
let sink_box = sink_added_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetSinkList.write().unwrap();
let index = ir.sink.index;
let alias = ir.sink.alias.clone();
let name = ir.sink.name.clone();
let mut is_default = false;
if output_box_imp.resetDefaultSink.borrow().name == ir.sink.name {
is_default = true;
}
let sink_entry = Arc::new(SinkEntry::new(
is_default,
output_box_imp.resetDefaultCheckButton.clone(),
ir.sink,
));
let sink_clone = sink_entry.clone();
let entry = Arc::new(ListEntry::new(&*sink_entry));
entry.set_activatable(false);
list.insert(index, (entry.clone(), sink_clone, alias.clone()));
output_box_imp.resetSinks.append(&*entry);
let mut map = output_box_imp.resetSinkMap.write().unwrap();
let mut index = output_box_imp.resetModelIndex.write().unwrap();
map.insert(alias, (*index, *index, name));
*index += 1;
});
});
true
});
if res.is_err() {
println!("fail on sink add");
return conn;
}
let res = conn.add_match(sink_removed, move |ir: SinkRemoved, _, _| {
let sink_box = sink_removed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetSinkList.write().unwrap();
let entry = list.get(&ir.index);
if entry.is_none() {
return;
}
output_box_imp.resetSinks.remove(&*entry.unwrap().0);
let alias = list.remove(&ir.index);
if alias.is_none() {
return;
}
let mut map = output_box_imp.resetSinkMap.write().unwrap();
map.remove(&alias.unwrap().2);
let mut index = output_box_imp.resetModelIndex.write().unwrap();
*index -= 1;
});
});
true
});
if res.is_err() {
println!("fail on sink remove");
return conn;
}
let res = conn.add_match(sink_changed, move |ir: SinkChanged, _, _| {
let sink_box = sink_changed_box.clone();
let default_sink = get_default_sink();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let list = output_box_imp.resetSinkList.read().unwrap();
let entry = list.get(&ir.sink.index);
if entry.is_none() {
return;
}
let imp = entry.unwrap().1.imp();
let is_default = ir.sink.name == default_sink.name;
imp.resetSinkName.set_text(ir.sink.alias.clone().as_str());
let volume = ir.sink.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);
if is_default {
imp.resetSelectedSink.set_active(true);
} else {
imp.resetSelectedSink.set_active(false);
}
});
});
true
});
if res.is_err() {
println!("fail on sink remove");
return conn;
}
let res = conn.add_match(input_stream_added, move |ir: InputStreamAdded, _, _| {
let sink_box = input_stream_added_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetInputStreamList.write().unwrap();
let index = ir.stream.index;
let input_stream = Arc::new(InputStreamEntry::new(output_box.clone(), ir.stream));
let entry = Arc::new(ListEntry::new(&*input_stream));
entry.set_activatable(false);
list.insert(index, (entry.clone(), input_stream.clone()));
output_box_imp.resetInputStreams.append(&*entry);
});
});
true
});
if res.is_err() {
println!("fail on stream add");
return conn;
}
let res = conn.add_match(input_stream_changed, move |ir: InputStreamChanged, _, _| {
let imp = input_stream_changed_box.imp();
let alias: String;
{
let sink_list = imp.resetSinkList.read().unwrap();
let alias_opt = sink_list.get(&ir.stream.sink_index);
if alias_opt.is_some() {
alias = alias_opt.unwrap().2.clone();
} else {
alias = String::from("");
}
}
let sink_box = input_stream_changed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let entry: Arc<InputStreamEntry>;
{
let list = output_box_imp.resetInputStreamList.read().unwrap();
let entry_opt = list.get(&ir.stream.index);
if entry_opt.is_none() {
return;
}
entry = entry_opt.unwrap().1.clone();
}
let imp = entry.imp();
if ir.stream.muted {
imp.resetSinkMute
.set_icon_name("audio-volume-muted-symbolic");
} else {
imp.resetSinkMute
.set_icon_name("audio-volume-high-symbolic");
}
let name = ir.stream.application_name.clone() + ": " + ir.stream.name.as_str();
imp.resetSinkName.set_text(name.as_str());
let volume = ir.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);
let map = output_box_imp.resetSinkMap.read().unwrap();
let index = map.get(&alias);
if index.is_some() {
imp.resetSelectedSink.set_selected(index.unwrap().1);
}
});
});
true
});
if res.is_err() {
println!("fail on stream change");
return conn;
}
let res = conn.add_match(input_stream_removed, move |ir: InputStreamRemoved, _, _| {
let sink_box = input_stream_removed_box.clone();
glib::spawn_future(async move {
glib::idle_add_once(move || {
let output_box = sink_box.clone();
let output_box_imp = output_box.imp();
let mut list = output_box_imp.resetInputStreamList.write().unwrap();
let entry = list.get(&ir.index);
if entry.is_none() {
return;
}
output_box_imp.resetInputStreams.remove(&*entry.unwrap().0);
list.remove(&ir.index);
});
});
true
});
if res.is_err() {
println!("fail on stream remove");
return conn;
}
listeners.network_listener.store(true, Ordering::SeqCst);
conn
}

View file

@ -1,6 +1,6 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
use crate::components::base::listEntry::ListEntry;
use crate::components::output::inputStreamEntry::InputStreamEntry;
@ -9,7 +9,7 @@ use gtk::{
glib, Box, Button, CheckButton, CompositeTemplate, DropDown, Label, StringList, TemplateChild,
};
use gtk::{prelude::*, ProgressBar, Scale};
use ReSet_Lib::audio::audio::{InputStream, Sink};
use ReSet_Lib::audio::audio::Sink;
use super::sinkBox;
use super::sinkEntry::SinkEntry;
@ -38,11 +38,14 @@ pub struct SinkBox {
pub resetInputStreams: TemplateChild<Box>,
pub resetDefaultCheckButton: Arc<CheckButton>,
pub resetDefaultSink: Arc<RefCell<Sink>>,
pub resetSinkList: Arc<Mutex<Vec<Sink>>>,
pub resetInputStreamList: Arc<Mutex<Vec<InputStream>>>,
pub resetModelList: Arc<RefCell<StringList>>,
// first u32 is the index of the sink, the second the index in the model list
pub resetSinkMap: Arc<RefCell<HashMap<String, (u32, u32, String)>>>,
pub resetSinkList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SinkEntry>, String)>>>,
pub resetInputStreamList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<InputStreamEntry>)>>>,
pub resetModelList: Arc<RwLock<StringList>>,
pub resetModelIndex: Arc<RwLock<u32>>,
// first u32 is the index of the sink, the second the index in the model list and the third is
// the full name
pub resetSinkMap: Arc<RwLock<HashMap<String, (u32, u32, String)>>>,
// pub : Arc<Mutex<Vec<ListEntry>>>,
}
#[glib::object_subclass]

View file

@ -1,5 +1,4 @@
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use adw::glib;
@ -9,7 +8,7 @@ use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Propagation};
use gtk::CheckButton;
use gtk::{gio, CheckButton};
use ReSet_Lib::audio::audio::Sink;
use super::sinkEntryImpl;
@ -38,7 +37,6 @@ impl SinkEntry {
imp.resetVolumeSlider.connect_change_value(
clone!(@weak imp => @default-return Propagation::Stop, move |_, _, value| {
let fraction = (value / 655.36).round();
println!("{fraction}");
let percentage = (fraction).to_string() + "%";
imp.resetVolumePercentage.set_text(&percentage);
let sink = imp.stream.borrow();
@ -81,52 +79,59 @@ impl SinkEntry {
}
pub fn set_sink_volume(value: f64, index: u32, channels: u16) -> bool {
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",
"SetSinkVolume",
(index, channels, value as u32),
);
if res.is_err() {
return false;
}
res.unwrap().0
}
pub fn toggle_sink_mute(index: u32, muted: bool) -> bool {
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", "SetSinkMute", (index, muted));
if res.is_err() {
return false;
}
res.unwrap().0
}
pub fn set_default_sink(name: Arc<String>) {
thread::spawn(move || {
dbg!(name.clone());
gio::spawn_blocking(move || {
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> =
let _: Result<(), Error> = proxy.method_call(
"org.xetibo.ReSet",
"SetSinkVolume",
(index, channels, value as u32),
);
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
pub fn toggle_sink_mute(index: u32, muted: bool) -> bool {
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetSinkMute", (index, muted));
// if res.is_err() {
// return false;
// }
// res.unwrap().0
});
true
}
pub fn set_default_sink(name: Arc<String>) {
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.xetibo.ReSet",
"/org/xetibo/ReSet",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),));
if res.is_err() {
return;
}
// if res.is_err() {
// return;
// }
// handle change
});
}
// TODO propagate error from dbus

View file

@ -32,10 +32,8 @@ impl SavedWifiEntry {
let res: Result<(bool,), Error> = proxy.method_call("org.xetibo.ReSet", "DeleteConnection", (entry.imp().resetConnectionPath.take(),));
if res.is_err() || res.unwrap() == (false,) {
// TODO handle error -> inform user
println!("no worky");
return;
}
println!("worked, should be ded");
let parent = entry.parent().unwrap();
parent.set_visible(false);
parent.unparent();

View file

@ -108,7 +108,6 @@ pub fn scanForWifi(listeners: Arc<Listeners>, wifiBox: Arc<WifiBox>) {
{
break;
}
println!("receiving!");
let res = receiver.recv();
if res.is_ok() {
let access_point = res.unwrap();
@ -211,7 +210,6 @@ pub fn get_stored_connections() -> Vec<(Path<'static>, Vec<u8>)> {
return Vec::new();
}
let (connections,) = res.unwrap();
dbg!(connections.clone());
connections
}
@ -227,13 +225,11 @@ pub fn getConnectionSettings(path: Path<'static>) -> Option<ResetConnection> {
Error,
> = proxy.method_call("org.xetibo.ReSet", "GetConnectionSettings", (path,));
if res.is_err() {
println!("lol not work");
return None;
}
let (res,) = res.unwrap();
let res = ResetConnection::convert_from_propmap(res);
if res.is_err() {
println!("lol none");
return None;
}
Some(res.unwrap())

View file

@ -79,8 +79,7 @@ impl WifiEntry {
let selfImp = self.imp();
selfImp.resetWifiEditButton.connect_clicked(clone!(@ weak selfImp => move |_| {
// TODO open navigationpage
let option = getConnectionSettings(selfImp.accessPoint.borrow().associated_connection.clone());
dbg!(option);
let _option = getConnectionSettings(selfImp.accessPoint.borrow().associated_connection.clone());
}));
}
}
@ -120,7 +119,6 @@ pub fn click_stored_network(entry: Arc<WifiEntry>) {
}
return;
}
dbg!(access_point.clone());
let res: Result<(bool,), Error> = proxy.method_call(
"org.xetibo.ReSet",
"ConnectToKnownAccessPoint",
@ -214,8 +212,4 @@ pub fn click_new_network(entry: Arc<WifiEntry>) {
}),
);
entryImp.resetWifiPopup.popup();
println!(
"result is {}",
result.load(std::sync::atomic::Ordering::SeqCst)
);
}

View file

@ -3,10 +3,10 @@ use std::sync::atomic::Ordering;
use std::sync::Arc;
use crate::components::base::settingBox::SettingBox;
use crate::components::base::utils::Listeners;
use crate::components::base::utils::{start_event_listener, Listeners};
use crate::components::bluetooth::bluetoothBox::BluetoothBox;
use crate::components::input::sourceBox::{SourceBox, populate_outputstreams, populate_sources};
use crate::components::output::sinkBox::{SinkBox, populate_inputstreams, populate_sinks};
use crate::components::input::sourceBox::{populate_sources, SourceBox};
use crate::components::output::sinkBox::{populate_sinks, SinkBox};
use crate::components::wifi::wifiBox::{scanForWifi, show_stored_connections, WifiBox};
use gtk::prelude::WidgetExt;
use gtk::{FlowBox, Frame, Label};
@ -64,12 +64,15 @@ pub const HANDLE_AUDIO_CLICK: fn(Arc<Listeners>, FlowBox) =
listeners.bluetooth_listener.store(false, Ordering::SeqCst);
listeners.pulse_listener.store(true, Ordering::SeqCst);
let audioOutput = Arc::new(SinkBox::new());
populate_inputstreams(listeners.clone(), audioOutput.clone());
populate_sinks(audioOutput.clone());
let audioFrame = wrapInFrame(SettingBox::new(&*audioOutput));
let audioInput = Arc::new(SourceBox::new());
populate_outputstreams(listeners.clone(), audioInput.clone());
populate_sources(audioInput.clone());
start_event_listener(
listeners.clone(),
Some(audioOutput.clone()),
Some(audioInput.clone()),
);
let sourceFrame = wrapInFrame(SettingBox::new(&*audioInput));
resetMain.remove_all();
resetMain.insert(&audioFrame, -1);
@ -83,8 +86,8 @@ pub const HANDLE_VOLUME_CLICK: fn(Arc<Listeners>, FlowBox) =
listeners.bluetooth_listener.store(false, Ordering::SeqCst);
listeners.pulse_listener.store(false, Ordering::SeqCst);
let audioOutput = Arc::new(SinkBox::new());
populate_inputstreams(listeners.clone(), audioOutput.clone());
populate_sinks(audioOutput.clone());
start_event_listener(listeners.clone(), Some(audioOutput.clone()), None);
let audioFrame = wrapInFrame(SettingBox::new(&*audioOutput));
resetMain.remove_all();
resetMain.insert(&audioFrame, -1);
@ -97,8 +100,8 @@ pub const HANDLE_MICROPHONE_CLICK: fn(Arc<Listeners>, FlowBox) =
listeners.bluetooth_listener.store(false, Ordering::SeqCst);
listeners.pulse_listener.store(false, Ordering::SeqCst);
let audioInput = Arc::new(SourceBox::new());
populate_outputstreams(listeners.clone(), audioInput.clone());
populate_sources(audioInput.clone());
start_event_listener(listeners.clone(), None, Some(audioInput.clone()));
let sourceFrame = wrapInFrame(SettingBox::new(&*audioInput));
resetMain.remove_all();
resetMain.insert(&sourceFrame, -1);