2016-07-05 20:54:03 +00:00
|
|
|
extern crate coreaudio;
|
2015-02-28 18:50:29 +00:00
|
|
|
extern crate libc;
|
|
|
|
|
2015-09-24 03:02:28 +00:00
|
|
|
use CreationError;
|
|
|
|
use Format;
|
|
|
|
use FormatsEnumerationError;
|
2016-08-12 07:49:13 +00:00
|
|
|
use Sample;
|
2015-09-24 03:02:28 +00:00
|
|
|
use SampleFormat;
|
|
|
|
use SamplesRate;
|
|
|
|
use ChannelPosition;
|
2016-08-12 07:49:13 +00:00
|
|
|
use UnknownTypeBuffer;
|
|
|
|
|
2016-10-01 07:21:29 +00:00
|
|
|
use futures::Poll;
|
|
|
|
use futures::Async;
|
|
|
|
use futures::task::Task;
|
|
|
|
use futures::task;
|
2016-08-12 07:49:13 +00:00
|
|
|
use futures::stream::Stream;
|
|
|
|
use std::sync::{Arc, Mutex};
|
2017-04-07 10:06:00 +00:00
|
|
|
use std::thread;
|
|
|
|
use std::time::Duration;
|
2016-08-12 07:49:13 +00:00
|
|
|
|
|
|
|
use self::coreaudio::audio_unit::AudioUnit;
|
|
|
|
use self::coreaudio::audio_unit::render_callback::{self, data};
|
2015-02-28 18:50:29 +00:00
|
|
|
|
2015-09-24 03:02:28 +00:00
|
|
|
mod enumerate;
|
|
|
|
|
|
|
|
pub use self::enumerate::{EndpointsIterator,
|
|
|
|
SupportedFormatsIterator,
|
|
|
|
get_default_endpoint};
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
|
|
|
pub struct Endpoint;
|
|
|
|
|
|
|
|
impl Endpoint {
|
|
|
|
pub fn get_supported_formats_list(&self)
|
|
|
|
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
|
|
|
|
{
|
2015-09-24 17:54:54 +00:00
|
|
|
Ok(vec!(Format {
|
|
|
|
channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
|
|
|
samples_rate: SamplesRate(44100),
|
|
|
|
data_type: SampleFormat::F32
|
|
|
|
}).into_iter())
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_name(&self) -> String {
|
|
|
|
"Default AudioUnit Endpoint".to_string()
|
|
|
|
}
|
2015-02-28 18:50:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
pub struct EventLoop;
|
|
|
|
impl EventLoop {
|
|
|
|
#[inline]
|
|
|
|
pub fn new() -> EventLoop { EventLoop }
|
|
|
|
#[inline]
|
2017-04-07 10:06:00 +00:00
|
|
|
pub fn run(&self) {
|
|
|
|
loop {
|
|
|
|
// So the loop does not get optimised out in --release
|
|
|
|
thread::sleep(Duration::new(1u64, 0u32));
|
|
|
|
}
|
|
|
|
}
|
2016-08-12 07:49:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Buffer<T> {
|
|
|
|
args: render_callback::Args<data::NonInterleaved<T>>,
|
|
|
|
buffer: Vec<T>,
|
2015-02-28 18:50:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
impl<T> Buffer<T> where T: Sample {
|
2015-09-24 03:02:28 +00:00
|
|
|
#[inline]
|
2016-08-12 07:49:13 +00:00
|
|
|
pub fn get_buffer(&mut self) -> &mut [T] {
|
|
|
|
&mut self.buffer[..]
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
2015-02-28 18:50:29 +00:00
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-24 03:02:28 +00:00
|
|
|
pub fn len(&self) -> usize {
|
2016-08-12 07:49:13 +00:00
|
|
|
self.buffer.len()
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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.
|
2016-08-12 07:49:13 +00:00
|
|
|
let Buffer { mut args, buffer } = self;
|
|
|
|
|
|
|
|
let num_channels = args.data.channels().count();
|
|
|
|
for (i, frame) in buffer.chunks(num_channels).enumerate() {
|
|
|
|
for (channel, sample) in args.data.channels_mut().zip(frame.iter()) {
|
|
|
|
channel[i] = *sample;
|
|
|
|
}
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-18 06:20:40 +00:00
|
|
|
pub struct Voice {
|
|
|
|
playing: bool,
|
2017-04-19 10:44:42 +00:00
|
|
|
audio_unit: Arc<Mutex<AudioUnit>>,
|
2016-10-18 06:20:40 +00:00
|
|
|
}
|
2016-08-12 07:49:13 +00:00
|
|
|
|
2015-09-24 21:24:12 +00:00
|
|
|
#[allow(dead_code)] // the audio_unit will be dropped if we don't hold it.
|
2016-08-12 07:49:13 +00:00
|
|
|
pub struct SamplesStream {
|
|
|
|
inner: Arc<Mutex<SamplesStreamInner>>,
|
2017-04-19 10:44:42 +00:00
|
|
|
audio_unit: Arc<Mutex<AudioUnit>>,
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
|
|
|
|
struct SamplesStreamInner {
|
2016-10-01 07:21:29 +00:00
|
|
|
scheduled_task: Option<Task>,
|
2016-08-12 07:49:13 +00:00
|
|
|
current_callback: Option<render_callback::Args<data::NonInterleaved<f32>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stream for SamplesStream {
|
|
|
|
type Item = UnknownTypeBuffer;
|
|
|
|
type Error = ();
|
|
|
|
|
2016-10-01 07:21:29 +00:00
|
|
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
2016-08-12 07:49:13 +00:00
|
|
|
let mut inner = self.inner.lock().unwrap();
|
|
|
|
|
|
|
|
// There are two possibilites: either we're answering a callback of coreaudio and we return
|
|
|
|
// a buffer, or we're not answering a callback and we return that we're not ready.
|
|
|
|
|
|
|
|
let current_callback = match inner.current_callback.take() {
|
|
|
|
Some(c) => c,
|
2016-10-01 07:21:29 +00:00
|
|
|
None => {
|
2016-10-01 08:19:27 +00:00
|
|
|
inner.scheduled_task = Some(task::park());
|
2016-10-01 07:21:29 +00:00
|
|
|
return Ok(Async::NotReady);
|
|
|
|
}
|
2016-08-12 07:49:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let buffer_len = current_callback.num_frames * current_callback.data.channels().count();
|
|
|
|
|
|
|
|
let buffer = Buffer {
|
|
|
|
args: current_callback,
|
|
|
|
buffer: vec![0.0; buffer_len],
|
|
|
|
};
|
|
|
|
|
2016-10-01 07:21:29 +00:00
|
|
|
Ok(Async::Ready(Some(UnknownTypeBuffer::F32(::Buffer { target: Some(buffer) }))))
|
2016-08-12 07:49:13 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-24 03:14:32 +00:00
|
|
|
|
2015-09-24 03:02:28 +00:00
|
|
|
impl Voice {
|
2016-08-12 07:49:13 +00:00
|
|
|
pub fn new(_: &Endpoint, _: &Format, _: &EventLoop)
|
|
|
|
-> Result<(Voice, SamplesStream), CreationError>
|
|
|
|
{
|
|
|
|
let inner = Arc::new(Mutex::new(SamplesStreamInner {
|
|
|
|
scheduled_task: None,
|
|
|
|
current_callback: None,
|
|
|
|
}));
|
|
|
|
|
|
|
|
fn convert_error(err: coreaudio::Error) -> CreationError {
|
|
|
|
match err {
|
|
|
|
coreaudio::Error::RenderCallbackBufferFormatDoesNotMatchAudioUnitStreamFormat |
|
|
|
|
coreaudio::Error::NoKnownSubtype |
|
|
|
|
coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::FormatNotSupported) |
|
|
|
|
coreaudio::Error::AudioCodec(_) |
|
|
|
|
coreaudio::Error::AudioFormat(_) => CreationError::FormatNotSupported,
|
|
|
|
_ => CreationError::DeviceNotAvailable,
|
|
|
|
}
|
|
|
|
}
|
2015-09-24 03:02:28 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
let au_type = coreaudio::audio_unit::IOType::DefaultOutput;
|
|
|
|
let mut audio_unit = try!(AudioUnit::new(au_type).map_err(convert_error));
|
2015-09-24 21:24:12 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
// TODO: iOS uses integer and fixed-point data
|
2016-06-28 23:09:54 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
{
|
|
|
|
let inner = inner.clone();
|
|
|
|
let result = audio_unit.set_render_callback(move |args| {
|
|
|
|
// This callback is entered whenever the coreaudio engine needs to be fed data.
|
2016-06-28 23:09:54 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
// Store the callback argument in the `SamplesStreamInner` and return the task
|
|
|
|
// that we're supposed to notify.
|
|
|
|
let scheduled = {
|
|
|
|
let mut inner = inner.lock().unwrap();
|
2016-01-12 16:06:14 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
assert!(inner.current_callback.is_none());
|
|
|
|
inner.current_callback = Some(args);
|
|
|
|
|
|
|
|
inner.scheduled_task.take()
|
|
|
|
};
|
|
|
|
|
|
|
|
// It is important that `inner` is unlocked here.
|
|
|
|
if let Some(scheduled) = scheduled {
|
2016-10-01 07:21:29 +00:00
|
|
|
// Calling `unpark()` should eventually call `poll()` on the `SamplesStream`,
|
2016-08-12 07:49:13 +00:00
|
|
|
// which will use the data we stored in `current_callback`.
|
2016-10-01 07:21:29 +00:00
|
|
|
scheduled.unpark();
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
2016-08-12 07:49:13 +00:00
|
|
|
|
|
|
|
// TODO: what should happen if the callback wasn't processed? in other word, what
|
|
|
|
// if the user didn't register any handler or did a stupid thing in the
|
|
|
|
// handler (like mem::forgetting the buffer)?
|
|
|
|
|
2015-09-24 03:02:28 +00:00
|
|
|
Ok(())
|
2016-08-12 07:49:13 +00:00
|
|
|
});
|
2015-09-24 03:02:28 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
try!(result.map_err(convert_error));
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
2016-01-12 16:06:14 +00:00
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
try!(audio_unit.start().map_err(convert_error));
|
2015-02-28 18:50:29 +00:00
|
|
|
|
2017-04-19 10:44:42 +00:00
|
|
|
let au_arc = Arc::new(Mutex::new(audio_unit));
|
|
|
|
|
2016-08-12 07:49:13 +00:00
|
|
|
let samples_stream = SamplesStream {
|
|
|
|
inner: inner,
|
2017-04-19 10:44:42 +00:00
|
|
|
audio_unit: au_arc.clone(),
|
2016-08-12 07:49:13 +00:00
|
|
|
};
|
|
|
|
|
2016-10-18 06:20:40 +00:00
|
|
|
Ok((Voice {
|
|
|
|
playing: true,
|
2017-04-19 10:44:42 +00:00
|
|
|
audio_unit: au_arc.clone(),
|
2016-10-18 06:20:40 +00:00
|
|
|
}, samples_stream))
|
2015-02-28 18:50:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-02-28 18:50:29 +00:00
|
|
|
pub fn play(&mut self) {
|
2016-10-18 06:20:40 +00:00
|
|
|
if !self.playing {
|
2017-04-19 10:44:42 +00:00
|
|
|
let mut unit = self.audio_unit.lock().unwrap();
|
|
|
|
unit.start().unwrap();
|
2016-10-18 06:20:40 +00:00
|
|
|
self.playing = true;
|
|
|
|
}
|
2015-02-28 18:50:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-02-28 18:50:29 +00:00
|
|
|
pub fn pause(&mut self) {
|
2016-10-18 06:20:40 +00:00
|
|
|
if self.playing {
|
2017-04-19 10:44:42 +00:00
|
|
|
let mut unit = self.audio_unit.lock().unwrap();
|
|
|
|
unit.stop().unwrap();
|
2016-10-18 06:20:40 +00:00
|
|
|
self.playing = false;
|
|
|
|
}
|
2015-02-28 18:50:29 +00:00
|
|
|
}
|
|
|
|
}
|