barnine/
pulse.rs

1use std::time::Duration;
2
3use log::debug;
4use tokio::sync::mpsc::UnboundedSender;
5use tokio::time::sleep;
6use zbus::{azync::Connection, Result};
7use zbus_macros::dbus_proxy;
8use zvariant::ObjectPath;
9
10use crate::bar::Update;
11use crate::err::Res;
12
13pub async fn watch_pulse(tx: UnboundedSender<Update>) -> Res<()> {
14    loop {
15        tx.send(Update::Volume(get_volume().await.ok()))?;
16        tx.send(Update::Mute(get_mute().await.ok()))?;
17        tx.send(Update::Redraw)?;
18        sleep(Duration::from_secs(5)).await;
19    }
20}
21
22pub async fn set_volume(vol: u32) -> Res<()> {
23    let pulse_conn = new_pulse_connection().await?;
24
25    let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
26    let sinks = core_proxy.sinks().await?;
27
28    for sink in sinks.iter().map(|s| s.to_string()) {
29        let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink)?;
30        let mut new_volume = Vec::new();
31        new_volume.push(vol);
32        match sink_proxy.set_volume(new_volume).await {
33            Ok(val) => debug!("Ok: {:?}", val),
34            Err(err) => debug!("Err: {:?}", err),
35        }
36    }
37
38    Ok(())
39}
40
41pub async fn toggle_mute() -> Res<()> {
42    let pulse_conn = new_pulse_connection().await?;
43
44    let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
45    let sinks = core_proxy.sinks().await?;
46
47    for sink in sinks.iter().map(|s| s.to_string()) {
48        let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink)?;
49        match sink_proxy.set_mute(!sink_proxy.mute().await.unwrap()).await {
50            Ok(val) => debug!("Ok: {:?}", val),
51            Err(err) => debug!("Err: {:?}", err),
52        }
53    }
54
55    Ok(())
56}
57
58pub async fn get_mute() -> Res<bool> {
59    let pulse_conn = new_pulse_connection().await?;
60
61    let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
62    let sinks = core_proxy.sinks().await?;
63
64    if let Some(sink) = sinks.get(0) {
65        let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink.to_string())?;
66        Ok(sink_proxy.mute().await?)
67    } else {
68        Err("No sink found".into())
69    }
70}
71
72pub async fn get_volume() -> Res<u32> {
73    let pulse_conn = new_pulse_connection().await?;
74
75    let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
76    let sinks = core_proxy.sinks().await?;
77
78    if let Some(sink) = sinks.get(0) {
79        let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink.to_string())?;
80        let vol = sink_proxy.volume().await?;
81        Ok(vol[0])
82    } else {
83        Err("No sink found".into())
84    }
85}
86
87async fn new_pulse_connection() -> Res<Connection> {
88    let conn = Connection::new_session().await?;
89    let addr_lookup = AsyncPulseAddressProxy::new(&conn)?;
90    let addr = addr_lookup.address().await?;
91    Ok(Connection::new_for_address(&addr, false).await?)
92}
93
94pub async fn pulse_info() -> Vec<String> {
95    let mut result = Vec::new();
96
97    let conn = Connection::new_session().await.unwrap();
98    let p = AsyncPulseAddressProxy::new(&conn).unwrap();
99    let addr = p.address().await.unwrap();
100    result.push(addr.to_string());
101
102    let pulse_conn = Connection::new_for_address(&addr, false).await.unwrap();
103    let c = AsyncPulseCoreProxy::new(&pulse_conn).unwrap();
104    let name = c.name().await.unwrap();
105    let version = c.version().await.unwrap();
106    let dsf = c.default_sample_format().await.unwrap();
107    let dsr = c.default_sample_rate().await.unwrap();
108    let sinks = c.sinks().await.unwrap();
109
110    result.push(format!("{} {}", name, version));
111    result.push(format!("dsr: {}", dsr));
112    result.push(format!("dsf: {:?}", SampleFormat::from(dsf)));
113    result.push(String::from("Sinks:"));
114
115    for sink in sinks.iter().map(|s| s.to_string()) {
116        let s = AsyncSinkProxy::new_for_path(&pulse_conn, sink).unwrap();
117        result.push(format!("name: {}", s.name().await.unwrap()));
118
119        let vol = s.volume().await.unwrap();
120        let vol: Vec<u32> = vol.iter().map(|x| x * 100 / 65536).collect();
121        result.push(format!("volume: {:?}", vol));
122
123        let sf = s.sample_format().await.unwrap();
124        result.push(format!("format: {:?}", SampleFormat::from(sf)));
125        result.push(format!("rate: {:?}", s.sample_rate().await.unwrap()));
126        result.push(format!("channels: {:?}", s.channels().await.unwrap()));
127
128        result.push(format!(
129            "flat vol?: {:?}",
130            s.has_flat_volume().await.unwrap()
131        ));
132        result.push(format!("base vol: {:?}", s.base_volume().await.unwrap()));
133        result.push(format!("vol steps: {:?}", s.volume_steps().await.unwrap()));
134        result.push(format!("mute: {:?}", s.mute().await.unwrap()));
135        result.push(format!(
136            "cfg latency: {:?}",
137            s.configured_latency().await.unwrap()
138        ));
139
140        result.push(format!("latency: {:?}", s.latency().await.unwrap()));
141        let ds = s.state().await.unwrap();
142        result.push(format!("state: {:?}", DeviceState::from(ds)));
143        result.push(format!(
144            "hardware vol: {:?}",
145            s.has_hardware_volume().await.unwrap()
146        ));
147        result.push(format!(
148            "hardware mute: {:?}",
149            s.has_hardware_mute().await.unwrap()
150        ));
151    }
152
153    result
154}
155
156#[derive(Debug)]
157enum DeviceState {
158    /*
159    Running, the device is being used by at least one non-corked stream.
160    Idle, the device is active, but no non-corked streams are connected to it.
161    Suspended, the device is not in use and may be currently closed.
162    */
163    Running,
164    Idle,
165    Suspended,
166    None,
167}
168
169impl From<u32> for DeviceState {
170    fn from(state: u32) -> Self {
171        match state {
172            0 => DeviceState::Running,
173            1 => DeviceState::Idle,
174            2 => DeviceState::Suspended,
175            _ => DeviceState::None,
176        }
177    }
178}
179
180#[derive(Debug)]
181enum SampleFormat {
182    /*
183    0 : Unsigned 8 bit PCM
184    1 : 8 bit a-Law
185    2 : 8 bit mu-Law
186    3 : Signed 16 bit PCM, little endian
187    4 : Signed 16 bit PCM, big endian
188    5 : 32 bit IEEE floating point, little endian, range -1.0 to 1.0
189    6 : 32 bit IEEE floating point, big endian, range -1.0 to 1.0
190    7 : Signed 32 bit PCM, little endian
191    8 : Signed 32 bit PCM, big endian
192    9 : Signed 24 bit PCM packed, little endian
193    10 : Signed 24 bit PCM packed, big endian
194    11 : Signed 24 bit PCM in LSB of 32 bit words, little endian
195    12 : Signed 24 bit PCM in LSB of 32 bit words, big endian
196    */
197    S16le,
198    None,
199}
200
201impl From<u32> for SampleFormat {
202    fn from(index: u32) -> Self {
203        match index {
204            3 => SampleFormat::S16le,
205            _ => SampleFormat::None,
206        }
207    }
208}
209
210#[dbus_proxy(
211    interface = "org.PulseAudio.ServerLookup1",
212    default_service = "org.PulseAudio1",
213    default_path = "/org/pulseaudio/server_lookup1"
214)]
215trait PulseAddress {
216    #[dbus_proxy(property)]
217    fn address(&self) -> Result<String>;
218}
219
220#[dbus_proxy(
221    interface = "org.PulseAudio.Core1",
222    default_service = "org.PulseAudio.Core1",
223    default_path = "/org/pulseaudio/core1"
224)]
225trait PulseCore {
226    #[dbus_proxy(property)]
227    fn name(&self) -> Result<String>;
228    #[dbus_proxy(property)]
229    fn version(&self) -> Result<String>;
230    #[dbus_proxy(property)]
231    fn sinks(&self) -> Result<Vec<ObjectPath<'_>>>;
232    #[dbus_proxy(property)]
233    fn default_sample_format(&self) -> Result<u32>;
234    #[dbus_proxy(property)]
235    fn default_sample_rate(&self) -> Result<u32>;
236}
237
238#[dbus_proxy(
239    interface = "org.PulseAudio.Core1.Device",
240    default_service = "org.PulseAudio.Core1.Device"
241)]
242trait Sink {
243    #[dbus_proxy(property)]
244    fn name(&self) -> Result<String>;
245    #[dbus_proxy(property)]
246    fn volume(&self) -> Result<Vec<u32>>;
247    #[dbus_proxy(property)]
248    fn sample_format(&self) -> Result<u32>;
249    #[dbus_proxy(property)]
250    fn sample_rate(&self) -> Result<u32>;
251    #[dbus_proxy(property)]
252    fn channels(&self) -> Result<Vec<u32>>;
253    #[dbus_proxy(property)]
254    fn has_flat_volume(&self) -> Result<bool>;
255    #[dbus_proxy(property)]
256    fn base_volume(&self) -> Result<u32>;
257    #[dbus_proxy(property)]
258    fn volume_steps(&self) -> Result<u32>;
259    #[dbus_proxy(property)]
260    fn mute(&self) -> Result<bool>;
261    #[dbus_proxy(property)]
262    fn configured_latency(&self) -> Result<u64>;
263    #[dbus_proxy(property)]
264    fn latency(&self) -> Result<u64>;
265    #[dbus_proxy(property)]
266    fn state(&self) -> Result<u32>;
267    #[dbus_proxy(property)]
268    fn has_hardware_volume(&self) -> Result<bool>;
269    #[dbus_proxy(property)]
270    fn has_hardware_mute(&self) -> Result<bool>;
271    #[dbus_proxy(property)]
272    fn set_volume(&self, vols: Vec<u32>) -> Result<()>;
273    #[dbus_proxy(property)]
274    fn set_mute(&self, mute: bool) -> Result<()>;
275}