1 use std::{
2     ffi::c_void,
3     marker::PhantomData,
4     ops::{Deref, DerefMut},
5     slice::{from_raw_parts, from_raw_parts_mut},
6 };
7 
8 use oboe_sys as ffi;
9 
10 use num_traits::FromPrimitive;
11 
12 use super::{
13     AudioInputStreamSafe, AudioOutputStreamSafe, AudioStreamRef, DataCallbackResult, Error, Input,
14     IsFrameType, Output,
15 };
16 
17 /**
18  * This trait defines a callback interface for:
19  *
20  * 1) moving data to/from an audio stream using `on_audio_ready`
21  * 2) being alerted when a stream has an error using `on_error_*` methods
22  */
23 pub trait AudioInputCallback {
24     /**
25      * The sample type and number of channels for processing.
26      *
27      * Oboe supports only two sample types:
28      *
29      * - **i16** - signed 16-bit integer samples
30      * - **f32** - 32-bit floating point samples
31      *
32      * Oboe supports only mono and stereo channel configurations.
33      */
34     type FrameType: IsFrameType;
35 
36     /**
37      * This will be called when an error occurs on a stream or when the stream is disconnected.
38      *
39      * Note that this will be called on a different thread than the onAudioReady() thread.
40      * This thread will be created by Oboe.
41      *
42      * The underlying stream will already be stopped by Oboe but not yet closed.
43      * So the stream can be queried.
44      *
45      * Do not close or delete the stream in this method because it will be
46      * closed after this method returns.
47      */
on_error_before_close( &mut self, _audio_stream: &mut dyn AudioInputStreamSafe, _error: Error, )48     fn on_error_before_close(
49         &mut self,
50         _audio_stream: &mut dyn AudioInputStreamSafe,
51         _error: Error,
52     ) {
53     }
54 
55     /**
56      * This will be called when an error occurs on a stream or when the stream is disconnected.
57      * The underlying AAudio or OpenSL ES stream will already be stopped AND closed by Oboe.
58      * So the underlying stream cannot be referenced.
59      * But you can still query most parameters.
60      *
61      * This callback could be used to reopen a new stream on another device.
62      * You can safely delete the old AudioStream in this method.
63      */
on_error_after_close( &mut self, _audio_stream: &mut dyn AudioInputStreamSafe, _error: Error, )64     fn on_error_after_close(
65         &mut self,
66         _audio_stream: &mut dyn AudioInputStreamSafe,
67         _error: Error,
68     ) {
69     }
70 
71     /**
72      * A buffer is ready for processing.
73      *
74      * For an output stream, this function should render and write `num_frames` of data
75      * in the stream's current data format to the audioData buffer.
76      *
77      * For an input stream, this function should read and process `num_frames` of data
78      * from the audioData buffer.
79      *
80      * The audio data is passed through the buffer. So do NOT call read() or
81      * write() on the stream that is making the callback.
82      *
83      * Note that numFrames can vary unless AudioStreamBuilder::setFramesPerCallback()
84      * is called.
85      *
86      * Also note that this callback function should be considered a "real-time" function.
87      * It must not do anything that could cause an unbounded delay because that can cause the
88      * audio to glitch or pop.
89      *
90      * These are things the function should NOT do:
91      *
92      * - allocate memory
93      * - any file operations such as opening, closing, reading or writing
94      * - any network operations such as streaming
95      * - use any mutexes or other blocking synchronization primitives
96      * - sleep
97      * - stop or close stream
98      * - read or write on stream which invoked it
99      *
100      * The following are OK to call from the data callback:
101      *
102      * - stream.get_*()
103      *
104      * If you need to move data, eg. MIDI commands, in or out of the callback function then
105      * we recommend the use of non-blocking techniques such as an atomic FIFO.
106      */
on_audio_ready( &mut self, audio_stream: &mut dyn AudioInputStreamSafe, audio_data: &[<Self::FrameType as IsFrameType>::Type], ) -> DataCallbackResult107     fn on_audio_ready(
108         &mut self,
109         audio_stream: &mut dyn AudioInputStreamSafe,
110         audio_data: &[<Self::FrameType as IsFrameType>::Type],
111     ) -> DataCallbackResult;
112 }
113 
114 /**
115  * This trait defines a callback interface for:
116  *
117  * 1) moving data to/from an audio stream using `on_audio_ready`
118  * 2) being alerted when a stream has an error using `on_error_*` methods
119  */
120 pub trait AudioOutputCallback {
121     /**
122      * The sample type and number of channels for processing.
123      *
124      * Oboe supports only two sample types:
125      *
126      * - **i16** - signed 16-bit integer samples
127      * - **f32** - 32-bit floating point samples
128      *
129      * Oboe supports only mono and stereo channel configurations.
130      */
131     type FrameType: IsFrameType;
132 
133     /**
134      * This will be called when an error occurs on a stream or when the stream is disconnected.
135      *
136      * Note that this will be called on a different thread than the onAudioReady() thread.
137      * This thread will be created by Oboe.
138      *
139      * The underlying stream will already be stopped by Oboe but not yet closed.
140      * So the stream can be queried.
141      *
142      * Do not close or delete the stream in this method because it will be
143      * closed after this method returns.
144      */
on_error_before_close( &mut self, _audio_stream: &mut dyn AudioOutputStreamSafe, _error: Error, )145     fn on_error_before_close(
146         &mut self,
147         _audio_stream: &mut dyn AudioOutputStreamSafe,
148         _error: Error,
149     ) {
150     }
151 
152     /**
153      * This will be called when an error occurs on a stream or when the stream is disconnected.
154      * The underlying AAudio or OpenSL ES stream will already be stopped AND closed by Oboe.
155      * So the underlying stream cannot be referenced.
156      * But you can still query most parameters.
157      *
158      * This callback could be used to reopen a new stream on another device.
159      * You can safely delete the old AudioStream in this method.
160      */
on_error_after_close( &mut self, _audio_stream: &mut dyn AudioOutputStreamSafe, _error: Error, )161     fn on_error_after_close(
162         &mut self,
163         _audio_stream: &mut dyn AudioOutputStreamSafe,
164         _error: Error,
165     ) {
166     }
167 
168     /**
169      * A buffer is ready for processing.
170      *
171      * For an output stream, this function should render and write numFrames of data
172      * in the stream's current data format to the audioData buffer.
173      *
174      * For an input stream, this function should read and process numFrames of data
175      * from the audioData buffer.
176      *
177      * The audio data is passed through the buffer. So do NOT call read() or
178      * write() on the stream that is making the callback.
179      *
180      * Note that numFrames can vary unless AudioStreamBuilder::set_frames_per_callback()
181      * is called.
182      *
183      * Also note that this callback function should be considered a "real-time" function.
184      * It must not do anything that could cause an unbounded delay because that can cause the
185      * audio to glitch or pop.
186      *
187      * These are things the function should NOT do:
188      *
189      * - allocate memory
190      * - any file operations such as opening, closing, reading or writing
191      * - any network operations such as streaming
192      * - use any mutexes or other blocking synchronization primitives
193      * - sleep
194      * - stop or close stream
195      * - read or write on stream which invoked it
196      *
197      * The following are OK to call from the data callback:
198      *
199      * - stream.get_*()
200      *
201      * If you need to move data, eg. MIDI commands, in or out of the callback function then
202      * we recommend the use of non-blocking techniques such as an atomic FIFO.
203      */
on_audio_ready( &mut self, audio_stream: &mut dyn AudioOutputStreamSafe, audio_data: &mut [<Self::FrameType as IsFrameType>::Type], ) -> DataCallbackResult204     fn on_audio_ready(
205         &mut self,
206         audio_stream: &mut dyn AudioOutputStreamSafe,
207         audio_data: &mut [<Self::FrameType as IsFrameType>::Type],
208     ) -> DataCallbackResult;
209 }
210 
211 #[repr(transparent)]
212 struct AudioStreamCallbackWrapperHandle(*mut ffi::oboe_AudioStreamCallbackWrapper);
213 
214 impl AudioStreamCallbackWrapperHandle {
new( audio_ready: ffi::oboe_AudioReadyHandler, before_close: ffi::oboe_ErrorCloseHandler, after_close: ffi::oboe_ErrorCloseHandler, ) -> Self215     fn new(
216         audio_ready: ffi::oboe_AudioReadyHandler,
217         before_close: ffi::oboe_ErrorCloseHandler,
218         after_close: ffi::oboe_ErrorCloseHandler,
219     ) -> Self {
220         Self(unsafe {
221             ffi::oboe_AudioStreamCallbackWrapper_new(audio_ready, before_close, after_close)
222         })
223     }
224 }
225 
226 impl Drop for AudioStreamCallbackWrapperHandle {
drop(&mut self)227     fn drop(&mut self) {
228         unsafe { ffi::oboe_AudioStreamCallbackWrapper_delete(self.0) }
229     }
230 }
231 
232 impl Deref for AudioStreamCallbackWrapperHandle {
233     type Target = ffi::oboe_AudioStreamCallbackWrapper;
234 
deref(&self) -> &Self::Target235     fn deref(&self) -> &Self::Target {
236         unsafe { &(*self.0) }
237     }
238 }
239 
240 impl DerefMut for AudioStreamCallbackWrapperHandle {
deref_mut(&mut self) -> &mut Self::Target241     fn deref_mut(&mut self) -> &mut Self::Target {
242         unsafe { &mut (*self.0) }
243     }
244 }
245 
246 pub(crate) struct AudioCallbackWrapper<D, T> {
247     raw: AudioStreamCallbackWrapperHandle,
248     callback: Box<T>,
249     _phantom: PhantomData<D>,
250 }
251 
252 impl<D, T> AudioCallbackWrapper<D, T> {
raw_callback(&mut self) -> &mut ffi::oboe_AudioStreamCallbackWrapper253     pub(crate) fn raw_callback(&mut self) -> &mut ffi::oboe_AudioStreamCallbackWrapper {
254         &mut *self.raw
255     }
256 }
257 
258 impl<T> AudioCallbackWrapper<Input, T>
259 where
260     T: AudioInputCallback,
261 {
wrap(callback: T) -> Self262     pub(crate) fn wrap(callback: T) -> Self {
263         let callback = Box::new(callback);
264         let mut wrapper = Self {
265             raw: AudioStreamCallbackWrapperHandle::new(
266                 Some(on_audio_ready_input_wrapper::<T>),
267                 Some(on_error_before_close_input_wrapper::<T>),
268                 Some(on_error_after_close_input_wrapper::<T>),
269             ),
270             callback,
271             _phantom: PhantomData,
272         };
273         unsafe {
274             (*wrapper.raw).setContext(&mut (*wrapper.callback) as *mut _ as *mut c_void);
275         }
276         wrapper
277     }
278 }
279 
280 impl<T> AudioCallbackWrapper<Output, T>
281 where
282     T: AudioOutputCallback,
283 {
wrap(callback: T) -> Self284     pub(crate) fn wrap(callback: T) -> Self {
285         let callback = Box::new(callback);
286         let mut wrapper = Self {
287             raw: AudioStreamCallbackWrapperHandle::new(
288                 Some(on_audio_ready_output_wrapper::<T>),
289                 Some(on_error_before_close_output_wrapper::<T>),
290                 Some(on_error_after_close_output_wrapper::<T>),
291             ),
292             callback,
293             _phantom: PhantomData,
294         };
295         unsafe {
296             (*wrapper.raw).setContext(&mut (*wrapper.callback) as *mut _ as *mut c_void);
297         }
298         wrapper
299     }
300 }
301 
on_error_before_close_input_wrapper<T: AudioInputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, error: ffi::oboe_Result, )302 unsafe extern "C" fn on_error_before_close_input_wrapper<T: AudioInputCallback>(
303     context: *mut c_void,
304     audio_stream: *mut ffi::oboe_AudioStream,
305     error: ffi::oboe_Result,
306 ) {
307     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
308     let callback = &mut *(context as *mut T);
309 
310     callback.on_error_before_close(&mut audio_stream, FromPrimitive::from_i32(error).unwrap());
311 }
312 
on_error_after_close_input_wrapper<T: AudioInputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, error: ffi::oboe_Result, )313 unsafe extern "C" fn on_error_after_close_input_wrapper<T: AudioInputCallback>(
314     context: *mut c_void,
315     audio_stream: *mut ffi::oboe_AudioStream,
316     error: ffi::oboe_Result,
317 ) {
318     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
319     let callback = &mut *(context as *mut T);
320 
321     callback.on_error_after_close(&mut audio_stream, FromPrimitive::from_i32(error).unwrap());
322 }
323 
on_audio_ready_input_wrapper<T: AudioInputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, audio_data: *mut c_void, num_frames: i32, ) -> ffi::oboe_DataCallbackResult324 unsafe extern "C" fn on_audio_ready_input_wrapper<T: AudioInputCallback>(
325     context: *mut c_void,
326     audio_stream: *mut ffi::oboe_AudioStream,
327     audio_data: *mut c_void,
328     num_frames: i32,
329 ) -> ffi::oboe_DataCallbackResult {
330     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
331 
332     let audio_data = from_raw_parts(
333         audio_data as *const <T::FrameType as IsFrameType>::Type,
334         num_frames as usize,
335     );
336 
337     let callback = &mut *(context as *mut T);
338 
339     callback.on_audio_ready(&mut audio_stream, audio_data) as i32
340 }
341 
on_error_before_close_output_wrapper<T: AudioOutputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, error: ffi::oboe_Result, )342 unsafe extern "C" fn on_error_before_close_output_wrapper<T: AudioOutputCallback>(
343     context: *mut c_void,
344     audio_stream: *mut ffi::oboe_AudioStream,
345     error: ffi::oboe_Result,
346 ) {
347     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
348 
349     let callback = &mut *(context as *mut T);
350 
351     callback.on_error_before_close(&mut audio_stream, FromPrimitive::from_i32(error).unwrap());
352 }
353 
on_error_after_close_output_wrapper<T: AudioOutputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, error: ffi::oboe_Result, )354 unsafe extern "C" fn on_error_after_close_output_wrapper<T: AudioOutputCallback>(
355     context: *mut c_void,
356     audio_stream: *mut ffi::oboe_AudioStream,
357     error: ffi::oboe_Result,
358 ) {
359     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
360     let callback = &mut *(context as *mut T);
361 
362     callback.on_error_after_close(&mut audio_stream, FromPrimitive::from_i32(error).unwrap());
363 }
364 
on_audio_ready_output_wrapper<T: AudioOutputCallback>( context: *mut c_void, audio_stream: *mut ffi::oboe_AudioStream, audio_data: *mut c_void, num_frames: i32, ) -> ffi::oboe_DataCallbackResult365 unsafe extern "C" fn on_audio_ready_output_wrapper<T: AudioOutputCallback>(
366     context: *mut c_void,
367     audio_stream: *mut ffi::oboe_AudioStream,
368     audio_data: *mut c_void,
369     num_frames: i32,
370 ) -> ffi::oboe_DataCallbackResult {
371     let mut audio_stream = AudioStreamRef::wrap_raw(&mut *audio_stream);
372 
373     let audio_data = from_raw_parts_mut(
374         audio_data as *mut <T::FrameType as IsFrameType>::Type,
375         num_frames as usize,
376     );
377 
378     let callback = &mut *(context as *mut T);
379 
380     callback.on_audio_ready(&mut audio_stream, audio_data) as i32
381 }
382