1extern crate libpulse_binding as pulse;
36
37use std::cell::RefCell;
38use std::ops::Deref;
39use std::rc::Rc;
40
41use pulse::{
42 context::{introspect, Context},
43 mainloop::standard::{IterateResult, Mainloop},
44 operation::{Operation, State},
45 proplist::Proplist,
46};
47
48use crate::errors::{PulseCtlError, PulseCtlErrorType::*};
49
50pub mod controllers;
51mod errors;
52
53pub struct Handler {
54 pub mainloop: Rc<RefCell<Mainloop>>,
55 pub context: Rc<RefCell<Context>>,
56 pub introspect: introspect::Introspector,
57}
58
59fn connect_error(err: &str) -> PulseCtlError {
60 PulseCtlError::new(ConnectError, err)
61}
62
63impl Handler {
64 pub fn connect(name: &str) -> Result<Handler, PulseCtlError> {
65 let mut proplist = Proplist::new().unwrap();
66 proplist
67 .set_str(pulse::proplist::properties::APPLICATION_NAME, name)
68 .unwrap();
69
70 let mainloop;
71 if let Some(m) = Mainloop::new() {
72 mainloop = Rc::new(RefCell::new(m));
73 } else {
74 return Err(connect_error("Failed to create mainloop"));
75 }
76
77 let context;
78 if let Some(c) =
79 Context::new_with_proplist(mainloop.borrow().deref(), "MainConn", &proplist)
80 {
81 context = Rc::new(RefCell::new(c));
82 } else {
83 return Err(connect_error("Failed to create new context"));
84 }
85
86 context
87 .borrow_mut()
88 .connect(None, pulse::context::FlagSet::NOFLAGS, None)
89 .map_err(|_| connect_error("Failed to connect context"))?;
90
91 loop {
92 match mainloop.borrow_mut().iterate(false) {
93 IterateResult::Err(e) => {
94 eprintln!("iterate state was not success, quitting...");
95 return Err(e.into());
96 }
97 IterateResult::Success(_) => {}
98 IterateResult::Quit(_) => {
99 eprintln!("iterate state was not success, quitting...");
100 return Err(PulseCtlError::new(
101 ConnectError,
102 "Iterate state quit without an error",
103 ));
104 }
105 }
106
107 match context.borrow().get_state() {
108 pulse::context::State::Ready => break,
109 pulse::context::State::Failed | pulse::context::State::Terminated => {
110 eprintln!("context state failed/terminated, quitting...");
111 return Err(PulseCtlError::new(
112 ConnectError,
113 "Context state failed/terminated without an error",
114 ));
115 }
116 _ => {}
117 }
118 }
119
120 let introspect = context.borrow_mut().introspect();
121 Ok(Handler {
122 mainloop,
123 context,
124 introspect,
125 })
126 }
127
128 pub fn wait_for_operation<G: ?Sized>(
130 &mut self,
131 op: Operation<G>,
132 ) -> Result<(), errors::PulseCtlError> {
133 loop {
134 match self.mainloop.borrow_mut().iterate(false) {
135 IterateResult::Err(e) => return Err(e.into()),
136 IterateResult::Success(_) => {}
137 IterateResult::Quit(_) => {
138 return Err(PulseCtlError::new(
139 OperationError,
140 "Iterate state quit without an error",
141 ));
142 }
143 }
144 match op.get_state() {
145 State::Done => {
146 break;
147 }
148 State::Running => {}
149 State::Cancelled => {
150 return Err(PulseCtlError::new(
151 OperationError,
152 "Operation cancelled without an error",
153 ));
154 }
155 }
156 }
157 Ok(())
158 }
159}
160
161impl Drop for Handler {
162 fn drop(&mut self) {
163 self.context.borrow_mut().disconnect();
164 self.mainloop.borrow_mut().quit(pulse::def::Retval(0));
165 }
166}