1use crate::bindings;
14use crate::error::{Error, Result};
15use core::ffi::c_void;
16
17#[derive(Clone, Copy, PartialEq, Eq)]
19pub enum SampleFmt {
20 S16,
21 S32,
22 F32,
23}
24
25impl SampleFmt {
26 fn to_raw(self) -> u32 {
27 match self {
28 SampleFmt::S16 => 0,
29 SampleFmt::S32 => 1,
30 SampleFmt::F32 => 2,
31 }
32 }
33}
34
35pub struct AudioFmt {
37 pub sample_rate: u32,
38 pub channels: u32,
39 pub sample_fmt: SampleFmt,
40}
41
42pub fn graph_init(
47 graph: &mut bindings::ove_audio_graph,
48 frames_per_period: u32,
49) -> Result<()> {
50 let rc = unsafe { bindings::ove_audio_graph_init(graph, frames_per_period) };
51 Error::from_code(rc)
52}
53
54pub fn graph_deinit(graph: &mut bindings::ove_audio_graph) {
56 unsafe { bindings::ove_audio_graph_deinit(graph) };
57}
58
59pub fn graph_add_node(
64 graph: &mut bindings::ove_audio_graph,
65 ops: &bindings::ove_audio_node_ops,
66 ctx: *mut c_void,
67 name: &core::ffi::CStr,
68 node_type: bindings::ove_audio_node_type,
69) -> core::result::Result<i32, Error> {
70 let rc = unsafe {
71 bindings::ove_audio_graph_add_node(graph, ops, ctx, name.as_ptr(), node_type)
72 };
73 if rc < 0 {
74 Err(Error::from_code(rc).unwrap_err())
75 } else {
76 Ok(rc)
77 }
78}
79
80pub fn graph_connect(
85 graph: &mut bindings::ove_audio_graph,
86 from: u32,
87 to: u32,
88) -> Result<()> {
89 let rc = unsafe { bindings::ove_audio_graph_connect(graph, from, to) };
90 Error::from_code(rc)
91}
92
93pub fn graph_build(graph: &mut bindings::ove_audio_graph) -> Result<()> {
98 let rc = unsafe { bindings::ove_audio_graph_build(graph) };
99 Error::from_code(rc)
100}
101
102pub fn graph_start(graph: &mut bindings::ove_audio_graph) -> Result<()> {
107 let rc = unsafe { bindings::ove_audio_graph_start(graph) };
108 Error::from_code(rc)
109}
110
111pub fn graph_stop(graph: &mut bindings::ove_audio_graph) -> Result<()> {
116 let rc = unsafe { bindings::ove_audio_graph_stop(graph) };
117 Error::from_code(rc)
118}
119
120pub fn graph_process(graph: &mut bindings::ove_audio_graph) -> Result<()> {
125 let rc = unsafe { bindings::ove_audio_graph_process(graph) };
126 Error::from_code(rc)
127}
128
129pub fn device_cfg_i2s(
138 sample_rate: u32,
139 channels: u32,
140 input_device: u32,
141) -> bindings::ove_audio_device_cfg {
142 let mut cfg: bindings::ove_audio_device_cfg = unsafe { core::mem::zeroed() };
143 cfg.transport = bindings::OVE_AUDIO_TRANSPORT_I2S;
144 cfg.fmt.sample_rate = sample_rate;
145 cfg.fmt.channels = channels;
146 cfg.fmt.sample_fmt = bindings::OVE_AUDIO_FMT_S16;
147 unsafe {
149 let union_ptr = &mut cfg as *mut _ as *mut u8;
150 let i2s_offset = core::mem::offset_of!(bindings::ove_audio_device_cfg, __bindgen_anon_1);
151 let i2s_ptr = union_ptr.add(i2s_offset) as *mut u32;
152 *i2s_ptr = input_device;
153 }
154 cfg
155}
156
157pub struct Graph {
180 inner: bindings::ove_audio_graph,
181}
182
183impl Graph {
184 pub fn new(frames_per_period: u32) -> Result<Self> {
186 let mut inner: bindings::ove_audio_graph = unsafe { core::mem::zeroed() };
187 let rc = unsafe { bindings::ove_audio_graph_init(&mut inner, frames_per_period) };
188 Error::from_code(rc)?;
189 Ok(Self { inner })
190 }
191
192 pub fn device_source(
194 &mut self,
195 cfg: &bindings::ove_audio_device_cfg,
196 name: &[u8],
197 ) -> core::result::Result<u32, Error> {
198 let rc = unsafe {
199 bindings::ove_audio_device_source(
200 &mut self.inner,
201 cfg,
202 name.as_ptr() as *const _,
203 )
204 };
205 if rc < 0 {
206 Err(Error::from_code(rc).unwrap_err())
207 } else {
208 Ok(rc as u32)
209 }
210 }
211
212 pub fn device_sink(
214 &mut self,
215 cfg: &bindings::ove_audio_device_cfg,
216 name: &[u8],
217 ) -> core::result::Result<u32, Error> {
218 let rc = unsafe {
219 bindings::ove_audio_device_sink(
220 &mut self.inner,
221 cfg,
222 name.as_ptr() as *const _,
223 )
224 };
225 if rc < 0 {
226 Err(Error::from_code(rc).unwrap_err())
227 } else {
228 Ok(rc as u32)
229 }
230 }
231
232 pub fn add_processor<T: AudioProcessor>(
234 &mut self,
235 processor: &'static mut T,
236 name: &[u8],
237 ) -> core::result::Result<u32, Error> {
238 graph_add_processor(&mut self.inner, processor, name)
239 .map(|i| i as u32)
240 }
241
242 pub fn connect(&mut self, from: u32, to: u32) -> Result<()> {
244 graph_connect(&mut self.inner, from, to)
245 }
246
247 pub fn build(&mut self) -> Result<()> {
249 graph_build(&mut self.inner)
250 }
251
252 pub fn start(&mut self) -> Result<()> {
254 graph_start(&mut self.inner)
255 }
256
257 pub fn stop(&mut self) -> Result<()> {
259 graph_stop(&mut self.inner)
260 }
261
262 pub fn process(&mut self) -> Result<()> {
264 graph_process(&mut self.inner)
265 }
266}
267
268impl Drop for Graph {
269 fn drop(&mut self) {
270 graph_deinit(&mut self.inner);
271 }
272}
273
274pub struct AudioBuf {
280 raw: *const bindings::ove_audio_buf,
281}
282
283impl AudioBuf {
284 pub fn data_s16(&self) -> &[i16] {
286 unsafe {
287 let buf = &*self.raw;
288 let count = buf.frames as usize * (*buf.fmt).channels as usize;
289 core::slice::from_raw_parts(buf.data as *const i16, count)
290 }
291 }
292
293 pub fn data_s16_mut(&self) -> &mut [i16] {
295 unsafe {
296 let buf = &*self.raw;
297 let count = buf.frames as usize * (*buf.fmt).channels as usize;
298 core::slice::from_raw_parts_mut(buf.data as *mut i16, count)
299 }
300 }
301
302 pub fn frames(&self) -> u32 {
304 unsafe { (*self.raw).frames }
305 }
306}
307
308pub trait AudioProcessor {
325 fn process(&mut self, input: &AudioBuf, output: &AudioBuf);
327}
328
329pub fn graph_add_processor<T: AudioProcessor>(
338 graph: &mut bindings::ove_audio_graph,
339 processor: &'static mut T,
340 name: &[u8],
341) -> core::result::Result<i32, Error> {
342 unsafe extern "C" fn configure_trampoline(
343 _ctx: *mut c_void,
344 in_fmt: *const bindings::ove_audio_fmt,
345 out_fmt: *mut bindings::ove_audio_fmt,
346 ) -> core::ffi::c_int {
347 if !in_fmt.is_null() && !out_fmt.is_null() {
348 *out_fmt = *in_fmt;
349 }
350 0
351 }
352
353 unsafe extern "C" fn process_trampoline<T: AudioProcessor>(
354 ctx: *mut c_void,
355 in_buf: *const bindings::ove_audio_buf,
356 out_buf: *mut bindings::ove_audio_buf,
357 ) -> core::ffi::c_int {
358 let proc_: &mut T = &mut *(ctx as *mut T);
359 let input = AudioBuf { raw: in_buf };
360 let output = AudioBuf { raw: out_buf };
361 proc_.process(&input, &output);
362 0
363 }
364
365 struct OpsHolder<U: AudioProcessor>(core::marker::PhantomData<U>);
368 impl<U: AudioProcessor> OpsHolder<U> {
369 #[allow(invalid_value)]
373 const OPS: bindings::ove_audio_node_ops = {
374 let mut ops: bindings::ove_audio_node_ops = unsafe { core::mem::zeroed() };
375 ops.configure = Some(configure_trampoline);
376 ops.process = Some(process_trampoline::<U>);
377 ops
378 };
379 }
380
381 let ctx = processor as *mut T as *mut c_void;
382 let rc = unsafe {
383 bindings::ove_audio_graph_add_node(
384 graph,
385 &OpsHolder::<T>::OPS,
386 ctx,
387 name.as_ptr() as *const _,
388 bindings::OVE_AUDIO_NODE_PROCESSOR,
389 )
390 };
391 if rc < 0 {
392 Err(Error::from_code(rc).unwrap_err())
393 } else {
394 Ok(rc)
395 }
396}
397
398pub struct StaticProcessor<T> {
408 inner: core::cell::UnsafeCell<T>,
409}
410
411unsafe impl<T: Send> Send for StaticProcessor<T> {}
412unsafe impl<T: Send> Sync for StaticProcessor<T> {}
413
414impl<T> StaticProcessor<T> {
415 pub const fn new(val: T) -> Self {
417 Self {
418 inner: core::cell::UnsafeCell::new(val),
419 }
420 }
421
422 #[allow(clippy::mut_from_ref)]
426 pub fn get_mut(&self) -> &mut T {
427 unsafe { &mut *self.inner.get() }
428 }
429}