pulsectl/controllers/
mod.rs

1/// Source = microphone etc. something that takes in audio
2/// Source Output = application consuming that audio
3///
4/// Sink = headphones etc. something that plays out audio
5/// Sink Input = application producing that audio
6/// When you create a `SinkController`, you are working with audio playback devices and applications
7/// if you want to manipulate recording devices such as microphone volume,
8/// you'll need to use a `SourceController`. Both of these implement the same api, defined by
9/// the traits DeviceControl and AppControl
10use std::cell::RefCell;
11use std::clone::Clone;
12use std::rc::Rc;
13
14use pulse::{
15    callbacks::ListResult,
16    context::introspect,
17    volume::{ChannelVolumes, Volume},
18};
19
20use errors::{ControllerError, ControllerErrorType::*};
21use types::{ApplicationInfo, DeviceInfo, ServerInfo};
22
23use crate::Handler;
24
25pub(crate) mod errors;
26pub mod types;
27
28pub trait DeviceControl<T> {
29    fn get_default_device(&mut self) -> Result<T, ControllerError>;
30    fn set_default_device(&mut self, name: &str) -> Result<bool, ControllerError>;
31
32    fn list_devices(&mut self) -> Result<Vec<T>, ControllerError>;
33    fn get_device_by_index(&mut self, index: u32) -> Result<T, ControllerError>;
34    fn get_device_by_name(&mut self, name: &str) -> Result<T, ControllerError>;
35    fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes);
36    fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes);
37    fn set_device_mute_by_index(&mut self, index: u32, mute: bool);
38    fn set_device_mute_by_name(&mut self, name: &str, mute: bool);
39    fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64);
40    fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64);
41}
42
43pub trait AppControl<T> {
44    fn list_applications(&mut self) -> Result<Vec<T>, ControllerError>;
45
46    fn get_app_by_index(&mut self, index: u32) -> Result<T, ControllerError>;
47    fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64);
48    fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64);
49
50    fn move_app_by_index(
51        &mut self,
52        stream_index: u32,
53        device_index: u32,
54    ) -> Result<bool, ControllerError>;
55    fn move_app_by_name(
56        &mut self,
57        stream_index: u32,
58        device_name: &str,
59    ) -> Result<bool, ControllerError>;
60    fn set_app_mute(&mut self, index: u32, mute: bool) -> Result<bool, ControllerError>;
61}
62
63fn volume_from_percent(volume: f64) -> f64 {
64    (volume * 100.0) * (f64::from(pulse::volume::Volume::NORMAL.0) / 100.0)
65}
66
67pub struct SinkController {
68    pub handler: Handler,
69}
70
71impl SinkController {
72    pub fn create() -> Result<Self, ControllerError> {
73        let handler = Handler::connect("SinkController")?;
74        Ok(SinkController { handler })
75    }
76
77    pub fn get_server_info(&mut self) -> Result<ServerInfo, ControllerError> {
78        let server = Rc::new(RefCell::new(Some(None)));
79        let server_ref = server.clone();
80
81        let op = self.handler.introspect.get_server_info(move |res| {
82            server_ref
83                .borrow_mut()
84                .as_mut()
85                .unwrap()
86                .replace(res.into());
87        });
88        self.handler.wait_for_operation(op)?;
89        let mut result = server.borrow_mut();
90        result.take().unwrap().ok_or(ControllerError::new(
91            GetInfoError,
92            "Error getting information about the server",
93        ))
94    }
95}
96
97impl DeviceControl<DeviceInfo> for SinkController {
98    fn get_default_device(&mut self) -> Result<DeviceInfo, ControllerError> {
99        let server_info = self.get_server_info();
100        match server_info {
101            Ok(info) => self.get_device_by_name(info.default_sink_name.unwrap().as_ref()),
102            Err(e) => Err(e),
103        }
104    }
105    fn set_default_device(&mut self, name: &str) -> Result<bool, ControllerError> {
106        let success = Rc::new(RefCell::new(false));
107        let success_ref = success.clone();
108
109        let op = self
110            .handler
111            .context
112            .borrow_mut()
113            .set_default_sink(name, move |res| success_ref.borrow_mut().clone_from(&res));
114        self.handler.wait_for_operation(op)?;
115        let result = success.borrow_mut().clone();
116        Ok(result)
117    }
118
119    fn list_devices(&mut self) -> Result<Vec<DeviceInfo>, ControllerError> {
120        let list = Rc::new(RefCell::new(Some(Vec::new())));
121        let list_ref = list.clone();
122
123        let op = self.handler.introspect.get_sink_info_list(
124            move |sink_list: ListResult<&introspect::SinkInfo>| {
125                if let ListResult::Item(item) = sink_list {
126                    list_ref.borrow_mut().as_mut().unwrap().push(item.into());
127                }
128            },
129        );
130        self.handler.wait_for_operation(op)?;
131        let mut result = list.borrow_mut();
132        result.take().ok_or(ControllerError::new(
133            GetInfoError,
134            "Error getting device list",
135        ))
136    }
137    fn get_device_by_index(&mut self, index: u32) -> Result<DeviceInfo, ControllerError> {
138        let device = Rc::new(RefCell::new(Some(None)));
139        let dev_ref = device.clone();
140        let op = self.handler.introspect.get_sink_info_by_index(
141            index,
142            move |sink_list: ListResult<&introspect::SinkInfo>| {
143                if let ListResult::Item(item) = sink_list {
144                    dev_ref.borrow_mut().as_mut().unwrap().replace(item.into());
145                }
146            },
147        );
148        self.handler.wait_for_operation(op)?;
149        let mut result = device.borrow_mut();
150        result.take().unwrap().ok_or(ControllerError::new(
151            GetInfoError,
152            "Error getting requested device",
153        ))
154    }
155    fn get_device_by_name(&mut self, name: &str) -> Result<DeviceInfo, ControllerError> {
156        let device = Rc::new(RefCell::new(Some(None)));
157        let dev_ref = device.clone();
158        let op = self.handler.introspect.get_sink_info_by_name(
159            name,
160            move |sink_list: ListResult<&introspect::SinkInfo>| {
161                if let ListResult::Item(item) = sink_list {
162                    dev_ref.borrow_mut().as_mut().unwrap().replace(item.into());
163                }
164            },
165        );
166        self.handler.wait_for_operation(op)?;
167        let mut result = device.borrow_mut();
168        result.take().unwrap().ok_or(ControllerError::new(
169            GetInfoError,
170            "Error getting requested device",
171        ))
172    }
173
174    fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes) {
175        let op = self
176            .handler
177            .introspect
178            .set_sink_volume_by_index(index, volume, None);
179        self.handler.wait_for_operation(op).ok();
180    }
181    fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes) {
182        let op = self
183            .handler
184            .introspect
185            .set_sink_volume_by_name(name, volume, None);
186        self.handler.wait_for_operation(op).ok();
187    }
188    fn set_device_mute_by_index(&mut self, index: u32, mute: bool) {
189        let op = self
190            .handler
191            .introspect
192            .set_sink_mute_by_index(index, mute, None);
193        self.handler.wait_for_operation(op).ok();
194    }
195    fn set_device_mute_by_name(&mut self, name: &str, mute: bool) {
196        let op = self
197            .handler
198            .introspect
199            .set_sink_mute_by_name(name, mute, None);
200        self.handler.wait_for_operation(op).ok();
201    }
202    fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64) {
203        if let Ok(mut dev_ref) = self.get_device_by_index(index) {
204            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
205            if let Some(volumes) = dev_ref.volume.increase(new_vol) {
206                let op = self
207                    .handler
208                    .introspect
209                    .set_sink_volume_by_index(index, &volumes, None);
210                self.handler.wait_for_operation(op).ok();
211            }
212        }
213    }
214    fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64) {
215        if let Ok(mut dev_ref) = self.get_device_by_index(index) {
216            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
217            if let Some(volumes) = dev_ref.volume.decrease(new_vol) {
218                let op = self
219                    .handler
220                    .introspect
221                    .set_sink_volume_by_index(index, &volumes, None);
222                self.handler.wait_for_operation(op).ok();
223            }
224        }
225    }
226}
227
228impl AppControl<ApplicationInfo> for SinkController {
229    fn list_applications(&mut self) -> Result<Vec<ApplicationInfo>, ControllerError> {
230        let list = Rc::new(RefCell::new(Some(Vec::new())));
231        let list_ref = list.clone();
232
233        let op = self.handler.introspect.get_sink_input_info_list(
234            move |sink_list: ListResult<&introspect::SinkInputInfo>| {
235                if let ListResult::Item(item) = sink_list {
236                    list_ref.borrow_mut().as_mut().unwrap().push(item.into());
237                }
238            },
239        );
240        self.handler.wait_for_operation(op)?;
241        let mut result = list.borrow_mut();
242        result.take().ok_or(ControllerError::new(
243            GetInfoError,
244            "Error getting application list",
245        ))
246    }
247
248    fn get_app_by_index(&mut self, index: u32) -> Result<ApplicationInfo, ControllerError> {
249        let app = Rc::new(RefCell::new(Some(None)));
250        let app_ref = app.clone();
251        let op = self.handler.introspect.get_sink_input_info(
252            index,
253            move |sink_list: ListResult<&introspect::SinkInputInfo>| {
254                if let ListResult::Item(item) = sink_list {
255                    app_ref.borrow_mut().as_mut().unwrap().replace(item.into());
256                }
257            },
258        );
259        self.handler.wait_for_operation(op)?;
260        let mut result = app.borrow_mut();
261        result.take().unwrap().ok_or(ControllerError::new(
262            GetInfoError,
263            "Error getting requested app",
264        ))
265    }
266
267    fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64) {
268        if let Ok(mut app_ref) = self.get_app_by_index(index) {
269            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
270            if let Some(volumes) = app_ref.volume.increase(new_vol) {
271                let op = self
272                    .handler
273                    .introspect
274                    .set_sink_input_volume(index, &volumes, None);
275                self.handler.wait_for_operation(op).ok();
276            }
277        }
278    }
279
280    fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64) {
281        if let Ok(mut app_ref) = self.get_app_by_index(index) {
282            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
283            if let Some(volumes) = app_ref.volume.decrease(new_vol) {
284                let op = self
285                    .handler
286                    .introspect
287                    .set_sink_input_volume(index, &volumes, None);
288                self.handler.wait_for_operation(op).ok();
289            }
290        }
291    }
292
293    fn move_app_by_index(
294        &mut self,
295        stream_index: u32,
296        device_index: u32,
297    ) -> Result<bool, ControllerError> {
298        let success = Rc::new(RefCell::new(false));
299        let success_ref = success.clone();
300        let op = self.handler.introspect.move_sink_input_by_index(
301            stream_index,
302            device_index,
303            Some(Box::new(move |res| {
304                success_ref.borrow_mut().clone_from(&res)
305            })),
306        );
307        self.handler.wait_for_operation(op)?;
308        let result = success.borrow_mut().clone();
309        Ok(result)
310    }
311
312    fn move_app_by_name(
313        &mut self,
314        stream_index: u32,
315        device_name: &str,
316    ) -> Result<bool, ControllerError> {
317        let success = Rc::new(RefCell::new(false));
318        let success_ref = success.clone();
319        let op = self.handler.introspect.move_sink_input_by_name(
320            stream_index,
321            device_name,
322            Some(Box::new(move |res| {
323                success_ref.borrow_mut().clone_from(&res)
324            })),
325        );
326        self.handler.wait_for_operation(op)?;
327        let result = success.borrow_mut().clone();
328        Ok(result)
329    }
330
331    fn set_app_mute(&mut self, index: u32, mute: bool) -> Result<bool, ControllerError> {
332        let success = Rc::new(RefCell::new(false));
333        let success_ref = success.clone();
334        let op = self.handler.introspect.set_sink_input_mute(
335            index,
336            mute,
337            Some(Box::new(move |res| {
338                success_ref.borrow_mut().clone_from(&res)
339            })),
340        );
341        self.handler.wait_for_operation(op)?;
342        let result = success.borrow_mut().clone();
343        Ok(result)
344    }
345}
346
347pub struct SourceController {
348    pub handler: Handler,
349}
350
351impl SourceController {
352    pub fn create() -> Result<Self, ControllerError> {
353        let handler = Handler::connect("SourceController")?;
354        Ok(SourceController { handler })
355    }
356
357    pub fn get_server_info(&mut self) -> Result<ServerInfo, ControllerError> {
358        let server = Rc::new(RefCell::new(Some(None)));
359        let server_ref = server.clone();
360
361        let op = self.handler.introspect.get_server_info(move |res| {
362            server_ref
363                .borrow_mut()
364                .as_mut()
365                .unwrap()
366                .replace(res.into());
367        });
368        self.handler.wait_for_operation(op)?;
369        let mut result = server.borrow_mut();
370        result.take().unwrap().ok_or(ControllerError::new(
371            GetInfoError,
372            "Error getting application list",
373        ))
374    }
375}
376
377impl DeviceControl<DeviceInfo> for SourceController {
378    fn get_default_device(&mut self) -> Result<DeviceInfo, ControllerError> {
379        let server_info = self.get_server_info();
380        match server_info {
381            Ok(info) => self.get_device_by_name(info.default_sink_name.unwrap().as_ref()),
382            Err(e) => Err(e),
383        }
384    }
385    fn set_default_device(&mut self, name: &str) -> Result<bool, ControllerError> {
386        let success = Rc::new(RefCell::new(false));
387        let success_ref = success.clone();
388
389        let op = self
390            .handler
391            .context
392            .borrow_mut()
393            .set_default_source(name, move |res| success_ref.borrow_mut().clone_from(&res));
394        self.handler.wait_for_operation(op)?;
395        let result = success.borrow_mut().clone();
396        Ok(result)
397    }
398
399    fn list_devices(&mut self) -> Result<Vec<DeviceInfo>, ControllerError> {
400        let list = Rc::new(RefCell::new(Some(Vec::new())));
401        let list_ref = list.clone();
402
403        let op = self.handler.introspect.get_source_info_list(
404            move |sink_list: ListResult<&introspect::SourceInfo>| {
405                if let ListResult::Item(item) = sink_list {
406                    list_ref.borrow_mut().as_mut().unwrap().push(item.into());
407                }
408            },
409        );
410        self.handler.wait_for_operation(op)?;
411        let mut result = list.borrow_mut();
412        result.take().ok_or(ControllerError::new(
413            GetInfoError,
414            "Error getting application list",
415        ))
416    }
417    fn get_device_by_index(&mut self, index: u32) -> Result<DeviceInfo, ControllerError> {
418        let device = Rc::new(RefCell::new(Some(None)));
419        let dev_ref = device.clone();
420        let op = self.handler.introspect.get_source_info_by_index(
421            index,
422            move |sink_list: ListResult<&introspect::SourceInfo>| {
423                if let ListResult::Item(item) = sink_list {
424                    dev_ref.borrow_mut().as_mut().unwrap().replace(item.into());
425                }
426            },
427        );
428        self.handler.wait_for_operation(op)?;
429        let mut result = device.borrow_mut();
430        result.take().unwrap().ok_or(ControllerError::new(
431            GetInfoError,
432            "Error getting application list",
433        ))
434    }
435    fn get_device_by_name(&mut self, name: &str) -> Result<DeviceInfo, ControllerError> {
436        let device = Rc::new(RefCell::new(Some(None)));
437        let dev_ref = device.clone();
438        let op = self.handler.introspect.get_source_info_by_name(
439            name,
440            move |sink_list: ListResult<&introspect::SourceInfo>| {
441                if let ListResult::Item(item) = sink_list {
442                    dev_ref.borrow_mut().as_mut().unwrap().replace(item.into());
443                }
444            },
445        );
446        self.handler.wait_for_operation(op)?;
447        let mut result = device.borrow_mut();
448        result.take().unwrap().ok_or(ControllerError::new(
449            GetInfoError,
450            "Error getting application list",
451        ))
452    }
453
454    fn set_device_volume_by_index(&mut self, index: u32, volume: &ChannelVolumes) {
455        let op = self
456            .handler
457            .introspect
458            .set_source_volume_by_index(index, volume, None);
459        self.handler.wait_for_operation(op).ok();
460    }
461    fn set_device_volume_by_name(&mut self, name: &str, volume: &ChannelVolumes) {
462        let op = self
463            .handler
464            .introspect
465            .set_source_volume_by_name(name, volume, None);
466        self.handler.wait_for_operation(op).ok();
467    }
468    fn increase_device_volume_by_percent(&mut self, index: u32, delta: f64) {
469        if let Ok(mut dev_ref) = self.get_device_by_index(index) {
470            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
471            if let Some(volumes) = dev_ref.volume.increase(new_vol) {
472                let op = self
473                    .handler
474                    .introspect
475                    .set_source_volume_by_index(index, &volumes, None);
476                self.handler.wait_for_operation(op).ok();
477            }
478        }
479    }
480    fn set_device_mute_by_index(&mut self, index: u32, mute: bool) {
481        let op = self
482            .handler
483            .introspect
484            .set_sink_mute_by_index(index, mute, None);
485        self.handler.wait_for_operation(op).ok();
486    }
487    fn set_device_mute_by_name(&mut self, name: &str, mute: bool) {
488        let op = self
489            .handler
490            .introspect
491            .set_sink_mute_by_name(name, mute, None);
492        self.handler.wait_for_operation(op).ok();
493    }
494    fn decrease_device_volume_by_percent(&mut self, index: u32, delta: f64) {
495        if let Ok(mut dev_ref) = self.get_device_by_index(index) {
496            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
497            if let Some(volumes) = dev_ref.volume.decrease(new_vol) {
498                let op = self
499                    .handler
500                    .introspect
501                    .set_source_volume_by_index(index, &volumes, None);
502                self.handler.wait_for_operation(op).ok();
503            }
504        }
505    }
506}
507
508impl AppControl<ApplicationInfo> for SourceController {
509    fn list_applications(&mut self) -> Result<Vec<ApplicationInfo>, ControllerError> {
510        let list = Rc::new(RefCell::new(Some(Vec::new())));
511        let list_ref = list.clone();
512
513        let op = self.handler.introspect.get_source_output_info_list(
514            move |sink_list: ListResult<&introspect::SourceOutputInfo>| {
515                if let ListResult::Item(item) = sink_list {
516                    list_ref.borrow_mut().as_mut().unwrap().push(item.into());
517                }
518            },
519        );
520        self.handler.wait_for_operation(op)?;
521        let mut result = list.borrow_mut();
522        result.take().ok_or(ControllerError::new(
523            GetInfoError,
524            "Error getting application list",
525        ))
526    }
527
528    fn get_app_by_index(&mut self, index: u32) -> Result<ApplicationInfo, ControllerError> {
529        let app = Rc::new(RefCell::new(Some(None)));
530        let app_ref = app.clone();
531        let op = self.handler.introspect.get_source_output_info(
532            index,
533            move |sink_list: ListResult<&introspect::SourceOutputInfo>| {
534                if let ListResult::Item(item) = sink_list {
535                    app_ref.borrow_mut().as_mut().unwrap().replace(item.into());
536                }
537            },
538        );
539        self.handler.wait_for_operation(op)?;
540        let mut result = app.borrow_mut();
541        result.take().unwrap().ok_or(ControllerError::new(
542            GetInfoError,
543            "Error getting application list",
544        ))
545    }
546
547    fn increase_app_volume_by_percent(&mut self, index: u32, delta: f64) {
548        if let Ok(mut app_ref) = self.get_app_by_index(index) {
549            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
550            if let Some(volumes) = app_ref.volume.increase(new_vol) {
551                let op = self
552                    .handler
553                    .introspect
554                    .set_source_output_volume(index, &volumes, None);
555                self.handler.wait_for_operation(op).ok();
556            }
557        }
558    }
559
560    fn decrease_app_volume_by_percent(&mut self, index: u32, delta: f64) {
561        if let Ok(mut app_ref) = self.get_app_by_index(index) {
562            let new_vol = Volume::from(Volume(volume_from_percent(delta) as u32));
563            if let Some(volumes) = app_ref.volume.decrease(new_vol) {
564                let op = self
565                    .handler
566                    .introspect
567                    .set_source_output_volume(index, &volumes, None);
568                self.handler.wait_for_operation(op).ok();
569            }
570        }
571    }
572
573    fn move_app_by_index(
574        &mut self,
575        stream_index: u32,
576        device_index: u32,
577    ) -> Result<bool, ControllerError> {
578        let success = Rc::new(RefCell::new(false));
579        let success_ref = success.clone();
580        let op = self.handler.introspect.move_source_output_by_index(
581            stream_index,
582            device_index,
583            Some(Box::new(move |res| {
584                success_ref.borrow_mut().clone_from(&res)
585            })),
586        );
587        self.handler.wait_for_operation(op)?;
588        let result = success.borrow_mut().clone();
589        Ok(result)
590    }
591
592    fn move_app_by_name(
593        &mut self,
594        stream_index: u32,
595        device_name: &str,
596    ) -> Result<bool, ControllerError> {
597        let success = Rc::new(RefCell::new(false));
598        let success_ref = success.clone();
599        let op = self.handler.introspect.move_source_output_by_name(
600            stream_index,
601            device_name,
602            Some(Box::new(move |res| {
603                success_ref.borrow_mut().clone_from(&res)
604            })),
605        );
606        self.handler.wait_for_operation(op)?;
607        let result = success.borrow_mut().clone();
608        Ok(result)
609    }
610
611    fn set_app_mute(&mut self, index: u32, mute: bool) -> Result<bool, ControllerError> {
612        let success = Rc::new(RefCell::new(false));
613        let success_ref = success.clone();
614        let op = self.handler.introspect.set_source_mute_by_index(
615            index,
616            mute,
617            Some(Box::new(move |res| {
618                success_ref.borrow_mut().clone_from(&res)
619            })),
620        );
621        self.handler.wait_for_operation(op)?;
622        let result = success.borrow_mut().clone();
623        Ok(result)
624    }
625}