mod.rs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. use std::io;
  2. pub trait Open {
  3. fn open(Option<String>) -> Self;
  4. }
  5. pub trait Sink {
  6. fn start(&mut self) -> io::Result<()>;
  7. fn stop(&mut self) -> io::Result<()>;
  8. fn write(&mut self, data: &[i16]) -> io::Result<()>;
  9. }
  10. /*
  11. * Allow #[cfg] rules around elements of a list.
  12. * Workaround until stmt_expr_attributes is stable.
  13. *
  14. * This generates 2^n declarations of the list, with every combination possible
  15. */
  16. macro_rules! declare_backends {
  17. (pub const $name:ident : $ty:ty = & [ $($tt:tt)* ];) => (
  18. _declare_backends!($name ; $ty ; []; []; []; $($tt)*);
  19. );
  20. }
  21. macro_rules! _declare_backends {
  22. ($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; #[cfg($m:meta)] $e:expr, $($rest:tt)* ) => (
  23. _declare_backends!($name ; $ty ; [ $m, $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; $($rest)*);
  24. _declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $m, $($no,)* ] ; [ $($exprs,)* ] ; $($rest)*);
  25. );
  26. ($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; $e:expr, $($rest:tt)*) => (
  27. _declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; $($rest)*);
  28. );
  29. ($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; #[cfg($m:meta)] $e:expr) => (
  30. _declare_backends!($name ; $ty ; [ $m, $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; );
  31. _declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $m, $($no,)* ] ; [ $($exprs,)* ] ; );
  32. );
  33. ($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; $e:expr ) => (
  34. _declare_backends!($name ; $ty ; [ $($yes,)* ] ; [ $($no,)* ] ; [ $($exprs,)* $e, ] ; );
  35. );
  36. ($name:ident ; $ty:ty ; [ $($yes:meta,)* ] ; [ $($no:meta,)* ] ; [ $($exprs:expr,)* ] ; ) => (
  37. #[cfg(all($($yes,)* not(any($($no),*))))]
  38. pub const $name : $ty = &[
  39. $($exprs,)*
  40. ];
  41. )
  42. }
  43. fn mk_sink<S: Sink + Open + 'static>(device: Option<String>) -> Box<Sink> {
  44. Box::new(S::open(device))
  45. }
  46. #[cfg(feature = "alsa-backend")]
  47. mod alsa;
  48. #[cfg(feature = "alsa-backend")]
  49. use self::alsa::AlsaSink;
  50. #[cfg(feature = "portaudio-backend")]
  51. mod portaudio;
  52. #[cfg(feature = "portaudio-backend")]
  53. use self::portaudio::PortAudioSink;
  54. #[cfg(feature = "pulseaudio-backend")]
  55. mod pulseaudio;
  56. #[cfg(feature = "pulseaudio-backend")]
  57. use self::pulseaudio::PulseAudioSink;
  58. mod pipe;
  59. use self::pipe::StdoutSink;
  60. declare_backends! {
  61. pub const BACKENDS : &'static [
  62. (&'static str, fn(Option<String>) -> Box<Sink>)
  63. ] = &[
  64. #[cfg(feature = "alsa-backend")]
  65. ("alsa", mk_sink::<AlsaSink>),
  66. #[cfg(feature = "portaudio-backend")]
  67. ("portaudio", mk_sink::<PortAudioSink>),
  68. #[cfg(feature = "pulseaudio-backend")]
  69. ("pulseaudio", mk_sink::<PulseAudioSink>),
  70. ("pipe", mk_sink::<StdoutSink>),
  71. ];
  72. }
  73. pub fn find(name: Option<String>) -> Option<fn(Option<String>) -> Box<Sink>> {
  74. if let Some(name) = name {
  75. BACKENDS.iter().find(|backend| name == backend.0).map(|backend| backend.1)
  76. } else {
  77. Some(BACKENDS.first().expect("No backends were enabled at build time").1)
  78. }
  79. }