sim_lib_stream_coreaudio/
model.rs1use sim_kernel::{Error, Result, Symbol};
2use sim_lib_stream_audio::PcmSpec;
3use sim_lib_stream_host::HostDirection;
4
5use crate::coreaudio_backend_symbol;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct CoreAudioTiming {
10 sample_rate_hz: u32,
11 buffer_frames: usize,
12 input_latency_frames: u32,
13 output_latency_frames: u32,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct CoreAudioDevice {
19 id: Symbol,
20 name: String,
21 direction: HostDirection,
22 channels: usize,
23 timing: CoreAudioTiming,
24 default_output: bool,
25 default_input: bool,
26}
27
28impl CoreAudioTiming {
29 pub fn new(
44 sample_rate_hz: u32,
45 buffer_frames: usize,
46 input_latency_frames: u32,
47 output_latency_frames: u32,
48 ) -> Result<Self> {
49 if sample_rate_hz == 0 {
50 return Err(Error::Eval(
51 "CoreAudio sample rate must be greater than zero".to_owned(),
52 ));
53 }
54 if buffer_frames == 0 {
55 return Err(Error::Eval(
56 "CoreAudio buffer size must be greater than zero".to_owned(),
57 ));
58 }
59 Ok(Self {
60 sample_rate_hz,
61 buffer_frames,
62 input_latency_frames,
63 output_latency_frames,
64 })
65 }
66
67 pub fn default_low_latency() -> Self {
70 Self::new(48_000, 128, 128, 128).expect("valid CoreAudio timing")
71 }
72
73 pub fn sample_rate_hz(self) -> u32 {
75 self.sample_rate_hz
76 }
77
78 pub fn buffer_frames(self) -> usize {
80 self.buffer_frames
81 }
82
83 pub fn input_latency_frames(self) -> u32 {
85 self.input_latency_frames
86 }
87
88 pub fn output_latency_frames(self) -> u32 {
90 self.output_latency_frames
91 }
92}
93
94impl CoreAudioDevice {
95 pub fn output(
97 id: impl Into<String>,
98 name: impl Into<String>,
99 channels: usize,
100 timing: CoreAudioTiming,
101 ) -> Result<Self> {
102 Self::new(id, name, HostDirection::Output, channels, timing)
103 }
104
105 pub fn input(
107 id: impl Into<String>,
108 name: impl Into<String>,
109 channels: usize,
110 timing: CoreAudioTiming,
111 ) -> Result<Self> {
112 Self::new(id, name, HostDirection::Input, channels, timing)
113 }
114
115 pub fn duplex(
117 id: impl Into<String>,
118 name: impl Into<String>,
119 channels: usize,
120 timing: CoreAudioTiming,
121 ) -> Result<Self> {
122 Self::new(id, name, HostDirection::Duplex, channels, timing)
123 }
124
125 pub fn new(
131 id: impl Into<String>,
132 name: impl Into<String>,
133 direction: HostDirection,
134 channels: usize,
135 timing: CoreAudioTiming,
136 ) -> Result<Self> {
137 if channels == 0 {
138 return Err(Error::Eval(
139 "CoreAudio device channel count must be greater than zero".to_owned(),
140 ));
141 }
142 Ok(Self {
143 id: Symbol::new(id.into()),
144 name: name.into(),
145 direction,
146 channels,
147 timing,
148 default_output: false,
149 default_input: false,
150 })
151 }
152
153 pub fn with_default_output(mut self) -> Self {
155 self.default_output = true;
156 self
157 }
158
159 pub fn with_default_input(mut self) -> Self {
161 self.default_input = true;
162 self
163 }
164
165 pub fn id(&self) -> &Symbol {
167 &self.id
168 }
169
170 pub fn name(&self) -> &str {
172 &self.name
173 }
174
175 pub fn direction(&self) -> HostDirection {
177 self.direction
178 }
179
180 pub fn channels(&self) -> usize {
182 self.channels
183 }
184
185 pub fn timing(&self) -> CoreAudioTiming {
187 self.timing
188 }
189
190 pub fn default_output(&self) -> bool {
192 self.default_output
193 }
194
195 pub fn default_input(&self) -> bool {
197 self.default_input
198 }
199
200 pub fn spec(&self) -> Result<PcmSpec> {
202 PcmSpec::f32(self.channels, self.timing.sample_rate_hz)
203 }
204
205 pub fn is_compatible_with(&self, requested: HostDirection) -> bool {
210 self.direction == requested || self.direction == HostDirection::Duplex
211 }
212
213 pub fn port_symbol(&self) -> Symbol {
215 Symbol::new(format!("{}/port", self.id))
216 }
217
218 pub fn backend(&self) -> Symbol {
220 coreaudio_backend_symbol()
221 }
222}
223
224pub fn macos_audio_backend_priority() -> Vec<Symbol> {
226 vec![
227 Symbol::qualified("stream/host", "portaudio"),
228 Symbol::qualified("stream/host", "rtaudio"),
229 coreaudio_backend_symbol(),
230 ]
231}
232
233pub fn macos_midi_backend_priority() -> Vec<Symbol> {
235 vec![
236 Symbol::qualified("stream/host", "rtmidi"),
237 Symbol::qualified("stream/host", "coremidi"),
238 ]
239}