diff --git a/.travis.yml b/.travis.yml index 27d5f0e88..36abbef92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,8 @@ script: - cargo build --verbose - cargo test --verbose - cargo doc --verbose +- cargo build --verbose --target aarch64-apple-ios +- cargo test --verbose --target aarch64-apple-ios after_success: | [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && diff --git a/src/audio_unit/mod.rs b/src/audio_unit/mod.rs index 9e4459bbe..480c0d189 100644 --- a/src/audio_unit/mod.rs +++ b/src/audio_unit/mod.rs @@ -171,6 +171,29 @@ impl AudioUnit { } } + /// On successful initialization, the audio formats for input and output are valid + /// and the audio unit is ready to render. During initialization, an audio unit + /// allocates memory according to the maximum number of audio frames it can produce + /// in response to a single render call. + /// + /// Usually, the state of an audio unit (such as its I/O formats and memory allocations) + /// cannot be changed while an audio unit is initialized. + pub fn initialize(&mut self) -> Result<(), Error> { + unsafe { try_os_status!(sys::AudioUnitInitialize(self.instance)); } + Ok(()) + } + + /// Before you change an initialize audio unit’s processing characteristics, + /// such as its input or output audio data format or its sample rate, you must + /// first uninitialize it. Calling this function deallocates the audio unit’s resources. + /// + /// After calling this function, you can reconfigure the audio unit and then call + /// AudioUnitInitialize to reinitialize it. + pub fn uninitialize(&mut self) -> Result<(), Error> { + unsafe { try_os_status!(sys::AudioUnitUninitialize(self.instance)); } + Ok(()) + } + /// Sets the value for some property of the **AudioUnit**. /// /// To clear an audio unit property value, set the data paramater with `None::<()>`. @@ -375,3 +398,20 @@ pub fn get_property( Ok(data) } } + +#[cfg(target_os = "ios")] +pub fn audio_session_get_property( + id: u32, +) -> Result +{ + let mut size = ::std::mem::size_of::() as u32; + unsafe { + let mut data: T = ::std::mem::uninitialized(); + let data_ptr = &mut data as *mut _ as *mut c_void; + let size_ptr = &mut size as *mut _; + try_os_status!( + sys::AudioSessionGetProperty(id, size_ptr, data_ptr) + ); + Ok(data) + } +} diff --git a/src/audio_unit/render_callback.rs b/src/audio_unit/render_callback.rs index e0c5668a7..141f86aa9 100644 --- a/src/audio_unit/render_callback.rs +++ b/src/audio_unit/render_callback.rs @@ -8,6 +8,9 @@ use sys; pub use self::action_flags::ActionFlags; pub use self::data::Data; +#[cfg(target_os = "ios")] +use audio_unit::audio_session_get_property; + /// When `set_render_callback` is called, a closure of this type will be used to wrap the given /// render callback function. @@ -398,7 +401,7 @@ impl AudioUnit { // First, we'll retrieve the stream format so that we can ensure that the given callback // format matches the audio unit's format. let id = sys::kAudioUnitProperty_StreamFormat; - let asbd = try!(self.get_property(id, Scope::Output, Element::Output)); + let asbd = try!(self.get_property(id, Scope::Input, Element::Output)); let stream_format = super::StreamFormat::from_asbd(asbd)?; // If the stream format does not match, return an error indicating this. @@ -471,7 +474,7 @@ impl AudioUnit { // First, we'll retrieve the stream format so that we can ensure that the given callback // format matches the audio unit's format. let id = sys::kAudioUnitProperty_StreamFormat; - let asbd = self.get_property(id, Scope::Input, Element::Input)?; + let asbd = self.get_property(id, Scope::Output, Element::Input)?; let stream_format = super::StreamFormat::from_asbd(asbd)?; // If the stream format does not match, return an error indicating this. @@ -482,8 +485,20 @@ impl AudioUnit { // Pre-allocate a buffer list for input stream. // // First, get the current buffer size for pre-allocating the `AudioBuffer`s. - let id = sys::kAudioDevicePropertyBufferFrameSize; - let mut buffer_frame_size: u32 = self.get_property(id, Scope::Global, Element::Output)?; + #[cfg(target_os = "macos")] + let mut buffer_frame_size: u32 = { + let id = sys::kAudioDevicePropertyBufferFrameSize; + let buffer_frame_size: u32 = self.get_property(id, Scope::Global, Element::Output)?; + buffer_frame_size + }; + #[cfg(target_os = "ios")] + let mut buffer_frame_size: u32 = { + let id = sys::kAudioSessionProperty_CurrentHardwareIOBufferDuration; + let seconds: f32 = super::audio_session_get_property(id)?; + let id = sys::kAudioSessionProperty_CurrentHardwareSampleRate; + let sample_rate: f64 = super::audio_session_get_property(id)?; + (sample_rate * seconds as f64).round() as u32 + }; let mut data: Vec = vec![]; let sample_bytes = stream_format.sample_format.size_in_bytes(); let n_channels = stream_format.channels_per_frame; @@ -525,7 +540,7 @@ impl AudioUnit { unsafe { // Retrieve the up-to-date stream format. let id = sys::kAudioUnitProperty_StreamFormat; - let asbd = match super::get_property(audio_unit, id, Scope::Input, Element::Output) { + let asbd = match super::get_property(audio_unit, id, Scope::Output, Element::Input) { Err(err) => return err.to_os_status(), Ok(asbd) => asbd, };