2016-03-20 16:16:11 +00:00
|
|
|
use std::io;
|
|
|
|
|
|
|
|
pub trait Open {
|
2016-07-06 09:54:46 +00:00
|
|
|
fn open(Option<&str>) -> Self;
|
2016-03-20 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Sink {
|
2016-08-01 19:20:17 +00:00
|
|
|
fn start(&mut self) -> io::Result<()>;
|
|
|
|
fn stop(&mut self) -> io::Result<()>;
|
|
|
|
fn write(&mut self, data: &[i16]) -> io::Result<()>;
|
2016-03-20 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allow #[cfg] rules around elements of a list.
|
|
|
|
* Workaround until stmt_expr_attributes is stable.
|
|
|
|
*
|
|
|
|
* This generates 2^n declarations of the list, with every combination possible
|
|
|
|
*/
|
|
|
|
macro_rules! declare_backends {
|
|
|
|
(pub const $name:ident : $ty:ty = & [ $($tt:tt)* ];) => (
|
|
|
|
_declare_backends!($name ; $ty ; []; []; []; $($tt)*);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! _declare_backends {
|
|
|
|
($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; #[cfg($m:meta)] $e:expr, $($rest:tt)* ) => (
|
|
|
|
_declare_backends!($name ; $ty ; [ $m, $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; $($rest)*);
|
|
|
|
_declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $m, $($no,)* ] ; [ $($exprs,)* ] ; $($rest)*);
|
|
|
|
);
|
|
|
|
|
|
|
|
($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; $e:expr, $($rest:tt)*) => (
|
|
|
|
_declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; $($rest)*);
|
|
|
|
);
|
|
|
|
|
|
|
|
($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; #[cfg($m:meta)] $e:expr) => (
|
|
|
|
_declare_backends!($name ; $ty ; [ $m, $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; );
|
|
|
|
_declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $m, $($no,)* ] ; [ $($exprs,)* ] ; );
|
|
|
|
);
|
|
|
|
|
|
|
|
($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; $e:expr ) => (
|
|
|
|
_declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; );
|
|
|
|
);
|
|
|
|
|
|
|
|
($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; ) => (
|
|
|
|
#[cfg(all($($yes,)* not(any($($no),*))))]
|
|
|
|
pub const $name : $ty = &[
|
|
|
|
$($exprs,)*
|
|
|
|
];
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2016-07-06 09:54:46 +00:00
|
|
|
fn mk_sink<S: Sink + Open + 'static>(device: Option<&str>) -> Box<Sink> {
|
|
|
|
Box::new(S::open(device))
|
2016-03-20 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2016-03-14 02:16:59 +00:00
|
|
|
#[cfg(feature = "alsa-backend")]
|
|
|
|
mod alsa;
|
|
|
|
#[cfg(feature = "alsa-backend")]
|
|
|
|
use self::alsa::AlsaSink;
|
|
|
|
|
2016-03-20 16:16:11 +00:00
|
|
|
#[cfg(feature = "portaudio-backend")]
|
|
|
|
mod portaudio;
|
2016-05-04 08:56:23 +00:00
|
|
|
#[cfg(feature = "portaudio-backend")]
|
|
|
|
use self::portaudio::PortAudioSink;
|
2016-03-20 16:16:11 +00:00
|
|
|
|
2016-03-20 19:16:32 +00:00
|
|
|
#[cfg(feature = "pulseaudio-backend")]
|
|
|
|
mod pulseaudio;
|
2016-05-04 08:56:23 +00:00
|
|
|
#[cfg(feature = "pulseaudio-backend")]
|
|
|
|
use self::pulseaudio::PulseAudioSink;
|
2016-03-20 19:16:32 +00:00
|
|
|
|
2016-12-31 12:17:06 +00:00
|
|
|
mod pipe;
|
|
|
|
use self::pipe::StdoutSink;
|
2016-03-20 19:16:32 +00:00
|
|
|
|
2016-03-20 16:16:11 +00:00
|
|
|
declare_backends! {
|
2016-07-06 09:54:46 +00:00
|
|
|
pub const BACKENDS : &'static [
|
|
|
|
(&'static str,
|
|
|
|
&'static (Fn(Option<&str>) -> Box<Sink> + Sync + Send + 'static))
|
|
|
|
] = &[
|
2016-03-14 02:16:59 +00:00
|
|
|
#[cfg(feature = "alsa-backend")]
|
|
|
|
("alsa", &mk_sink::<AlsaSink>),
|
2016-03-20 16:16:11 +00:00
|
|
|
#[cfg(feature = "portaudio-backend")]
|
2016-05-04 08:56:23 +00:00
|
|
|
("portaudio", &mk_sink::<PortAudioSink>),
|
2016-03-20 19:16:32 +00:00
|
|
|
#[cfg(feature = "pulseaudio-backend")]
|
2016-05-04 08:56:23 +00:00
|
|
|
("pulseaudio", &mk_sink::<PulseAudioSink>),
|
2016-12-31 12:17:06 +00:00
|
|
|
("pipe", &mk_sink::<StdoutSink>),
|
2016-03-20 16:16:11 +00:00
|
|
|
];
|
|
|
|
}
|
2017-01-10 16:31:12 +00:00
|
|
|
|
|
|
|
pub fn find<T: AsRef<str>>(name: Option<T>) -> Option<&'static (Fn(Option<&str>) -> Box<Sink> + Send + Sync)> {
|
|
|
|
if let Some(name) = name.as_ref().map(AsRef::as_ref) {
|
|
|
|
BACKENDS.iter().find(|backend| name == backend.0).map(|backend| backend.1)
|
|
|
|
} else {
|
|
|
|
Some(BACKENDS.first().expect("No backends were enabled at build time").1)
|
|
|
|
}
|
|
|
|
}
|