use ffi;
use libc;
use num::FromPrimitive;
use std::os::raw;
use std::{self, ptr};
use super::error::Error;
use super::types::{
sample_format_flags, DeviceIndex, DeviceKind, SampleFormat, SampleFormatFlags, Time,
};
use super::Sample;
pub use self::callback_flags::CallbackFlags;
pub use self::flags::Flags;
pub trait Mode {}
pub trait Settings {
type Flow;
fn into_flow_and_settings(self) -> (Self::Flow, f64, u32, Flags);
}
pub trait Flow {
type Buffer;
type CallbackArgs;
type CallbackTimeInfo;
fn new_buffer(&self, frames_per_buffer: u32) -> Self::Buffer;
fn params_both_directions(
&self,
) -> (
Option<ffi::PaStreamParameters>,
Option<ffi::PaStreamParameters>,
);
fn new_callback_args(
input: *const raw::c_void,
output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags,
in_channels: i32,
out_channels: i32,
) -> Self::CallbackArgs;
}
pub trait Reader: Flow {
type Sample;
fn readable_buffer(blocking: &Blocking<Self::Buffer>) -> &Buffer;
fn channel_count(&self) -> i32;
}
pub trait Writer: Flow {
type Sample;
fn writable_buffer(blocking: &mut Blocking<Self::Buffer>) -> &mut Buffer;
fn channel_count(&self) -> i32;
}
type CallbackFn = FnMut(
*const raw::c_void,
*mut raw::c_void,
raw::c_ulong,
*const ffi::PaStreamCallbackTimeInfo,
ffi::PaStreamCallbackFlags,
) -> ffi::PaStreamCallbackResult;
struct CallbackFnWrapper {
f: Box<CallbackFn>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct InputCallbackTimeInfo {
pub current: Time,
pub buffer_adc: Time,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct OutputCallbackTimeInfo {
pub current: Time,
pub buffer_dac: Time,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DuplexCallbackTimeInfo {
pub current: Time,
pub in_buffer_adc: Time,
pub out_buffer_dac: Time,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct InputCallbackArgs<'a, I: 'a> {
pub buffer: &'a [I],
pub frames: usize,
pub flags: CallbackFlags,
pub time: InputCallbackTimeInfo,
}
#[derive(Debug, PartialEq)]
pub struct OutputCallbackArgs<'a, O: 'a> {
pub buffer: &'a mut [O],
pub frames: usize,
pub flags: CallbackFlags,
pub time: OutputCallbackTimeInfo,
}
#[derive(Debug, PartialEq)]
pub struct DuplexCallbackArgs<'a, I: 'a, O: 'a> {
pub in_buffer: &'a [I],
pub out_buffer: &'a mut [O],
pub frames: usize,
pub flags: CallbackFlags,
pub time: DuplexCallbackTimeInfo,
}
pub struct Blocking<B> {
buffer: B,
}
pub struct NonBlocking {
callback: Box<CallbackFnWrapper>,
}
#[allow(dead_code)]
pub struct Stream<M, F> {
pa_stream: *mut ffi::PaStream,
mode: M,
flow: F,
port_audio_life: std::sync::Arc<super::Life>,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Parameters<S> {
pub device: DeviceKind,
pub channel_count: i32,
pub suggested_latency: Time,
pub is_interleaved: bool,
sample_format: std::marker::PhantomData<S>,
}
#[derive(Copy, Clone, Debug)]
pub struct InputSettings<I> {
pub params: Parameters<I>,
pub sample_rate: f64,
pub frames_per_buffer: u32,
pub flags: Flags,
}
#[derive(Copy, Clone, Debug)]
pub struct OutputSettings<O> {
pub params: Parameters<O>,
pub sample_rate: f64,
pub frames_per_buffer: u32,
pub flags: Flags,
}
#[derive(Copy, Clone, Debug)]
pub struct DuplexSettings<I, O> {
pub in_params: Parameters<I>,
pub out_params: Parameters<O>,
pub sample_rate: f64,
pub frames_per_buffer: u32,
pub flags: Flags,
}
pub struct Input<I> {
params: Parameters<I>,
}
pub struct Output<O> {
params: Parameters<O>,
}
pub struct Duplex<I, O> {
in_params: Parameters<I>,
out_params: Parameters<O>,
}
unsafe impl Send for NonBlocking {}
unsafe impl<M, F> Send for Stream<M, F>
where
M: Send,
F: Send,
{
}
impl<S> Parameters<S> {
pub fn new(
device: DeviceIndex,
channel_count: i32,
is_interleaved: bool,
suggested_latency: Time,
) -> Self {
Self::new_internal(
device.into(),
channel_count,
is_interleaved,
suggested_latency,
)
}
pub fn host_api_specific_device(
channel_count: i32,
is_interleaved: bool,
suggested_latency: Time,
) -> Self {
let kind = DeviceKind::UseHostApiSpecificDeviceSpecification;
Self::new_internal(kind, channel_count, is_interleaved, suggested_latency)
}
fn new_internal(
device_kind: DeviceKind,
channel_count: i32,
is_interleaved: bool,
suggested_latency: Time,
) -> Self {
Parameters {
device: device_kind,
channel_count: channel_count,
is_interleaved: is_interleaved,
suggested_latency: suggested_latency,
sample_format: std::marker::PhantomData,
}
}
}
macro_rules! impl_half_duplex_settings {
($name:ident) => {
impl<S> $name<S> {
pub fn new(params: Parameters<S>, sample_rate: f64, frames_per_buffer: u32) -> Self {
Self::with_flags(params, sample_rate, frames_per_buffer, Flags::empty())
}
pub fn with_flags(
params: Parameters<S>,
sample_rate: f64,
frames_per_buffer: u32,
flags: Flags,
) -> Self {
$name {
params: params,
sample_rate: sample_rate,
frames_per_buffer: frames_per_buffer,
flags: flags,
}
}
}
};
}
impl_half_duplex_settings!(OutputSettings);
impl_half_duplex_settings!(InputSettings);
impl<I, O> DuplexSettings<I, O> {
pub fn new(
in_params: Parameters<I>,
out_params: Parameters<O>,
sample_rate: f64,
frames_per_buffer: u32,
) -> Self {
Self::with_flags(
in_params,
out_params,
sample_rate,
frames_per_buffer,
Flags::empty(),
)
}
pub fn with_flags(
in_params: Parameters<I>,
out_params: Parameters<O>,
sample_rate: f64,
frames_per_buffer: u32,
flags: Flags,
) -> Self {
DuplexSettings {
in_params: in_params,
out_params: out_params,
sample_rate: sample_rate,
frames_per_buffer: frames_per_buffer,
flags: flags,
}
}
}
impl<I> Flow for Input<I>
where
I: Sample + 'static,
{
type Buffer = Buffer;
type CallbackArgs = InputCallbackArgs<'static, I>;
type CallbackTimeInfo = InputCallbackTimeInfo;
fn new_buffer(&self, frames_per_buffer: u32) -> Self::Buffer {
let channel_count = self.params.channel_count;
Buffer::new::<I>(frames_per_buffer, channel_count)
}
fn params_both_directions(
&self,
) -> (
Option<ffi::PaStreamParameters>,
Option<ffi::PaStreamParameters>,
) {
(Some(self.params.into()), None)
}
fn new_callback_args(
input: *const raw::c_void,
_output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags,
in_channels: i32,
_out_channels: i32,
) -> Self::CallbackArgs {
let flags = CallbackFlags::from_bits(flags).unwrap_or_else(|| CallbackFlags::empty());
let time = unsafe {
InputCallbackTimeInfo {
current: (*time_info).currentTime,
buffer_adc: (*time_info).inputBufferAdcTime,
}
};
let buffer: &[I] = {
let buffer_len = in_channels as usize * frame_count as usize;
let buffer_ptr = input as *const I;
unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_len) }
};
InputCallbackArgs {
buffer: buffer,
frames: frame_count as usize,
flags: flags,
time: time,
}
}
}
impl<O> Flow for Output<O>
where
O: Sample + 'static,
{
type Buffer = Buffer;
type CallbackArgs = OutputCallbackArgs<'static, O>;
type CallbackTimeInfo = OutputCallbackTimeInfo;
fn params_both_directions(
&self,
) -> (
Option<ffi::PaStreamParameters>,
Option<ffi::PaStreamParameters>,
) {
(None, Some(self.params.into()))
}
fn new_buffer(&self, frames_per_buffer: u32) -> Self::Buffer {
let channel_count = self.params.channel_count;
Buffer::new::<O>(frames_per_buffer, channel_count)
}
fn new_callback_args(
_input: *const raw::c_void,
output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags,
_in_channels: i32,
out_channels: i32,
) -> Self::CallbackArgs {
let flags = CallbackFlags::from_bits(flags).unwrap_or_else(|| CallbackFlags::empty());
let time = unsafe {
OutputCallbackTimeInfo {
current: (*time_info).currentTime,
buffer_dac: (*time_info).outputBufferDacTime,
}
};
let buffer: &mut [O] = {
let buffer_len = out_channels as usize * frame_count as usize;
let buffer_ptr = output as *mut O;
unsafe { std::slice::from_raw_parts_mut(buffer_ptr, buffer_len) }
};
OutputCallbackArgs {
buffer: buffer,
frames: frame_count as usize,
flags: flags,
time: time,
}
}
}
impl<I, O> Flow for Duplex<I, O>
where
I: Sample + 'static,
O: Sample + 'static,
{
type Buffer = (Buffer, Buffer);
type CallbackArgs = DuplexCallbackArgs<'static, I, O>;
type CallbackTimeInfo = DuplexCallbackTimeInfo;
fn params_both_directions(
&self,
) -> (
Option<ffi::PaStreamParameters>,
Option<ffi::PaStreamParameters>,
) {
(Some(self.in_params.into()), Some(self.out_params.into()))
}
fn new_buffer(&self, frames_per_buffer: u32) -> Self::Buffer {
let in_channel_count = self.in_params.channel_count;
let in_buffer = Buffer::new::<I>(frames_per_buffer, in_channel_count);
let out_channel_count = self.out_params.channel_count;
let out_buffer = Buffer::new::<O>(frames_per_buffer, out_channel_count);
(in_buffer, out_buffer)
}
fn new_callback_args(
input: *const raw::c_void,
output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags,
in_channels: i32,
out_channels: i32,
) -> Self::CallbackArgs {
let flags = CallbackFlags::from_bits(flags).unwrap_or_else(|| CallbackFlags::empty());
let time = unsafe {
DuplexCallbackTimeInfo {
current: (*time_info).currentTime,
in_buffer_adc: (*time_info).inputBufferAdcTime,
out_buffer_dac: (*time_info).outputBufferDacTime,
}
};
let in_buffer: &[I] = {
let buffer_len = in_channels as usize * frame_count as usize;
let buffer_ptr = input as *const I;
unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_len) }
};
let out_buffer: &mut [O] = {
let buffer_len = out_channels as usize * frame_count as usize;
let buffer_ptr = output as *mut O;
unsafe { std::slice::from_raw_parts_mut(buffer_ptr, buffer_len) }
};
DuplexCallbackArgs {
in_buffer: in_buffer,
out_buffer: out_buffer,
frames: frame_count as usize,
flags: flags,
time: time,
}
}
}
impl<I> Reader for Input<I>
where
I: Sample + 'static,
{
type Sample = I;
fn readable_buffer(blocking: &Blocking<<Input<I> as Flow>::Buffer>) -> &Buffer {
&blocking.buffer
}
fn channel_count(&self) -> i32 {
self.params.channel_count
}
}
impl<I, O> Reader for Duplex<I, O>
where
I: Sample + 'static,
O: Sample + 'static,
{
type Sample = I;
fn readable_buffer(blocking: &Blocking<<Duplex<I, O> as Flow>::Buffer>) -> &Buffer {
&blocking.buffer.0
}
fn channel_count(&self) -> i32 {
self.in_params.channel_count
}
}
impl<O> Writer for Output<O>
where
O: Sample + 'static,
{
type Sample = O;
fn writable_buffer(blocking: &mut Blocking<<Output<O> as Flow>::Buffer>) -> &mut Buffer {
&mut blocking.buffer
}
fn channel_count(&self) -> i32 {
self.params.channel_count
}
}
impl<I, O> Writer for Duplex<I, O>
where
I: Sample + 'static,
O: Sample + 'static,
{
type Sample = O;
fn writable_buffer(blocking: &mut Blocking<<Duplex<I, O> as Flow>::Buffer>) -> &mut Buffer {
&mut blocking.buffer.1
}
fn channel_count(&self) -> i32 {
self.out_params.channel_count
}
}
pub struct Buffer {
data: *mut libc::c_void,
}
pub mod flags {
use ffi;
bitflags! {
pub flags Flags: ::std::os::raw::c_ulong {
const NO_FLAG = ffi::PA_NO_FLAG,
const CLIP_OFF = ffi::PA_CLIP_OFF,
const DITHER_OFF = ffi::PA_DITHER_OFF,
const NEVER_DROP_INPUT = ffi::PA_NEVER_DROP_INPUT,
const PA_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK = ffi::PA_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK,
const PA_PLATFORM_SPECIFIC_FLAGS = ffi::PA_PLATFORM_SPECIFIC_FLAGS,
}
}
impl ::std::fmt::Display for Flags {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(
f,
"{:?}",
match self.bits() {
ffi::PA_NO_FLAG => "NO_FLAG",
ffi::PA_CLIP_OFF => "CLIP_OFF",
ffi::PA_DITHER_OFF => "DITHER_OFF",
ffi::PA_NEVER_DROP_INPUT => "NEVER_DROP_INPUT",
ffi::PA_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK => {
"PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK"
}
ffi::PA_PLATFORM_SPECIFIC_FLAGS => "PLATFORM_SPECIFIC_FLAGS",
_ => "<Unknown StreamFlags>",
}
)
}
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Available {
Frames(::std::os::raw::c_long),
InputOverflowed,
OutputUnderflowed,
}
pub mod callback_flags {
use ffi;
bitflags! {
pub flags CallbackFlags: ::std::os::raw::c_ulong {
const NO_FLAG = ffi::PA_NO_FLAG,
const INPUT_UNDERFLOW = ffi::INPUT_UNDERFLOW,
const INPUT_OVERFLOW = ffi::INPUT_OVERFLOW,
const OUTPUT_UNDERFLOW = ffi::OUTPUT_UNDERFLOW,
const OUTPUT_OVERFLOW = ffi::OUTPUT_OVERFLOW,
const PRIMING_OUTPUT = ffi::PRIMING_OUTPUT,
}
}
impl ::std::fmt::Display for CallbackFlags {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(
f,
"{:?}",
match self.bits() {
ffi::PA_NO_FLAG => "NO_FLAG",
ffi::INPUT_UNDERFLOW => "INPUT_UNDERFLOW",
ffi::INPUT_OVERFLOW => "INPUT_OVERFLOW",
ffi::OUTPUT_UNDERFLOW => "OUTPUT_UNDERFLOW",
ffi::OUTPUT_OVERFLOW => "OUTPUT_OVERFLOW",
ffi::PRIMING_OUTPUT => "PRIMING_INPUT",
_ => "<Unknown StreamCallbackFlags>",
}
)
}
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct CallbackTimeInfo {
pub input_buffer_adc_time: Time,
pub current_time: Time,
pub output_buffer_dac_time: Time,
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
#[repr(C)]
pub struct Info {
pub struct_version: i32,
pub input_latency: Time,
pub output_latency: Time,
pub sample_rate: f64,
}
impl From<ffi::PaStreamInfo> for Info {
fn from(info: ffi::PaStreamInfo) -> Info {
Info {
struct_version: info.structVersion,
input_latency: info.inputLatency,
output_latency: info.outputLatency,
sample_rate: info.sampleRate,
}
}
}
impl<B> Mode for Blocking<B> {}
impl Mode for NonBlocking {}
impl<S: Sample> Parameters<S> {
pub fn from_c_params(c_params: ffi::PaStreamParameters) -> Option<Self> {
let sample_format_flags: SampleFormatFlags = c_params.sampleFormat.into();
let is_interleaved = !sample_format_flags.contains(sample_format_flags::NON_INTERLEAVED);
let c_sample_format = SampleFormat::from_flags(c_params.sampleFormat.into());
if S::sample_format() != c_sample_format {
return None;
}
let device = match c_params.device {
n if n >= 0 => DeviceIndex(n as u32).into(),
-1 => DeviceKind::UseHostApiSpecificDeviceSpecification,
_ => return None,
};
Some(Parameters {
device: device,
channel_count: c_params.channelCount,
suggested_latency: c_params.suggestedLatency,
is_interleaved: is_interleaved,
sample_format: std::marker::PhantomData,
})
}
}
impl<S: Sample> From<Parameters<S>> for ffi::PaStreamParameters {
fn from(params: Parameters<S>) -> Self {
let Parameters {
device,
channel_count,
suggested_latency,
is_interleaved,
..
} = params;
let sample_format = S::sample_format();
let mut sample_format_flags = sample_format.flags();
if !is_interleaved {
sample_format_flags.insert(sample_format_flags::NON_INTERLEAVED);
}
ffi::PaStreamParameters {
device: device.into(),
channelCount: channel_count as raw::c_int,
sampleFormat: sample_format_flags.bits(),
suggestedLatency: suggested_latency,
hostApiSpecificStreamInfo: ptr::null_mut(),
}
}
}
impl<I> Settings for InputSettings<I> {
type Flow = Input<I>;
fn into_flow_and_settings(self) -> (Self::Flow, f64, u32, Flags) {
let InputSettings {
params,
sample_rate,
frames_per_buffer,
flags,
} = self;
let flow = Input { params: params };
(flow, sample_rate, frames_per_buffer, flags)
}
}
impl<O> Settings for OutputSettings<O> {
type Flow = Output<O>;
fn into_flow_and_settings(self) -> (Self::Flow, f64, u32, Flags) {
let OutputSettings {
params,
sample_rate,
frames_per_buffer,
flags,
} = self;
let flow = Output { params: params };
(flow, sample_rate, frames_per_buffer, flags)
}
}
impl<I, O> Settings for DuplexSettings<I, O> {
type Flow = Duplex<I, O>;
fn into_flow_and_settings(self) -> (Self::Flow, f64, u32, Flags) {
let DuplexSettings {
in_params,
out_params,
sample_rate,
frames_per_buffer,
flags,
} = self;
let flow = Duplex {
in_params: in_params,
out_params: out_params,
};
(flow, sample_rate, frames_per_buffer, flags)
}
}
impl Buffer {
fn new<S>(frames_per_buffer: u32, channel_count: i32) -> Buffer {
let sample_format_bytes = ::std::mem::size_of::<S>() as libc::size_t;
let n_frames = frames_per_buffer as libc::size_t;
let n_channels = channel_count as libc::size_t;
let malloc_size = sample_format_bytes * n_frames * n_channels;
Buffer {
data: unsafe { libc::malloc(malloc_size) as *mut libc::c_void },
}
}
unsafe fn slice<'a, S>(&'a self, frames: u32, channels: i32) -> &'a [S] {
let len = (frames * channels as u32) as usize;
std::slice::from_raw_parts(self.data as *const S, len)
}
unsafe fn slice_mut<'a, S>(&'a mut self, frames: u32, channels: i32) -> &'a mut [S] {
let len = (frames * channels as u32) as usize;
std::slice::from_raw_parts_mut(self.data as *mut S, len)
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe { libc::free(self.data) }
}
}
fn open_blocking_stream(
in_params: Option<ffi::PaStreamParameters>,
out_params: Option<ffi::PaStreamParameters>,
sample_rate: f64,
frames_per_buffer: u32,
flags: Flags,
) -> Result<*mut raw::c_void, Error> {
let mut c_stream_ptr: *mut raw::c_void = ptr::null_mut();
let in_c_params = in_params.map(|p| p.into());
let out_c_params = out_params.map(|p| p.into());
let in_c_params_ptr = in_c_params
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null());
let out_c_params_ptr = out_c_params
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null());
let c_flags = flags.bits();
unsafe {
let error_code = ffi::Pa_OpenStream(
&mut c_stream_ptr,
in_c_params_ptr,
out_c_params_ptr,
sample_rate,
frames_per_buffer as raw::c_ulong,
c_flags,
None,
ptr::null_mut(),
);
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
Error::NoError => Ok(c_stream_ptr),
err => Err(err),
}
}
}
fn open_non_blocking_stream(
in_params: Option<ffi::PaStreamParameters>,
out_params: Option<ffi::PaStreamParameters>,
sample_rate: f64,
frames_per_buffer: u32,
flags: Flags,
callback: &mut CallbackFnWrapper,
) -> Result<*mut raw::c_void, Error> {
let mut c_stream_ptr: *mut raw::c_void = ptr::null_mut();
let in_c_params = in_params.map(|p| p.into());
let out_c_params = out_params.map(|p| p.into());
let in_c_params_ptr = in_c_params
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null());
let out_c_params_ptr = out_c_params
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null());
let c_flags = flags.bits();
let user_data = {
let callback_fn_ptr = callback as *mut CallbackFnWrapper;
callback_fn_ptr as *mut raw::c_void
};
unsafe {
let error_code = ffi::Pa_OpenStream(
&mut c_stream_ptr,
in_c_params_ptr,
out_c_params_ptr,
sample_rate,
frames_per_buffer as raw::c_ulong,
c_flags,
Some(stream_callback_proc),
user_data,
);
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
Error::NoError => Ok(c_stream_ptr),
err => Err(err),
}
}
}
impl<M, F> Stream<M, F> {
fn new_unopened(mode: M, flow: F, life: std::sync::Arc<super::Life>) -> Self {
Stream {
pa_stream: ptr::null_mut(),
mode: mode,
flow: flow,
port_audio_life: life,
}
}
pub fn close(&mut self) -> Result<(), Error> {
let error_code = unsafe { ffi::Pa_CloseStream(self.pa_stream) };
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
Error::NoError => Ok(()),
err => Err(err),
}
}
pub fn start(&mut self) -> Result<(), Error> {
let error_code = unsafe { ffi::Pa_StartStream(self.pa_stream) };
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
0 => Ok(()),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
pub fn stop(&mut self) -> Result<(), Error> {
let error_code = unsafe { ffi::Pa_StopStream(self.pa_stream) };
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
0 => Ok(()),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
pub fn abort(&mut self) -> Result<(), Error> {
let error_code = unsafe { ffi::Pa_AbortStream(self.pa_stream) };
let error = FromPrimitive::from_i32(error_code).unwrap();
match error {
0 => Ok(()),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
pub fn is_stopped(&self) -> Result<bool, Error> {
let error_code = unsafe { ffi::Pa_IsStreamStopped(self.pa_stream) };
match error_code {
1 => Ok(true),
0 => Ok(false),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
pub fn is_active(&self) -> Result<bool, Error> {
let error_code = unsafe { ffi::Pa_IsStreamActive(self.pa_stream) };
match error_code {
0 => Ok(false),
1 => Ok(true),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
pub fn time(&self) -> Time {
unsafe { ffi::Pa_GetStreamTime(self.pa_stream) }
}
pub fn info(&self) -> Info {
unsafe {
let info = ffi::Pa_GetStreamInfo(self.pa_stream);
Info::from(*info)
}
}
pub fn unsafe_pa_stream(&self) -> *mut ffi::PaStream {
self.pa_stream
}
}
impl<F> Stream<Blocking<F::Buffer>, F>
where
F: Flow,
{
pub fn open<S>(life: std::sync::Arc<super::Life>, settings: S) -> Result<Self, Error>
where
S: Settings<Flow = F>,
{
let (flow, sample_rate, frames_per_buffer, flags) = settings.into_flow_and_settings();
let buffer = flow.new_buffer(frames_per_buffer);
let blocking = Blocking { buffer: buffer };
let (in_params, out_params) = flow.params_both_directions();
let mut stream = Stream::new_unopened(blocking, flow, life);
open_blocking_stream(in_params, out_params, sample_rate, frames_per_buffer, flags).map(
|pa_stream| {
stream.pa_stream = pa_stream;
stream
},
)
}
}
impl<F> Stream<Blocking<F::Buffer>, F>
where
F: Flow + Reader,
{
pub fn read_available(&self) -> Result<Available, Error> {
match unsafe { ffi::Pa_GetStreamReadAvailable(self.pa_stream) } {
n if n >= 0 => Ok(Available::Frames(n)),
n => match FromPrimitive::from_i64(n as i64) {
Some(Error::InputOverflowed) => Ok(Available::InputOverflowed),
Some(Error::OutputUnderflowed) => Ok(Available::OutputUnderflowed),
Some(err) => Err(err),
_ => panic!("Undefined error code: {:?}", n),
},
}
}
pub fn read<'b>(&'b self, frames: u32) -> Result<&'b [F::Sample], Error> {
let buffer = F::readable_buffer(&self.mode);
let err = unsafe {
ffi::Pa_ReadStream(
self.pa_stream,
buffer.data as *mut raw::c_void,
frames as raw::c_ulong,
)
};
match err {
0 => unsafe {
let channel_count = Reader::channel_count(&self.flow);
Ok(buffer.slice(frames, channel_count))
},
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
}
impl<F> Stream<Blocking<F::Buffer>, F>
where
F: Flow + Writer,
{
pub fn write_available(&self) -> Result<Available, Error> {
match unsafe { ffi::Pa_GetStreamWriteAvailable(self.pa_stream) } {
n if n >= 0 => Ok(Available::Frames(n)),
n => match FromPrimitive::from_i64(n as i64) {
Some(Error::InputOverflowed) => Ok(Available::InputOverflowed),
Some(Error::OutputUnderflowed) => Ok(Available::OutputUnderflowed),
Some(err) => Err(err),
_ => panic!("Undefined error code: {:?}", n),
},
}
}
pub fn write<WF>(&mut self, frames: u32, write_fn: WF) -> Result<(), Error>
where
WF: for<'b> FnOnce(&'b mut [F::Sample]),
{
let pa_stream = self.pa_stream;
let channels = Writer::channel_count(&self.flow);
let out_buffer = F::writable_buffer(&mut self.mode);
let written_slice = {
let slice = unsafe { out_buffer.slice_mut(frames, channels) };
write_fn(slice);
slice
};
let result = unsafe {
let written_slice_ptr = written_slice.as_ptr() as *mut raw::c_void;
ffi::Pa_WriteStream(pa_stream, written_slice_ptr, frames as raw::c_ulong)
};
match result {
0 => Ok(()),
err => Err(FromPrimitive::from_i32(err).unwrap()),
}
}
}
impl<F> Stream<NonBlocking, F> {
pub fn open<S, C>(
life: std::sync::Arc<super::Life>,
settings: S,
mut callback: C,
) -> Result<Self, Error>
where
S: Settings<Flow = F>,
F: Flow,
C: FnMut(F::CallbackArgs) -> ffi::PaStreamCallbackResult + 'static,
{
let (flow, sample_rate, frames_per_buffer, flags) = settings.into_flow_and_settings();
let (in_params, out_params) = flow.params_both_directions();
let in_channels = in_params.map(|p| p.channelCount).unwrap_or(0);
let out_channels = out_params.map(|p| p.channelCount).unwrap_or(0);
let callback_wrapper_fn = move |input: *const raw::c_void,
output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags|
-> ffi::PaStreamCallbackResult {
let args = F::new_callback_args(
input,
output,
frame_count,
time_info,
flags,
in_channels,
out_channels,
);
callback(args)
};
let non_blocking = NonBlocking {
callback: Box::new(CallbackFnWrapper {
f: Box::new(callback_wrapper_fn),
}),
};
let mut stream = Stream::new_unopened(non_blocking, flow, life);
open_non_blocking_stream(
in_params,
out_params,
sample_rate,
frames_per_buffer,
flags,
&mut stream.mode.callback,
)
.map(|pa_stream| {
stream.pa_stream = pa_stream;
stream
})
}
pub fn cpu_load(&self) -> f64 {
unsafe { ffi::Pa_GetStreamCpuLoad(self.pa_stream) }
}
}
impl<M, F> Drop for Stream<M, F> {
fn drop(&mut self) {
self.stop().ok();
self.close().ok();
}
}
extern "C" fn stream_callback_proc(
input: *const raw::c_void,
output: *mut raw::c_void,
frame_count: raw::c_ulong,
time_info: *const ffi::PaStreamCallbackTimeInfo,
flags: ffi::PaStreamCallbackFlags,
user_callback_ptr: *mut raw::c_void,
) -> ffi::PaStreamCallbackResult {
let callback = user_callback_ptr as *mut CallbackFnWrapper;
unsafe { ((*callback).f)(input, output, frame_count, time_info, flags) }
}