pulseaudio.rs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. use super::{Open, Sink};
  2. use libpulse_binding::{self as pulse, stream::Direction};
  3. use libpulse_simple_binding::Simple;
  4. use std::io;
  5. const APP_NAME: &str = "librespot";
  6. const STREAM_NAME: &str = "Spotify endpoint";
  7. pub struct PulseAudioSink {
  8. s: Option<Simple>,
  9. ss: pulse::sample::Spec,
  10. device: Option<String>,
  11. }
  12. impl Open for PulseAudioSink {
  13. fn open(device: Option<String>) -> PulseAudioSink {
  14. debug!("Using PulseAudio sink");
  15. let ss = pulse::sample::Spec {
  16. format: pulse::sample::Format::S16le,
  17. channels: 2, // stereo
  18. rate: 44100,
  19. };
  20. debug_assert!(ss.is_valid());
  21. PulseAudioSink {
  22. s: None,
  23. ss: ss,
  24. device: device,
  25. }
  26. }
  27. }
  28. impl Sink for PulseAudioSink {
  29. fn start(&mut self) -> io::Result<()> {
  30. if self.s.is_some() {
  31. return Ok(());
  32. }
  33. let device = self.device.as_ref().map(|s| (*s).as_str());
  34. let result = Simple::new(
  35. None, // Use the default server.
  36. APP_NAME, // Our application's name.
  37. Direction::Playback, // Direction.
  38. device, // Our device (sink) name.
  39. STREAM_NAME, // Description of our stream.
  40. &self.ss, // Our sample format.
  41. None, // Use default channel map.
  42. None, // Use default buffering attributes.
  43. );
  44. match result {
  45. Ok(s) => {
  46. self.s = Some(s);
  47. Ok(())
  48. }
  49. Err(e) => Err(io::Error::new(
  50. io::ErrorKind::ConnectionRefused,
  51. e.to_string().unwrap(),
  52. )),
  53. }
  54. }
  55. fn stop(&mut self) -> io::Result<()> {
  56. self.s = None;
  57. Ok(())
  58. }
  59. fn write(&mut self, data: &[i16]) -> io::Result<()> {
  60. if let Some(s) = &self.s {
  61. // SAFETY: An i16 consists of two bytes, so that the given slice can be interpreted
  62. // as a byte array of double length. Each byte pointer is validly aligned, and so
  63. // is the newly created slice.
  64. let d: &[u8] =
  65. unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 2) };
  66. match s.write(d) {
  67. Ok(_) => Ok(()),
  68. Err(e) => Err(io::Error::new(
  69. io::ErrorKind::BrokenPipe,
  70. e.to_string().unwrap(),
  71. )),
  72. }
  73. } else {
  74. Err(io::Error::new(
  75. io::ErrorKind::NotConnected,
  76. "Not connected to pulseaudio",
  77. ))
  78. }
  79. }
  80. }