Skip to main content

miniaudio/
decoder.rs

1use crate::base::*;
2use crate::lock::{RwLockReadGuard, RwLockWriteGuard, SpinRwLock};
3use crate::{Error, Format, FramesMut};
4use miniaudio_sys as sys;
5use std::ffi::CString;
6use std::io;
7use std::mem::MaybeUninit;
8use std::ops::{Deref, DerefMut};
9use std::path::Path;
10use std::sync::Arc;
11
12#[repr(transparent)]
13#[derive(Clone)]
14pub struct DecoderConfig(sys::ma_decoder_config);
15
16impl DecoderConfig {
17    #[inline]
18    pub fn new(format: Format, output_channels: u32, output_sample_rate: u32) -> Self {
19        DecoderConfig(unsafe {
20            sys::ma_decoder_config_init(format as _, output_channels as _, output_sample_rate as _)
21        })
22    }
23}
24
25#[repr(transparent)]
26pub struct RawDecoder {
27    inner: sys::ma_decoder,
28}
29
30impl RawDecoder {
31    #[inline]
32    pub fn read_pcm_frames(&mut self, output: &mut FramesMut) -> u64 {
33        assert!(
34            output.format() == self.output_format(),
35            "output and decoder format did not match (output: {:?}, input: {:?}",
36            output.format(),
37            self.output_format()
38        );
39
40        unsafe {
41            sys::ma_decoder_read_pcm_frames(
42                &self.inner as *const _ as *mut _,
43                output.as_mut_ptr() as *mut _,
44                output.frame_count() as u64,
45            )
46        }
47    }
48
49    #[inline]
50    pub fn length_in_pcm_frames(&mut self) -> u64 {
51        unsafe { sys::ma_decoder_get_length_in_pcm_frames(&self.inner as *const _ as *mut _) }
52    }
53
54    #[inline]
55    pub fn seek_to_pcm_frame(&mut self, frame_index: u64) -> Result<(), Error> {
56        Error::from_c_result(unsafe {
57            sys::ma_decoder_seek_to_pcm_frame(&self.inner as *const _ as *mut _, frame_index)
58        })
59    }
60
61    pub fn output_format(&self) -> Format {
62        Format::from_c(self.inner.outputFormat)
63    }
64
65    pub fn output_channels(&self) -> u32 {
66        self.inner.outputChannels as _
67    }
68
69    pub fn output_sample_rate(&self) -> u32 {
70        self.inner.outputSampleRate as _
71    }
72}
73
74impl Drop for RawDecoder {
75    fn drop(&mut self) {
76        Error::from_c_result(unsafe { sys::ma_decoder_uninit(&mut self.inner) })
77            .expect("failed to uninit decoder");
78    }
79}
80
81/// A decoder with synchronization. This will use a spinlock to synchronize access to the decoder
82/// on each function call. The decoder may have multiple readers or one writer. Cloning this
83/// decoder will simply return another reference to the same decoder.
84pub struct SyncDecoder {
85    inner: Arc<SpinRwLock<RawDecoder>>,
86    has_reader: bool,
87}
88
89impl SyncDecoder {
90    /// Creates a `SyncDecoder` from a file. This will fail with an `InvalidFile` error if the path is
91    /// not valid utf-8.
92    pub fn from_file<P: AsRef<Path>>(
93        file: P,
94        config: Option<&DecoderConfig>,
95    ) -> Result<Self, Error> {
96        let decoder = Arc::new(SpinRwLock::new(MaybeUninit::<RawDecoder>::uninit()));
97
98        let filename = file
99            .as_ref()
100            .to_str()
101            .ok_or(Error::InvalidFile)
102            .and_then(|s| CString::new(s.to_string()).map_err(|_err| Error::InvalidFile))?;
103
104        let result = unsafe {
105            sys::ma_decoder_init_file(
106                filename.as_ptr() as *const _,
107                config.map(|c| &c.0 as *const _).unwrap_or(std::ptr::null()),
108                Arc::deref(&decoder).as_ptr() as *mut _,
109            )
110        };
111
112        map_result!(
113            result,
114            SyncDecoder {
115                inner: unsafe { std::mem::transmute(decoder) },
116                has_reader: false,
117            }
118        )
119    }
120
121    pub fn from_memory<M: Into<Vec<u8>>>(
122        data: M,
123        config: Option<&DecoderConfig>,
124    ) -> Result<Self, Error> {
125        Self::from_read(std::io::Cursor::new(data.into()), config)
126    }
127
128    pub fn from_read<T: 'static + SeekRead>(
129        reader: T,
130        config: Option<&DecoderConfig>,
131    ) -> Result<Self, Error> {
132        Self::from_boxed_read(Box::new(reader), config)
133    }
134
135    pub fn from_boxed_read(
136        reader: Box<dyn SeekRead>,
137        config: Option<&DecoderConfig>,
138    ) -> Result<Self, Error> {
139        let decoder = Arc::new(SpinRwLock::new(MaybeUninit::<RawDecoder>::uninit()));
140
141        let user_data = Box::new(reader);
142
143        let result = unsafe {
144            sys::ma_decoder_init(
145                Some(decoder_read_with_reader),
146                Some(decoder_seek_with_reader),
147                Box::into_raw(user_data) as *mut _,
148                config.map(|c| &c.0 as *const _).unwrap_or(std::ptr::null()),
149                Arc::deref(&decoder).as_ptr() as *mut _,
150            )
151        };
152
153        map_result!(
154            result,
155            SyncDecoder {
156                inner: unsafe { std::mem::transmute(decoder) },
157                has_reader: true,
158            }
159        )
160    }
161
162    /// This will block until the lock for the inner decoder is acquired before calling
163    /// `read_pcm_frames`.
164    #[inline]
165    pub fn read_pcm_frames(&self, output: &mut FramesMut) -> u64 {
166        self.inner.write().read_pcm_frames(output)
167    }
168
169    /// This will immediately return with 0 if the inner decoder is currently locked, if it is not
170    /// this will acquire the lock and return the number of frames written.
171    #[inline]
172    pub fn try_read_pcm_frames(&self, output: &mut FramesMut) -> u64 {
173        if let Some(ref mut locked) = self.inner.try_write() {
174            locked.read_pcm_frames(output)
175        } else {
176            0
177        }
178    }
179
180    #[inline]
181    pub fn seek_to_pcm_frame(&self, frame_index: u64) -> Result<(), Error> {
182        self.inner.write().seek_to_pcm_frame(frame_index)
183    }
184
185    #[inline]
186    pub fn length_in_pcm_frames(&self) -> u64 {
187        self.inner.write().length_in_pcm_frames()
188    }
189
190    #[inline]
191    pub fn output_format(&self) -> Format {
192        self.inner.read().output_format()
193    }
194
195    #[inline]
196    pub fn output_channels(&self) -> u32 {
197        self.inner.read().output_channels()
198    }
199
200    #[inline]
201    pub fn output_sample_rate(&self) -> u32 {
202        self.inner.read().output_sample_rate()
203    }
204
205    #[inline]
206    pub fn write(&self) -> RwLockWriteGuard<'_, RawDecoder> {
207        self.inner.write()
208    }
209
210    #[inline]
211    pub fn read(&self) -> RwLockReadGuard<'_, RawDecoder> {
212        self.inner.read()
213    }
214
215    #[inline]
216    pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, RawDecoder>> {
217        self.inner.try_write()
218    }
219
220    #[inline]
221    pub fn try_read(&self) -> Option<RwLockReadGuard<'_, RawDecoder>> {
222        self.inner.try_read()
223    }
224}
225
226impl Clone for SyncDecoder {
227    fn clone(&self) -> SyncDecoder {
228        SyncDecoder {
229            inner: Arc::clone(&self.inner),
230            has_reader: self.has_reader,
231        }
232    }
233}
234
235impl Drop for SyncDecoder {
236    fn drop(&mut self) {
237        if self.has_reader {
238            if let Some(inner) = Arc::get_mut(&mut self.inner) {
239                // Recreate the box and allow it to be dropped.
240                let _reader: Box<Box<dyn SeekRead>> =
241                    unsafe { Box::from_raw((*inner.as_ptr()).inner.pUserData as *mut _) };
242                unsafe { (*inner.as_ptr()).inner.pUserData = std::ptr::null_mut() };
243                self.has_reader = false;
244            }
245        }
246    }
247}
248
249unsafe impl Send for SyncDecoder {}
250unsafe impl Sync for SyncDecoder {}
251
252pub struct Decoder {
253    inner: Box<RawDecoder>,
254    has_reader: bool,
255}
256
257impl Decoder {
258    /// Creates a `Decoder` from a file. This will fail with an `InvalidFile` error if the path is
259    /// not valid utf-8.
260    pub fn from_file<P: AsRef<Path>>(
261        file: P,
262        config: Option<&DecoderConfig>,
263    ) -> Result<Self, Error> {
264        let decoder = Box::new(MaybeUninit::<RawDecoder>::uninit());
265        let filename = file
266            .as_ref()
267            .to_str()
268            .ok_or(Error::InvalidFile)
269            .and_then(|s| CString::new(s.to_string()).map_err(|_err| Error::InvalidFile))?;
270
271        let result = unsafe {
272            sys::ma_decoder_init_file(
273                filename.as_ptr() as *const _,
274                config.map(|c| &c.0 as *const _).unwrap_or(std::ptr::null()),
275                decoder.as_ptr() as *mut _,
276            )
277        };
278
279        map_result!(
280            result,
281            Decoder {
282                inner: unsafe { std::mem::transmute(decoder) },
283                has_reader: false,
284            }
285        )
286    }
287
288    pub fn from_memory<M: Into<Vec<u8>>>(
289        data: M,
290        config: Option<&DecoderConfig>,
291    ) -> Result<Self, Error> {
292        Self::from_read(std::io::Cursor::new(data.into()), config)
293    }
294
295    pub fn from_read<T: 'static + SeekRead>(
296        reader: T,
297        config: Option<&DecoderConfig>,
298    ) -> Result<Self, Error> {
299        Self::from_boxed_read(Box::new(reader), config)
300    }
301
302    pub fn from_boxed_read(
303        reader: Box<dyn SeekRead>,
304        config: Option<&DecoderConfig>,
305    ) -> Result<Self, Error> {
306        let decoder = Box::new(MaybeUninit::<RawDecoder>::uninit());
307        let user_data = Box::new(reader);
308
309        let result = unsafe {
310            sys::ma_decoder_init(
311                Some(decoder_read_with_reader),
312                Some(decoder_seek_with_reader),
313                Box::into_raw(user_data) as *mut _,
314                config.map(|c| &c.0 as *const _).unwrap_or(std::ptr::null()),
315                decoder.as_ptr() as *mut _,
316            )
317        };
318
319        map_result!(
320            result,
321            Decoder {
322                inner: unsafe { std::mem::transmute(decoder) },
323                has_reader: true,
324            }
325        )
326    }
327}
328
329pub trait SeekRead: io::Read + io::Seek {}
330
331// Create a blanket implementation so that everything that implements both
332// io::Read and io::Seek also implements SeekRead.
333impl<T> SeekRead for T where T: io::Read + io::Seek {}
334
335unsafe extern "C" fn decoder_read_with_reader(
336    decoder: *mut sys::ma_decoder,
337    buffer_out: *mut std::ffi::c_void,
338    bytes_to_read: usize,
339) -> usize {
340    if decoder.is_null() {
341        return 0;
342    }
343
344    let reader: &mut Box<dyn SeekRead> = &mut *((*decoder).pUserData as *mut _);
345    let buffer = std::slice::from_raw_parts_mut(buffer_out as _, bytes_to_read);
346
347    reader.read(buffer).ok().unwrap_or(0)
348}
349
350unsafe extern "C" fn decoder_seek_with_reader(
351    decoder: *mut sys::ma_decoder,
352    byte_offset: std::os::raw::c_int,
353    origin: sys::ma_seek_origin,
354) -> sys::ma_bool32 {
355    if decoder.is_null() {
356        return to_bool32(false);
357    }
358
359    let reader: &mut Box<dyn SeekRead> = &mut *((*decoder).pUserData as *mut _);
360    let pos = match origin {
361        sys::ma_seek_origin_start => io::SeekFrom::Start(byte_offset as _),
362        sys::ma_seek_origin_current => io::SeekFrom::Current(byte_offset as _),
363        sys::ma_seek_origin_end => io::SeekFrom::End(byte_offset as _),
364
365        // FIXME: unwinding in foreign code causes undefined behavior, we shouldn't be hitting this
366        // path though.
367        _ => unreachable!("unknown seek origin"),
368    };
369
370    to_bool32(reader.seek(pos).is_ok())
371}
372
373impl Deref for Decoder {
374    type Target = RawDecoder;
375
376    fn deref(&self) -> &Self::Target {
377        &self.inner
378    }
379}
380
381impl DerefMut for Decoder {
382    fn deref_mut(&mut self) -> &mut Self::Target {
383        &mut self.inner
384    }
385}
386
387impl Drop for Decoder {
388    fn drop(&mut self) {
389        if self.has_reader {
390            // Recreate the box and allow it to be dropped.
391            let _reader: Box<Box<dyn SeekRead>> =
392                unsafe { Box::from_raw(self.inner.inner.pUserData as *mut _) };
393            self.has_reader = false;
394            self.inner.inner.pUserData = std::ptr::null_mut();
395        }
396    }
397}
398
399unsafe impl Send for Decoder {}
400unsafe impl Sync for Decoder {}