1use std::collections::BTreeMap;
7
8use crate::wire::DeviceUid;
9
10use super::V2ipStreamSource;
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct AudioFeatures(u32);
15
16impl AudioFeatures {
17 pub const INPUT: Self = Self(1 << 0);
19 pub const OUTPUT: Self = Self(1 << 1);
21 pub const V2IP_TX: Self = Self(1 << 2);
23 pub const V2IP_RX: Self = Self(1 << 3);
25 pub const HDMI: Self = Self(1 << 4);
27 pub const RCA: Self = Self(1 << 5);
29 pub const SPDIF: Self = Self(1 << 6);
31 pub const TRIGGER: Self = Self(1 << 7);
33 pub const MUTE: Self = Self(1 << 8);
35 pub const ROUTE_INPUT: Self = Self(1 << 9);
37 pub const ROUTE_OUTPUT: Self = Self(1 << 10);
39 pub const ROUTE_IN_NONE: Self = Self(1 << 11);
41 pub const AMP_OUTPUT: Self = Self(1 << 12);
43 pub const VOLUME_CONTROL: Self = Self(1 << 13);
45 pub const GAIN_CONTROL: Self = Self(1 << 14);
47 pub const AUDIO_LOCK: Self = Self(1 << 15);
49
50 pub const fn from_bits(bits: u32) -> Self {
52 Self(bits)
53 }
54
55 pub const fn bits(self) -> u32 {
57 self.0
58 }
59
60 pub const fn has(self, other: Self) -> bool {
62 self.0 & other.0 == other.0
63 }
64
65 pub const fn is_v2ip(self) -> bool {
67 self.has(Self::V2IP_TX) || self.has(Self::V2IP_RX)
68 }
69}
70
71#[derive(Clone, Debug, Default, PartialEq, Eq)]
76pub struct AudioEndpoint {
77 pub id: u8,
79 pub features: AudioFeatures,
81 pub address: Option<V2ipStreamSource>,
83 pub parent: Option<u8>,
85 pub children: Vec<u8>,
87 pub inputs_available: Option<u32>,
89 pub inputs_routed: Option<u32>,
91 pub linked_device: DeviceUid,
93 pub linked_endpoint: Option<u8>,
95}
96
97impl AudioEndpoint {
98 pub fn input(&self) -> Option<u8> {
100 let routed = self.inputs_routed?;
101 (0..32).find(|id| routed & (1 << id) != 0)
102 }
103
104 pub fn available_inputs(&self) -> Vec<u8> {
106 let Some(mask) = self.inputs_available else {
107 return Vec::new();
108 };
109 (0..32).filter(|id| mask & (1 << id) != 0).collect()
110 }
111}
112
113#[derive(Clone, Debug, Default, PartialEq, Eq)]
115pub struct AudioEndpoints {
116 order: Vec<u8>,
117 endpoints: BTreeMap<u8, AudioEndpoint>,
118 status: BTreeMap<u8, AudioFeatures>,
119}
120
121impl AudioEndpoints {
122 pub(crate) fn add(&mut self, endpoint: AudioEndpoint) {
125 if !self.endpoints.contains_key(&endpoint.id) {
126 self.order.push(endpoint.id);
127 }
128 self.endpoints.insert(endpoint.id, endpoint);
129 }
130
131 pub fn status(&self, id: u8) -> Option<AudioFeatures> {
136 self.status.get(&id).copied()
137 }
138
139 pub(crate) fn set_status(&mut self, id: u8, status: AudioFeatures) {
140 self.status.insert(id, status);
141 }
142
143 pub fn get(&self, id: u8) -> Option<&AudioEndpoint> {
145 self.endpoints.get(&id)
146 }
147
148 pub(crate) fn get_mut(&mut self, id: u8) -> Option<&mut AudioEndpoint> {
149 self.endpoints.get_mut(&id)
150 }
151
152 pub fn list(&self) -> impl Iterator<Item = &AudioEndpoint> {
154 self.order.iter().filter_map(|id| self.endpoints.get(id))
155 }
156
157 pub fn roots(&self) -> impl Iterator<Item = &AudioEndpoint> {
159 self.list().filter(|ep| ep.parent.is_none())
160 }
161
162 pub fn first_root_input(&self) -> Option<&AudioEndpoint> {
164 self.roots()
165 .find(|ep| ep.features.has(AudioFeatures::INPUT))
166 }
167
168 pub fn first_root_output(&self) -> Option<&AudioEndpoint> {
170 self.roots()
171 .find(|ep| ep.features.has(AudioFeatures::OUTPUT))
172 }
173
174 pub(crate) fn same_tree(&self, other: &Self) -> bool {
180 self.endpoints.len() == other.endpoints.len()
181 && self.endpoints.iter().all(|(id, ep)| {
182 other
183 .endpoints
184 .get(id)
185 .is_some_and(|o| o.features == ep.features && o.parent == ep.parent)
186 })
187 }
188
189 pub(crate) fn same_status(&self, other: &Self) -> bool {
191 self.status == other.status
192 }
193
194 pub(crate) fn apply_link(&mut self, link: &AudioLink) {
196 if let Some(ep) = self.endpoints.get_mut(&link.endpoint) {
197 ep.linked_device = link.linked_device;
198 ep.linked_endpoint = Some(link.linked_endpoint);
199 }
200 }
201}
202
203#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
205pub struct AudioLink {
206 pub endpoint: u8,
208 pub linked_endpoint: u8,
210 pub linked_device: DeviceUid,
212}