use error::Error;
use portaudio::pa;
use portaudio::pa::Sample as PaSample;
use sample::Format as SampleFormat;
use sample::Sample;
use settings::Frames;
use std::marker::PhantomData;
pub mod duplex;
pub mod input;
pub mod output;
pub const MINIMUM_BUFFER_RESERVATION: usize = 2048;
#[derive(Clone, PartialEq)]
pub struct SoundStream {
maybe_buffer_frequency: Option<BufferFrequency>,
maybe_sample_hz: Option<f64>,
maybe_flags: Option<StreamFlags>,
}
pub type StreamFlags = pa::StreamFlags;
pub type CallbackFlags = pa::StreamCallbackFlags;
#[derive(Copy, Clone, PartialEq)]
enum BufferFrequency {
Hz(f32),
Frames(Frames),
}
pub type DeltaTimeSeconds = f64;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CallbackResult {
Complete,
Continue,
Abort,
}
pub type PaParams = (StreamFlags, pa::StreamParameters, f64, u32);
pub type Idx = pa::DeviceIndex;
pub type Latency = pa::Time;
#[derive(Copy, Clone, PartialEq)]
pub struct StreamParams<S> {
pub idx: Option<Idx>,
pub channel_count: Option<i32>,
pub suggested_latency: Option<Latency>,
pub phantom_sample: PhantomData<S>,
}
impl SoundStream {
#[inline]
pub fn new() -> SoundStream {
SoundStream {
maybe_buffer_frequency: None,
maybe_sample_hz: None,
maybe_flags: None,
}
}
#[inline]
pub fn sample_hz(self, sample_hz: f64) -> SoundStream {
SoundStream { maybe_sample_hz: Some(sample_hz), ..self }
}
#[inline]
pub fn flags(self, flags: StreamFlags) -> SoundStream {
SoundStream { maybe_flags: Some(flags), ..self }
}
#[inline]
pub fn buffer_hz(self, hz: f32) -> SoundStream {
assert!(hz > 0.0, "`update_hz` must be greater than 0.0, but you gave {:?}", hz);
SoundStream { maybe_buffer_frequency: Some(BufferFrequency::Hz(hz)), ..self }
}
#[inline]
pub fn frames_per_buffer(self, frames: Frames) -> SoundStream {
SoundStream { maybe_buffer_frequency: Some(BufferFrequency::Frames(frames)), ..self }
}
#[inline]
pub fn input<I>(self, params: StreamParams<I>) -> input::Builder<I>
where
I: Sample + PaSample
{
input::Builder { stream_params: self, input_params: params }
}
#[inline]
pub fn output<O>(self, params: StreamParams<O>) -> output::Builder<O>
where
O: Sample + PaSample
{
output::Builder { stream_params: self, output_params: params }
}
#[inline]
pub fn duplex<I, O>(self,
input_params: StreamParams<I>,
output_params: StreamParams<O>) -> duplex::Builder<I, O>
where
I: Sample + PaSample,
O: Sample + PaSample,
{
duplex::Builder {
stream_params: self,
input_params: input_params,
output_params: output_params,
}
}
}
impl<S> StreamParams<S> {
pub fn new() -> StreamParams<S> {
StreamParams {
idx: None,
channel_count: None,
suggested_latency: None,
phantom_sample: PhantomData,
}
}
#[inline]
pub fn device_idx(self, idx: Idx) -> StreamParams<S> {
StreamParams { idx: Some(idx), ..self }
}
#[inline]
pub fn channels(self, channels: i32) -> StreamParams<S> {
StreamParams { channel_count: Some(channels), ..self }
}
#[inline]
pub fn sample_format(&self) -> pa::SampleFormat where S: pa::Sample {
S::sample_format_for::<S>()
}
#[inline]
pub fn suggest_latency(self, latency: Latency) -> StreamParams<S> {
StreamParams { suggested_latency: Some(latency), ..self }
}
}
fn wait_for_stream<F>(f: F) -> Result<u32, Error>
where
F: Fn() -> Result<pa::StreamAvailable, pa::Error>,
{
loop {
match f() {
Ok(available) => match available {
pa::StreamAvailable::Frames(frames) => return Ok(frames as u32),
pa::StreamAvailable::InputOverflowed => println!("Input stream has overflowed"),
pa::StreamAvailable::OutputUnderflowed => println!("Output stream has underflowed"),
},
Err(err) => return Err(Error::PortAudio(err)),
}
}
}