alsa/
io.rs

1use crate::alsa;
2use super::error::*;
3use core::{slice, ptr, fmt};
4use core::cell::RefCell;
5use ::alloc::rc::Rc;
6use libc::{c_char, c_int};
7
8/// [snd_output_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___output.html) wrapper
9pub struct Output(*mut alsa::snd_output_t);
10
11unsafe impl Send for Output {}
12
13#[cfg(feature = "std")]
14std::thread_local! {
15    static ERROR_OUTPUT: RefCell<Option<Rc<RefCell<Output>>>> = RefCell::new(None);
16}
17
18impl Drop for Output {
19    fn drop(&mut self) { unsafe { alsa::snd_output_close(self.0) }; }
20}
21
22impl Output {
23
24    pub fn buffer_open() -> Result<Output> {
25        let mut q = ptr::null_mut();
26        acheck!(snd_output_buffer_open(&mut q)).map(|_| Output(q))
27    }
28
29    pub fn buffer_string<T, F: FnOnce(&[u8]) -> T>(&self, f: F) -> T {
30        let b = unsafe {
31            let mut q = ptr::null_mut();
32            let s = alsa::snd_output_buffer_string(self.0, &mut q);
33            if s == 0 { &[] } else { slice::from_raw_parts(q as *const u8, s as usize) }
34        };
35        f(b)
36    }
37
38
39    /// Installs a thread local error handler.
40    ///
41    /// Sometimes alsa-lib writes to stderr, but if you prefer, you can write it here instead.
42    /// Should you wish to empty the buffer; just call local_error_handler again and drop the old instance.
43    ///
44    /// This is not available in `no-std` environments, because we use thread_local variables.
45    #[cfg(feature = "std")]
46    pub fn local_error_handler() -> Result<Rc<RefCell<Output>>> {
47        let output = Output::buffer_open()?;
48        let r = Rc::new(RefCell::new(output));
49        ERROR_OUTPUT.with_borrow_mut(|e| *e = Some(r.clone()));
50        unsafe { alsa::snd_lib_error_set_local(Some(our_error_handler)); }
51        Ok(r)
52    }
53}
54
55impl fmt::Debug for Output {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        write!(f, "Output(")?;
58        fmt::Display::fmt(self, f)?;
59        write!(f, ")")
60        /* self.buffer_string(|b| f.write_str(try!(str::from_utf8(b).map_err(|_| fmt::Error)))) */
61    }
62}
63
64impl fmt::Display for Output {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        self.buffer_string(|b| {
67            let s = ::alloc::string::String::from_utf8_lossy(b);
68            f.write_str(&*s)
69        })
70    }
71}
72
73pub fn output_handle(o: &Output) -> *mut alsa::snd_output_t { o.0 }
74
75#[cfg(feature = "std")]
76unsafe extern "C" fn our_error_handler(_file: *const c_char,
77    _line: c_int,
78    func: *const c_char,
79    _err: c_int,
80    fmt: *const c_char,
81    arg: *mut alsa::__va_list_tag,
82) {
83    ERROR_OUTPUT.with_borrow(|e| {
84        let b = e.as_ref().expect("ERROR_OUTPUT not set").borrow_mut();
85        alsa::snd_output_puts(b.0, func);
86        alsa::snd_output_puts(b.0, c": ".as_ptr());
87        alsa::snd_output_vprintf(b.0, fmt, arg);
88        alsa::snd_output_putc(b.0, '\n' as i32);
89    })
90}