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