Merge pull request #112 from Furyhunter/coreaudio-get-period

[osx] Add get_period to Voice
This commit is contained in:
tomaka 2016-06-29 08:35:31 +02:00 committed by GitHub
commit 7e4f9f00d1
1 changed files with 24 additions and 5 deletions

View File

@ -3,6 +3,7 @@ extern crate libc;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::RefCell; use std::cell::RefCell;
use std::mem; use std::mem;
use std::cmp; use std::cmp;
@ -47,6 +48,7 @@ pub struct Buffer<'a, T: 'a> {
samples: Vec<T>, samples: Vec<T>,
num_channels: NumChannels, num_channels: NumChannels,
marker: PhantomData<&'a T>, marker: PhantomData<&'a T>,
pending_samples: Arc<AtomicUsize>
} }
impl<'a, T> Buffer<'a, T> { impl<'a, T> Buffer<'a, T> {
@ -62,10 +64,12 @@ impl<'a, T> Buffer<'a, T> {
#[inline] #[inline]
pub fn finish(self) { pub fn finish(self) {
let Buffer { samples_sender, samples, num_channels, .. } = self; let Buffer { samples_sender, samples, num_channels, pending_samples, .. } = self;
// TODO: At the moment this assumes the Vec<T> is a Vec<f32>. // TODO: At the moment this assumes the Vec<T> is a Vec<f32>.
// Need to add T: Sample and use Sample::to_vec_f32. // Need to add T: Sample and use Sample::to_vec_f32.
let num_samples = samples.len();
let samples = unsafe { mem::transmute(samples) }; let samples = unsafe { mem::transmute(samples) };
pending_samples.fetch_add(num_samples, Ordering::SeqCst);
match samples_sender.send((samples, num_channels)) { match samples_sender.send((samples, num_channels)) {
Err(_) => panic!("Failed to send samples to audio unit callback."), Err(_) => panic!("Failed to send samples to audio unit callback."),
Ok(()) => (), Ok(()) => (),
@ -82,7 +86,8 @@ pub struct Voice {
ready_receiver: Receiver<(NumChannels, NumFrames)>, ready_receiver: Receiver<(NumChannels, NumFrames)>,
samples_sender: Sender<(Vec<f32>, NumChannels)>, samples_sender: Sender<(Vec<f32>, NumChannels)>,
underflow: Arc<Mutex<RefCell<bool>>>, underflow: Arc<Mutex<RefCell<bool>>>,
last_ready: Arc<Mutex<RefCell<Option<(NumChannels, NumFrames)>>>> last_ready: Arc<Mutex<RefCell<Option<(NumChannels, NumFrames)>>>>,
pending_samples: Arc<AtomicUsize>
} }
unsafe impl Sync for Voice {} unsafe impl Sync for Voice {}
@ -98,6 +103,10 @@ impl Voice {
let underflow = Arc::new(Mutex::new(RefCell::new(false))); let underflow = Arc::new(Mutex::new(RefCell::new(false)));
let uf_clone = underflow.clone(); let uf_clone = underflow.clone();
let pending_samples: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
let pending_samples_c = pending_samples.clone();
let audio_unit_result = AudioUnit::new(IOType::HalOutput); let audio_unit_result = AudioUnit::new(IOType::HalOutput);
if let Ok(mut audio_unit) = audio_unit_result { if let Ok(mut audio_unit) = audio_unit_result {
@ -112,11 +121,14 @@ impl Voice {
*(uf.borrow_mut()) = num_frames > samples.len() / num_channels; *(uf.borrow_mut()) = num_frames > samples.len() / num_channels;
} else { return Err("Couldn't lock underflow flag field.".to_string()) } } else { return Err("Couldn't lock underflow flag field.".to_string()) }
pending_samples_c.fetch_sub(samples.len(), Ordering::SeqCst);
for (i, frame) in samples.chunks(num_channels).enumerate() { for (i, frame) in samples.chunks(num_channels).enumerate() {
for (channel, sample) in channels.iter_mut().zip(frame.iter()) { for (channel, sample) in channels.iter_mut().zip(frame.iter()) {
channel[i] = *sample; channel[i] = *sample;
} }
} }
break; break;
}; };
} }
@ -129,7 +141,8 @@ impl Voice {
ready_receiver: ready_receiver, ready_receiver: ready_receiver,
samples_sender: samples_sender, samples_sender: samples_sender,
underflow: underflow, underflow: underflow,
last_ready: Arc::new(Mutex::new(RefCell::new(None))) last_ready: Arc::new(Mutex::new(RefCell::new(None))),
pending_samples: pending_samples
}) })
} }
} }
@ -146,7 +159,8 @@ impl Voice {
samples_sender: self.samples_sender.clone(), samples_sender: self.samples_sender.clone(),
samples: vec![unsafe { mem::uninitialized() }; buffer_size], samples: vec![unsafe { mem::uninitialized() }; buffer_size],
num_channels: channels as usize, num_channels: channels as usize,
marker: PhantomData marker: PhantomData,
pending_samples: self.pending_samples.clone()
} }
} }
@ -161,7 +175,7 @@ impl Voice {
} }
#[inline] #[inline]
pub fn get_pending_samples(&self) -> usize { pub fn get_period(&self) -> usize {
if let Some(ready) = self.update_last_ready() { if let Some(ready) = self.update_last_ready() {
(ready.0 * ready.1) as usize (ready.0 * ready.1) as usize
} else { } else {
@ -169,6 +183,11 @@ impl Voice {
} }
} }
#[inline]
pub fn get_pending_samples(&self) -> usize {
self.pending_samples.load(Ordering::Relaxed)
}
/// Attempts to store the most recent ready message into the internal /// Attempts to store the most recent ready message into the internal
/// ref cell, then return the last ready message. If the last ready hasn't /// ref cell, then return the last ready message. If the last ready hasn't
/// been reset with `clear_last_ready`, then it will not be set and the /// been reset with `clear_last_ready`, then it will not be set and the