sim_lib_stream_host/
catalog.rs1use sim_kernel::{
4 Error, Result, Symbol,
5 library::{ExportKind, ExportRecord, ExportState, Registry},
6};
7
8use crate::audio_provider::ModeledAudioProvider;
9use crate::eval_site::{DeviceProvider, StreamEvalSite};
10use crate::midi_live_eval_site::MidiLiveEvalSite;
11use crate::midi_provider::ModeledMidiProvider;
12use crate::placement::{DeviceDirection, DeviceKind, DeviceRecord};
13use crate::{AudioRouter, Placement};
14
15pub struct DeviceCatalog {
17 providers: Vec<Box<dyn DeviceProvider>>,
18}
19
20impl Default for DeviceCatalog {
21 fn default() -> Self {
22 Self::default_modeled()
23 }
24}
25
26impl DeviceCatalog {
27 pub fn new() -> Self {
29 Self {
30 providers: Vec::new(),
31 }
32 }
33
34 pub fn default_modeled() -> Self {
36 let mut catalog = Self::new();
37 catalog.register(Box::new(ModeledMidiProvider::default()));
38 catalog.register(Box::new(ModeledAudioProvider::default()));
39 catalog
40 }
41
42 pub fn with_registry_audio_devices(registry: &Registry) -> Self {
44 let mut catalog = Self::default_modeled();
45 catalog.register_registry_audio_devices(registry);
46 catalog
47 }
48
49 #[cfg(any(feature = "rtmidi-hardware", feature = "ble-midi-hardware"))]
51 pub fn with_native_midi(provider: Box<dyn DeviceProvider>) -> Self {
52 let mut catalog = Self::default_modeled();
53 catalog.register(provider);
54 catalog
55 }
56
57 #[cfg(feature = "rtmidi-hardware")]
59 pub fn with_alsa_midi(provider: Box<dyn DeviceProvider>) -> Self {
60 Self::with_native_midi(provider)
61 }
62
63 #[cfg(feature = "ble-midi-hardware")]
65 pub fn with_ble_midi(provider: Box<dyn DeviceProvider>) -> Self {
66 Self::with_native_midi(provider)
67 }
68
69 pub fn register(&mut self, provider: Box<dyn DeviceProvider>) {
71 self.providers.push(provider);
72 }
73
74 pub fn register_provider_sites(&mut self, router: &AudioRouter) {
76 let provider = ProviderAudioSites::from_router(router);
77 if !provider.is_empty() {
78 self.register(Box::new(provider));
79 }
80 }
81
82 pub fn register_registry_audio_devices(&mut self, registry: &Registry) {
84 let provider = RegistryAudioDevices::from_registry(registry);
85 if !provider.is_empty() {
86 self.register(Box::new(provider));
87 }
88 }
89
90 pub fn enumerate(&self) -> Result<Vec<DeviceRecord>> {
92 let mut records = Vec::new();
93 for provider in &self.providers {
94 records.extend(provider.enumerate()?);
95 }
96 Ok(records)
97 }
98
99 pub fn open(&self, id: &Symbol) -> Result<Box<dyn StreamEvalSite>> {
101 for provider in &self.providers {
102 let records = provider.enumerate()?;
103 if records.iter().any(|record| &record.id == id) {
104 return provider.open(id);
105 }
106 }
107 Err(Error::Eval(format!("DeviceCatalog: no device '{id}'")))
108 }
109
110 pub fn open_live(&self, id: &Symbol) -> Result<MidiLiveEvalSite> {
112 MidiLiveEvalSite::from_eval_site(id, self.open(id)?)
113 }
114
115 pub fn enumerate_midi(&self) -> Result<Vec<DeviceRecord>> {
117 self.enumerate_kind(DeviceKind::Midi)
118 }
119
120 pub fn enumerate_audio(&self) -> Result<Vec<DeviceRecord>> {
122 self.enumerate_kind(DeviceKind::Audio)
123 }
124
125 fn enumerate_kind(&self, kind: DeviceKind) -> Result<Vec<DeviceRecord>> {
126 Ok(self
127 .enumerate()?
128 .into_iter()
129 .filter(|record| record.kind == kind)
130 .collect())
131 }
132}
133
134pub fn audio_device_export_symbol(name: &str) -> Symbol {
136 Symbol::qualified("audio/device", name)
137}
138
139struct ProviderAudioSites {
140 records: Vec<DeviceRecord>,
141}
142
143impl ProviderAudioSites {
144 fn from_router(router: &AudioRouter) -> Self {
145 let mut records = router
146 .site_keys()
147 .filter_map(|key| router.site(key))
148 .map(|site| DeviceRecord::modeled_audio_from_card(site.card()))
149 .collect::<Vec<_>>();
150 records.sort_by_key(|record| record.id.to_string());
151 Self { records }
152 }
153
154 fn is_empty(&self) -> bool {
155 self.records.is_empty()
156 }
157}
158
159impl DeviceProvider for ProviderAudioSites {
160 fn enumerate(&self) -> Result<Vec<DeviceRecord>> {
161 Ok(self.records.clone())
162 }
163
164 fn open(&self, id: &Symbol) -> Result<Box<dyn StreamEvalSite>> {
165 let record = self
166 .records
167 .iter()
168 .find(|record| &record.id == id)
169 .ok_or_else(|| Error::Eval(format!("ProviderAudioSites: unknown id '{id}'")))?
170 .clone();
171 Ok(Box::new(ProviderAudioSite { record }))
172 }
173}
174
175struct RegistryAudioDevices {
176 records: Vec<DeviceRecord>,
177}
178
179impl RegistryAudioDevices {
180 fn from_registry(registry: &Registry) -> Self {
181 let mut records = registry
182 .libs()
183 .iter()
184 .flat_map(|lib| lib.exports.iter())
185 .filter_map(registry_audio_device_record)
186 .collect::<Vec<_>>();
187 records.sort_by_key(|record| record.id.to_string());
188 records.dedup_by(|left, right| left.id == right.id);
189 Self { records }
190 }
191
192 fn is_empty(&self) -> bool {
193 self.records.is_empty()
194 }
195}
196
197impl DeviceProvider for RegistryAudioDevices {
198 fn enumerate(&self) -> Result<Vec<DeviceRecord>> {
199 Ok(self.records.clone())
200 }
201
202 fn open(&self, id: &Symbol) -> Result<Box<dyn StreamEvalSite>> {
203 let record = self
204 .records
205 .iter()
206 .find(|record| &record.id == id)
207 .ok_or_else(|| Error::Eval(format!("RegistryAudioDevices: unknown id '{id}'")))?
208 .clone();
209 Ok(Box::new(ProviderAudioSite { record }))
210 }
211}
212
213fn registry_audio_device_record(record: &ExportRecord) -> Option<DeviceRecord> {
214 if record.kind != ExportKind::named(ExportKind::VALUE) {
215 return None;
216 }
217 if record.symbol.namespace.as_deref() != Some("audio/device") {
218 return None;
219 }
220 if matches!(record.state, ExportState::Invalid { .. }) {
221 return None;
222 }
223 Some(DeviceRecord {
224 id: record.symbol.clone(),
225 display_name: format!("{} audio device", record.symbol.name),
226 kind: DeviceKind::Audio,
227 direction: DeviceDirection::Duplex,
228 placement: Placement::Modeled,
229 })
230}
231
232struct ProviderAudioSite {
233 record: DeviceRecord,
234}
235
236impl StreamEvalSite for ProviderAudioSite {
237 fn placement(&self) -> &Placement {
238 &self.record.placement
239 }
240
241 fn device_record(&self) -> &DeviceRecord {
242 &self.record
243 }
244
245 fn close(self: Box<Self>) -> Result<()> {
246 Ok(())
247 }
248}