use std::time::Duration;
use log::debug;
use tokio::sync::mpsc::UnboundedSender;
use tokio::time::sleep;
use zbus::{azync::Connection, Result};
use zbus_macros::dbus_proxy;
use zvariant::ObjectPath;
use crate::bar::Update;
use crate::err::Res;
pub async fn watch_pulse(tx: UnboundedSender<Update>) -> Res<()> {
loop {
tx.send(Update::Volume(get_volume().await.ok()))?;
tx.send(Update::Mute(get_mute().await.ok()))?;
tx.send(Update::Redraw)?;
sleep(Duration::from_secs(5)).await;
}
}
pub async fn set_volume(vol: u32) -> Res<()> {
let pulse_conn = new_pulse_connection().await?;
let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
let sinks = core_proxy.sinks().await?;
for sink in sinks.iter().map(|s| s.to_string()) {
let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink)?;
let mut new_volume = Vec::new();
new_volume.push(vol);
match sink_proxy.set_volume(new_volume).await {
Ok(val) => debug!("Ok: {:?}", val),
Err(err) => debug!("Err: {:?}", err),
}
}
Ok(())
}
pub async fn toggle_mute() -> Res<()> {
let pulse_conn = new_pulse_connection().await?;
let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
let sinks = core_proxy.sinks().await?;
for sink in sinks.iter().map(|s| s.to_string()) {
let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink)?;
match sink_proxy.set_mute(!sink_proxy.mute().await.unwrap()).await {
Ok(val) => debug!("Ok: {:?}", val),
Err(err) => debug!("Err: {:?}", err),
}
}
Ok(())
}
pub async fn get_mute() -> Res<bool> {
let pulse_conn = new_pulse_connection().await?;
let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
let sinks = core_proxy.sinks().await?;
if let Some(sink) = sinks.get(0) {
let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink.to_string())?;
Ok(sink_proxy.mute().await?)
} else {
Err("No sink found".into())
}
}
pub async fn get_volume() -> Res<u32> {
let pulse_conn = new_pulse_connection().await?;
let core_proxy = AsyncPulseCoreProxy::new(&pulse_conn)?;
let sinks = core_proxy.sinks().await?;
if let Some(sink) = sinks.get(0) {
let sink_proxy = AsyncSinkProxy::new_for_path(&pulse_conn, sink.to_string())?;
let vol = sink_proxy.volume().await?;
Ok(vol[0])
} else {
Err("No sink found".into())
}
}
async fn new_pulse_connection() -> Res<Connection> {
let conn = Connection::new_session().await?;
let addr_lookup = AsyncPulseAddressProxy::new(&conn)?;
let addr = addr_lookup.address().await?;
Ok(Connection::new_for_address(&addr, false).await?)
}
pub async fn pulse_info() -> Vec<String> {
let mut result = Vec::new();
let conn = Connection::new_session().await.unwrap();
let p = AsyncPulseAddressProxy::new(&conn).unwrap();
let addr = p.address().await.unwrap();
result.push(addr.to_string());
let pulse_conn = Connection::new_for_address(&addr, false).await.unwrap();
let c = AsyncPulseCoreProxy::new(&pulse_conn).unwrap();
let name = c.name().await.unwrap();
let version = c.version().await.unwrap();
let dsf = c.default_sample_format().await.unwrap();
let dsr = c.default_sample_rate().await.unwrap();
let sinks = c.sinks().await.unwrap();
result.push(format!("{} {}", name, version));
result.push(format!("dsr: {}", dsr));
result.push(format!("dsf: {:?}", SampleFormat::from(dsf)));
result.push(String::from("Sinks:"));
for sink in sinks.iter().map(|s| s.to_string()) {
let s = AsyncSinkProxy::new_for_path(&pulse_conn, sink).unwrap();
result.push(format!("name: {}", s.name().await.unwrap()));
let vol = s.volume().await.unwrap();
let vol: Vec<u32> = vol.iter().map(|x| x * 100 / 65536).collect();
result.push(format!("volume: {:?}", vol));
let sf = s.sample_format().await.unwrap();
result.push(format!("format: {:?}", SampleFormat::from(sf)));
result.push(format!("rate: {:?}", s.sample_rate().await.unwrap()));
result.push(format!("channels: {:?}", s.channels().await.unwrap()));
result.push(format!(
"flat vol?: {:?}",
s.has_flat_volume().await.unwrap()
));
result.push(format!("base vol: {:?}", s.base_volume().await.unwrap()));
result.push(format!("vol steps: {:?}", s.volume_steps().await.unwrap()));
result.push(format!("mute: {:?}", s.mute().await.unwrap()));
result.push(format!(
"cfg latency: {:?}",
s.configured_latency().await.unwrap()
));
result.push(format!("latency: {:?}", s.latency().await.unwrap()));
let ds = s.state().await.unwrap();
result.push(format!("state: {:?}", DeviceState::from(ds)));
result.push(format!(
"hardware vol: {:?}",
s.has_hardware_volume().await.unwrap()
));
result.push(format!(
"hardware mute: {:?}",
s.has_hardware_mute().await.unwrap()
));
}
result
}
#[derive(Debug)]
enum DeviceState {
Running,
Idle,
Suspended,
None,
}
impl From<u32> for DeviceState {
fn from(state: u32) -> Self {
match state {
0 => DeviceState::Running,
1 => DeviceState::Idle,
2 => DeviceState::Suspended,
_ => DeviceState::None,
}
}
}
#[derive(Debug)]
enum SampleFormat {
S16le,
None,
}
impl From<u32> for SampleFormat {
fn from(index: u32) -> Self {
match index {
3 => SampleFormat::S16le,
_ => SampleFormat::None,
}
}
}
#[dbus_proxy(
interface = "org.PulseAudio.ServerLookup1",
default_service = "org.PulseAudio1",
default_path = "/org/pulseaudio/server_lookup1"
)]
trait PulseAddress {
#[dbus_proxy(property)]
fn address(&self) -> Result<String>;
}
#[dbus_proxy(
interface = "org.PulseAudio.Core1",
default_service = "org.PulseAudio.Core1",
default_path = "/org/pulseaudio/core1"
)]
trait PulseCore {
#[dbus_proxy(property)]
fn name(&self) -> Result<String>;
#[dbus_proxy(property)]
fn version(&self) -> Result<String>;
#[dbus_proxy(property)]
fn sinks(&self) -> Result<Vec<ObjectPath<'_>>>;
#[dbus_proxy(property)]
fn default_sample_format(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn default_sample_rate(&self) -> Result<u32>;
}
#[dbus_proxy(
interface = "org.PulseAudio.Core1.Device",
default_service = "org.PulseAudio.Core1.Device"
)]
trait Sink {
#[dbus_proxy(property)]
fn name(&self) -> Result<String>;
#[dbus_proxy(property)]
fn volume(&self) -> Result<Vec<u32>>;
#[dbus_proxy(property)]
fn sample_format(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn sample_rate(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn channels(&self) -> Result<Vec<u32>>;
#[dbus_proxy(property)]
fn has_flat_volume(&self) -> Result<bool>;
#[dbus_proxy(property)]
fn base_volume(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn volume_steps(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn mute(&self) -> Result<bool>;
#[dbus_proxy(property)]
fn configured_latency(&self) -> Result<u64>;
#[dbus_proxy(property)]
fn latency(&self) -> Result<u64>;
#[dbus_proxy(property)]
fn state(&self) -> Result<u32>;
#[dbus_proxy(property)]
fn has_hardware_volume(&self) -> Result<bool>;
#[dbus_proxy(property)]
fn has_hardware_mute(&self) -> Result<bool>;
#[dbus_proxy(property)]
fn set_volume(&self, vols: Vec<u32>) -> Result<()>;
#[dbus_proxy(property)]
fn set_mute(&self, mute: bool) -> Result<()>;
}