nandi/jolt-nativepublic Fork 0
cfd3e3677bed92e80cfe447469a249cfdc0b1401
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

device.rs · 261 lines · 9.4 KBRust Blame HistoryRaw
Lift freeq's AV media plane out of sleek 90f8b89 nandi 19d ago1pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};
2
3use super::sys;
4use crate::host::com;
5use crate::ChannelCount;
6use crate::DefaultStreamConfigError;
7use crate::DeviceDescription;
8use crate::DeviceDescriptionBuilder;
9use crate::DeviceId;
10use crate::DeviceIdError;
11use crate::DeviceNameError;
12use crate::DevicesError;
13use crate::FrameCount;
14use crate::SampleFormat;
15use crate::SampleRate;
16use crate::SupportedBufferSize;
17use crate::SupportedStreamConfig;
18use crate::SupportedStreamConfigRange;
19use crate::SupportedStreamConfigsError;
20
21use std::hash::{Hash, Hasher};
22use std::sync::atomic::AtomicU32;
23use std::sync::{Arc, Mutex};
24
25/// A ASIO Device
26#[derive(Clone)]
27pub struct Device {
28 name: String,
29
30 // Metadata cached during enumeration
31 channels_in: ChannelCount,
32 channels_out: ChannelCount,
33 sample_rate: SampleRate,
34 buffer_size_min: FrameCount,
35 buffer_size_max: FrameCount,
36 input_sample_format: Option<SampleFormat>,
37 output_sample_format: Option<SampleFormat>,
38 supported_sample_rates: Vec<SampleRate>,
39
40 // Input and/or Output stream.
41 // A driver can only have one of each.
42 // They need to be created at the same time.
43 pub(super) asio_streams: Arc<Mutex<sys::AsioStreams>>,
44 pub(super) current_callback_flag: Arc<AtomicU32>,
45}
46
47/// All available devices.
48pub struct Devices {
49 asio: Arc<sys::Asio>,
50 drivers: std::vec::IntoIter<String>,
51 current_driver: Option<sys::Driver>,
52}
53
54impl PartialEq for Device {
55 fn eq(&self, other: &Self) -> bool {
56 self.name == other.name
57 }
58}
59
60impl Eq for Device {}
61
62impl Hash for Device {
63 fn hash<H: Hasher>(&self, state: &mut H) {
64 self.name.hash(state);
65 }
66}
67
68impl Device {
69 pub fn description(&self) -> Result<DeviceDescription, DeviceNameError> {
70 let direction = crate::device_description::direction_from_counts(
71 Some(self.channels_in),
72 Some(self.channels_out),
73 );
74
75 Ok(DeviceDescriptionBuilder::new(self.name.clone())
76 .driver(self.name.clone())
77 .direction(direction)
78 .build())
79 }
80
81 pub fn id(&self) -> Result<DeviceId, DeviceIdError> {
82 Ok(DeviceId(crate::platform::HostId::Asio, self.name.clone()))
83 }
84
85 /// Gets the supported input configs.
86 /// TODO currently only supports the default.
87 /// Need to find all possible configs.
88 pub fn supported_input_configs(
89 &self,
90 ) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
91 let default = self
92 .default_input_config()
93 .map_err(|_| SupportedStreamConfigsError::DeviceNotAvailable)?;
94 Ok(self.configs_for(default).into_iter())
95 }
96
97 /// Gets the supported output configs.
98 /// TODO currently only supports the default.
99 /// Need to find all possible configs.
100 pub fn supported_output_configs(
101 &self,
102 ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
103 let default = self
104 .default_output_config()
105 .map_err(|_| SupportedStreamConfigsError::DeviceNotAvailable)?;
106 Ok(self.configs_for(default).into_iter())
107 }
108
109 /// Returns the default input config
110 pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
111 self.default_config(self.channels_in, self.input_sample_format)
112 }
113
114 /// Returns the default output config
115 pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
116 self.default_config(self.channels_out, self.output_sample_format)
117 }
118
119 fn default_config(
120 &self,
121 channels: ChannelCount,
122 sample_format: Option<SampleFormat>,
123 ) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
124 if channels == 0 {
125 return Err(DefaultStreamConfigError::StreamTypeNotSupported);
126 }
127 let sample_format =
128 sample_format.ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?;
129 Ok(SupportedStreamConfig {
130 channels,
131 sample_rate: self.sample_rate,
132 buffer_size: SupportedBufferSize::Range {
133 min: self.buffer_size_min,
134 max: self.buffer_size_max,
135 },
136 sample_format,
137 })
138 }
139
140 fn configs_for(&self, default: SupportedStreamConfig) -> Vec<SupportedStreamConfigRange> {
141 let mut configs = Vec::with_capacity(default.channels as usize);
142 for &rate in &self.supported_sample_rates {
143 for channels in 1..=default.channels {
144 configs.push(SupportedStreamConfigRange {
145 channels,
146 min_sample_rate: rate,
147 max_sample_rate: rate,
148 buffer_size: default.buffer_size,
149 sample_format: default.sample_format,
150 });
151 }
152 }
153 configs
154 }
155}
156
157impl Devices {
158 pub fn new(asio: Arc<sys::Asio>) -> Result<Self, DevicesError> {
159 // Make sure that COM is initialized.
160 com::com_initialized();
161 let drivers = asio.driver_names().into_iter();
162 Ok(Self {
163 asio,
164 drivers,
165 current_driver: None,
166 })
167 }
168}
169
170impl Iterator for Devices {
171 type Item = Device;
172
173 /// Enumerate devices by briefly loading each driver to capture its metadata.
174 fn next(&mut self) -> Option<Device> {
175 // Drop the previously loaded driver before attempting to load the next one.
176 self.current_driver = None;
177
178 loop {
179 match self.drivers.next() {
180 Some(name) => match self.asio.load_driver(&name) {
181 Ok(driver) => {
182 let Ok(channels) = driver.channels() else {
183 continue;
184 };
185 if channels.ins == 0 && channels.outs == 0 {
186 continue;
187 }
188
189 // Some drivers (e.g. Realtek ASIO) return 0 for sample_rate() until a
190 // stream is active. Treat 0 as "not yet known" rather than skipping.
191 let sample_rate = driver.sample_rate().unwrap_or(0.0);
192
193 let Ok(buffer_size_range) = driver.buffersize_range() else {
194 continue;
195 };
196
197 let input_sample_format = driver
198 .input_data_type()
199 .ok()
200 .and_then(|t| convert_data_type(&t));
201 let output_sample_format = driver
202 .output_data_type()
203 .ok()
204 .and_then(|t| convert_data_type(&t));
205
206 let supported_sample_rates: Vec<SampleRate> = crate::COMMON_SAMPLE_RATES
207 .iter()
208 .copied()
209 .filter(|&r| driver.can_sample_rate(r.into()).unwrap_or(false))
210 .collect();
211
212 self.current_driver = Some(driver);
213
214 let asio_streams = Arc::new(Mutex::new(sys::AsioStreams {
215 input: None,
216 output: None,
217 }));
218
219 return Some(Device {
220 name,
221 channels_in: channels.ins as ChannelCount,
222 channels_out: channels.outs as ChannelCount,
223 sample_rate: sample_rate as SampleRate,
224 buffer_size_min: buffer_size_range.min as FrameCount,
225 buffer_size_max: buffer_size_range.max as FrameCount,
226 input_sample_format,
227 output_sample_format,
228 supported_sample_rates,
229 asio_streams,
230 // Initialize with sentinel value so it never matches global flag state (0 or 1).
231 current_callback_flag: Arc::new(AtomicU32::new(u32::MAX)),
232 });
233 }
234 // A different driver is already loaded (e.g. an active Stream holds it). Stop
235 // cleanly rather than spinning through the rest of the list.
236 Err(sys::LoadDriverError::DriverAlreadyExists) => return None,
237 // Driver failed to load for its own reasons; skip and try the next.
238 Err(_) => continue,
239 },
240 None => return None,
241 }
242 }
243 }
244}
245
246pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option<SampleFormat> {
247 let fmt = match *ty {
248 sys::AsioSampleType::ASIOSTInt16MSB => SampleFormat::I16,
249 sys::AsioSampleType::ASIOSTInt16LSB => SampleFormat::I16,
250 sys::AsioSampleType::ASIOSTInt24MSB => SampleFormat::I24,
251 sys::AsioSampleType::ASIOSTInt24LSB => SampleFormat::I24,
252 sys::AsioSampleType::ASIOSTInt32MSB => SampleFormat::I32,
253 sys::AsioSampleType::ASIOSTInt32LSB => SampleFormat::I32,
254 sys::AsioSampleType::ASIOSTFloat32MSB => SampleFormat::F32,
255 sys::AsioSampleType::ASIOSTFloat32LSB => SampleFormat::F32,
256 sys::AsioSampleType::ASIOSTFloat64MSB => SampleFormat::F64,
257 sys::AsioSampleType::ASIOSTFloat64LSB => SampleFormat::F64,
258 _ => return None,
259 };
260 Some(fmt)
261}