[coreaudio] Remove intermediate buffer (#182)

* [coreaudio] Remove intermediate buffer

Fixes #181

* [coreaudio] Create voice id after setting format
This commit is contained in:
Eidolon 2017-11-03 04:51:02 -05:00 committed by tomaka
parent 77cd690b00
commit e9856c07ed
4 changed files with 50 additions and 24 deletions

View File

@ -3,6 +3,7 @@
- Changed the emscripten backend to consume less CPU.
- Added improvements to the crate documentation.
- Implement `pause` and `play` for ALSA backend.
- Reduced the number of allocations in the CoreAudio backend.
# Version 0.5.1 (2017-10-21)

View File

@ -1,6 +1,5 @@
use super::Endpoint;
use Format;
use SupportedFormat;
use std::vec::IntoIter as VecIntoIter;

View File

@ -14,9 +14,18 @@ use std::mem;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use std::slice;
use self::coreaudio::audio_unit::AudioUnit;
use self::coreaudio::audio_unit::{AudioUnit, Scope, Element};
use self::coreaudio::audio_unit::render_callback::{self, data};
use self::coreaudio::bindings::audio_unit::{
AudioStreamBasicDescription,
AudioBuffer,
kAudioFormatLinearPCM,
kAudioFormatFlagIsFloat,
kAudioFormatFlagIsPacked,
kAudioUnitProperty_StreamFormat
};
mod enumerate;
@ -108,7 +117,7 @@ impl EventLoop {
}
#[inline]
pub fn build_voice(&self, endpoint: &Endpoint, format: &Format)
pub fn build_voice(&self, _endpoint: &Endpoint, _format: &Format)
-> Result<VoiceId, CreationError> {
let mut audio_unit = {
let au_type = if cfg!(target_os = "ios") {
@ -123,6 +132,27 @@ impl EventLoop {
AudioUnit::new(au_type)?
};
// TODO: iOS uses integer and fixed-point data
// Set the stream in interleaved mode.
let asbd = AudioStreamBasicDescription {
mBitsPerChannel: 32,
mBytesPerFrame: 8,
mChannelsPerFrame: 2,
mBytesPerPacket: 8,
mFramesPerPacket: 1,
mFormatFlags: (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked) as u32,
mFormatID: kAudioFormatLinearPCM,
mSampleRate: 44100.0,
..Default::default()
};
audio_unit.set_property(
kAudioUnitProperty_StreamFormat,
Scope::Input,
Element::Output,
Some(&asbd)
).map_err(convert_error)?;
// Determine the future ID of the voice.
let mut voices_lock = self.voices.lock().unwrap();
let voice_id = voices_lock
@ -130,31 +160,34 @@ impl EventLoop {
.position(|n| n.is_none())
.unwrap_or(voices_lock.len());
// TODO: iOS uses integer and fixed-point data
// Register the callback that is being called by coreaudio whenever it needs data to be
// fed to the audio buffer.
let active_callbacks = self.active_callbacks.clone();
audio_unit.set_render_callback(move |mut args: render_callback::Args<data::NonInterleaved<f32>>| {
audio_unit.set_render_callback(move |args: render_callback::Args<data::Raw>| unsafe {
// If `run()` is currently running, then a callback will be available from this list.
// Otherwise, we just fill the buffer with zeroes and return.
let AudioBuffer {
mNumberChannels: _num_channels,
mDataByteSize: data_byte_size,
mData: data
} = (*args.data.data).mBuffers[0];
let data_slice = slice::from_raw_parts_mut(data as *mut f32, (data_byte_size / 4) as usize);
let mut callbacks = active_callbacks.callbacks.lock().unwrap();
let callback = if let Some(cb) = callbacks.get_mut(0) {
cb
} else {
for channel in args.data.channels_mut() {
for elem in channel.iter_mut() {
*elem = 0.0;
}
for sample in data_slice.iter_mut() {
*sample = 0.0;
}
return Ok(());
};
let buffer = {
let buffer_len = args.num_frames * args.data.channels().count();
Buffer {
args: &mut args,
buffer: vec![0.0; buffer_len],
buffer: data_slice
}
};
@ -210,8 +243,7 @@ impl EventLoop {
}
pub struct Buffer<'a, T: 'a> {
args: &'a mut render_callback::Args<data::NonInterleaved<T>>,
buffer: Vec<T>,
buffer: &'a mut [T],
}
impl<'a, T> Buffer<'a, T>
@ -219,7 +251,7 @@ impl<'a, T> Buffer<'a, T>
{
#[inline]
pub fn buffer(&mut self) -> &mut [T] {
&mut self.buffer[..]
&mut self.buffer
}
#[inline]
@ -229,13 +261,6 @@ impl<'a, T> Buffer<'a, T>
#[inline]
pub fn finish(self) {
// TODO: At the moment this assumes the Vec<T> is a Vec<f32>.
// Need to add T: Sample and use Sample::to_vec_f32.
let num_channels = self.args.data.channels().count();
for (i, frame) in self.buffer.chunks(num_channels).enumerate() {
for (channel, sample) in self.args.data.channels_mut().zip(frame.iter()) {
channel[i] = *sample;
}
}
// Do nothing. We wrote directly to the buffer.
}
}

View File

@ -111,6 +111,7 @@
#![recursion_limit = "512"]
#[cfg(target_os = "windows")]
#[macro_use]
extern crate lazy_static;