1use crate::get_error;
53use crate::iostream::IOStream;
54use crate::sys;
55use crate::AudioSubsystem;
56use crate::Error;
57use libc::c_void;
58use std::convert::TryInto;
59use std::ffi::{c_int, CStr};
60use std::fmt;
61use std::fmt::{Debug, Display};
62use std::io::{self, Read};
63use std::marker::PhantomData;
64use std::ops::Deref;
65use std::ops::DerefMut;
66use std::path::Path;
67use sys::audio::{SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, SDL_AUDIO_DEVICE_DEFAULT_RECORDING};
68use sys::stdinc::SDL_free;
69
70impl AudioSubsystem {
71 #[doc(alias = "SDL_GetAudioPlaybackDevices")]
73 pub fn audio_playback_device_ids(&self) -> Result<Vec<AudioDeviceID>, Error> {
74 unsafe {
75 self.audio_device_ids(|num_devices| {
76 sys::audio::SDL_GetAudioPlaybackDevices(num_devices)
77 })
78 }
79 }
80
81 #[doc(alias = "SDL_GetAudioRecordingDevices")]
83 pub fn audio_recording_device_ids(&self) -> Result<Vec<AudioDeviceID>, Error> {
84 self.audio_device_ids(|num_devices| unsafe {
85 sys::audio::SDL_GetAudioRecordingDevices(num_devices)
86 })
87 }
88
89 fn audio_device_ids<F>(&self, get_devices: F) -> Result<Vec<AudioDeviceID>, Error>
90 where
91 F: FnOnce(&mut i32) -> *mut sys::audio::SDL_AudioDeviceID,
92 {
93 let mut num_devices: i32 = 0;
94 let devices = get_devices(&mut num_devices);
95 if devices.is_null() {
96 return Err(get_error());
97 }
98
99 let mut ret = Vec::new();
100 for i in 0..num_devices {
101 let instance_id = unsafe { *devices.offset(i as isize) };
102 ret.push(AudioDeviceID::Device(instance_id));
103 }
104
105 unsafe { SDL_free(devices as *mut c_void) };
106 Ok(ret)
107 }
108 pub fn open_playback_device(&self, spec: &AudioSpec) -> Result<AudioDevice, Error> {
110 self.open_device(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, spec)
111 }
112
113 pub fn open_recording_device(&self, spec: &AudioSpec) -> Result<AudioDevice, Error> {
115 self.open_device(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, spec)
116 }
117
118 pub fn default_playback_device(&self) -> AudioDevice {
119 AudioDevice::new(
120 AudioDeviceID::Device(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK),
121 self.clone(),
122 )
123 }
124
125 pub fn default_recording_device(&self) -> AudioDevice {
126 AudioDevice::new(
127 AudioDeviceID::Device(SDL_AUDIO_DEVICE_DEFAULT_RECORDING),
128 self.clone(),
129 )
130 }
131
132 fn open_device(
134 &self,
135 device_id: sys::audio::SDL_AudioDeviceID,
136 spec: &AudioSpec,
137 ) -> Result<AudioDevice, Error> {
138 let sdl_spec: sys::audio::SDL_AudioSpec = spec.clone().into();
139 let device = unsafe { sys::audio::SDL_OpenAudioDevice(device_id, &sdl_spec) };
140 if device == 0 {
141 Err(get_error())
142 } else {
143 Ok(AudioDevice::new(
144 AudioDeviceID::Device(device),
145 self.clone(),
146 ))
147 }
148 }
149
150 pub fn open_playback_stream_with_callback<CB, Channel>(
151 &self,
152 device: &AudioDevice,
153 spec: &AudioSpec,
154 callback: CB,
155 ) -> Result<AudioStreamWithCallback<CB>, Error>
156 where
157 CB: AudioCallback<Channel>,
158 Channel: AudioFormatNum + 'static,
159 {
160 device.open_playback_stream_with_callback(spec, callback)
161 }
162
163 pub fn open_playback_stream<CB, Channel>(
164 &self,
165 spec: &AudioSpec,
166 callback: CB,
167 ) -> Result<AudioStreamWithCallback<CB>, Error>
168 where
169 CB: AudioCallback<Channel>,
170 Channel: AudioFormatNum + 'static,
171 {
172 let device = AudioDevice::open_playback(self, None, spec)?;
173 device.open_playback_stream_with_callback(spec, callback)
174 }
175
176 pub fn open_recording_stream<CB, Channel>(
177 &self,
178 spec: &AudioSpec,
179 callback: CB,
180 ) -> Result<AudioStreamWithCallback<CB>, Error>
181 where
182 CB: AudioRecordingCallback<Channel>,
183 Channel: AudioFormatNum + 'static,
184 {
185 let device = AudioDevice::open_recording(self, None, spec)?;
186 device.open_recording_stream_with_callback(spec, callback)
187 }
188
189 #[doc(alias = "SDL_GetCurrentAudioDriver")]
190 pub fn current_audio_driver(&self) -> &'static str {
191 unsafe {
192 let buf = sys::audio::SDL_GetCurrentAudioDriver();
193 assert!(!buf.is_null());
194
195 CStr::from_ptr(buf as *const _).to_str().unwrap()
196 }
197 }
198
199 #[doc(alias = "SDL_GetAudioDeviceName")]
200 pub fn audio_playback_device_name(&self, index: u32) -> Result<String, Error> {
201 unsafe {
202 let dev_name = sys::audio::SDL_GetAudioDeviceName(index);
203 if dev_name.is_null() {
204 Err(get_error())
205 } else {
206 let cstr = CStr::from_ptr(dev_name as *const _);
207 Ok(cstr.to_str().unwrap().to_owned())
208 }
209 }
210 }
211
212 #[doc(alias = "SDL_GetAudioDeviceName")]
213 pub fn audio_recording_device_name(&self, index: u32) -> Result<String, Error> {
214 unsafe {
215 let dev_name = sys::audio::SDL_GetAudioDeviceName(index);
216 if dev_name.is_null() {
217 Err(get_error())
218 } else {
219 let cstr = CStr::from_ptr(dev_name as *const _);
220 Ok(cstr.to_str().unwrap().to_owned())
221 }
222 }
223 }
224
225 pub fn new_stream(
241 &self,
242 src_spec: Option<&AudioSpec>,
243 dst_spec: Option<&AudioSpec>,
244 ) -> Result<AudioStreamOwner, Error> {
245 let sdl_src_spec = src_spec.map(sys::audio::SDL_AudioSpec::from);
246 let sdl_dst_spec = dst_spec.map(sys::audio::SDL_AudioSpec::from);
247
248 let sdl_src_spec_ptr = sdl_src_spec
249 .as_ref()
250 .map_or(std::ptr::null(), |spec| spec as *const _);
251 let sdl_dst_spec_ptr = sdl_dst_spec
252 .as_ref()
253 .map_or(std::ptr::null(), |spec| spec as *const _);
254
255 let stream =
256 unsafe { sys::audio::SDL_CreateAudioStream(sdl_src_spec_ptr, sdl_dst_spec_ptr) };
257 if stream.is_null() {
258 Err(get_error())
259 } else {
260 Ok(AudioStreamOwner {
261 inner: AudioStream { stream },
262 audio_subsystem: self.clone().into(),
263 })
264 }
265 }
266
267 pub fn new_playback_stream(
275 &self,
276 app_spec: &AudioSpec,
277 device_spec: Option<&AudioSpec>,
278 ) -> Result<AudioStreamOwner, Error> {
279 self.new_stream(Some(app_spec), device_spec)
280 }
281
282 pub fn new_recording_stream(
290 &self,
291 device_spec: Option<&AudioSpec>,
292 app_spec: &AudioSpec,
293 ) -> Result<AudioStreamOwner, Error> {
294 self.new_stream(device_spec, Some(app_spec))
295 }
296}
297
298#[repr(u32)]
299#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
300pub enum AudioFormat {
301 UNKNOWN = sys::audio::SDL_AUDIO_UNKNOWN.0,
302
303 U8 = sys::audio::SDL_AUDIO_U8.0,
305 S8 = sys::audio::SDL_AUDIO_S8.0,
307 S16LE = sys::audio::SDL_AUDIO_S16LE.0,
309 S16BE = sys::audio::SDL_AUDIO_S16BE.0,
311 S32LE = sys::audio::SDL_AUDIO_S32LE.0,
313 S32BE = sys::audio::SDL_AUDIO_S32BE.0,
315 F32LE = sys::audio::SDL_AUDIO_F32LE.0,
317 F32BE = sys::audio::SDL_AUDIO_F32BE.0,
319}
320
321impl AudioFormat {
322 fn from_ll(raw: sys::audio::SDL_AudioFormat) -> Option<AudioFormat> {
323 match raw {
324 sys::audio::SDL_AUDIO_UNKNOWN => Some(AudioFormat::UNKNOWN),
325 sys::audio::SDL_AUDIO_U8 => Some(AudioFormat::U8),
326 sys::audio::SDL_AUDIO_S8 => Some(AudioFormat::S8),
327 sys::audio::SDL_AUDIO_S16LE => Some(AudioFormat::S16LE),
328 sys::audio::SDL_AUDIO_S16BE => Some(AudioFormat::S16BE),
329 sys::audio::SDL_AUDIO_S32LE => Some(AudioFormat::S32LE),
330 sys::audio::SDL_AUDIO_S32BE => Some(AudioFormat::S32BE),
331 sys::audio::SDL_AUDIO_F32LE => Some(AudioFormat::F32LE),
332 sys::audio::SDL_AUDIO_F32BE => Some(AudioFormat::F32BE),
333 _ => None,
334 }
335 }
336
337 #[doc(alias = "SDL_AudioFormat")]
338 fn to_ll(self) -> sys::audio::SDL_AudioFormat {
339 self.into()
340 }
341}
342
343impl From<AudioFormat> for sys::audio::SDL_AudioFormat {
344 fn from(format: AudioFormat) -> sys::audio::SDL_AudioFormat {
345 match format {
346 AudioFormat::UNKNOWN => sys::audio::SDL_AUDIO_UNKNOWN,
347 AudioFormat::U8 => sys::audio::SDL_AUDIO_U8,
348 AudioFormat::S8 => sys::audio::SDL_AUDIO_S8,
349 AudioFormat::S16LE => sys::audio::SDL_AUDIO_S16LE,
350 AudioFormat::S16BE => sys::audio::SDL_AUDIO_S16BE,
351 AudioFormat::S32LE => sys::audio::SDL_AUDIO_S32LE,
352 AudioFormat::S32BE => sys::audio::SDL_AUDIO_S32BE,
353 AudioFormat::F32LE => sys::audio::SDL_AUDIO_F32LE,
354 AudioFormat::F32BE => sys::audio::SDL_AUDIO_F32BE,
355 }
356 }
357}
358
359#[cfg(target_endian = "little")]
360impl AudioFormat {
361 #[inline]
363 pub const fn s16_sys() -> AudioFormat {
364 AudioFormat::S16LE
365 }
366 #[inline]
368 pub const fn s32_sys() -> AudioFormat {
369 AudioFormat::S32LE
370 }
371 #[inline]
373 pub const fn f32_sys() -> AudioFormat {
374 AudioFormat::F32LE
375 }
376}
377
378#[cfg(target_endian = "big")]
379impl AudioFormat {
380 #[inline]
382 pub const fn s16_sys() -> AudioFormat {
383 AudioFormat::S16MSB
384 }
385 #[inline]
387 pub const fn s32_sys() -> AudioFormat {
388 AudioFormat::S32MSB
389 }
390 #[inline]
392 pub const fn f32_sys() -> AudioFormat {
393 AudioFormat::F32MSB
394 }
395}
396
397#[doc(alias = "SDL_GetAudioDriver")]
398#[derive(Copy, Clone)]
399pub struct DriverIterator {
400 length: i32,
401 index: i32,
402}
403
404impl Iterator for DriverIterator {
405 type Item = &'static str;
406
407 #[inline]
408 fn next(&mut self) -> Option<&'static str> {
409 if self.index >= self.length {
410 None
411 } else {
412 unsafe {
413 let buf = sys::audio::SDL_GetAudioDriver(self.index);
414 assert!(!buf.is_null());
415 self.index += 1;
416
417 Some(CStr::from_ptr(buf as *const _).to_str().unwrap())
418 }
419 }
420 }
421
422 #[inline]
423 fn size_hint(&self) -> (usize, Option<usize>) {
424 let l = self.length as usize;
425 (l, Some(l))
426 }
427}
428
429impl ExactSizeIterator for DriverIterator {}
430
431#[doc(alias = "SDL_GetAudioDriver")]
433#[inline]
434pub fn drivers() -> DriverIterator {
435 DriverIterator {
440 length: unsafe { sys::audio::SDL_GetNumAudioDrivers() },
441 index: 0,
442 }
443}
444
445pub struct AudioSpecWAV {
446 pub freq: i32,
447 pub format: AudioFormat,
448 pub channels: u8,
449 audio_buf: *mut u8,
450 audio_len: u32,
451}
452
453impl AudioSpecWAV {
454 pub fn load_wav<P: AsRef<Path>>(path: P) -> Result<AudioSpecWAV, Error> {
456 let mut file = IOStream::from_file(path, "rb")?;
457 AudioSpecWAV::load_wav_rw(&mut file)
458 }
459
460 #[doc(alias = "SDL_LoadWAV_RW")]
462 pub fn load_wav_rw(src: &mut IOStream) -> Result<AudioSpecWAV, Error> {
463 use std::mem::MaybeUninit;
464 use std::ptr::null_mut;
465
466 let mut desired = MaybeUninit::uninit();
467 let mut audio_buf: *mut u8 = null_mut();
468 let mut audio_len: u32 = 0;
469 unsafe {
470 let ret = sys::audio::SDL_LoadWAV_IO(
471 src.raw(),
472 false,
473 desired.as_mut_ptr(),
474 &mut audio_buf,
475 &mut audio_len,
476 );
477 if !ret {
478 Err(get_error())
479 } else {
480 let desired = desired.assume_init();
481 Ok(AudioSpecWAV {
482 freq: desired.freq,
483 format: AudioFormat::from_ll(desired.format).unwrap(),
484 channels: desired.channels.try_into().unwrap(),
485 audio_buf,
486 audio_len,
487 })
488 }
489 }
490 }
491
492 pub fn buffer(&self) -> &[u8] {
493 use std::slice::from_raw_parts;
494 unsafe {
495 let ptr = self.audio_buf as *const u8;
496 let len = self.audio_len as usize;
497 from_raw_parts(ptr, len)
498 }
499 }
500}
501
502impl Drop for AudioSpecWAV {
503 #[doc(alias = "SDL_free")]
504 fn drop(&mut self) {
505 unsafe {
506 SDL_free(self.audio_buf as *mut _);
507 }
508 }
509}
510
511pub trait AudioCallback<Channel>: Send + 'static
512where
513 Channel: AudioFormatNum + 'static,
514{
515 fn callback(&mut self, stream: &mut AudioStream, requested: i32);
516}
517
518pub trait AudioFormatNum: Copy + 'static {
521 fn audio_format() -> AudioFormat;
522
523 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 i32 {
570 fn audio_format() -> AudioFormat {
571 AudioFormat::s32_sys()
572 }
573 const SILENCE: i32 = 0;
574}
575impl AudioFormatNum for f32 {
577 fn audio_format() -> AudioFormat {
578 AudioFormat::f32_sys()
579 }
580 const SILENCE: f32 = 0.0;
581}
582
583#[derive(Clone, Debug)]
584pub struct AudioSpec {
585 pub freq: Option<i32>,
587 pub channels: Option<i32>,
589 pub format: Option<AudioFormat>,
591}
592
593impl From<AudioSpec> for sys::audio::SDL_AudioSpec {
594 fn from(val: AudioSpec) -> Self {
595 AudioSpec::convert_to_ll(val.freq, val.channels, val.format)
596 }
597}
598
599impl From<&AudioSpec> for sys::audio::SDL_AudioSpec {
600 fn from(spec: &AudioSpec) -> Self {
601 sys::audio::SDL_AudioSpec {
602 freq: spec.freq.unwrap_or(0), format: spec.format.unwrap_or(AudioFormat::UNKNOWN).to_ll(), channels: spec.channels.unwrap_or(0), }
606 }
607}
608
609impl AudioSpec {
610 fn convert_to_ll<R, C, F>(rate: R, channels: C, format: F) -> sys::audio::SDL_AudioSpec
611 where
612 R: Into<Option<i32>>,
613 C: Into<Option<i32>>,
614 F: Into<Option<AudioFormat>>,
615 {
616 let channels = channels.into();
617 let freq = rate.into();
618 let format = format.into();
619
620 sys::audio::SDL_AudioSpec {
621 freq: freq.unwrap_or(0),
622 format: format.unwrap_or(AudioFormat::UNKNOWN).to_ll(),
623 channels: channels.unwrap_or(0),
624 }
625 }
626}
627
628impl From<&sys::audio::SDL_AudioSpec> for AudioSpec {
629 fn from(sdl_spec: &sys::audio::SDL_AudioSpec) -> Self {
630 Self {
631 freq: if sdl_spec.freq != 0 {
632 Some(sdl_spec.freq)
633 } else {
634 None },
636 format: if sdl_spec.format != sys::audio::SDL_AUDIO_UNKNOWN {
637 Some(AudioFormat::from_ll(sdl_spec.format).expect("Unknown audio format"))
638 } else {
639 None },
641 channels: if sdl_spec.channels != 0 {
642 Some(sdl_spec.channels)
643 } else {
644 None },
646 }
647 }
648}
649impl AudioSpec {
650 pub fn new(freq: Option<i32>, channels: Option<i32>, format: Option<AudioFormat>) -> Self {
653 Self {
654 freq,
655 channels,
656 format,
657 }
658 }
659
660 }
668
669impl Default for AudioSpec {
670 fn default() -> Self {
672 Self {
673 freq: None,
674 channels: None,
675 format: None,
676 }
677 }
678}
679
680#[derive(Clone, Debug)]
681pub enum AudioDeviceID {
682 Device(sys::audio::SDL_AudioDeviceID),
683}
684
685impl Copy for AudioDeviceID {}
686
687impl AudioDeviceID {
688 pub fn id(&self) -> sys::audio::SDL_AudioDeviceID {
689 match *self {
690 AudioDeviceID::Device(id) => id,
691 }
692 }
693
694 pub fn name(&self) -> Result<String, Error> {
695 unsafe {
696 let name_ptr = sys::audio::SDL_GetAudioDeviceName(self.id());
697 if name_ptr.is_null() {
698 return Err(get_error());
699 }
700 Ok(CStr::from_ptr(name_ptr).to_str().unwrap().to_owned())
701 }
702 }
703}
704
705impl PartialEq for AudioDeviceID {
706 fn eq(&self, other: &Self) -> bool {
707 self.id() == other.id()
708 }
709}
710impl Eq for AudioDeviceID {}
711
712#[derive(Clone)]
714pub struct AudioDevice {
715 device_id: AudioDeviceID,
716 audio_subsystem: AudioSubsystem,
718}
719
720impl PartialEq for AudioDevice {
721 fn eq(&self, other: &Self) -> bool {
722 self.device_id == other.device_id
723 }
724}
725
726impl Eq for AudioDevice {}
727
728impl Drop for AudioDevice {
729 fn drop(&mut self) {
730 unsafe {
731 sys::audio::SDL_CloseAudioDevice(self.device_id.id());
732 }
733 }
734}
735
736impl AudioDevice {
737 pub fn id(&self) -> AudioDeviceID {
738 self.device_id
739 }
740
741 pub fn new(device_id: AudioDeviceID, audio_subsystem: AudioSubsystem) -> Self {
742 AudioDevice {
743 device_id,
744 audio_subsystem,
745 }
746 }
747
748 #[doc(alias = "SDL_GetAudioDeviceName")]
750 pub fn name(&self) -> Result<String, Error> {
751 unsafe {
752 let name_ptr = sys::audio::SDL_GetAudioDeviceName(self.device_id.id());
753 if name_ptr.is_null() {
754 return Err(get_error());
755 }
756 Ok(CStr::from_ptr(name_ptr).to_str().unwrap().to_owned())
757 }
758 }
759
760 #[doc(alias = "SDL_OpenAudioDeviceStream")]
764 pub fn open_device_stream(self, spec: Option<&AudioSpec>) -> Result<AudioStreamOwner, Error> {
765 let sdl_spec = spec.map(|spec| spec.into());
766 let sdl_spec_ptr = crate::util::option_to_ptr(sdl_spec.as_ref());
767
768 let stream = unsafe {
769 sys::audio::SDL_OpenAudioDeviceStream(
770 self.device_id.id(),
771 sdl_spec_ptr,
772 None,
774 std::ptr::null_mut(),
775 )
776 };
777 if stream.is_null() {
778 Err(get_error())
779 } else {
780 core::mem::forget(self);
782 let audio_subsystem = unsafe { AudioSubsystem::new_unchecked() };
783
784 Ok(AudioStreamOwner {
785 inner: AudioStream { stream },
786 audio_subsystem: audio_subsystem.into(),
787 })
788 }
789 }
790
791 #[doc(alias = "SDL_BindAudioStream")]
793 pub fn bind_stream(&self, stream: &AudioStream) -> Result<(), Error> {
794 let result = unsafe { sys::audio::SDL_BindAudioStream(self.device_id.id(), stream.stream) };
795 if result {
796 Ok(())
797 } else {
798 Err(get_error())
799 }
800 }
801
802 #[doc(alias = "SDL_BindAudioStreams")]
804 pub fn bind_streams(&self, streams: &[&AudioStream]) -> Result<(), Error> {
805 let streams_ptrs: Vec<*mut sys::audio::SDL_AudioStream> =
806 streams.iter().map(|s| s.stream).collect();
807 let result = unsafe {
808 sys::audio::SDL_BindAudioStreams(
809 self.device_id.id(),
810 streams_ptrs.as_ptr() as *mut _,
811 streams.len() as i32,
812 )
813 };
814 if result {
815 Ok(())
816 } else {
817 Err(get_error())
818 }
819 }
820
821 #[doc(alias = "SDL_OpenAudioDevice")]
823 fn open<'a, D>(
824 device: D,
825 spec: &AudioSpec,
826 recording: bool,
827 audio_subsystem: &AudioSubsystem,
828 ) -> Result<AudioDevice, Error>
829 where
830 D: Into<Option<&'a AudioDeviceID>>,
831 {
832 let desired = AudioSpec::convert_to_ll(spec.freq, spec.channels, spec.format);
833
834 unsafe {
835 let sdl_device = match device.into() {
836 Some(device) => device.id(),
837 None => {
839 if recording {
840 SDL_AUDIO_DEVICE_DEFAULT_RECORDING
841 } else {
842 SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK
843 }
844 }
845 };
846 let device_id = sys::audio::SDL_OpenAudioDevice(sdl_device, &desired);
847 match device_id {
848 0 => Err(get_error()),
849 id => {
850 let device_id = AudioDeviceID::Device(id);
851
852 Ok(AudioDevice::new(device_id, audio_subsystem.clone()))
853 }
854 }
855 }
856 }
857
858 pub fn open_playback<'a, D>(
860 _a: &AudioSubsystem,
861 device: D,
862 spec: &AudioSpec,
863 ) -> Result<AudioDevice, Error>
864 where
865 D: Into<Option<&'a AudioDeviceID>>,
866 {
867 AudioDevice::open(device, spec, false, _a)
868 }
869
870 pub fn open_recording<'a, D>(
872 _a: &AudioSubsystem,
873 device: D,
874 spec: &AudioSpec,
875 ) -> Result<AudioDevice, Error>
876 where
877 D: Into<Option<&'a AudioDeviceID>>,
878 {
879 AudioDevice::open(device, spec, true, _a)
880 }
881
882 #[doc(alias = "SDL_PauseAudioDevice")]
884 pub fn pause(&self) -> bool {
885 unsafe { sys::audio::SDL_PauseAudioDevice(self.device_id.id()) }
886 }
887
888 #[doc(alias = "SDL_ResumeAudioDevice")]
890 pub fn resume(&self) -> bool {
891 unsafe { sys::audio::SDL_ResumeAudioDevice(self.device_id.id()) }
892 }
893
894 #[doc(alias = "SDL_OpenAudioDeviceStream")]
897 pub fn open_playback_stream_with_callback<CB, Channel>(
898 &self,
899 spec: &AudioSpec,
900 callback: CB,
901 ) -> Result<AudioStreamWithCallback<CB>, Error>
902 where
903 CB: AudioCallback<Channel>,
904 Channel: AudioFormatNum + 'static,
905 {
906 let sdl_audiospec: sys::audio::SDL_AudioSpec = spec.clone().into();
907
908 if sdl_audiospec.format != Channel::audio_format().to_ll() {
909 return Err(Error(
910 "AudioSpec format does not match AudioCallback Channel type".to_string(),
911 ));
912 }
913
914 let callback_box = Box::new(callback);
915 let c_userdata = Box::into_raw(callback_box) as *mut c_void;
916
917 unsafe extern "C" fn audio_stream_callback<CB, Channel>(
918 userdata: *mut c_void,
919 sdl_stream: *mut sys::audio::SDL_AudioStream,
920 len: c_int,
921 _bytes: c_int,
922 ) where
923 CB: AudioCallback<Channel>,
924 Channel: AudioFormatNum + 'static,
925 {
926 let callback = &mut *(userdata as *mut CB);
927
928 let mut stream = AudioStream { stream: sdl_stream };
929
930 callback.callback(&mut stream, len / size_of::<Channel>() as i32);
931 }
932
933 unsafe {
934 let stream = sys::audio::SDL_OpenAudioDeviceStream(
935 self.device_id.id(),
936 &sdl_audiospec,
937 Some(audio_stream_callback::<CB, Channel>),
938 c_userdata,
939 );
940
941 if stream.is_null() {
942 let _ = Box::from_raw(c_userdata as *mut CB);
944 Err(get_error())
945 } else {
946 Ok(AudioStreamWithCallback {
947 base_stream: AudioStreamOwner {
948 inner: AudioStream { stream },
949 audio_subsystem: self.audio_subsystem.clone().into(),
950 },
951 _marker: PhantomData,
952 c_userdata,
953 })
954 }
955 }
956 }
957
958 #[doc(alias = "SDL_OpenAudioDeviceStream")]
961 pub fn open_recording_stream_with_callback<CB, Channel>(
962 &self,
963 spec: &AudioSpec,
964 callback: CB,
965 ) -> Result<AudioStreamWithCallback<CB>, Error>
966 where
967 CB: AudioRecordingCallback<Channel>,
968 Channel: AudioFormatNum + 'static,
969 {
970 let sdl_audiospec: sys::audio::SDL_AudioSpec = spec.clone().into();
972
973 if sdl_audiospec.format != Channel::audio_format().to_ll() {
974 return Err(Error(
975 "AudioSpec format does not match AudioCallback Channel type".to_string(),
976 ));
977 }
978
979 let callback_box = Box::new(callback);
980 let c_userdata = Box::into_raw(callback_box) as *mut c_void;
981
982 unsafe {
983 let stream = sys::audio::SDL_OpenAudioDeviceStream(
984 self.device_id.id(),
985 &sdl_audiospec,
986 Some(audio_recording_stream_callback::<CB, Channel>),
987 c_userdata,
988 );
989
990 if stream.is_null() {
991 let _ = Box::from_raw(c_userdata as *mut CB);
993 Err(get_error())
994 } else {
995 Ok(AudioStreamWithCallback {
996 base_stream: AudioStreamOwner {
997 inner: AudioStream { stream },
998 audio_subsystem: self.audio_subsystem.clone().into(),
999 },
1000 _marker: PhantomData,
1001 c_userdata,
1002 })
1003 }
1004 }
1005 }
1006}
1007
1008pub struct AudioStreamOwner {
1009 inner: AudioStream,
1010 #[expect(dead_code, reason = "keep the audio subsystem alive")]
1011 audio_subsystem: Option<AudioSubsystem>,
1012}
1013
1014pub struct AudioStream {
1015 stream: *mut sys::audio::SDL_AudioStream,
1016}
1017
1018impl Deref for AudioStreamOwner {
1019 type Target = AudioStream;
1020
1021 fn deref(&self) -> &Self::Target {
1022 &self.inner
1023 }
1024}
1025
1026impl DerefMut for AudioStreamOwner {
1027 fn deref_mut(&mut self) -> &mut Self::Target {
1028 &mut self.inner
1029 }
1030}
1031
1032impl Drop for AudioStreamOwner {
1033 fn drop(&mut self) {
1036 if !self.inner.stream.is_null() {
1037 unsafe {
1038 sys::audio::SDL_DestroyAudioStream(self.inner.stream);
1039 }
1040 self.inner.stream = std::ptr::null_mut();
1041 }
1042 }
1043}
1044
1045impl Debug for AudioStream {
1046 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1047 let device_name = self
1049 .device_id()
1050 .and_then(|id| id.name().ok())
1051 .unwrap_or("Unknown".to_string());
1052 let device_name = format!(
1053 "{} [{}]",
1054 device_name,
1055 self.device_id().map(|id| id.id()).unwrap_or(0)
1056 );
1057
1058 let (src_spec, dst_spec) = match self.get_format() {
1060 Ok((src, dst)) => (Some(src), Some(dst)),
1061 Err(_) => (None, None),
1062 };
1063
1064 let gain = self.get_gain().ok();
1066
1067 let mut ds = f.debug_struct("AudioStream");
1069
1070 ds.field("device", &device_name);
1071
1072 if let Some(src_spec) = src_spec {
1073 ds.field("src_spec", &src_spec);
1074 } else {
1075 ds.field("src_spec", &"Unknown");
1076 }
1077
1078 if let Some(dst_spec) = dst_spec {
1079 ds.field("dst_spec", &dst_spec);
1080 } else {
1081 ds.field("dst_spec", &"Unknown");
1082 }
1083
1084 if let Some(gain) = gain {
1085 ds.field("gain", &gain);
1086 } else {
1087 ds.field("gain", &"Unknown");
1088 }
1089
1090 ds.finish()
1091 }
1092}
1093impl Display for AudioStream {
1094 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1095 if let Some(name) = self.device_id().and_then(|id| id.name().ok()) {
1096 write!(f, "AudioStream({})", name)
1097 } else {
1098 write!(f, "AudioStream")
1099 }
1100 }
1101}
1102
1103impl AudioStream {
1104 #[doc(alias = "SDL_AudioStream")]
1106 pub fn stream(&mut self) -> *mut sys::audio::SDL_AudioStream {
1107 self.stream
1108 }
1109
1110 #[doc(alias = "SDL_GetAudioStreamDevice")]
1113 pub fn device_id(&self) -> Option<AudioDeviceID> {
1114 let device_id = unsafe { sys::audio::SDL_GetAudioStreamDevice(self.stream) };
1115 if device_id != 0 {
1117 Some(AudioDeviceID::Device(device_id))
1118 } else {
1119 None
1120 }
1121 }
1122
1123 pub fn device_name(&self) -> Option<String> {
1124 self.device_id().and_then(|id| id.name().ok())
1125 }
1126
1127 #[doc(alias = "SDL_GetAudioStreamFormat")]
1131 pub fn get_format(&self) -> Result<(Option<AudioSpec>, Option<AudioSpec>), Error> {
1132 let mut sdl_src_spec = AudioSpec::default().into();
1133 let mut sdl_dst_spec = AudioSpec::default().into();
1134 let result = unsafe {
1135 sys::audio::SDL_GetAudioStreamFormat(self.stream, &mut sdl_src_spec, &mut sdl_dst_spec)
1136 };
1137 if result {
1138 let src_spec = if sdl_src_spec.format != sys::audio::SDL_AUDIO_UNKNOWN {
1139 Some(AudioSpec::from(&sdl_src_spec))
1140 } else {
1141 None
1142 };
1143 let dst_spec = if sdl_dst_spec.format != sys::audio::SDL_AUDIO_UNKNOWN {
1144 Some(AudioSpec::from(&sdl_dst_spec))
1145 } else {
1146 None
1147 };
1148 Ok((src_spec, dst_spec))
1149 } else {
1150 Err(get_error())
1151 }
1152 }
1153
1154 #[doc(alias = "SDL_GetAudioStreamGain")]
1158 pub fn get_gain(&self) -> Result<f32, Error> {
1159 let gain = unsafe { sys::audio::SDL_GetAudioStreamGain(self.stream) };
1160 if gain >= 0.0 {
1161 Ok(gain)
1162 } else {
1163 Err(get_error())
1164 }
1165 }
1166
1167 #[doc(alias = "SDL_PauseAudioStream")]
1169 pub fn pause(&self) -> Result<(), Error> {
1170 let result = unsafe { sys::audio::SDL_PauseAudioStreamDevice(self.stream) };
1171 if result {
1172 Ok(())
1173 } else {
1174 Err(get_error())
1175 }
1176 }
1177
1178 #[doc(alias = "SDL_ResumeAudioStream")]
1180 pub fn resume(&self) -> Result<(), Error> {
1181 let result = unsafe { sys::audio::SDL_ResumeAudioStreamDevice(self.stream) };
1182 if result {
1183 Ok(())
1184 } else {
1185 Err(get_error())
1186 }
1187 }
1188
1189 #[doc(alias = "SDL_GetAudioStreamAvailable")]
1191 pub fn available_bytes(&self) -> Result<i32, Error> {
1192 let available = unsafe { sys::audio::SDL_GetAudioStreamAvailable(self.stream) };
1193 if available == -1 {
1194 Err(get_error())
1195 } else {
1196 Ok(available)
1197 }
1198 }
1199
1200 fn read_bytes_to_f32(&self, chunk: &[u8]) -> Result<f32, Error> {
1203 let (_, output_spec) = self.get_format()?;
1205 match output_spec.unwrap().format {
1206 Some(AudioFormat::F32LE) => {
1207 Ok(f32::from_le_bytes(chunk.try_into().map_err(|_| {
1208 Error("Invalid byte slice length for f32 LE".to_owned())
1209 })?))
1210 }
1211 Some(AudioFormat::F32BE) => {
1212 Ok(f32::from_be_bytes(chunk.try_into().map_err(|_| {
1213 Error("Invalid byte slice length for f32 BE".to_owned())
1214 })?))
1215 }
1216 _ => Err(Error(
1217 "Unsupported AudioFormat for f32 conversion".to_string(),
1218 )),
1219 }
1220 }
1221
1222 fn read_bytes_to_i16(&self, chunk: &[u8]) -> Result<i16, Error> {
1225 let (_, output_spec) = self.get_format()?;
1227 match output_spec.unwrap().format {
1228 Some(AudioFormat::S16LE) => {
1229 Ok(i16::from_le_bytes(chunk.try_into().map_err(|_| {
1230 Error("Invalid byte slice length for i16 LE".to_owned())
1231 })?))
1232 }
1233 Some(AudioFormat::S16BE) => {
1234 Ok(i16::from_be_bytes(chunk.try_into().map_err(|_| {
1235 Error("Invalid byte slice length for i16 BE".to_owned())
1236 })?))
1237 }
1238 _ => Err(Error(
1239 "Unsupported AudioFormat for i16 conversion".to_string(),
1240 )),
1241 }
1242 }
1243
1244 pub fn read_f32_samples(&mut self, buf: &mut [f32]) -> io::Result<usize> {
1247 let byte_len = std::mem::size_of_val(buf);
1248 let mut byte_buf = vec![0u8; byte_len];
1249
1250 let bytes_read = self.read(&mut byte_buf)?;
1252
1253 let samples_read = bytes_read / size_of::<f32>();
1255
1256 for (i, v) in buf.iter_mut().enumerate().take(samples_read) {
1258 let start = i * size_of::<f32>();
1259 let end = start + size_of::<f32>();
1260 let chunk = &byte_buf[start..end];
1261
1262 *v = self
1264 .read_bytes_to_f32(chunk)
1265 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1266 }
1267
1268 Ok(samples_read)
1269 }
1270
1271 pub fn read_i16_samples(&mut self, buf: &mut [i16]) -> io::Result<usize> {
1274 let byte_len = std::mem::size_of_val(buf);
1275 let mut byte_buf = vec![0u8; byte_len];
1276
1277 let bytes_read = self.read(&mut byte_buf)?;
1279
1280 let samples_read = bytes_read / size_of::<i16>();
1282
1283 for (i, v) in buf.iter_mut().enumerate().take(samples_read) {
1285 let start = i * size_of::<i16>();
1286 let end = start + size_of::<i16>();
1287 let chunk = &byte_buf[start..end];
1288
1289 *v = self
1291 .read_bytes_to_i16(chunk)
1292 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1293 }
1294
1295 Ok(samples_read)
1296 }
1297
1298 pub fn put_data(&self, buf: &[u8]) -> Result<(), Error> {
1300 let result = unsafe {
1301 sys::audio::SDL_PutAudioStreamData(self.stream, buf.as_ptr().cast(), buf.len() as i32)
1302 };
1303 if result {
1304 Ok(())
1305 } else {
1306 Err(get_error())
1307 }
1308 }
1309
1310 pub fn put_data_i16(&self, buf: &[i16]) -> Result<(), Error> {
1312 let result = unsafe {
1313 sys::audio::SDL_PutAudioStreamData(
1314 self.stream,
1315 buf.as_ptr().cast(),
1316 buf.len() as i32 * size_of::<i16>() as i32,
1317 )
1318 };
1319 if result {
1320 Ok(())
1321 } else {
1322 Err(get_error())
1323 }
1324 }
1325
1326 pub fn put_data_f32(&self, buf: &[f32]) -> Result<(), Error> {
1328 let result = unsafe {
1329 sys::audio::SDL_PutAudioStreamData(
1330 self.stream,
1331 buf.as_ptr().cast(),
1332 buf.len() as i32 * size_of::<f32>() as i32,
1333 )
1334 };
1335 if result {
1336 Ok(())
1337 } else {
1338 Err(get_error())
1339 }
1340 }
1341}
1342
1343impl Read for AudioStream {
1344 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1349 let ret = unsafe {
1350 sys::audio::SDL_GetAudioStreamData(
1351 self.stream,
1352 buf.as_mut_ptr().cast(),
1353 buf.len() as c_int,
1354 )
1355 };
1356 if ret == -1 {
1357 Err(io::Error::new(io::ErrorKind::Other, get_error()))
1358 } else {
1359 Ok(ret as usize)
1360 }
1361 }
1362}
1363
1364pub struct AudioStreamWithCallback<CB> {
1366 base_stream: AudioStreamOwner,
1367 c_userdata: *mut c_void,
1368 _marker: PhantomData<CB>,
1369}
1370
1371impl<CB> Drop for AudioStreamWithCallback<CB> {
1372 fn drop(&mut self) {
1373 if !self.c_userdata.is_null() {
1375 unsafe {
1376 let _ = Box::from_raw(self.c_userdata as *mut CB);
1378 }
1379 self.c_userdata = std::ptr::null_mut();
1380 }
1381 }
1382}
1383
1384impl<CB> AudioStreamWithCallback<CB> {
1385 pub fn pause(&self) -> Result<(), Error> {
1387 self.base_stream.pause()
1388 }
1389
1390 pub fn resume(&self) -> Result<(), Error> {
1392 self.base_stream.resume()
1393 }
1394
1395 pub fn lock(&mut self) -> Option<AudioStreamLockGuard<CB>> {
1396 let raw_stream = self.base_stream.stream;
1397 let result = unsafe { sys::audio::SDL_LockAudioStream(raw_stream) };
1398
1399 if result {
1400 Some(AudioStreamLockGuard {
1401 stream: self,
1402 _nosend: PhantomData,
1403 })
1404 } else {
1405 None
1406 }
1407 }
1408}
1409
1410pub trait AudioRecordingCallback<Channel>: Send + 'static
1411where
1412 Channel: AudioFormatNum + 'static,
1413{
1414 fn callback(&mut self, stream: &mut AudioStream, available: i32);
1415}
1416
1417unsafe extern "C" fn audio_recording_stream_callback<CB, Channel>(
1418 userdata: *mut c_void,
1419 sdl_stream: *mut sys::audio::SDL_AudioStream,
1420 len: c_int,
1421 _bytes: c_int,
1422) where
1423 CB: AudioRecordingCallback<Channel>,
1424 Channel: AudioFormatNum + 'static,
1425{
1426 let callback = &mut *(userdata as *mut CB);
1427
1428 let mut stream = AudioStream { stream: sdl_stream };
1429
1430 callback.callback(&mut stream, len / size_of::<Channel>() as c_int);
1432}
1433
1434pub struct AudioStreamLockGuard<'a, CB>
1436where
1437 CB: 'a,
1438{
1439 stream: &'a mut AudioStreamWithCallback<CB>,
1440 _nosend: PhantomData<*mut ()>,
1441}
1442
1443impl<'a, CB> Deref for AudioStreamLockGuard<'a, CB>
1444where
1445 CB: 'a,
1446{
1447 type Target = CB;
1448 #[doc(alias = "SDL_UnlockAudioStream")]
1449 fn deref(&self) -> &CB {
1450 unsafe {
1451 (self.stream.c_userdata as *const CB)
1452 .as_ref()
1453 .expect("Missing callback")
1454 }
1455 }
1456}
1457
1458impl<'a, CB> DerefMut for AudioStreamLockGuard<'a, CB> {
1459 fn deref_mut(&mut self) -> &mut CB {
1460 unsafe {
1461 (self.stream.c_userdata as *mut CB)
1462 .as_mut()
1463 .expect("Missing callback")
1464 }
1465 }
1466}
1467
1468impl<'a, CB> Drop for AudioStreamLockGuard<'a, CB> {
1469 fn drop(&mut self) {
1470 unsafe {
1471 sys::audio::SDL_UnlockAudioStream(self.stream.base_stream.stream);
1472 }
1473 }
1474}
1475
1476#[cfg(test)]
1477mod test {}