fix(sound): only consider active routes when setting volume and mute-ness
This commit is contained in:
parent
9db1681e0d
commit
1139e34928
3 changed files with 71 additions and 32 deletions
|
|
@ -66,17 +66,18 @@ fn run_service(
|
||||||
let registry = core.get_registry_rc()?;
|
let registry = core.get_registry_rc()?;
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(State {
|
let state = Rc::new(RefCell::new(State {
|
||||||
nodes: IntMap::new(),
|
main_loop: main_loop.downgrade(),
|
||||||
proxies: Proxies {
|
proxies: Proxies {
|
||||||
devices: IntMap::new(),
|
devices: IntMap::new(),
|
||||||
metadata: IntMap::new(),
|
metadata: IntMap::new(),
|
||||||
nodes: IntMap::new(),
|
nodes: IntMap::new(),
|
||||||
},
|
},
|
||||||
|
nodes: IntMap::new(),
|
||||||
|
active_routes: IntMap::new(),
|
||||||
routes: IntMap::new(),
|
routes: IntMap::new(),
|
||||||
node_devices: IntMap::new(),
|
node_devices: IntMap::new(),
|
||||||
node_card_profile_device: IntMap::new(),
|
node_card_profile_device: IntMap::new(),
|
||||||
node_props: IntMap::new(),
|
node_props: IntMap::new(),
|
||||||
main_loop: main_loop.downgrade(),
|
|
||||||
on_event,
|
on_event,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -207,7 +208,9 @@ fn run_service(
|
||||||
match param_type {
|
match param_type {
|
||||||
ParamType::EnumProfile => {
|
ParamType::EnumProfile => {
|
||||||
if let Some(profile) = Profile::from_pod(pod) {
|
if let Some(profile) = Profile::from_pod(pod) {
|
||||||
state.borrow_mut().add_profile(device_id, profile);
|
state
|
||||||
|
.borrow_mut()
|
||||||
|
.add_profile(device_id, index, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,7 +426,7 @@ pub enum Event {
|
||||||
/// A new node was detected.
|
/// A new node was detected.
|
||||||
AddNode(Node),
|
AddNode(Node),
|
||||||
/// A profile was enumerated
|
/// A profile was enumerated
|
||||||
AddProfile(DeviceId, Profile),
|
AddProfile(DeviceId, u32, Profile),
|
||||||
/// A route was enumerated
|
/// A route was enumerated
|
||||||
AddRoute(DeviceId, u32, Route),
|
AddRoute(DeviceId, u32, Route),
|
||||||
/// The default sink was changed.
|
/// The default sink was changed.
|
||||||
|
|
@ -496,13 +499,21 @@ struct Proxies {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
nodes: IntMap<PipewireId, (NodeId, Option<DeviceId>)>,
|
|
||||||
pub(self) proxies: Proxies,
|
|
||||||
routes: IntMap<DeviceId, Vec<Route>>,
|
|
||||||
node_devices: IntMap<NodeId, DeviceId>,
|
|
||||||
node_props: IntMap<NodeId, NodeProps>,
|
|
||||||
node_card_profile_device: IntMap<NodeId, u32>,
|
|
||||||
main_loop: MainLoopWeak,
|
main_loop: MainLoopWeak,
|
||||||
|
/// Stores pipewire objects that we are monitoring.
|
||||||
|
pub(self) proxies: Proxies,
|
||||||
|
/// Associates the pipewire ID of a node to its node and device IDs.
|
||||||
|
nodes: IntMap<PipewireId, (NodeId, Option<DeviceId>)>,
|
||||||
|
/// Routes which are currently in use by devices.
|
||||||
|
active_routes: IntMap<DeviceId, Vec<Route>>,
|
||||||
|
/// Routes which are supported by devices.
|
||||||
|
routes: IntMap<DeviceId, Vec<Route>>,
|
||||||
|
/// Associates node objects to their device objects.
|
||||||
|
node_devices: IntMap<NodeId, DeviceId>,
|
||||||
|
/// Additional properties of nodes for managing volume, mute, etc.
|
||||||
|
node_props: IntMap<NodeId, NodeProps>,
|
||||||
|
/// Associates a node with a card profile device for matching nodes to routes.
|
||||||
|
node_card_profile_device: IntMap<NodeId, u32>,
|
||||||
/// Handle events and exit the loop when `true` is returned.
|
/// Handle events and exit the loop when `true` is returned.
|
||||||
on_event: Box<dyn FnMut(Event)>,
|
on_event: Box<dyn FnMut(Event)>,
|
||||||
}
|
}
|
||||||
|
|
@ -513,6 +524,16 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_route(&mut self, id: DeviceId, index: u32, route: Route) {
|
fn active_route(&mut self, id: DeviceId, index: u32, route: Route) {
|
||||||
|
// Keep a record of routes attached to a device for setting properties.
|
||||||
|
// This will overwrite routes on updates to
|
||||||
|
let routes = self.active_routes.entry(id).or_default();
|
||||||
|
if routes.len() < index as usize + 1 {
|
||||||
|
let additional = (index as usize + 1) - routes.capacity();
|
||||||
|
routes.reserve_exact(additional);
|
||||||
|
routes.extend(std::iter::repeat(Route::default()).take(additional));
|
||||||
|
}
|
||||||
|
routes[index as usize] = route.clone();
|
||||||
|
|
||||||
self.on_event(Event::ActiveRoute(id, index, route));
|
self.on_event(Event::ActiveRoute(id, index, route));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,8 +575,8 @@ impl State {
|
||||||
self.on_event(Event::AddNode(node));
|
self.on_event(Event::AddNode(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_profile(&mut self, id: DeviceId, profile: Profile) {
|
fn add_profile(&mut self, id: DeviceId, index: u32, profile: Profile) {
|
||||||
self.on_event(Event::AddProfile(id, profile));
|
self.on_event(Event::AddProfile(id, index, profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_route(&mut self, id: DeviceId, index: u32, route: Route) {
|
fn add_route(&mut self, id: DeviceId, index: u32, route: Route) {
|
||||||
|
|
@ -592,8 +613,8 @@ impl State {
|
||||||
self.on_event(Event::DefaultSource(name));
|
self.on_event(Event::DefaultSource(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_route(&self, device_id: DeviceId, route_device: i32) -> Option<&Route> {
|
fn active_node_route(&self, device_id: DeviceId, route_device: i32) -> Option<&Route> {
|
||||||
self.routes
|
self.active_routes
|
||||||
.get(device_id)?
|
.get(device_id)?
|
||||||
.iter()
|
.iter()
|
||||||
.find(|r| r.devices.contains(&route_device))
|
.find(|r| r.devices.contains(&route_device))
|
||||||
|
|
@ -682,14 +703,14 @@ impl State {
|
||||||
fn set_mute_node(&self, id: NodeId, mute: bool) {
|
fn set_mute_node(&self, id: NodeId, mute: bool) {
|
||||||
// Prefer to mute the device instead of the node.
|
// Prefer to mute the device instead of the node.
|
||||||
// Muting a node will not emit a notification.
|
// Muting a node will not emit a notification.
|
||||||
if let Some((&device_id, &route_device)) = self
|
if let Some((&device_id, &card_profile_device)) = self
|
||||||
.node_devices
|
.node_devices
|
||||||
.get(id)
|
.get(id)
|
||||||
.zip(self.node_card_profile_device.get(id))
|
.zip(self.node_card_profile_device.get(id))
|
||||||
{
|
{
|
||||||
let route_device = route_device as i32;
|
let card_profile_device = card_profile_device as i32;
|
||||||
if let Some(route) = self.node_route(device_id, route_device) {
|
if let Some(route) = self.active_node_route(device_id, card_profile_device) {
|
||||||
self.set_mute(device_id, route_device, route, mute);
|
self.set_mute(device_id, card_profile_device, route, mute);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -762,14 +783,21 @@ impl State {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prefer to change the volume of the device instead of the node.
|
// Prefer to change the volume of the device instead of the node.
|
||||||
if let Some((&device_id, &route_device)) = self
|
if let Some((&device_id, &card_profile_device)) = self
|
||||||
.node_devices
|
.node_devices
|
||||||
.get(id)
|
.get(id)
|
||||||
.zip(self.node_card_profile_device.get(id))
|
.zip(self.node_card_profile_device.get(id))
|
||||||
{
|
{
|
||||||
let route_device = route_device as i32;
|
let card_profile_device = card_profile_device as i32;
|
||||||
if let Some(route) = self.node_route(device_id, route_device) {
|
if let Some(route) = self.active_node_route(device_id, card_profile_device) {
|
||||||
self.set_volume(device_id, props, route_device, route, volume, balance);
|
self.set_volume(
|
||||||
|
device_id,
|
||||||
|
props,
|
||||||
|
card_profile_device,
|
||||||
|
route,
|
||||||
|
volume,
|
||||||
|
balance,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
use crate::{Availability, spa_utils::string_from_pod};
|
use crate::{Availability, spa_utils::string_from_pod};
|
||||||
use libspa::pod::Pod;
|
use libspa::pod::Pod;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
pub index: i32,
|
pub index: i32,
|
||||||
pub priority: i32,
|
pub priority: i32,
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,7 @@ impl Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pipewire::Event::AddProfile(id, profile) => {
|
pipewire::Event::AddProfile(id, index, profile) => {
|
||||||
if let Some(p) = self.active_profiles.get_mut(id) {
|
if let Some(p) = self.active_profiles.get_mut(id) {
|
||||||
if p.index == profile.index {
|
if p.index == profile.index {
|
||||||
*p = profile.clone();
|
*p = profile.clone();
|
||||||
|
|
@ -534,16 +534,17 @@ impl Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
let profiles = self.device_profiles.entry(id).or_default();
|
let profiles = self.device_profiles.entry(id).or_default();
|
||||||
for p in profiles.iter_mut() {
|
if profiles.len() < index as usize + 1 {
|
||||||
if p.index == profile.index {
|
let additional = (index as usize + 1) - profiles.capacity();
|
||||||
*p = profile;
|
profiles.reserve_exact(additional);
|
||||||
|
profiles.extend(std::iter::repeat_n(
|
||||||
self.update_ui_profiles();
|
pipewire::Profile::default(),
|
||||||
return;
|
additional,
|
||||||
}
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles.push(profile);
|
profiles[index as usize] = profile;
|
||||||
|
|
||||||
self.update_ui_profiles();
|
self.update_ui_profiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -676,12 +677,22 @@ impl Model {
|
||||||
|
|
||||||
fn add_route(&mut self, id: DeviceId, index: u32, route: pipewire::Route) {
|
fn add_route(&mut self, id: DeviceId, index: u32, route: pipewire::Route) {
|
||||||
self.update_device_route_name(&route, id);
|
self.update_device_route_name(&route, id);
|
||||||
|
|
||||||
|
tracing::debug!(target: "sound",
|
||||||
|
"Device {} added route {} ({:?}); {:?}",
|
||||||
|
id,
|
||||||
|
route.name,
|
||||||
|
route.direction,
|
||||||
|
route.available
|
||||||
|
);
|
||||||
|
|
||||||
let routes = self.device_routes.entry(id).or_default();
|
let routes = self.device_routes.entry(id).or_default();
|
||||||
if routes.len() < index as usize + 1 {
|
if routes.len() < index as usize + 1 {
|
||||||
let additional = (index as usize + 1) - routes.capacity();
|
let additional = (index as usize + 1) - routes.capacity();
|
||||||
routes.reserve_exact(additional);
|
routes.reserve_exact(additional);
|
||||||
routes.extend(std::iter::repeat_n(pipewire::Route::default(), additional));
|
routes.extend(std::iter::repeat_n(pipewire::Route::default(), additional));
|
||||||
}
|
}
|
||||||
|
|
||||||
routes[index as usize] = route;
|
routes[index as usize] = route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue