From 262dd60a032ff673a3a9847de83a5cf60806648b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 6 Mar 2021 12:20:38 +0400 Subject: [PATCH] listener: add audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- qemu-display-listener/src/audio.rs | 279 +++++++++++++++++++++++++++++ qemu-display-listener/src/lib.rs | 4 +- 2 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 qemu-display-listener/src/audio.rs diff --git a/qemu-display-listener/src/audio.rs b/qemu-display-listener/src/audio.rs new file mode 100644 index 0000000..9c89338 --- /dev/null +++ b/qemu-display-listener/src/audio.rs @@ -0,0 +1,279 @@ +use std::cell::RefCell; +use std::os::unix::net::UnixStream; +use std::sync::mpsc::{self, Receiver, SendError}; +use std::sync::Arc; +use std::{os::unix::io::AsRawFd, thread}; + +use zbus::{dbus_interface, dbus_proxy, export::zvariant::Fd}; + +use crate::{EventSender, Result}; + +#[derive(Debug)] +pub enum AudioOutEvent { + Init { + id: u64, + bits: u8, + is_signed: bool, + is_float: bool, + freq: u32, + nchannels: u8, + bytes_per_frame: u32, + bytes_per_second: u32, + swap_endianness: u32, + }, + Fini { + id: u64, + }, + SetEnabled { + id: u64, + enabled: bool, + }, + Write { + id: u64, + data: Vec, + }, +} + +#[derive(Debug)] +pub enum AudioInEvent { + Init { + id: u64, + bits: u8, + is_signed: bool, + is_float: bool, + freq: u32, + nchannels: u8, + bytes_per_frame: u32, + bytes_per_second: u32, + swap_endianness: u32, + }, + Fini { + id: u64, + }, + SetEnabled { + id: u64, + enabled: bool, + }, + Read { + id: u64, + }, +} + +#[dbus_proxy( + default_service = "org.qemu", + default_path = "/org/qemu/Display1/Audio", + interface = "org.qemu.Display1.Audio" +)] +trait Audio { + /// RegisterOutListener method + fn register_out_listener(&self, listener: Fd) -> zbus::Result<()>; + + /// RegisterInListener method + fn register_in_listener(&self, listener: Fd) -> zbus::Result<()>; +} + +#[derive(derivative::Derivative)] +#[derivative(Debug)] +pub struct Audio { + #[derivative(Debug = "ignore")] + pub proxy: AudioProxy<'static>, +} + +#[derive(Debug)] +pub(crate) struct AudioOutListener> { + tx: E, + err: Arc>>>, +} + +impl> AudioOutListener { + pub(crate) fn new(tx: E) -> Self { + let err = Arc::new(RefCell::new(None)); + AudioOutListener { tx, err } + } + + fn send(&mut self, event: AudioOutEvent) { + if let Err(e) = self.tx.send_event(event) { + *self.err.borrow_mut() = Some(e); + } + } + + pub fn err(&self) -> Arc>>> { + self.err.clone() + } +} + +#[dbus_interface(name = "org.qemu.Display1.AudioOutListener")] +impl> AudioOutListener { + /// Init method + fn init( + &mut self, + id: u64, + bits: u8, + is_signed: bool, + is_float: bool, + freq: u32, + nchannels: u8, + bytes_per_frame: u32, + bytes_per_second: u32, + swap_endianness: u32, + ) { + self.send(AudioOutEvent::Init { + id, + bits, + is_signed, + is_float, + freq, + nchannels, + bytes_per_frame, + bytes_per_second, + swap_endianness, + }) + } + + /// Fini method + fn fini(&mut self, id: u64) { + self.send(AudioOutEvent::Fini { id }) + } + + /// SetEnabled method + fn set_enabled(&mut self, id: u64, enabled: bool) { + self.send(AudioOutEvent::SetEnabled { id, enabled }) + } + + /// Write method + fn write(&mut self, id: u64, data: serde_bytes::ByteBuf) { + self.send(AudioOutEvent::Write { + id, + data: data.into_vec(), + }) + } +} + +#[derive(Debug)] +pub(crate) struct AudioInListener> { + tx: E, + err: Arc>>>, +} + +impl> AudioInListener { + pub(crate) fn new(tx: E) -> Self { + let err = Arc::new(RefCell::new(None)); + AudioInListener { tx, err } + } + + fn send(&mut self, event: AudioInEvent) { + if let Err(e) = self.tx.send_event(event) { + *self.err.borrow_mut() = Some(e); + } + } + + pub fn err(&self) -> Arc>>> { + self.err.clone() + } +} + +#[dbus_interface(name = "org.qemu.Display1.AudioInListener")] +impl> AudioInListener { + /// Init method + fn init( + &mut self, + id: u64, + bits: u8, + is_signed: bool, + is_float: bool, + freq: u32, + nchannels: u8, + bytes_per_frame: u32, + bytes_per_second: u32, + swap_endianness: u32, + ) { + self.send(AudioInEvent::Init { + id, + bits, + is_signed, + is_float, + freq, + nchannels, + bytes_per_frame, + bytes_per_second, + swap_endianness, + }) + } + + /// Fini method + fn fini(&mut self, id: u64) { + self.send(AudioInEvent::Fini { id }) + } + + /// SetEnabled method + fn set_enabled(&mut self, id: u64, enabled: bool) { + self.send(AudioInEvent::SetEnabled { id, enabled }) + } + + /// Read method + fn read(&mut self, id: u64, size: u64) -> Vec { + dbg!((id, size)); + vec![0; size as usize] + } +} + +impl Audio { + pub fn new(conn: &zbus::Connection) -> Result { + let proxy = AudioProxy::new(conn)?; + Ok(Self { proxy }) + } + + pub fn listen_out(&self) -> Result> { + let (p0, p1) = UnixStream::pair()?; + let (tx, rx) = mpsc::channel(); + self.proxy.register_out_listener(p0.as_raw_fd().into())?; + + let _thread = thread::spawn(move || { + let c = zbus::Connection::new_unix_client(p1, false).unwrap(); + let mut s = zbus::ObjectServer::new(&c); + let listener = AudioOutListener::new(tx); + let err = listener.err(); + s.at("/org/qemu/Display1/AudioOutListener", listener) + .unwrap(); + loop { + if let Err(e) = s.try_handle_next() { + eprintln!("Listener DBus error: {}", e); + return; + } + if let Some(e) = &*err.borrow() { + eprintln!("Listener channel error: {}", e); + return; + } + } + }); + + Ok(rx) + } + + pub fn listen_in(&self) -> Result> { + let (p0, p1) = UnixStream::pair()?; + let (tx, rx) = mpsc::channel(); + self.proxy.register_in_listener(p0.as_raw_fd().into())?; + + let _thread = thread::spawn(move || { + let c = zbus::Connection::new_unix_client(p1, false).unwrap(); + let mut s = zbus::ObjectServer::new(&c); + let listener = AudioInListener::new(tx); + let err = listener.err(); + s.at("/org/qemu/Display1/AudioInListener", listener) + .unwrap(); + loop { + if let Err(e) = s.try_handle_next() { + eprintln!("Listener DBus error: {}", e); + return; + } + if let Some(e) = &*err.borrow() { + eprintln!("Listener channel error: {}", e); + return; + } + } + }); + + Ok(rx) + } +} diff --git a/qemu-display-listener/src/lib.rs b/qemu-display-listener/src/lib.rs index bc315c2..2a7263b 100644 --- a/qemu-display-listener/src/lib.rs +++ b/qemu-display-listener/src/lib.rs @@ -9,8 +9,8 @@ use event_sender::*; mod vm; pub use vm::*; -// mod audio; -// pub use audio::*; +mod audio; +pub use audio::*; mod console; pub use console::*;