pulseaudio.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. use super::{Open, Sink};
  2. use std::io;
  3. use libpulse_sys::*;
  4. use std::ptr::{null, null_mut};
  5. use std::ffi::CString;
  6. use std::ffi::CStr;
  7. use std::mem;
  8. use libc;
  9. pub struct PulseAudioSink {
  10. s : *mut pa_simple,
  11. ss : pa_sample_spec,
  12. name : CString,
  13. desc : CString
  14. }
  15. fn call_pulseaudio<T, F, FailCheck>(f: F, fail_check: FailCheck, kind: io::ErrorKind) -> io::Result<T> where
  16. T: Copy,
  17. F: Fn(*mut libc::c_int) -> T,
  18. FailCheck: Fn(T) -> bool,
  19. {
  20. let mut error: libc::c_int = 0;
  21. let ret = f(&mut error);
  22. if fail_check(ret) {
  23. let err_cstr = unsafe { CStr::from_ptr(pa_strerror(error)) };
  24. let errstr = err_cstr.to_string_lossy().into_owned();
  25. Err(io::Error::new(kind, errstr))
  26. } else {
  27. Ok(ret)
  28. }
  29. }
  30. impl PulseAudioSink {
  31. fn free_connection(&mut self) {
  32. if self.s != null_mut() {
  33. unsafe {
  34. pa_simple_free(self.s);
  35. }
  36. self.s = null_mut();
  37. }
  38. }
  39. }
  40. impl Drop for PulseAudioSink {
  41. fn drop(&mut self) {
  42. self.free_connection();
  43. }
  44. }
  45. impl Open for PulseAudioSink {
  46. fn open(device: Option<String>) -> PulseAudioSink {
  47. debug!("Using PulseAudio sink");
  48. if device.is_some() {
  49. panic!("pulseaudio sink does not support specifying a device name");
  50. }
  51. let ss = pa_sample_spec {
  52. format: PA_SAMPLE_S16LE,
  53. channels: 2, // stereo
  54. rate: 44100
  55. };
  56. let name = CString::new("librespot").unwrap();
  57. let description = CString::new("Spotify endpoint").unwrap();
  58. PulseAudioSink {
  59. s: null_mut(),
  60. ss: ss,
  61. name: name,
  62. desc: description
  63. }
  64. }
  65. }
  66. impl Sink for PulseAudioSink {
  67. fn start(&mut self) -> io::Result<()> {
  68. if self.s == null_mut() {
  69. self.s = call_pulseaudio(
  70. |err| unsafe {
  71. pa_simple_new(null(), // Use the default server.
  72. self.name.as_ptr(), // Our application's name.
  73. PA_STREAM_PLAYBACK,
  74. null(), // Use the default device.
  75. self.desc.as_ptr(), // desc of our stream.
  76. &self.ss, // Our sample format.
  77. null(), // Use default channel map
  78. null(), // Use default buffering attributes.
  79. err)
  80. },
  81. |ptr| ptr == null_mut(),
  82. io::ErrorKind::ConnectionRefused)?;
  83. }
  84. Ok(())
  85. }
  86. fn stop(&mut self) -> io::Result<()> {
  87. self.free_connection();
  88. Ok(())
  89. }
  90. fn write(&mut self, data: &[i16]) -> io::Result<()> {
  91. if self.s == null_mut() {
  92. Err(io::Error::new(io::ErrorKind::NotConnected, "Not connected to pulseaudio"))
  93. }
  94. else {
  95. let ptr = data.as_ptr() as *const libc::c_void;
  96. let len = data.len() as usize * mem::size_of::<i16>();
  97. call_pulseaudio(
  98. |err| unsafe {
  99. pa_simple_write(self.s, ptr, len, err)
  100. },
  101. |ret| ret < 0,
  102. io::ErrorKind::BrokenPipe)?;
  103. Ok(())
  104. }
  105. }
  106. }