288 lines
7.1 KiB
Rust
288 lines
7.1 KiB
Rust
#[cfg(windows)]
|
|
use crate::win32::Fd;
|
|
#[cfg(unix)]
|
|
use std::os::unix::net::UnixStream;
|
|
#[cfg(windows)]
|
|
use uds_windows::UnixStream;
|
|
#[cfg(unix)]
|
|
use zbus::zvariant::Fd;
|
|
use zbus::Connection;
|
|
|
|
use crate::{util, Result};
|
|
|
|
#[derive(Debug)]
|
|
pub struct PCMInfo {
|
|
pub bits: u8,
|
|
pub is_signed: bool,
|
|
pub is_float: bool,
|
|
pub freq: u32,
|
|
pub nchannels: u8,
|
|
pub bytes_per_frame: u32,
|
|
pub bytes_per_second: u32,
|
|
pub be: bool,
|
|
}
|
|
|
|
impl PCMInfo {
|
|
pub fn gst_caps(&self) -> String {
|
|
let format = format!(
|
|
"{}{}{}",
|
|
if self.is_float {
|
|
"F"
|
|
} else if self.is_signed {
|
|
"S"
|
|
} else {
|
|
"U"
|
|
},
|
|
self.bits,
|
|
if self.be { "BE" } else { "LE" }
|
|
);
|
|
format!(
|
|
"audio/x-raw,format={format},channels={channels},rate={rate},layout=interleaved",
|
|
format = format,
|
|
channels = self.nchannels,
|
|
rate = self.freq,
|
|
)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Volume {
|
|
pub mute: bool,
|
|
pub volume: Vec<u8>,
|
|
}
|
|
|
|
#[zbus::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>,
|
|
out_listener: Option<Connection>,
|
|
in_listener: Option<Connection>,
|
|
#[cfg(windows)]
|
|
peer_pid: u32,
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait AudioOutHandler: 'static + Send + Sync {
|
|
async fn init(&mut self, id: u64, info: PCMInfo);
|
|
|
|
async fn fini(&mut self, id: u64);
|
|
|
|
async fn set_enabled(&mut self, id: u64, enabled: bool);
|
|
|
|
async fn set_volume(&mut self, id: u64, volume: Volume);
|
|
|
|
async fn write(&mut self, id: u64, data: Vec<u8>);
|
|
}
|
|
|
|
struct AudioOutListener<H: AudioOutHandler> {
|
|
handler: H,
|
|
}
|
|
|
|
#[zbus::interface(name = "org.qemu.Display1.AudioOutListener")]
|
|
impl<H: AudioOutHandler> AudioOutListener<H> {
|
|
/// Init method
|
|
async 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,
|
|
be: bool,
|
|
) {
|
|
self.handler
|
|
.init(
|
|
id,
|
|
PCMInfo {
|
|
bits,
|
|
is_signed,
|
|
is_float,
|
|
freq,
|
|
nchannels,
|
|
bytes_per_frame,
|
|
bytes_per_second,
|
|
be,
|
|
},
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Fini method
|
|
async fn fini(&mut self, id: u64) {
|
|
self.handler.fini(id).await
|
|
}
|
|
|
|
/// SetEnabled method
|
|
async fn set_enabled(&mut self, id: u64, enabled: bool) {
|
|
self.handler.set_enabled(id, enabled).await
|
|
}
|
|
|
|
/// SetVolume method
|
|
async fn set_volume(&mut self, id: u64, mute: bool, volume: serde_bytes::ByteBuf) {
|
|
self.handler
|
|
.set_volume(
|
|
id,
|
|
Volume {
|
|
mute,
|
|
volume: volume.into_vec(),
|
|
},
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Write method
|
|
async fn write(&mut self, id: u64, data: serde_bytes::ByteBuf) {
|
|
self.handler.write(id, data.into_vec()).await
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait AudioInHandler: 'static + Send + Sync {
|
|
async fn init(&mut self, id: u64, info: PCMInfo);
|
|
|
|
async fn fini(&mut self, id: u64);
|
|
|
|
async fn set_enabled(&mut self, id: u64, enabled: bool);
|
|
|
|
async fn set_volume(&mut self, id: u64, volume: Volume);
|
|
|
|
async fn read(&mut self, id: u64, size: u64) -> Vec<u8>;
|
|
}
|
|
|
|
struct AudioInListener<H: AudioInHandler> {
|
|
handler: H,
|
|
}
|
|
|
|
#[zbus::interface(name = "org.qemu.Display1.AudioInListener")]
|
|
impl<H: AudioInHandler> AudioInListener<H> {
|
|
/// Init method
|
|
async 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,
|
|
be: bool,
|
|
) {
|
|
self.handler
|
|
.init(
|
|
id,
|
|
PCMInfo {
|
|
bits,
|
|
is_signed,
|
|
is_float,
|
|
freq,
|
|
nchannels,
|
|
bytes_per_frame,
|
|
bytes_per_second,
|
|
be,
|
|
},
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Fini method
|
|
async fn fini(&mut self, id: u64) {
|
|
self.handler.fini(id).await
|
|
}
|
|
|
|
/// SetEnabled method
|
|
async fn set_enabled(&mut self, id: u64, enabled: bool) {
|
|
self.handler.set_enabled(id, enabled).await
|
|
}
|
|
|
|
/// SetVolume method
|
|
async fn set_volume(&mut self, id: u64, mute: bool, volume: serde_bytes::ByteBuf) {
|
|
self.handler
|
|
.set_volume(
|
|
id,
|
|
Volume {
|
|
mute,
|
|
volume: volume.into_vec(),
|
|
},
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Read method
|
|
async fn read(&mut self, id: u64, size: u64) -> Vec<u8> {
|
|
self.handler.read(id, size).await
|
|
// dbg!((id, size));
|
|
// vec![0; size as usize]
|
|
}
|
|
}
|
|
|
|
impl Audio {
|
|
pub async fn new(conn: &zbus::Connection, #[cfg(windows)] peer_pid: u32) -> Result<Self> {
|
|
let proxy = AudioProxy::new(conn).await?;
|
|
Ok(Self {
|
|
proxy,
|
|
in_listener: None,
|
|
out_listener: None,
|
|
#[cfg(windows)]
|
|
peer_pid,
|
|
})
|
|
}
|
|
|
|
pub async fn register_out_listener<H: AudioOutHandler>(&mut self, handler: H) -> Result<()> {
|
|
let (p0, p1) = UnixStream::pair()?;
|
|
let p0 = util::prepare_uds_pass(
|
|
#[cfg(windows)]
|
|
self.peer_pid,
|
|
&p0,
|
|
)?;
|
|
self.proxy.register_out_listener(p0).await?;
|
|
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
|
.p2p()
|
|
.serve_at(
|
|
"/org/qemu/Display1/AudioOutListener",
|
|
AudioOutListener { handler },
|
|
)?
|
|
.build()
|
|
.await?;
|
|
self.out_listener.replace(c);
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn register_in_listener<H: AudioInHandler>(&mut self, handler: H) -> Result<()> {
|
|
let (p0, p1) = UnixStream::pair()?;
|
|
let p0 = util::prepare_uds_pass(
|
|
#[cfg(windows)]
|
|
self.peer_pid,
|
|
&p0,
|
|
)?;
|
|
self.proxy.register_in_listener(p0).await?;
|
|
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
|
.p2p()
|
|
.serve_at(
|
|
"/org/qemu/Display1/AudioInListener",
|
|
AudioInListener { handler },
|
|
)?
|
|
.build()
|
|
.await?;
|
|
self.in_listener.replace(c);
|
|
Ok(())
|
|
}
|
|
}
|