use std::collections::BTreeMap;
use crate::wire::DeviceUid;
use super::V2ipStreamSource;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AudioFeatures(u32);
impl AudioFeatures {
pub const INPUT: Self = Self(1 << 0);
pub const OUTPUT: Self = Self(1 << 1);
pub const V2IP_TX: Self = Self(1 << 2);
pub const V2IP_RX: Self = Self(1 << 3);
pub const HDMI: Self = Self(1 << 4);
pub const RCA: Self = Self(1 << 5);
pub const SPDIF: Self = Self(1 << 6);
pub const TRIGGER: Self = Self(1 << 7);
pub const MUTE: Self = Self(1 << 8);
pub const ROUTE_INPUT: Self = Self(1 << 9);
pub const ROUTE_OUTPUT: Self = Self(1 << 10);
pub const ROUTE_IN_NONE: Self = Self(1 << 11);
pub const AMP_OUTPUT: Self = Self(1 << 12);
pub const VOLUME_CONTROL: Self = Self(1 << 13);
pub const GAIN_CONTROL: Self = Self(1 << 14);
pub const fn from_bits(bits: u32) -> Self {
Self(bits)
}
pub const fn bits(self) -> u32 {
self.0
}
pub const fn has(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
pub const fn is_v2ip(self) -> bool {
self.has(Self::V2IP_TX) || self.has(Self::V2IP_RX)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AudioEndpoint {
pub id: u8,
pub features: AudioFeatures,
pub address: Option<V2ipStreamSource>,
pub parent: Option<u8>,
pub children: Vec<u8>,
pub inputs_available: Option<u32>,
pub inputs_routed: Option<u32>,
pub linked_device: DeviceUid,
pub linked_endpoint: Option<u8>,
}
impl AudioEndpoint {
pub fn input(&self) -> Option<u8> {
let routed = self.inputs_routed?;
(0..32).find(|id| routed & (1 << id) != 0)
}
pub fn available_inputs(&self) -> Vec<u8> {
let Some(mask) = self.inputs_available else {
return Vec::new();
};
(0..32).filter(|id| mask & (1 << id) != 0).collect()
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AudioEndpoints {
order: Vec<u8>,
endpoints: BTreeMap<u8, AudioEndpoint>,
}
impl AudioEndpoints {
pub(crate) fn add(&mut self, endpoint: AudioEndpoint) {
if !self.endpoints.contains_key(&endpoint.id) {
self.order.push(endpoint.id);
}
self.endpoints.insert(endpoint.id, endpoint);
}
pub fn get(&self, id: u8) -> Option<&AudioEndpoint> {
self.endpoints.get(&id)
}
pub(crate) fn get_mut(&mut self, id: u8) -> Option<&mut AudioEndpoint> {
self.endpoints.get_mut(&id)
}
pub fn list(&self) -> impl Iterator<Item = &AudioEndpoint> {
self.order.iter().filter_map(|id| self.endpoints.get(id))
}
pub fn roots(&self) -> impl Iterator<Item = &AudioEndpoint> {
self.list().filter(|ep| ep.parent.is_none())
}
pub fn first_root_input(&self) -> Option<&AudioEndpoint> {
self.roots()
.find(|ep| ep.features.has(AudioFeatures::INPUT))
}
pub fn first_root_output(&self) -> Option<&AudioEndpoint> {
self.roots()
.find(|ep| ep.features.has(AudioFeatures::OUTPUT))
}
pub(crate) fn same_tree(&self, other: &Self) -> bool {
self.endpoints.len() == other.endpoints.len()
&& self.endpoints.iter().all(|(id, ep)| {
other
.endpoints
.get(id)
.is_some_and(|o| o.features == ep.features && o.parent == ep.parent)
})
}
pub(crate) fn apply_link(&mut self, link: &AudioLink) {
if let Some(ep) = self.endpoints.get_mut(&link.endpoint) {
ep.linked_device = link.linked_device;
ep.linked_endpoint = Some(link.linked_endpoint);
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct AudioLink {
pub endpoint: u8,
pub linked_endpoint: u8,
pub linked_device: DeviceUid,
}