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
8pub 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 #[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 }
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}