use crate::PlaySoundParams; use std::sync::mpsc; pub use crate::mixer::Playback; #[path = "coreaudio/coreaudio.rs"] mod coreaudio; // bindgen lost some defines from coreaudio.rs const _saudio_kAudioFormatLinearPCM: u32 = 1819304813; //'lpcm'; const _saudio_kLinearPCMFormatFlagIsFloat: u32 = 1 << 0; const _saudio_kAudioFormatFlagIsPacked: u32 = 1 << 3; use coreaudio::*; mod consts { pub const DEVICE: &'static str = "default\0"; pub const RATE: u32 = 44100; pub const CHANNELS: u32 = 2; pub const BUFFER_FRAMES: u32 = 4096; } pub struct AudioContext { pub(crate) mixer_ctrl: crate::mixer::MixerControl, } unsafe extern "C" fn saudio_coreaudio_callback( user_data: *mut ::std::os::raw::c_void, queue: _saudio_AudioQueueRef, buffer: _saudio_AudioQueueBufferRef, ) { let mut mixer = &mut *(user_data as *mut crate::mixer::Mixer); let num_frames = (*buffer).mAudioDataByteSize / (2 * 4); let buf = std::slice::from_raw_parts_mut((*buffer).mAudioData as *mut f32, num_frames as usize * 2); mixer.fill_audio_buffer(buf, num_frames as _); AudioQueueEnqueueBuffer(queue, buffer, 0, std::ptr::null_mut()); } impl AudioContext { pub fn new() -> AudioContext { use crate::mixer::{self, Mixer}; let (mixer_builder, mixer_ctrl) = Mixer::new(); let mixer = Box::new(mixer_builder.build()); unsafe { let fmt = _saudio_AudioStreamBasicDescription { mSampleRate: consts::RATE as f64, mFormatID: _saudio_kAudioFormatLinearPCM, mFormatFlags: _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked, mFramesPerPacket: 1, mChannelsPerFrame: consts::CHANNELS, mBytesPerFrame: 4 * consts::CHANNELS, mBytesPerPacket: 4 * consts::CHANNELS, mBitsPerChannel: 32, mReserved: 0, }; let mut ca_audio_queue: _saudio_AudioQueueRef = std::mem::zeroed(); let res = AudioQueueNewOutput( &fmt, Some(saudio_coreaudio_callback), Box::into_raw(mixer) as *mut _, std::ptr::null_mut(), std::ptr::null_mut(), 0, &mut ca_audio_queue, ); assert!(res == 0); assert!(ca_audio_queue.is_null() == false); // create 2 audio buffers for _ in 0..2 { let mut buf: _saudio_AudioQueueBufferRef = std::ptr::null_mut(); let buf_byte_size = consts::BUFFER_FRAMES * fmt.mBytesPerFrame; let res = AudioQueueAllocateBuffer(ca_audio_queue, buf_byte_size, &mut buf); assert!(res == 0); assert!(buf.is_null() == false); (*buf).mAudioDataByteSize = buf_byte_size; std::ptr::write_bytes( (*buf).mAudioData as *mut u8, 0, (*buf).mAudioDataByteSize as usize, ); AudioQueueEnqueueBuffer(ca_audio_queue, buf, 0, std::ptr::null_mut()); } let res = AudioQueueStart(ca_audio_queue, std::ptr::null_mut()); assert!(res == 0); } AudioContext { mixer_ctrl } } } pub struct Sound { sound_id: u32, } impl Sound { pub fn load(ctx: &AudioContext, data: &[u8]) -> Sound { let sound_id = ctx.mixer_ctrl.load(data); Sound { sound_id } } pub fn play(&self, ctx: &AudioContext, params: PlaySoundParams) -> Playback { ctx.mixer_ctrl.play(self.sound_id, params) } pub fn stop(&self, ctx: &AudioContext) { ctx.mixer_ctrl.stop_all(self.sound_id); } pub fn set_volume(&self, ctx: &AudioContext, volume: f32) { ctx.mixer_ctrl.set_volume_all(self.sound_id, volume); } pub fn delete(&self, ctx: &AudioContext) { ctx.mixer_ctrl.delete(self.sound_id); } }