Initial untested VecDeque concept.

This commit is contained in:
Will Stott 2018-11-15 19:34:13 +00:00
parent 8b32e7a63e
commit 891298171c
4 changed files with 102 additions and 0 deletions

View file

@ -63,6 +63,7 @@ alsa-backend = ["librespot-playback/alsa-backend"]
portaudio-backend = ["librespot-playback/portaudio-backend"]
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
cpal-backend = ["librespot-playback/cpal-backend"]
with-tremor = ["librespot-audio/with-tremor"]
with-vorbis = ["librespot-audio/with-vorbis"]

View file

@ -20,9 +20,11 @@ portaudio-rs = { version = "0.3.0", optional = true }
libpulse-sys = { version = "0.0.0", optional = true }
jack = { version = "0.5.3", optional = true }
libc = { version = "0.2", optional = true }
cpal = { version = "0.8.2", optional = true }
[features]
alsa-backend = ["alsa"]
portaudio-backend = ["portaudio-rs"]
pulseaudio-backend = ["libpulse-sys", "libc"]
jackaudio-backend = ["jack"]
cpal-backend = ["cpal"]

View file

@ -0,0 +1,92 @@
use super::{Open, Sink};
extern crate cpal;
use std::io;
use std::thread;
use std::collections::VecDeque;
pub struct CpalSink {
event_loop: cpal::EventLoop,
buffer: mut VecDeque<i16>,
stream_id: Option<cpal::StreamId>,
}
impl Open for CpalSink {
fn open(device: Option<String>) -> CpalSink {
info!("Using cpal sink");
if device.is_some() {
// N.B. This is perfectly possible to support.
// TODO: First need to enable listing of devices.
// Remember to filter to those which support Stereo 16bit 44100Hz
// TODO: Choose cpal sink by name.
panic!("cpal sink does not support specifying a device name");
}
let event_loop = cpal::EventLoop::new();
CpalSink {
// Allow an (arbitrary) 2 second buffer before resizing.
buffer: VecDeque::with_capacity(44100 * 2 * 2),
event_loop: event_loop,
}
}
}
impl Sink for CpalSink {
fn start(&mut self) -> io::Result<()> {
if self.stream_id.is_none() {
let device = cpal::default_output_device().expect("no output device available");
// TODO: Support more formats.
let format = cpal::Format(2, 44100, cpal::SampleFormat::I16);
self.stream_id = self.event_loop.build_output_stream(&device, &format)?;
self.event_loop.play_stream(self.stream_id.clone());
}
if self.thread.is_none() {
let event_loop = self.event_loop;
let source = self.buffer;
thread::spawn(move |event_loop, source| {
event_loop.run(move |_stream_id, mut stream_data| {
match data {
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => {
let sl = source.len();
if (sl > buffer.len()) {
sl = buffer.len();
}
// let u: Vec<_> = source.drain(..sl).collect();
// buffer[..s1].copy_from_slice(u[..s1]);
for (sample, data) in buffer.iter_mut().zip(source.drain(..sl)) {
*sample = data;
}
},
_ => (),
}
});
})
}
Ok(())
}
fn stop(&mut self) -> io::Result<()> {
if !self.stream_id.is_none() {
self.event_loop.destroy_stream(self.stream_id);
self.stream_id = None;
self.buffer.clear();
}
Ok(())
}
fn write(&mut self, data: &[i16]) -> io::Result<()> {
// self.0.as_mut().unwrap().write_interleaved(&data).unwrap();
// self.buffer.reserve(data.len()); // Unneccessary?
// self.buffer.extend_from_slice(data);
self.buffer.extend(data);
Ok(())
}
}

View file

@ -34,6 +34,11 @@ mod jackaudio;
#[cfg(feature = "jackaudio-backend")]
use self::jackaudio::JackSink;
#[cfg(feature = "cpal-backend")]
mod cpal;
#[cfg(feature = "cpal-backend")]
use self::cpal::CpalSink;
mod pipe;
use self::pipe::StdoutSink;
@ -46,6 +51,8 @@ pub const BACKENDS: &'static [(&'static str, fn(Option<String>) -> Box<Sink>)] =
("pulseaudio", mk_sink::<PulseAudioSink>),
#[cfg(feature = "jackaudio-backend")]
("jackaudio", mk_sink::<JackSink>),
#[cfg(feature = "cpal-backend")]
("cpal", mk_sink::<CpalSink>),
("pipe", mk_sink::<StdoutSink>),
];