librespot/playback/src/audio_backend/pulseaudio.rs

87 lines
2.3 KiB
Rust
Raw Normal View History

2016-03-20 19:16:32 +00:00
use super::{Open, Sink};
use libpulse_binding as pulse;
use libpulse_simple_binding::Simple;
2018-02-26 01:50:41 +00:00
use std::io;
2016-03-20 19:16:32 +00:00
const APP_NAME: &str = "librespot";
const STREAM_NAME: &str = "Spotify endpoint";
pub struct PulseAudioSink {
s: Option<Simple>,
ss: pulse::sample::Spec,
device: Option<String>,
}
2016-03-20 19:16:32 +00:00
impl Open for PulseAudioSink {
2018-02-26 01:50:41 +00:00
fn open(device: Option<String>) -> PulseAudioSink {
2016-07-06 09:54:46 +00:00
debug!("Using PulseAudio sink");
let ss = pulse::sample::Spec {
format: pulse::sample::Format::S16le,
2016-03-20 19:16:32 +00:00
channels: 2, // stereo
2018-02-26 01:50:41 +00:00
rate: 44100,
2016-03-20 19:16:32 +00:00
};
debug_assert!(ss.is_valid());
2016-03-20 19:16:32 +00:00
2017-01-14 21:22:33 +00:00
PulseAudioSink {
s: None,
2017-01-14 21:22:33 +00:00
ss: ss,
device: device,
2017-01-14 21:22:33 +00:00
}
2016-03-20 19:16:32 +00:00
}
}
impl Sink for PulseAudioSink {
2016-08-01 19:20:17 +00:00
fn start(&mut self) -> io::Result<()> {
if self.s.is_some() {
return Ok(());
}
let device = self.device.as_ref().map(|s| (*s).as_str());
let result = Simple::new(
None, // Use the default server.
APP_NAME, // Our application's name.
pulse::stream::Direction::Playback,
device,
STREAM_NAME, // desc of our stream.
&self.ss, // Our sample format.
None, // Use default channel map
None, // Use default buffering attributes.
);
match result {
Ok(s) => {
self.s = Some(s);
Ok(())
}
Err(e) => Err(io::Error::new(
2018-02-26 01:50:41 +00:00
io::ErrorKind::ConnectionRefused,
e.to_string().unwrap(),
)),
2017-01-14 21:22:33 +00:00
}
2016-03-20 19:16:32 +00:00
}
2016-08-01 19:20:17 +00:00
fn stop(&mut self) -> io::Result<()> {
self.s = None;
2016-03-20 19:16:32 +00:00
Ok(())
}
2016-08-01 19:20:17 +00:00
fn write(&mut self, data: &[i16]) -> io::Result<()> {
if let Some(s) = &self.s {
let d: &[u8] = unsafe { std::mem::transmute(data) };
match s.write(d) {
Ok(_) => Ok(()),
Err(e) => Err(io::Error::new(
io::ErrorKind::BrokenPipe,
e.to_string().unwrap(),
)),
}
} else {
2018-02-26 01:50:41 +00:00
Err(io::Error::new(
io::ErrorKind::NotConnected,
"Not connected to pulseaudio",
))
}
2016-03-20 19:16:32 +00:00
}
}