123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- use super::{Open, Sink};
- use libpulse_binding::{self as pulse, stream::Direction};
- use libpulse_simple_binding::Simple;
- use std::io;
- const APP_NAME: &str = "librespot";
- const STREAM_NAME: &str = "Spotify endpoint";
- pub struct PulseAudioSink {
- s: Option<Simple>,
- ss: pulse::sample::Spec,
- device: Option<String>,
- }
- impl Open for PulseAudioSink {
- fn open(device: Option<String>) -> PulseAudioSink {
- debug!("Using PulseAudio sink");
- let ss = pulse::sample::Spec {
- format: pulse::sample::Format::S16le,
- channels: 2, // stereo
- rate: 44100,
- };
- debug_assert!(ss.is_valid());
- PulseAudioSink {
- s: None,
- ss: ss,
- device: device,
- }
- }
- }
- impl Sink for PulseAudioSink {
- 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.
- Direction::Playback, // Direction.
- device, // Our device (sink) name.
- STREAM_NAME, // Description 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(
- io::ErrorKind::ConnectionRefused,
- e.to_string().unwrap(),
- )),
- }
- }
- fn stop(&mut self) -> io::Result<()> {
- self.s = None;
- Ok(())
- }
- fn write(&mut self, data: &[i16]) -> io::Result<()> {
- if let Some(s) = &self.s {
- // SAFETY: An i16 consists of two bytes, so that the given slice can be interpreted
- // as a byte array of double length. Each byte pointer is validly aligned, and so
- // is the newly created slice.
- let d: &[u8] =
- unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 2) };
- match s.write(d) {
- Ok(_) => Ok(()),
- Err(e) => Err(io::Error::new(
- io::ErrorKind::BrokenPipe,
- e.to_string().unwrap(),
- )),
- }
- } else {
- Err(io::Error::new(
- io::ErrorKind::NotConnected,
- "Not connected to pulseaudio",
- ))
- }
- }
- }
|