qdl: start an Introspect helper

This commit is contained in:
Marc-André Lureau 2021-08-16 00:06:13 +04:00
parent 0f653ea6d5
commit 75a0fd7bc7
8 changed files with 101 additions and 34 deletions

View File

@ -19,3 +19,4 @@ serde_repr = "0.1.6"
serde_bytes = "0.11.5"
futures-util = { version = "0.3.8", features = ["async-await-macro"] }
once_cell = "1.5"
futures = "0.3.13"

View File

@ -1,7 +1,6 @@
use once_cell::sync::OnceCell;
use std::default::Default;
use std::os::unix::net::UnixStream;
use std::str::FromStr;
use std::sync::mpsc::{self, Receiver, SendError};
use std::sync::{Arc, Mutex};
use std::{os::unix::io::AsRawFd, thread};
@ -263,24 +262,6 @@ impl Audio {
Ok(Self { proxy })
}
pub async fn available(conn: &zbus::azync::Connection) -> bool {
// TODO: we may want to generalize interface detection
let ip = zbus::fdo::AsyncIntrospectableProxy::builder(conn)
.destination("org.qemu")
.unwrap()
.path("/org/qemu/Display1")
.unwrap()
.build()
.await
.unwrap();
let introspect = zbus::xml::Node::from_str(&ip.introspect().await.unwrap()).unwrap();
let has_audio = introspect
.nodes()
.iter()
.any(|n| n.name().map(|n| n == "Audio").unwrap_or(false));
has_audio
}
pub async fn listen_out(&self) -> Result<Receiver<AudioOutEvent>> {
let (p0, p1) = UnixStream::pair()?;
let (tx, rx) = mpsc::channel();

View File

@ -6,7 +6,6 @@ use std::io;
pub enum Error {
Io(io::Error),
Zbus(zbus::Error),
Zvariant(zvariant::Error),
Failed(String),
}
@ -15,7 +14,6 @@ impl fmt::Display for Error {
match self {
Error::Io(e) => write!(f, "{}", e),
Error::Zbus(e) => write!(f, "{}", e),
Error::Zvariant(e) => write!(f, "{}", e),
Error::Failed(e) => write!(f, "{}", e),
}
}
@ -26,7 +24,6 @@ impl error::Error for Error {
match self {
Error::Io(e) => Some(e),
Error::Zbus(e) => Some(e),
Error::Zvariant(e) => Some(e),
Error::Failed(_) => None,
}
}
@ -44,9 +41,15 @@ impl From<zbus::Error> for Error {
}
}
impl From<zbus::fdo::Error> for Error {
fn from(e: zbus::fdo::Error) -> Self {
Error::Zbus(e.into())
}
}
impl From<zvariant::Error> for Error {
fn from(e: zvariant::Error) -> Self {
Error::Zvariant(e)
Error::Zbus(e.into())
}
}

View File

@ -0,0 +1,68 @@
use futures::stream::{self, StreamExt};
use std::convert::TryFrom;
use zbus::azync::Connection;
use zbus::fdo::ManagedObjects;
use zvariant::OwnedObjectPath;
use crate::{Audio, Chardev, Result, UsbRedir};
pub struct Introspect {
conn: Connection,
objects: ManagedObjects,
}
impl Introspect {
pub async fn new(conn: &Connection) -> Result<Self> {
let objects = zbus::fdo::AsyncObjectManagerProxy::builder(&conn)
.destination("org.qemu")?
.path("/org/qemu/Display1")?
.build()
.await?
.get_managed_objects()
.await?;
// TODO: listen for changes ?
Ok(Self {
conn: conn.clone(),
objects,
})
}
pub async fn audio(&self) -> Result<Option<Audio>> {
if !self
.objects
.contains_key(&OwnedObjectPath::try_from("/org/qemu/Display1/Audio").unwrap())
{
return Ok(None);
}
Ok(Some(Audio::new(&self.conn).await?))
}
pub async fn chardevs(&self) -> Vec<Chardev> {
stream::iter(&self.objects)
.filter_map(|(p, _ifaces)| async move {
match p.strip_prefix("/org/qemu/Display1/Chardev_") {
Some(id) => Chardev::new(&self.conn, id).await.ok(),
_ => None,
}
})
.collect()
.await
}
pub async fn usbredir(&self) -> UsbRedir {
let chardevs = stream::iter(self.chardevs().await)
.filter_map(|c| async move {
if c.proxy.name().await.ok() == Some("org.qemu.usbredir".to_string()) {
Some(c)
} else {
None
}
})
.collect()
.await;
let redir = UsbRedir::new(chardevs);
redir
}
}

View File

@ -30,6 +30,12 @@ pub use keyboard::*;
mod mouse;
pub use mouse::*;
mod introspect;
pub use introspect::*;
mod usbredir;
pub use usbredir::*;
#[cfg(test)]
mod tests {
#[test]

View File

@ -0,0 +1,10 @@
use crate::Chardev;
pub struct UsbRedir;
impl UsbRedir {
pub fn new(chardevs: Vec<Chardev>) -> Self {
dbg!(chardevs);
Self
}
}

View File

@ -10,13 +10,7 @@ pub struct Handler {
}
impl Handler {
pub async fn new(conn: &zbus::azync::Connection) -> Result<Self, Box<dyn Error>> {
if !Audio::available(conn).await {
log::debug!("No qemu audio provided on the bus");
return Ok(Self::default());
}
let audio = Audio::new(conn).await?;
pub async fn new(audio: Audio) -> Result<Self, Box<dyn Error>> {
let rx = audio.listen_out().await?;
let mut gst = rdw::GstAudio::new()?;

View File

@ -2,7 +2,7 @@ use gio::ApplicationFlags;
use glib::{clone, MainContext};
use gtk::{gio, glib, prelude::*};
use once_cell::sync::OnceCell;
use qemu_display_listener::{Chardev, Console};
use qemu_display_listener::{Chardev, Console, Introspect};
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixStream;
use zbus::Connection;
@ -33,13 +33,17 @@ fn main() {
let audio_clone = audio.clone();
let clipboard_clone = clipboard.clone();
MainContext::default().spawn_local(clone!(@strong window => async move {
let intro = Introspect::new(&conn).await.unwrap();
let console = Console::new(&conn, 0).await.expect("Failed to get the QEMU console");
let display = display_qemu::DisplayQemu::new(console);
window.set_child(Some(&display));
match audio::Handler::new(&conn).await {
Ok(handler) => audio_clone.set(handler).unwrap(),
Err(e) => log::warn!("Failed to setup audio: {}", e),
if let Ok(Some(audio)) = intro.audio().await {
match audio::Handler::new(audio).await {
Ok(handler) => audio_clone.set(handler).unwrap(),
Err(e) => log::warn!("Failed to setup audio: {}", e),
}
}
match clipboard::Handler::new(&conn).await {