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 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 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}