mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Initial untested VecDeque concept.
This commit is contained in:
parent
8b32e7a63e
commit
891298171c
4 changed files with 102 additions and 0 deletions
|
@ -63,6 +63,7 @@ alsa-backend = ["librespot-playback/alsa-backend"]
|
||||||
portaudio-backend = ["librespot-playback/portaudio-backend"]
|
portaudio-backend = ["librespot-playback/portaudio-backend"]
|
||||||
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
|
pulseaudio-backend = ["librespot-playback/pulseaudio-backend"]
|
||||||
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
|
jackaudio-backend = ["librespot-playback/jackaudio-backend"]
|
||||||
|
cpal-backend = ["librespot-playback/cpal-backend"]
|
||||||
|
|
||||||
with-tremor = ["librespot-audio/with-tremor"]
|
with-tremor = ["librespot-audio/with-tremor"]
|
||||||
with-vorbis = ["librespot-audio/with-vorbis"]
|
with-vorbis = ["librespot-audio/with-vorbis"]
|
||||||
|
|
|
@ -20,9 +20,11 @@ portaudio-rs = { version = "0.3.0", optional = true }
|
||||||
libpulse-sys = { version = "0.0.0", optional = true }
|
libpulse-sys = { version = "0.0.0", optional = true }
|
||||||
jack = { version = "0.5.3", optional = true }
|
jack = { version = "0.5.3", optional = true }
|
||||||
libc = { version = "0.2", optional = true }
|
libc = { version = "0.2", optional = true }
|
||||||
|
cpal = { version = "0.8.2", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alsa-backend = ["alsa"]
|
alsa-backend = ["alsa"]
|
||||||
portaudio-backend = ["portaudio-rs"]
|
portaudio-backend = ["portaudio-rs"]
|
||||||
pulseaudio-backend = ["libpulse-sys", "libc"]
|
pulseaudio-backend = ["libpulse-sys", "libc"]
|
||||||
jackaudio-backend = ["jack"]
|
jackaudio-backend = ["jack"]
|
||||||
|
cpal-backend = ["cpal"]
|
||||||
|
|
92
playback/src/audio_backend/cpal.rs
Normal file
92
playback/src/audio_backend/cpal.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,11 @@ mod jackaudio;
|
||||||
#[cfg(feature = "jackaudio-backend")]
|
#[cfg(feature = "jackaudio-backend")]
|
||||||
use self::jackaudio::JackSink;
|
use self::jackaudio::JackSink;
|
||||||
|
|
||||||
|
#[cfg(feature = "cpal-backend")]
|
||||||
|
mod cpal;
|
||||||
|
#[cfg(feature = "cpal-backend")]
|
||||||
|
use self::cpal::CpalSink;
|
||||||
|
|
||||||
mod pipe;
|
mod pipe;
|
||||||
use self::pipe::StdoutSink;
|
use self::pipe::StdoutSink;
|
||||||
|
|
||||||
|
@ -46,6 +51,8 @@ pub const BACKENDS: &'static [(&'static str, fn(Option<String>) -> Box<Sink>)] =
|
||||||
("pulseaudio", mk_sink::<PulseAudioSink>),
|
("pulseaudio", mk_sink::<PulseAudioSink>),
|
||||||
#[cfg(feature = "jackaudio-backend")]
|
#[cfg(feature = "jackaudio-backend")]
|
||||||
("jackaudio", mk_sink::<JackSink>),
|
("jackaudio", mk_sink::<JackSink>),
|
||||||
|
#[cfg(feature = "cpal-backend")]
|
||||||
|
("cpal", mk_sink::<CpalSink>),
|
||||||
("pipe", mk_sink::<StdoutSink>),
|
("pipe", mk_sink::<StdoutSink>),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue