2021-03-12 22:05:38 +00:00
|
|
|
use crate::config::AudioFormat;
|
2021-04-13 08:29:34 +00:00
|
|
|
use crate::decoder::AudioPacket;
|
2016-03-20 16:16:11 +00:00
|
|
|
use std::io;
|
|
|
|
|
|
|
|
pub trait Open {
|
2021-03-12 22:05:38 +00:00
|
|
|
fn open(_: Option<String>, format: AudioFormat) -> 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<()>;
|
2021-01-07 06:42:38 +00:00
|
|
|
fn write(&mut self, packet: &AudioPacket) -> io::Result<()>;
|
2016-03-20 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-10 08:27:24 +00:00
|
|
|
pub type SinkBuilder = fn(Option<String>, AudioFormat) -> Box<dyn Sink>;
|
2021-01-22 21:51:41 +00:00
|
|
|
|
2021-03-12 22:05:38 +00:00
|
|
|
pub trait SinkAsBytes {
|
|
|
|
fn write_bytes(&mut self, data: &[u8]) -> io::Result<()>;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk_sink<S: Sink + Open + 'static>(device: Option<String>, format: AudioFormat) -> Box<dyn Sink> {
|
|
|
|
Box::new(S::open(device, format))
|
|
|
|
}
|
|
|
|
|
|
|
|
// reuse code for various backends
|
|
|
|
macro_rules! sink_as_bytes {
|
|
|
|
() => {
|
|
|
|
fn write(&mut self, packet: &AudioPacket) -> io::Result<()> {
|
2021-04-13 08:29:34 +00:00
|
|
|
use crate::convert::{self, i24};
|
2021-03-12 22:05:38 +00:00
|
|
|
use zerocopy::AsBytes;
|
|
|
|
match packet {
|
|
|
|
AudioPacket::Samples(samples) => match self.format {
|
|
|
|
AudioFormat::F32 => self.write_bytes(samples.as_bytes()),
|
2021-03-13 22:43:24 +00:00
|
|
|
AudioFormat::S32 => {
|
2021-04-10 12:06:41 +00:00
|
|
|
let samples_s32: &[i32] = &convert::to_s32(samples);
|
2021-03-13 22:43:24 +00:00
|
|
|
self.write_bytes(samples_s32.as_bytes())
|
|
|
|
}
|
2021-03-16 23:00:27 +00:00
|
|
|
AudioFormat::S24 => {
|
2021-04-10 12:06:41 +00:00
|
|
|
let samples_s24: &[i32] = &convert::to_s24(samples);
|
2021-03-16 23:00:27 +00:00
|
|
|
self.write_bytes(samples_s24.as_bytes())
|
|
|
|
}
|
|
|
|
AudioFormat::S24_3 => {
|
2021-04-10 12:06:41 +00:00
|
|
|
let samples_s24_3: &[i24] = &convert::to_s24_3(samples);
|
2021-03-16 23:00:27 +00:00
|
|
|
self.write_bytes(samples_s24_3.as_bytes())
|
|
|
|
}
|
2021-03-12 22:05:38 +00:00
|
|
|
AudioFormat::S16 => {
|
2021-04-10 12:06:41 +00:00
|
|
|
let samples_s16: &[i16] = &convert::to_s16(samples);
|
2021-03-12 22:05:38 +00:00
|
|
|
self.write_bytes(samples_s16.as_bytes())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
AudioPacket::OggData(samples) => self.write_bytes(samples),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! start_stop_noop {
|
|
|
|
() => {
|
|
|
|
fn start(&mut self) -> io::Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn stop(&mut self) -> io::Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
};
|
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
|
|
|
|
2017-10-05 18:41:02 +00:00
|
|
|
#[cfg(feature = "jackaudio-backend")]
|
|
|
|
mod jackaudio;
|
|
|
|
#[cfg(feature = "jackaudio-backend")]
|
|
|
|
use self::jackaudio::JackSink;
|
|
|
|
|
2019-12-25 11:19:12 +00:00
|
|
|
#[cfg(feature = "gstreamer-backend")]
|
|
|
|
mod gstreamer;
|
|
|
|
#[cfg(feature = "gstreamer-backend")]
|
|
|
|
use self::gstreamer::GstreamerSink;
|
|
|
|
|
2021-02-23 14:05:02 +00:00
|
|
|
#[cfg(any(feature = "rodio-backend", feature = "rodiojack-backend"))]
|
2019-03-20 13:24:03 +00:00
|
|
|
mod rodio;
|
2021-02-23 14:05:02 +00:00
|
|
|
|
2018-12-28 02:46:27 +00:00
|
|
|
#[cfg(feature = "sdl-backend")]
|
|
|
|
mod sdl;
|
|
|
|
#[cfg(feature = "sdl-backend")]
|
|
|
|
use self::sdl::SdlSink;
|
2018-11-15 19:34:13 +00:00
|
|
|
|
2016-12-31 12:17:06 +00:00
|
|
|
mod pipe;
|
|
|
|
use self::pipe::StdoutSink;
|
2016-03-20 19:16:32 +00:00
|
|
|
|
2020-01-24 00:35:24 +00:00
|
|
|
mod subprocess;
|
|
|
|
use self::subprocess::SubprocessSink;
|
|
|
|
|
2021-03-01 02:37:22 +00:00
|
|
|
pub const BACKENDS: &[(&str, SinkBuilder)] = &[
|
2017-05-10 15:26:48 +00:00
|
|
|
#[cfg(feature = "alsa-backend")]
|
|
|
|
("alsa", mk_sink::<AlsaSink>),
|
|
|
|
#[cfg(feature = "portaudio-backend")]
|
|
|
|
("portaudio", mk_sink::<PortAudioSink>),
|
|
|
|
#[cfg(feature = "pulseaudio-backend")]
|
|
|
|
("pulseaudio", mk_sink::<PulseAudioSink>),
|
2017-10-05 18:41:02 +00:00
|
|
|
#[cfg(feature = "jackaudio-backend")]
|
|
|
|
("jackaudio", mk_sink::<JackSink>),
|
2019-12-25 11:19:12 +00:00
|
|
|
#[cfg(feature = "gstreamer-backend")]
|
|
|
|
("gstreamer", mk_sink::<GstreamerSink>),
|
2019-03-20 13:24:03 +00:00
|
|
|
#[cfg(feature = "rodio-backend")]
|
2021-02-23 14:05:02 +00:00
|
|
|
("rodio", rodio::mk_rodio),
|
|
|
|
#[cfg(feature = "rodiojack-backend")]
|
|
|
|
("rodiojack", rodio::mk_rodiojack),
|
2018-12-28 02:46:27 +00:00
|
|
|
#[cfg(feature = "sdl-backend")]
|
|
|
|
("sdl", mk_sink::<SdlSink>),
|
2017-05-10 15:26:48 +00:00
|
|
|
("pipe", mk_sink::<StdoutSink>),
|
2020-01-24 00:35:24 +00:00
|
|
|
("subprocess", mk_sink::<SubprocessSink>),
|
2017-05-10 15:26:48 +00:00
|
|
|
];
|
2017-01-10 16:31:12 +00:00
|
|
|
|
2021-01-22 21:51:41 +00:00
|
|
|
pub fn find(name: Option<String>) -> Option<SinkBuilder> {
|
2017-04-28 22:24:55 +00:00
|
|
|
if let Some(name) = name {
|
2018-02-26 01:50:41 +00:00
|
|
|
BACKENDS
|
|
|
|
.iter()
|
|
|
|
.find(|backend| name == backend.0)
|
|
|
|
.map(|backend| backend.1)
|
2017-01-10 16:31:12 +00:00
|
|
|
} else {
|
2018-02-26 01:50:41 +00:00
|
|
|
Some(
|
|
|
|
BACKENDS
|
|
|
|
.first()
|
|
|
|
.expect("No backends were enabled at build time")
|
|
|
|
.1,
|
|
|
|
)
|
2017-01-10 16:31:12 +00:00
|
|
|
}
|
|
|
|
}
|