123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- use super::{Open, Sink};
- use std::io;
- use libpulse_sys::*;
- use std::ptr::{null, null_mut};
- use std::ffi::CString;
- use std::ffi::CStr;
- use std::mem;
- use libc;
- pub struct PulseAudioSink {
- s : *mut pa_simple,
- ss : pa_sample_spec,
- name : CString,
- desc : CString
- }
- fn call_pulseaudio<T, F, FailCheck>(f: F, fail_check: FailCheck, kind: io::ErrorKind) -> io::Result<T> where
- T: Copy,
- F: Fn(*mut libc::c_int) -> T,
- FailCheck: Fn(T) -> bool,
- {
- let mut error: libc::c_int = 0;
- let ret = f(&mut error);
- if fail_check(ret) {
- let err_cstr = unsafe { CStr::from_ptr(pa_strerror(error)) };
- let errstr = err_cstr.to_string_lossy().into_owned();
- Err(io::Error::new(kind, errstr))
- } else {
- Ok(ret)
- }
- }
- impl PulseAudioSink {
- fn free_connection(&mut self) {
- if self.s != null_mut() {
- unsafe {
- pa_simple_free(self.s);
- }
- self.s = null_mut();
- }
- }
- }
- impl Drop for PulseAudioSink {
- fn drop(&mut self) {
- self.free_connection();
- }
- }
- impl Open for PulseAudioSink {
- fn open(device: Option<String>) -> PulseAudioSink {
- debug!("Using PulseAudio sink");
- if device.is_some() {
- panic!("pulseaudio sink does not support specifying a device name");
- }
- let ss = pa_sample_spec {
- format: PA_SAMPLE_S16LE,
- channels: 2, // stereo
- rate: 44100
- };
-
- let name = CString::new("librespot").unwrap();
- let description = CString::new("Spotify endpoint").unwrap();
- PulseAudioSink {
- s: null_mut(),
- ss: ss,
- name: name,
- desc: description
- }
- }
- }
- impl Sink for PulseAudioSink {
- fn start(&mut self) -> io::Result<()> {
- if self.s == null_mut() {
- self.s = call_pulseaudio(
- |err| unsafe {
- pa_simple_new(null(), // Use the default server.
- self.name.as_ptr(), // Our application's name.
- PA_STREAM_PLAYBACK,
- null(), // Use the default device.
- self.desc.as_ptr(), // desc of our stream.
- &self.ss, // Our sample format.
- null(), // Use default channel map
- null(), // Use default buffering attributes.
- err)
- },
- |ptr| ptr == null_mut(),
- io::ErrorKind::ConnectionRefused)?;
- }
- Ok(())
- }
- fn stop(&mut self) -> io::Result<()> {
- self.free_connection();
- Ok(())
- }
- fn write(&mut self, data: &[i16]) -> io::Result<()> {
- if self.s == null_mut() {
- Err(io::Error::new(io::ErrorKind::NotConnected, "Not connected to pulseaudio"))
- }
- else {
- let ptr = data.as_ptr() as *const libc::c_void;
- let len = data.len() as usize * mem::size_of::<i16>();
- call_pulseaudio(
- |err| unsafe {
- pa_simple_write(self.s, ptr, len, err)
- },
- |ret| ret < 0,
- io::ErrorKind::BrokenPipe)?;
- Ok(())
- }
- }
- }
|