feat(audio): allow switching input/output and update outputs/inputs when the popup or revealer is toggled
This commit is contained in:
parent
22b729b966
commit
92bacfdf0b
2 changed files with 176 additions and 9 deletions
|
|
@ -133,6 +133,14 @@ impl Application for Audio {
|
|||
.min_width(1)
|
||||
.max_width(400)
|
||||
.max_height(1080);
|
||||
|
||||
if let Some(conn) = self.pulse_state.connection() {
|
||||
conn.send(pulse::Message::GetDefaultSink);
|
||||
conn.send(pulse::Message::GetDefaultSource);
|
||||
conn.send(pulse::Message::GetSinks);
|
||||
conn.send(pulse::Message::GetSources);
|
||||
}
|
||||
|
||||
return get_popup(popup_settings);
|
||||
}
|
||||
}
|
||||
|
|
@ -169,12 +177,27 @@ impl Application for Audio {
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::OutputChanged(val) => log::info!("changed output {}", val),
|
||||
Message::InputChanged(val) => log::info!("changed input {}", val),
|
||||
Message::OutputChanged(val) => {
|
||||
if let Some(conn) = self.pulse_state.connection() {
|
||||
if let Some(val) = self.outputs.iter().find(|o| o.name.as_ref() == Some(&val)) {
|
||||
conn.send(pulse::Message::SetDefaultSink(val.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::InputChanged(val) => {
|
||||
if let Some(conn) = self.pulse_state.connection() {
|
||||
if let Some(val) = self.inputs.iter().find(|i| i.name.as_ref() == Some(&val)) {
|
||||
conn.send(pulse::Message::SetDefaultSource(val.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::OutputToggle => {
|
||||
self.is_open = if self.is_open == IsOpen::Output {
|
||||
IsOpen::None
|
||||
} else {
|
||||
if let Some(conn) = self.pulse_state.connection() {
|
||||
conn.send(pulse::Message::GetSinks);
|
||||
}
|
||||
IsOpen::Output
|
||||
}
|
||||
}
|
||||
|
|
@ -182,6 +205,9 @@ impl Application for Audio {
|
|||
self.is_open = if self.is_open == IsOpen::Input {
|
||||
IsOpen::None
|
||||
} else {
|
||||
if let Some(conn) = self.pulse_state.connection() {
|
||||
conn.send(pulse::Message::GetSources);
|
||||
}
|
||||
IsOpen::Input
|
||||
}
|
||||
}
|
||||
|
|
@ -315,10 +341,13 @@ impl Application for Audio {
|
|||
self.outputs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|output| pretty_name(output.description))
|
||||
.map(|output| (
|
||||
output.name.clone().unwrap_or_default(),
|
||||
pretty_name(output.description)
|
||||
))
|
||||
.collect(),
|
||||
Message::OutputToggle,
|
||||
Message::OutputChanged(String::from("test")),
|
||||
Message::OutputChanged,
|
||||
),
|
||||
revealer(
|
||||
self.is_open == IsOpen::Input,
|
||||
|
|
@ -330,10 +359,13 @@ impl Application for Audio {
|
|||
self.inputs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|input| pretty_name(input.description))
|
||||
.map(|input| (
|
||||
input.name.clone().unwrap_or_default(),
|
||||
pretty_name(input.description)
|
||||
))
|
||||
.collect(),
|
||||
Message::InputToggle,
|
||||
Message::InputChanged(String::from("test")),
|
||||
Message::InputChanged,
|
||||
)
|
||||
]
|
||||
.align_items(Alignment::Start)
|
||||
|
|
@ -372,14 +404,22 @@ fn revealer(
|
|||
open: bool,
|
||||
title: &str,
|
||||
selected: String,
|
||||
options: Vec<String>,
|
||||
options: Vec<(String, String)>,
|
||||
toggle: Message,
|
||||
_change: Message,
|
||||
mut change: impl FnMut(String) -> Message + 'static,
|
||||
) -> widget::Column<Message, Renderer> {
|
||||
if open {
|
||||
options.iter().fold(
|
||||
column![revealer_head(open, title, selected, toggle)].width(Length::Fill),
|
||||
|col, device| col.push(container(text(device)).padding([8, 48])),
|
||||
|col, (id, name)| {
|
||||
col.push(
|
||||
button(APPLET_BUTTON_THEME)
|
||||
.custom(vec![text(name).into()])
|
||||
.on_press(change(id.clone()))
|
||||
.width(Length::Fill)
|
||||
.padding([8, 48]),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
column![revealer_head(open, title, selected, toggle)]
|
||||
|
|
|
|||
|
|
@ -251,6 +251,44 @@ impl PulseHandle {
|
|||
server = Some(new_server);
|
||||
}
|
||||
}
|
||||
Message::SetDefaultSink(device) => {
|
||||
let server = match server.as_mut() {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
let default_sink = match server.get_default_sink() {
|
||||
Ok(sink) => sink,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let to_move = server.get_sink_inputs(default_sink.index);
|
||||
if let Some(name) = device.name.as_ref() {
|
||||
if server.set_default_sink(name, to_move) {
|
||||
from_pulse_send
|
||||
.send(Message::SetDefaultSink(device))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::SetDefaultSource(device) => {
|
||||
let server = match server.as_mut() {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
let default_source = match server.get_default_source() {
|
||||
Ok(source) => source,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let to_move = server.get_source_outputs(default_source.index);
|
||||
if let Some(name) = device.name.as_ref() {
|
||||
if server.set_default_source(name, to_move) {
|
||||
from_pulse_send
|
||||
.send(Message::SetDefaultSource(device))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::warn!("message doesn't match")
|
||||
}
|
||||
|
|
@ -408,6 +446,67 @@ impl PulseServer {
|
|||
.ok_or(PulseServerError::Misc("get_server_info(): failed"))
|
||||
}
|
||||
|
||||
fn set_default_sink(&mut self, sink: &str, to_move: Vec<u32>) -> bool {
|
||||
let set_default_success = Rc::new(RefCell::new(false));
|
||||
let set_default_success_ref = set_default_success.clone();
|
||||
let op = self
|
||||
.context
|
||||
.borrow_mut()
|
||||
.set_default_sink(sink, move |ret| {
|
||||
*set_default_success.borrow_mut() = ret;
|
||||
});
|
||||
self.wait_for_result(op).ok();
|
||||
if !set_default_success_ref.replace(true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for index in to_move {
|
||||
let move_success = Rc::new(RefCell::new(false));
|
||||
let op = self.introspector.move_sink_input_by_name(
|
||||
index,
|
||||
sink,
|
||||
Some(Box::new(move |ret| {
|
||||
*move_success.borrow_mut() = ret;
|
||||
})),
|
||||
);
|
||||
|
||||
self.wait_for_result(op).ok();
|
||||
}
|
||||
// TODO handle errors
|
||||
true
|
||||
}
|
||||
|
||||
fn set_default_source(&mut self, sink: &str, to_move: Vec<u32>) -> bool {
|
||||
let set_default_success = Rc::new(RefCell::new(false));
|
||||
let set_default_success_ref = set_default_success.clone();
|
||||
let op = self
|
||||
.context
|
||||
.borrow_mut()
|
||||
.set_default_source(sink, move |ret| {
|
||||
*set_default_success.borrow_mut() = ret;
|
||||
});
|
||||
self.wait_for_result(op).ok();
|
||||
|
||||
if !set_default_success_ref.replace(true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for index in to_move {
|
||||
let move_success = Rc::new(RefCell::new(false));
|
||||
let op = self.introspector.move_source_output_by_name(
|
||||
index,
|
||||
sink,
|
||||
Some(Box::new(move |ret| {
|
||||
*move_success.borrow_mut() = ret;
|
||||
})),
|
||||
);
|
||||
|
||||
self.wait_for_result(op).ok();
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn get_default_sink(&mut self) -> Result<DeviceInfo, PulseServerError> {
|
||||
let server_info = self.get_server_info();
|
||||
match server_info {
|
||||
|
|
@ -472,6 +571,34 @@ impl PulseServer {
|
|||
self.wait_for_result(op).ok();
|
||||
}
|
||||
|
||||
fn get_source_outputs(&mut self, source: u32) -> Vec<u32> {
|
||||
let result = Rc::new(RefCell::new(Vec::new()));
|
||||
let result_ref = Rc::new(RefCell::new(Vec::new()));
|
||||
let op = self.introspector.get_source_output_info_list(move |list| {
|
||||
if let ListResult::Item(item) = list {
|
||||
if source == item.source {
|
||||
result.borrow_mut().push(item.index);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.wait_for_result(op).ok();
|
||||
result_ref.replace(Vec::new())
|
||||
}
|
||||
|
||||
fn get_sink_inputs(&mut self, sink: u32) -> Vec<u32> {
|
||||
let result = Rc::new(RefCell::new(Vec::new()));
|
||||
let result_ref = Rc::new(RefCell::new(Vec::new()));
|
||||
let op = self.introspector.get_sink_input_info_list(move |list| {
|
||||
if let ListResult::Item(item) = list {
|
||||
if sink == item.sink {
|
||||
result.borrow_mut().push(item.index);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.wait_for_result(op).ok();
|
||||
result_ref.replace(Vec::new())
|
||||
}
|
||||
|
||||
// after building an operation such as get_devices() we need to keep polling
|
||||
// the pulse audio server to "wait" for the operation to complete
|
||||
fn wait_for_result<G: ?Sized>(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue