use crate::audio_format::AudioFormat;
use crate::error::{Error, Result};
use crate::ffi;
use std::ptr::NonNull;
const SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK: ffi::SDL_AudioDeviceID = 0xFFFF_FFFF;
pub(crate) struct AudioStream {
raw: NonNull<ffi::SDL_AudioStream>,
}
impl AudioStream {
pub(crate) fn open(sample_rate: i32, channels: i32, format: AudioFormat) -> Result<Self> {
let spec = ffi::SDL_AudioSpec {
format: format.to_sdl(),
channels,
freq: sample_rate,
};
let raw = unsafe {
ffi::SDL_OpenAudioDeviceStream(
SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK,
&spec,
None,
std::ptr::null_mut(),
)
};
NonNull::new(raw)
.map(|raw| Self { raw })
.ok_or_else(Error::from_sdl)
}
pub(crate) fn put_data(&mut self, data: &[u8]) -> Result<()> {
let len = i32::try_from(data.len())
.map_err(|_| Error::invalid_argument("data length exceeds i32::MAX"))?;
if unsafe { ffi::SDL_PutAudioStreamData(self.raw.as_ptr(), data.as_ptr().cast(), len) } {
Ok(())
} else {
Err(Error::from_sdl())
}
}
pub(crate) fn queued_bytes(&self) -> i32 {
let bytes = unsafe { ffi::SDL_GetAudioStreamQueued(self.raw.as_ptr()) };
if bytes < 0 { 0 } else { bytes }
}
pub(crate) fn set_gain(&mut self, gain: f32) -> Result<()> {
if unsafe { ffi::SDL_SetAudioStreamGain(self.raw.as_ptr(), gain) } {
Ok(())
} else {
Err(Error::from_sdl())
}
}
pub(crate) fn resume(&mut self) -> Result<()> {
if unsafe { ffi::SDL_ResumeAudioStreamDevice(self.raw.as_ptr()) } {
Ok(())
} else {
Err(Error::from_sdl())
}
}
pub(crate) fn pause(&mut self) -> Result<()> {
if unsafe { ffi::SDL_PauseAudioStreamDevice(self.raw.as_ptr()) } {
Ok(())
} else {
Err(Error::from_sdl())
}
}
pub(crate) fn clear(&mut self) -> Result<()> {
if unsafe { ffi::SDL_ClearAudioStream(self.raw.as_ptr()) } {
Ok(())
} else {
Err(Error::from_sdl())
}
}
}
impl Drop for AudioStream {
fn drop(&mut self) {
unsafe { ffi::SDL_DestroyAudioStream(self.raw.as_ptr()) };
}
}
unsafe impl Send for AudioStream {}