1use libc::{c_char, c_int, c_void};
56use std::convert::TryFrom;
57use std::ffi::{CStr, CString};
58use std::marker::PhantomData;
59use std::mem;
60use std::ops::{Deref, DerefMut};
61use std::path::Path;
62use std::ptr;
63
64use crate::get_error;
65use crate::rwops::RWops;
66use crate::AudioSubsystem;
67
68use crate::sys;
69use crate::sys::SDL_AudioStatus;
70
71impl AudioSubsystem {
72 #[inline]
78 pub fn open_playback<'a, CB, F, D>(
79 &self,
80 device: D,
81 spec: &AudioSpecDesired,
82 get_callback: F,
83 ) -> Result<AudioDevice<CB>, String>
84 where
85 CB: AudioCallback,
86 F: FnOnce(AudioSpec) -> CB,
87 D: Into<Option<&'a str>>,
88 {
89 AudioDevice::open_playback(self, device, spec, get_callback)
90 }
91
92 pub fn open_capture<'a, CB, F, D>(
99 &self,
100 device: D,
101 spec: &AudioSpecDesired,
102 get_callback: F,
103 ) -> Result<AudioDevice<CB>, String>
104 where
105 CB: AudioCallback,
106 F: FnOnce(AudioSpec) -> CB,
107 D: Into<Option<&'a str>>,
108 {
109 AudioDevice::open_capture(self, device, spec, get_callback)
110 }
111
112 #[inline]
114 pub fn open_queue<'a, Channel, D>(
115 &self,
116 device: D,
117 spec: &AudioSpecDesired,
118 ) -> Result<AudioQueue<Channel>, String>
119 where
120 Channel: AudioFormatNum,
121 D: Into<Option<&'a str>>,
122 {
123 AudioQueue::open_queue(self, device, spec)
124 }
125
126 #[doc(alias = "SDL_GetCurrentAudioDriver")]
127 pub fn current_audio_driver(&self) -> &'static str {
128 unsafe {
129 let buf = sys::SDL_GetCurrentAudioDriver();
130 assert!(!buf.is_null());
131
132 CStr::from_ptr(buf as *const _).to_str().unwrap()
133 }
134 }
135
136 #[doc(alias = "SDL_GetNumAudioDevices")]
137 pub fn num_audio_playback_devices(&self) -> Option<u32> {
138 let result = unsafe { sys::SDL_GetNumAudioDevices(0) };
139 if result < 0 {
140 None
142 } else {
143 Some(result as u32)
144 }
145 }
146
147 #[doc(alias = "SDL_GetNumAudioDevices")]
148 pub fn num_audio_capture_devices(&self) -> Option<u32> {
149 let result = unsafe { sys::SDL_GetNumAudioDevices(1) };
150 if result < 0 {
151 None
153 } else {
154 Some(result as u32)
155 }
156 }
157
158 #[doc(alias = "SDL_GetAudioDeviceName")]
159 pub fn audio_playback_device_name(&self, index: u32) -> Result<String, String> {
160 unsafe {
161 let dev_name = sys::SDL_GetAudioDeviceName(index as c_int, 0);
162 if dev_name.is_null() {
163 Err(get_error())
164 } else {
165 let cstr = CStr::from_ptr(dev_name as *const _);
166 Ok(cstr.to_str().unwrap().to_owned())
167 }
168 }
169 }
170
171 #[doc(alias = "SDL_GetAudioDeviceName")]
172 pub fn audio_capture_device_name(&self, index: u32) -> Result<String, String> {
173 unsafe {
174 let dev_name = sys::SDL_GetAudioDeviceName(index as c_int, 1);
175 if dev_name.is_null() {
176 Err(get_error())
177 } else {
178 let cstr = CStr::from_ptr(dev_name as *const _);
179 Ok(cstr.to_str().unwrap().to_owned())
180 }
181 }
182 }
183
184 #[doc(alias = "SDL_GetAudioDeviceSpec")]
185 pub fn audio_playback_device_spec(&self, index: u32) -> Result<AudioSpec, String> {
186 let mut spec = sys::SDL_AudioSpec {
187 freq: 0,
188 format: 0,
189 channels: 0,
190 silence: 0,
191 samples: 0,
192 padding: 0,
193 size: 0,
194 callback: None,
195 userdata: ptr::null_mut(),
196 };
197
198 let result = unsafe { sys::SDL_GetAudioDeviceSpec(index as c_int, 0, &mut spec) };
199 if result != 0 {
200 Err(get_error())
201 } else {
202 Ok(AudioSpec::convert_from_ll(spec))
203 }
204 }
205 #[doc(alias = "SDL_GetAudioDeviceSpec")]
206 pub fn audio_capture_device_spec(&self, index: u32) -> Result<AudioSpec, String> {
207 let mut spec = sys::SDL_AudioSpec {
208 freq: 0,
209 format: 0,
210 channels: 0,
211 silence: 0,
212 samples: 0,
213 padding: 0,
214 size: 0,
215 callback: None,
216 userdata: ptr::null_mut(),
217 };
218
219 let result = unsafe { sys::SDL_GetAudioDeviceSpec(index as c_int, 1, &mut spec) };
220 if result != 0 {
221 Err(get_error())
222 } else {
223 Ok(AudioSpec::convert_from_ll(spec))
224 }
225 }
226}
227
228#[repr(i32)]
229#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
230pub enum AudioFormat {
231 U8 = sys::AUDIO_U8 as i32,
233 S8 = sys::AUDIO_S8 as i32,
235 U16LSB = sys::AUDIO_U16LSB as i32,
237 U16MSB = sys::AUDIO_U16MSB as i32,
239 S16LSB = sys::AUDIO_S16LSB as i32,
241 S16MSB = sys::AUDIO_S16MSB as i32,
243 S32LSB = sys::AUDIO_S32LSB as i32,
245 S32MSB = sys::AUDIO_S32MSB as i32,
247 F32LSB = sys::AUDIO_F32LSB as i32,
249 F32MSB = sys::AUDIO_F32MSB as i32,
251}
252
253impl AudioFormat {
254 fn from_ll(raw: sys::SDL_AudioFormat) -> Option<AudioFormat> {
255 use self::AudioFormat::*;
256 match raw as u32 {
257 sys::AUDIO_U8 => Some(U8),
258 sys::AUDIO_S8 => Some(S8),
259 sys::AUDIO_U16LSB => Some(U16LSB),
260 sys::AUDIO_U16MSB => Some(U16MSB),
261 sys::AUDIO_S16LSB => Some(S16LSB),
262 sys::AUDIO_S16MSB => Some(S16MSB),
263 sys::AUDIO_S32LSB => Some(S32LSB),
264 sys::AUDIO_S32MSB => Some(S32MSB),
265 sys::AUDIO_F32LSB => Some(F32LSB),
266 sys::AUDIO_F32MSB => Some(F32MSB),
267 _ => None,
268 }
269 }
270
271 #[doc(alias = "SDL_AudioFormat")]
272 fn to_ll(self) -> sys::SDL_AudioFormat {
273 self as sys::SDL_AudioFormat
274 }
275}
276
277#[cfg(target_endian = "little")]
278impl AudioFormat {
279 #[inline]
281 pub const fn u16_sys() -> AudioFormat {
282 AudioFormat::U16LSB
283 }
284 #[inline]
286 pub const fn s16_sys() -> AudioFormat {
287 AudioFormat::S16LSB
288 }
289 #[inline]
291 pub const fn s32_sys() -> AudioFormat {
292 AudioFormat::S32LSB
293 }
294 #[inline]
296 pub const fn f32_sys() -> AudioFormat {
297 AudioFormat::F32LSB
298 }
299}
300
301#[cfg(target_endian = "big")]
302impl AudioFormat {
303 #[inline]
305 pub const fn u16_sys() -> AudioFormat {
306 AudioFormat::U16MSB
307 }
308 #[inline]
310 pub const fn s16_sys() -> AudioFormat {
311 AudioFormat::S16MSB
312 }
313 #[inline]
315 pub const fn s32_sys() -> AudioFormat {
316 AudioFormat::S32MSB
317 }
318 #[inline]
320 pub const fn f32_sys() -> AudioFormat {
321 AudioFormat::F32MSB
322 }
323}
324
325#[repr(i32)]
326#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
327pub enum AudioStatus {
328 Stopped = SDL_AudioStatus::SDL_AUDIO_STOPPED as i32,
329 Playing = SDL_AudioStatus::SDL_AUDIO_PLAYING as i32,
330 Paused = SDL_AudioStatus::SDL_AUDIO_PAUSED as i32,
331}
332
333impl TryFrom<u32> for AudioStatus {
334 type Error = ();
335
336 fn try_from(n: u32) -> Result<Self, Self::Error> {
337 use self::AudioStatus::*;
338 use crate::sys::SDL_AudioStatus::*;
339
340 Ok(match unsafe { mem::transmute(n) } {
341 SDL_AUDIO_STOPPED => Stopped,
342 SDL_AUDIO_PLAYING => Playing,
343 SDL_AUDIO_PAUSED => Paused,
344 })
345 }
346}
347
348#[doc(alias = "SDL_GetAudioDriver")]
349#[derive(Copy, Clone)]
350pub struct DriverIterator {
351 length: i32,
352 index: i32,
353}
354
355fn get_audio_driver(index: i32) -> &'static str {
359 unsafe {
360 let buf = sys::SDL_GetAudioDriver(index);
361 assert!(!buf.is_null());
362
363 CStr::from_ptr(buf as *const _).to_str().unwrap()
364 }
365}
366
367impl Iterator for DriverIterator {
368 type Item = &'static str;
369
370 #[inline]
371 fn next(&mut self) -> Option<&'static str> {
372 if self.index >= self.length {
373 None
374 } else {
375 let driver = get_audio_driver(self.index);
376 self.index += 1;
377
378 Some(driver)
379 }
380 }
381
382 #[inline]
383 fn size_hint(&self) -> (usize, Option<usize>) {
384 let remaining = (self.length - self.index) as usize;
385 (remaining, Some(remaining))
386 }
387
388 #[inline]
389 fn nth(&mut self, n: usize) -> Option<&'static str> {
390 use std::convert::TryInto;
391
392 self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
393 Some(index) if index < self.length => index,
394 _ => self.length,
395 };
396
397 self.next()
398 }
399}
400
401impl DoubleEndedIterator for DriverIterator {
402 #[inline]
403 fn next_back(&mut self) -> Option<&'static str> {
404 if self.index >= self.length {
405 None
406 } else {
407 self.length -= 1;
408
409 Some(get_audio_driver(self.length))
410 }
411 }
412
413 #[inline]
414 fn nth_back(&mut self, n: usize) -> Option<&'static str> {
415 use std::convert::TryInto;
416
417 self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
418 Some(length) if length > self.index => length,
419 _ => self.index,
420 };
421
422 self.next_back()
423 }
424}
425
426impl ExactSizeIterator for DriverIterator {}
427
428impl std::iter::FusedIterator for DriverIterator {}
429
430#[doc(alias = "SDL_GetAudioDriver")]
432#[inline]
433pub fn drivers() -> DriverIterator {
434 DriverIterator {
439 length: unsafe { sys::SDL_GetNumAudioDrivers() },
440 index: 0,
441 }
442}
443
444pub struct AudioSpecWAV {
445 pub freq: i32,
446 pub format: AudioFormat,
447 pub channels: u8,
448 audio_buf: *mut u8,
449 audio_len: u32,
450}
451
452impl AudioSpecWAV {
453 pub fn load_wav<P: AsRef<Path>>(path: P) -> Result<AudioSpecWAV, String> {
455 let mut file = RWops::from_file(path, "rb")?;
456 AudioSpecWAV::load_wav_rw(&mut file)
457 }
458
459 #[doc(alias = "SDL_LoadWAV_RW")]
461 pub fn load_wav_rw(src: &mut RWops) -> Result<AudioSpecWAV, String> {
462 use std::mem::MaybeUninit;
463 use std::ptr::null_mut;
464
465 let mut desired = MaybeUninit::uninit();
466 let mut audio_buf: *mut u8 = null_mut();
467 let mut audio_len: u32 = 0;
468 unsafe {
469 let ret = sys::SDL_LoadWAV_RW(
470 src.raw(),
471 0,
472 desired.as_mut_ptr(),
473 &mut audio_buf,
474 &mut audio_len,
475 );
476 if ret.is_null() {
477 Err(get_error())
478 } else {
479 let desired = desired.assume_init();
480 Ok(AudioSpecWAV {
481 freq: desired.freq,
482 format: AudioFormat::from_ll(desired.format).unwrap(),
483 channels: desired.channels,
484 audio_buf,
485 audio_len,
486 })
487 }
488 }
489 }
490
491 pub fn buffer(&self) -> &[u8] {
492 use std::slice::from_raw_parts;
493 unsafe {
494 let ptr = self.audio_buf as *const u8;
495 let len = self.audio_len as usize;
496 from_raw_parts(ptr, len)
497 }
498 }
499}
500
501impl Drop for AudioSpecWAV {
502 #[doc(alias = "SDL_FreeWAV")]
503 fn drop(&mut self) {
504 unsafe {
505 sys::SDL_FreeWAV(self.audio_buf);
506 }
507 }
508}
509
510pub trait AudioCallback: Send
511where
512 Self::Channel: AudioFormatNum + 'static,
513{
514 type Channel;
515
516 fn callback(&mut self, _: &mut [Self::Channel]);
517}
518
519pub trait AudioFormatNum {
522 fn audio_format() -> AudioFormat;
523
524 const SILENCE: Self;
545}
546
547impl AudioFormatNum for i8 {
549 fn audio_format() -> AudioFormat {
550 AudioFormat::S8
551 }
552 const SILENCE: i8 = 0;
553}
554impl AudioFormatNum for u8 {
556 fn audio_format() -> AudioFormat {
557 AudioFormat::U8
558 }
559 const SILENCE: u8 = 0x80;
560}
561impl AudioFormatNum for i16 {
563 fn audio_format() -> AudioFormat {
564 AudioFormat::s16_sys()
565 }
566 const SILENCE: i16 = 0;
567}
568impl AudioFormatNum for u16 {
570 fn audio_format() -> AudioFormat {
571 AudioFormat::u16_sys()
572 }
573 const SILENCE: u16 = 0x8000;
574}
575impl AudioFormatNum for i32 {
577 fn audio_format() -> AudioFormat {
578 AudioFormat::s32_sys()
579 }
580 const SILENCE: i32 = 0;
581}
582impl AudioFormatNum for f32 {
584 fn audio_format() -> AudioFormat {
585 AudioFormat::f32_sys()
586 }
587 const SILENCE: f32 = 0.0;
588}
589
590extern "C" fn audio_callback_marshall<CB: AudioCallback>(
591 userdata: *mut c_void,
592 stream: *mut u8,
593 len: c_int,
594) {
595 use std::mem::size_of;
596 use std::slice::from_raw_parts_mut;
597 unsafe {
598 let cb_userdata: &mut Option<CB> = &mut *(userdata as *mut _);
599 let buf: &mut [CB::Channel] = from_raw_parts_mut(
600 stream as *mut CB::Channel,
601 len as usize / size_of::<CB::Channel>(),
602 );
603
604 if let Some(cb) = cb_userdata {
605 cb.callback(buf);
606 }
607 }
608}
609
610#[derive(Clone)]
611pub struct AudioSpecDesired {
612 pub freq: Option<i32>,
614 pub channels: Option<u8>,
616 pub samples: Option<u16>,
618}
619
620impl AudioSpecDesired {
621 fn convert_to_ll<CB, F, C, S>(
622 freq: F,
623 channels: C,
624 samples: S,
625 userdata: *mut Option<CB>,
626 ) -> sys::SDL_AudioSpec
627 where
628 CB: AudioCallback,
629 F: Into<Option<i32>>,
630 C: Into<Option<u8>>,
631 S: Into<Option<u16>>,
632 {
633 let freq = freq.into();
634 let channels = channels.into();
635 let samples = samples.into();
636
637 if let Some(freq) = freq {
638 assert!(freq > 0);
639 }
640 if let Some(channels) = channels {
641 assert!(channels > 0);
642 }
643 if let Some(samples) = samples {
644 assert!(samples > 0);
645 }
646
647 sys::SDL_AudioSpec {
650 freq: freq.unwrap_or(0),
651 format: <CB::Channel as AudioFormatNum>::audio_format().to_ll(),
652 channels: channels.unwrap_or(0),
653 silence: 0,
654 samples: samples.unwrap_or(0),
655 padding: 0,
656 size: 0,
657 callback: Some(
658 audio_callback_marshall::<CB>
659 as extern "C" fn(arg1: *mut c_void, arg2: *mut u8, arg3: c_int),
660 ),
661 userdata: userdata as *mut _,
662 }
663 }
664
665 fn convert_queue_to_ll<Channel, F, C, S>(freq: F, channels: C, samples: S) -> sys::SDL_AudioSpec
666 where
667 Channel: AudioFormatNum,
668 F: Into<Option<i32>>,
669 C: Into<Option<u8>>,
670 S: Into<Option<u16>>,
671 {
672 let freq = freq.into();
673 let channels = channels.into();
674 let samples = samples.into();
675
676 if let Some(freq) = freq {
677 assert!(freq > 0);
678 }
679 if let Some(channels) = channels {
680 assert!(channels > 0);
681 }
682 if let Some(samples) = samples {
683 assert!(samples > 0);
684 }
685
686 sys::SDL_AudioSpec {
689 freq: freq.unwrap_or(0),
690 format: <Channel as AudioFormatNum>::audio_format().to_ll(),
691 channels: channels.unwrap_or(0),
692 silence: 0,
693 samples: samples.unwrap_or(0),
694 padding: 0,
695 size: 0,
696 callback: None,
697 userdata: ptr::null_mut(),
698 }
699 }
700}
701
702#[allow(missing_copy_implementations)]
703#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
704pub struct AudioSpec {
705 pub freq: i32,
706 pub format: AudioFormat,
707 pub channels: u8,
708 pub silence: u8,
713 pub samples: u16,
714 pub size: u32,
715}
716
717impl AudioSpec {
718 fn convert_from_ll(spec: sys::SDL_AudioSpec) -> AudioSpec {
719 AudioSpec {
720 freq: spec.freq,
721 format: AudioFormat::from_ll(spec.format).unwrap(),
722 channels: spec.channels,
723 silence: spec.silence,
724 samples: spec.samples,
725 size: spec.size,
726 }
727 }
728}
729
730enum AudioDeviceID {
731 PlaybackDevice(sys::SDL_AudioDeviceID),
732}
733
734impl AudioDeviceID {
735 fn id(&self) -> sys::SDL_AudioDeviceID {
736 match *self {
737 AudioDeviceID::PlaybackDevice(id) => id,
738 }
739 }
740}
741
742impl Drop for AudioDeviceID {
743 #[doc(alias = "SDL_CloseAudioDevice")]
744 fn drop(&mut self) {
745 unsafe { sys::SDL_CloseAudioDevice(self.id()) }
747 }
748}
749
750pub struct AudioQueue<Channel: AudioFormatNum> {
752 subsystem: AudioSubsystem,
753 device_id: AudioDeviceID,
754 phantom: PhantomData<Channel>,
755 spec: AudioSpec,
756}
757
758impl<'a, Channel: AudioFormatNum> AudioQueue<Channel> {
759 #[doc(alias = "SDL_OpenAudioDevice")]
761 pub fn open_queue<D: Into<Option<&'a str>>>(
762 a: &AudioSubsystem,
763 device: D,
764 spec: &AudioSpecDesired,
765 ) -> Result<AudioQueue<Channel>, String> {
766 use std::mem::MaybeUninit;
767
768 let desired = AudioSpecDesired::convert_queue_to_ll::<
769 Channel,
770 Option<i32>,
771 Option<u8>,
772 Option<u16>,
773 >(spec.freq, spec.channels, spec.samples);
774
775 let mut obtained = MaybeUninit::uninit();
776 unsafe {
777 let device = device.into().map(|device| CString::new(device).unwrap());
778 let device_ptr = device.as_ref().map_or(ptr::null(), |s| s.as_ptr());
782
783 let iscapture_flag = 0;
784 let device_id = sys::SDL_OpenAudioDevice(
785 device_ptr as *const c_char,
786 iscapture_flag,
787 &desired,
788 obtained.as_mut_ptr(),
789 0,
790 );
791 match device_id {
792 0 => Err(get_error()),
793 id => {
794 let obtained = obtained.assume_init();
795 let device_id = AudioDeviceID::PlaybackDevice(id);
796 let spec = AudioSpec::convert_from_ll(obtained);
797
798 Ok(AudioQueue {
799 subsystem: a.clone(),
800 device_id,
801 phantom: PhantomData,
802 spec,
803 })
804 }
805 }
806 }
807 }
808
809 #[inline]
810 #[doc(alias = "SDL_GetAudioDeviceStatus")]
811 pub fn subsystem(&self) -> &AudioSubsystem {
812 &self.subsystem
813 }
814
815 #[inline]
816 pub fn spec(&self) -> &AudioSpec {
817 &self.spec
818 }
819
820 pub fn status(&self) -> AudioStatus {
821 unsafe {
822 let status = sys::SDL_GetAudioDeviceStatus(self.device_id.id());
823 AudioStatus::try_from(status as u32).unwrap()
824 }
825 }
826
827 #[doc(alias = "SDL_PauseAudioDevice")]
829 pub fn pause(&self) {
830 unsafe { sys::SDL_PauseAudioDevice(self.device_id.id(), 1) }
831 }
832
833 #[doc(alias = "SDL_PauseAudioDevice")]
835 pub fn resume(&self) {
836 unsafe { sys::SDL_PauseAudioDevice(self.device_id.id(), 0) }
837 }
838
839 #[doc(alias = "SDL_QueueAudio")]
841 #[deprecated(
842 since = "0.35.2",
843 note = "Users should instead use AudioQueue::queue_audio"
844 )]
845 pub fn queue(&self, data: &[Channel]) -> bool {
846 let result = unsafe {
847 sys::SDL_QueueAudio(
848 self.device_id.id(),
849 data.as_ptr() as *const c_void,
850 mem::size_of_val(data) as u32,
851 )
852 };
853 result == 0
854 }
855
856 #[doc(alias = "SDL_QueueAudio")]
858 pub fn queue_audio(&self, data: &[Channel]) -> Result<(), String> {
859 let result = unsafe {
860 sys::SDL_QueueAudio(
861 self.device_id.id(),
862 data.as_ptr() as *const c_void,
863 mem::size_of_val(data) as u32,
864 )
865 };
866 if result == 0 {
867 Ok(())
868 } else {
869 Err(get_error())
870 }
871 }
872
873 #[doc(alias = "SDL_GetQueuedAudioSize")]
874 pub fn size(&self) -> u32 {
875 unsafe { sys::SDL_GetQueuedAudioSize(self.device_id.id()) }
876 }
877
878 #[doc(alias = "SDL_ClearQueuedAudio")]
880 pub fn clear(&self) {
881 unsafe {
882 sys::SDL_ClearQueuedAudio(self.device_id.id());
883 }
884 }
885}
886
887pub struct AudioDevice<CB: AudioCallback> {
889 subsystem: AudioSubsystem,
890 device_id: AudioDeviceID,
891 spec: AudioSpec,
892 userdata: Box<Option<CB>>,
894}
895
896impl<CB: AudioCallback> AudioDevice<CB> {
897 #[doc(alias = "SDL_OpenAudioDevice")]
899 fn open<'a, F, D>(
900 a: &AudioSubsystem,
901 device: D,
902 spec: &AudioSpecDesired,
903 get_callback: F,
904 capture: bool,
905 ) -> Result<AudioDevice<CB>, String>
906 where
907 F: FnOnce(AudioSpec) -> CB,
908 D: Into<Option<&'a str>>,
909 {
910 use std::mem::MaybeUninit;
911
912 let mut userdata: Box<Option<CB>> = Box::new(None);
913 let desired =
914 AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, &mut *userdata);
915
916 let mut obtained = MaybeUninit::uninit();
917 unsafe {
918 let device = device.into().map(|device| CString::new(device).unwrap());
919 let device_ptr = device.as_ref().map_or(ptr::null(), |s| s.as_ptr());
923
924 let iscapture_flag = if capture { 1 } else { 0 };
925 let device_id = sys::SDL_OpenAudioDevice(
926 device_ptr as *const c_char,
927 iscapture_flag,
928 &desired,
929 obtained.as_mut_ptr(),
930 0,
931 );
932 match device_id {
933 0 => Err(get_error()),
934 id => {
935 let obtained = obtained.assume_init();
936 let device_id = AudioDeviceID::PlaybackDevice(id);
937 let spec = AudioSpec::convert_from_ll(obtained);
938
939 *userdata = Some(get_callback(spec));
940
941 Ok(AudioDevice {
942 subsystem: a.clone(),
943 device_id,
944 userdata,
945 spec,
946 })
947 }
948 }
949 }
950 }
951
952 pub fn open_playback<'a, F, D>(
957 a: &AudioSubsystem,
958 device: D,
959 spec: &AudioSpecDesired,
960 get_callback: F,
961 ) -> Result<AudioDevice<CB>, String>
962 where
963 F: FnOnce(AudioSpec) -> CB,
964 D: Into<Option<&'a str>>,
965 {
966 AudioDevice::open(a, device, spec, get_callback, false)
967 }
968
969 pub fn open_capture<'a, F, D>(
975 a: &AudioSubsystem,
976 device: D,
977 spec: &AudioSpecDesired,
978 get_callback: F,
979 ) -> Result<AudioDevice<CB>, String>
980 where
981 F: FnOnce(AudioSpec) -> CB,
982 D: Into<Option<&'a str>>,
983 {
984 AudioDevice::open(a, device, spec, get_callback, true)
985 }
986
987 #[inline]
988 #[doc(alias = "SDL_GetAudioDeviceStatus")]
989 pub fn subsystem(&self) -> &AudioSubsystem {
990 &self.subsystem
991 }
992
993 #[inline]
994 pub fn spec(&self) -> &AudioSpec {
995 &self.spec
996 }
997
998 pub fn status(&self) -> AudioStatus {
999 unsafe {
1000 let status = sys::SDL_GetAudioDeviceStatus(self.device_id.id());
1001 AudioStatus::try_from(status as u32).unwrap()
1002 }
1003 }
1004
1005 #[doc(alias = "SDL_PauseAudioDevice")]
1007 pub fn pause(&self) {
1008 unsafe { sys::SDL_PauseAudioDevice(self.device_id.id(), 1) }
1009 }
1010
1011 #[doc(alias = "SDL_PauseAudioDevice")]
1013 pub fn resume(&self) {
1014 unsafe { sys::SDL_PauseAudioDevice(self.device_id.id(), 0) }
1015 }
1016
1017 #[doc(alias = "SDL_LockAudioDevice")]
1023 pub fn lock(&mut self) -> AudioDeviceLockGuard<CB> {
1024 unsafe { sys::SDL_LockAudioDevice(self.device_id.id()) };
1025 AudioDeviceLockGuard {
1026 device: self,
1027 _nosend: PhantomData,
1028 }
1029 }
1030
1031 pub fn close_and_get_callback(self) -> CB {
1036 drop(self.device_id);
1037 self.userdata.expect("Missing callback")
1038 }
1039}
1040
1041pub struct AudioDeviceLockGuard<'a, CB>
1043where
1044 CB: AudioCallback,
1045 CB: 'a,
1046{
1047 device: &'a mut AudioDevice<CB>,
1048 _nosend: PhantomData<*mut ()>,
1049}
1050
1051impl<'a, CB: AudioCallback> Deref for AudioDeviceLockGuard<'a, CB> {
1052 type Target = CB;
1053 #[doc(alias = "SDL_UnlockAudioDevice")]
1054 fn deref(&self) -> &CB {
1055 (*self.device.userdata).as_ref().expect("Missing callback")
1056 }
1057}
1058
1059impl<'a, CB: AudioCallback> DerefMut for AudioDeviceLockGuard<'a, CB> {
1060 fn deref_mut(&mut self) -> &mut CB {
1061 (*self.device.userdata).as_mut().expect("Missing callback")
1062 }
1063}
1064
1065impl<'a, CB: AudioCallback> Drop for AudioDeviceLockGuard<'a, CB> {
1066 fn drop(&mut self) {
1067 unsafe { sys::SDL_UnlockAudioDevice(self.device.device_id.id()) }
1068 }
1069}
1070
1071#[derive(Copy, Clone)]
1072pub struct AudioCVT {
1073 raw: sys::SDL_AudioCVT,
1074}
1075
1076impl AudioCVT {
1077 #[doc(alias = "SDL_BuildAudioCVT")]
1078 pub fn new(
1079 src_format: AudioFormat,
1080 src_channels: u8,
1081 src_rate: i32,
1082 dst_format: AudioFormat,
1083 dst_channels: u8,
1084 dst_rate: i32,
1085 ) -> Result<AudioCVT, String> {
1086 use std::mem::MaybeUninit;
1087
1088 let mut raw: MaybeUninit<sys::SDL_AudioCVT> = mem::MaybeUninit::uninit();
1089
1090 unsafe {
1091 let ret = sys::SDL_BuildAudioCVT(
1092 raw.as_mut_ptr(),
1093 src_format.to_ll(),
1094 src_channels,
1095 src_rate as c_int,
1096 dst_format.to_ll(),
1097 dst_channels,
1098 dst_rate as c_int,
1099 );
1100 if ret == 1 || ret == 0 {
1101 let raw = raw.assume_init();
1102 Ok(AudioCVT { raw })
1103 } else {
1104 Err(get_error())
1105 }
1106 }
1107 }
1108
1109 #[doc(alias = "SDL_ConvertAudio")]
1110 pub fn convert(&self, mut src: Vec<u8>) -> Vec<u8> {
1111 unsafe {
1116 if self.raw.needed != 0 {
1117 use std::convert::TryInto;
1118 use std::slice::from_raw_parts_mut;
1119
1120 let mut raw = self.raw;
1121
1122 let dst_size = self.capacity(src.len());
1125
1126 raw.len = src.len().try_into().expect("Buffer length overflow");
1128 raw.buf = sys::SDL_malloc(dst_size as _) as *mut _;
1129 if raw.buf.is_null() {
1130 panic!("Failed SDL_malloc needed for SDL_ConvertAudio");
1131 }
1132 assert!(src.len() <= dst_size);
1134 from_raw_parts_mut(raw.buf, src.len()).copy_from_slice(src.as_ref());
1135
1136 let ret = sys::SDL_ConvertAudio(&mut raw);
1137 if ret != 0 {
1140 panic!("{}", get_error())
1141 }
1142
1143 let outlen: usize = raw.len_cvt.try_into().expect("Buffer size rollover");
1145 debug_assert!(outlen <= dst_size);
1146 src.resize(outlen, 0);
1147 src.copy_from_slice(from_raw_parts_mut(raw.buf, outlen));
1148 sys::SDL_free(raw.buf as *mut _);
1149
1150 src
1151 } else {
1152 src
1154 }
1155 }
1156 }
1157
1158 pub fn is_conversion_needed(&self) -> bool {
1161 self.raw.needed != 0
1162 }
1163
1164 pub fn capacity(&self, src_len: usize) -> usize {
1167 src_len
1168 .checked_mul(self.raw.len_mult as usize)
1169 .expect("Integer overflow")
1170 }
1171}
1172
1173#[cfg(test)]
1174mod test {
1175 use super::{AudioCVT, AudioFormat};
1176
1177 #[test]
1178 fn test_audio_cvt() {
1179 use std::iter::repeat;
1180
1181 let buffer: Vec<u8> = (0..255).collect();
1183
1184 let new_buffer_expected: Vec<u8> = (0..255).flat_map(|v| repeat(v).take(2)).collect();
1186
1187 let cvt = AudioCVT::new(AudioFormat::U8, 1, 44100, AudioFormat::U8, 2, 44100).unwrap();
1188 assert!(cvt.is_conversion_needed());
1189
1190 assert!(
1192 cvt.capacity(255) >= 255 * 2,
1193 "capacity must be able to hold the converted audio sample"
1194 );
1195
1196 let new_buffer = cvt.convert(buffer);
1197 assert_eq!(
1198 new_buffer.len(),
1199 new_buffer_expected.len(),
1200 "capacity must be exactly equal to twice the original vec size"
1201 );
1202
1203 }
1207}