Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/backends/pipewire/driver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::error::PipewireError;
use crate::backends::pipewire::device::PipewireDevice;
use crate::backends::pipewire::utils;
use crate::backends::pipewire::utils::get_info;
use crate::{AudioDriver, DeviceType};
use std::borrow::Cow;
use std::marker::PhantomData;
Expand All @@ -15,8 +16,13 @@ impl AudioDriver for PipewireDriver {
const DISPLAY_NAME: &'static str = "Pipewire";

fn version(&self) -> Result<Cow<str>, Self::Error> {
// TODO: Figure out how to get version
Ok(Cow::Borrowed("unkonwn"))
let info = get_info()?;

if let Some(version) = info.get("version") {
return Ok(Cow::Owned(version.to_owned()));
}

Ok(Cow::Borrowed("unknown"))
}

fn default_device(&self, device_type: DeviceType) -> Result<Option<Self::Device>, Self::Error> {
Expand Down
63 changes: 63 additions & 0 deletions src/backends/pipewire/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use pipewire::context::Context;
use pipewire::main_loop::MainLoop;
use pipewire::registry::GlobalObject;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;

fn get_device_type(object: &GlobalObject<&DictRef>) -> Option<DeviceType> {
Expand Down Expand Up @@ -89,3 +90,65 @@ pub fn get_devices() -> Result<Vec<(u32, DeviceType, String)>, PipewireError> {
drop(_listener_reg);
Ok(Rc::into_inner(data).unwrap().into_inner())
}

/// Returns a hashmap of core information
///
/// See [pw_core_info](https://docs.pipewire.org/structpw__core__info.html)
pub fn get_info() -> Result<HashMap<String, String>, PipewireError> {
let mainloop = MainLoop::new(None)?;
let context = Context::new(&mainloop)?;
let core = context.connect(None)?;
Comment on lines +98 to +100
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this behave when the user has already started to manipulate AudioDevices? It feels like pipewire is going to reject creating the loop and contexwt a second time. Maybe it's worth moving these to the driver itself, so that as long as people have a handle to the driver, it all works?


// To comply with Rust's safety rules, we wrap this variable in an `Rc` and a `Cell`.
let done = Rc::new(Cell::new(false));

// Create new reference for each variable so that they can be moved into the closure.
let done_clone = done.clone();
let loop_clone = mainloop.clone();

// Trigger the sync event. The server's answer won't be processed until we start the main loop,
// so we can safely do this before setting up a callback. This lets us avoid using a Cell.
let pending = core.sync(0)?;

let data = Rc::new(RefCell::new(HashMap::<String, String>::new()));
let _listener_core = core
.add_listener_local()
.info({
let data = data.clone();
move |info| {
log::debug!("core.info(...): {:#?}", info);

let mut d = data.borrow_mut();
if let Some(props) = info.props() {
for (key, element) in props.iter() {
d.insert(key.into(), element.into());
}
}

d.insert("id".to_owned(), info.id().to_string());
d.insert("cookie".to_owned(), info.cookie().to_string());
d.insert("user-name".to_owned(), info.user_name().to_owned());
d.insert("host-name".to_owned(), info.host_name().to_owned());
d.insert("version".to_owned(), info.version().to_owned());
d.insert("name".to_owned(), info.name().to_owned());
d.insert(
"change-mask".to_owned(),
format!("{:?}", info.change_mask()), // Call Debug for `bitflags` type
);
}
})
.done(move |id, seq| {
log::debug!("[Core/Done] id: {id} seq: {}", seq.seq());
if id == pipewire::core::PW_ID_CORE && seq == pending {
done_clone.set(true);
loop_clone.quit();
}
})
.register();

while !done.get() {
mainloop.run();
}
drop(_listener_core);
Ok(Rc::into_inner(data).unwrap().into_inner())
}
Loading