Skip to content

Commit

Permalink
Merge pull request #73 from mitchmindtree/master
Browse files Browse the repository at this point in the history
Added StreamAvailable struct for handling both frame availability and over/underflow.
  • Loading branch information
mitchmindtree committed Apr 18, 2015
2 parents 5844d9d + 676f42b commit e2a307c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "portaudio"
version = "0.4.0"
version = "0.4.1"
authors = ["Jeremy Letang <letang.jeremy@gmail.com>",
"Mitchell Nordine <mitchell.nordine@gmail.com>"]
description = "PortAudio bindings for Rust."
Expand Down
14 changes: 9 additions & 5 deletions examples/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,17 @@ fn main() {
}

// We'll use this function to wait for read/write availability.
fn wait_for_stream<F: Fn() -> Result<Option<i64>, pa::error::Error>>(f: F, name: &str) {
fn wait_for_stream<F: Fn() -> Result<pa::StreamAvailable, pa::error::Error>>(f: F, name: &str) {
'waiting_for_stream: loop {
match f() {
Ok(None) => (),
Ok(Some(frames)) => {
println!("{} stream available with {} frames.", name, frames);
break 'waiting_for_stream
Ok(available) => match available {
pa::StreamAvailable::Frames(0) => (),
pa::StreamAvailable::Frames(frames) => {
println!("{} stream available with {} frames.", name, frames);
break 'waiting_for_stream
},
pa::StreamAvailable::InputOverflowed => println!("Input stream has overflowed"),
pa::StreamAvailable::OutputUnderflowed => println!("Output stream has underflowed"),
},
Err(err) => panic!("An error occurred while waiting for the {} stream: {}", name, err.description()),
}
Expand Down
4 changes: 2 additions & 2 deletions src/pa/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub enum Error {
StreamIsNotStopped,
/// The input stream has overflowed
InputOverflowed,
/// The output has overflowed
/// The output has underflowed
OutputUnderflowed,
/// The host API is not found by Portaudio
HostApiNotFound,
Expand Down Expand Up @@ -99,7 +99,7 @@ impl ::std::error::Error for Error {
Error::StreamIsStopped => "The stream is stopped",
Error::StreamIsNotStopped => "The stream is not stopped",
Error::InputOverflowed => "The input stream has overflowed",
Error::OutputUnderflowed => "The output stream has overflowed",
Error::OutputUnderflowed => "The output stream has underflowed",
Error::HostApiNotFound => "The host api is not found by Portaudio",
Error::InvalidHostApi => "The host API is invalid",
Error::CanNotReadFromACallbackStream => "Portaudio cannot read from the callback stream",
Expand Down
76 changes: 37 additions & 39 deletions src/pa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ use num::FromPrimitive;
use std::{ptr, mem};
use std::mem::{transmute};
use std::vec::{Vec};

use ffi;

pub use self::error::Error;
pub use self::types::{
StreamCallbackFn,
DeviceIndex,
DeviceInfo,
Frames,
Expand All @@ -40,7 +39,9 @@ pub use self::types::{
HostApiTypeId,
HostErrorInfo,
SampleFormat,
StreamAvailable,
StreamCallbackFlags,
StreamCallbackFn,
StreamCallbackTimeInfo,
StreamCallbackResult,
StreamFlags,
Expand Down Expand Up @@ -629,52 +630,50 @@ impl<I: Sample, O: Sample> Stream<I, O> {
}
}

/// Retrieve the number of frames that can be read from the stream without
/// waiting.
/// Retrieve the number of frames that can be read from the stream without waiting.
///
/// Returns a non-negative value representing the maximum number of frames
/// that can be read from the stream without blocking or busy waiting or,
/// a ErrorCode (which are always negative) if PortAudio is not initialized
/// or an error is encountered.
pub fn get_stream_read_available(&self) -> Result<Option<Frames>, Error> {
/// Returns a Result with either:
/// - An Ok variant with a `StreamAvailable` enum describing either:
/// - The number of frames available to be read from the stream (without blocking or busy
/// waiting) or
/// - Flags indicating whether or not there has been input overflow or output underflow.
/// - An Err variant in the case PortAudio is not initialized or some error is encountered.
///
/// See the blocking.rs example for a usage example.
pub fn get_stream_read_available(&self) -> Result<StreamAvailable, Error> {
match unsafe { ffi::Pa_GetStreamReadAvailable(self.c_pa_stream) } {
0 => Ok(None),
n if n > 0 => Ok(Some(n)),
n => Err(FromPrimitive::from_i64(n).expect("Undefined error code.")),
n if n >= 0 => Ok(StreamAvailable::Frames(n)),
n => match FromPrimitive::from_i64(n) {
Some(Error::InputOverflowed) => Ok(StreamAvailable::InputOverflowed),
Some(Error::OutputUnderflowed) => Ok(StreamAvailable::OutputUnderflowed),
Some(err) => Err(err),
_ => panic!("Undefined error code: {:?}", n),
},
}
}

/// Retrieve the number of frames that can be written to the stream without
/// waiting.
/// Retrieve the number of frames that can be written to the stream without waiting.
///
/// Returns a Result with either:
/// - An Ok variant with a `StreamAvailable` enum describing either:
/// - The number of frames available to be written to the stream (without blocking or busy
/// waiting) or
/// - Flags indicating whether or not there has been input overflow or output underflow.
/// - An Err variant in the case PortAudio is not initialized or some error is encountered.
///
/// Return a non-negative value representing the maximum number of frames that
/// can be written to the stream without blocking or busy waiting or,
/// a ErrorCode (which are always negative) if PortAudio is not initialized
/// or an error is encountered.
pub fn get_stream_write_available(&self) -> Result<Option<Frames>, Error> {
/// See the blocking.rs example for a usage example.
pub fn get_stream_write_available(&self) -> Result<StreamAvailable, Error> {
match unsafe { ffi::Pa_GetStreamWriteAvailable(self.c_pa_stream) } {
0 => Ok(None),
n if n > 0 => Ok(Some(n)),
n => Err(FromPrimitive::from_i64(n).expect("Undefined error code.")),
n if n >= 0 => Ok(StreamAvailable::Frames(n)),
n => match FromPrimitive::from_i64(n) {
Some(Error::InputOverflowed) => Ok(StreamAvailable::InputOverflowed),
Some(Error::OutputUnderflowed) => Ok(StreamAvailable::OutputUnderflowed),
Some(err) => Err(err),
_ => panic!("Undefined error code: {:?}", n),
},
}
}

#[doc(hidden)]
// Temporary OSX Fixe : Return always PaInputOverflowed
#[cfg(target_os="macos")]
pub fn read(&self, frames_per_buffer: u32) -> Result<Vec<I>, Error> {
unsafe {
ffi::Pa_ReadStream(self.c_pa_stream,
self.unsafe_buffer,
frames_per_buffer)
};
Ok(unsafe {
let len = (frames_per_buffer * self.num_input_channels as u32) as usize;
let slice = ::std::slice::from_raw_parts(self.unsafe_buffer as *const I, len);
slice.iter().map(|&sample| sample).collect()
})
}

/// Read samples from an input stream.
/// The function doesn't return until the entire buffer has been filled - this
/// may involve waiting for the operating system to supply the data.
Expand All @@ -684,7 +683,6 @@ impl<I: Sample, O: Sample> Stream<I, O> {
///
/// Return Ok(~[S]), a buffer containing the sample of the format S.
/// If fail return a Error code.
#[cfg(any(target_os="win32", target_os="linux"))]
pub fn read(&self, frames_per_buffer: u32) -> Result<Vec<I>, Error> {
let err = unsafe {
ffi::Pa_ReadStream(self.c_pa_stream, self.unsafe_buffer, frames_per_buffer)
Expand Down
12 changes: 12 additions & 0 deletions src/pa/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ pub enum StreamFlags {
PlatformSpecificFlags = ffi::PA_PLATFORM_SPECIFIC_FLAGS
}

/// Describes stream availability and the number for frames available for reading/writing if there
/// is any.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum StreamAvailable {
/// The number of frames available for reading.
Frames(i64),
/// The input stream has overflowed.
InputOverflowed,
/// The output stream has underflowed.
OutputUnderflowed,
}

/// A rust enum representation of the C_PaStreamCallbackFlag
#[repr(u64)]
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
Expand Down

0 comments on commit e2a307c

Please sign in to comment.