diff --git a/qemu-display-listener/src/audio.rs b/qemu-display-listener/src/audio.rs index 97b8c7a..e26b880 100644 --- a/qemu-display-listener/src/audio.rs +++ b/qemu-display-listener/src/audio.rs @@ -20,11 +20,18 @@ pub struct PCMInfo { pub be: bool, } +#[derive(Debug)] +pub struct Volume { + pub mute: bool, + pub volume: Vec, +} + #[derive(Debug)] pub enum AudioOutEvent { Init { id: u64, info: PCMInfo }, Fini { id: u64 }, SetEnabled { id: u64, enabled: bool }, + SetVolume { id: u64, volume: Volume }, Write { id: u64, data: Vec }, } @@ -33,6 +40,7 @@ pub enum AudioInEvent { Init { id: u64, info: PCMInfo }, Fini { id: u64 }, SetEnabled { id: u64, enabled: bool }, + SetVolume { id: u64, volume: Volume }, Read { id: u64 }, } @@ -119,6 +127,17 @@ impl> AudioOutListener { self.send(AudioOutEvent::SetEnabled { id, enabled }) } + /// SetVolume method + fn set_volume(&mut self, id: u64, mute: bool, volume: serde_bytes::ByteBuf) { + self.send(AudioOutEvent::SetVolume { + id, + volume: Volume { + mute, + volume: volume.into_vec(), + }, + }); + } + /// Write method fn write(&mut self, id: u64, data: serde_bytes::ByteBuf) { self.send(AudioOutEvent::Write { @@ -191,6 +210,17 @@ impl> AudioInListener { self.send(AudioInEvent::SetEnabled { id, enabled }) } + /// SetVolume method + fn set_volume(&mut self, id: u64, mute: bool, volume: serde_bytes::ByteBuf) { + self.send(AudioInEvent::SetVolume { + id, + volume: Volume { + mute, + volume: volume.into_vec(), + }, + }); + } + /// Read method fn read(&mut self, id: u64, size: u64) -> Vec { dbg!((id, size)); diff --git a/qemu-gtk4/Cargo.toml b/qemu-gtk4/Cargo.toml index ecb566c..c32b77c 100644 --- a/qemu-gtk4/Cargo.toml +++ b/qemu-gtk4/Cargo.toml @@ -20,6 +20,7 @@ glib = { git = "https://github.com/gtk-rs/gtk-rs", optional = true } derivative = "2.2.0" gst = { package = "gstreamer", version = "0.16.7" } gst-app = { package = "gstreamer-app", version = "0.16.5" } +gst-audio = { package = "gstreamer-audio", version = "0.16.5" } [dependencies.gtk] package = "gtk4" diff --git a/qemu-gtk4/src/gstaudio.rs b/qemu-gtk4/src/gstaudio.rs index 7aa6a05..dda17c8 100644 --- a/qemu-gtk4/src/gstaudio.rs +++ b/qemu-gtk4/src/gstaudio.rs @@ -1,13 +1,15 @@ use gst::prelude::*; - -use qemu_display_listener::{Audio, PCMInfo}; +use gst_audio::StreamVolumeExt; use std::thread::{self, JoinHandle}; use std::{collections::HashMap, error::Error}; +use qemu_display_listener::{Audio, PCMInfo}; + #[derive(Debug)] struct OutStream { pipeline: gst::Pipeline, src: gst_app::AppSrc, + sink: gst::Element, } fn pcminfo_as_caps(info: &PCMInfo) -> String { @@ -44,23 +46,28 @@ impl OutStream { .unwrap() .dynamic_cast::() .unwrap(); - - Ok(Self { pipeline, src }) + let sink = pipeline.get_by_name("sink").unwrap(); + Ok(Self { + pipeline, + src, + sink, + }) } } #[derive(Debug)] pub struct GstAudio { - thread: JoinHandle<()>, + out_thread: JoinHandle<()>, } impl GstAudio { pub fn new(audio: Audio) -> Result> { gst::init()?; + // TODO audio.listen_in() for capture. let rx = audio.listen_out()?; let mut out = HashMap::new(); - let thread = thread::spawn(move || loop { + let out_thread = thread::spawn(move || loop { match rx.recv() { Ok(event) => { use qemu_display_listener::AudioOutEvent::*; @@ -95,6 +102,28 @@ impl GstAudio { eprintln!("Stream was not setup yet: {}", id); } } + SetVolume { id, volume } => { + if let Some(s) = out.get(&id) { + if let Some(stream_vol) = s + .pipeline + .get_by_interface(gst_audio::StreamVolume::static_type()) + { + let stream_vol = stream_vol + .dynamic_cast::() + .unwrap(); + stream_vol.set_mute(volume.mute); + if let Some(vol) = volume.volume.first() { + let vol = *vol as f64 / 255f64; + stream_vol + .set_volume(gst_audio::StreamVolumeFormat::Cubic, vol); + } + } else { + eprintln!("Volume not implemented for this pipeline"); + } + } else { + eprintln!("Stream was not setup yet: {}", id); + } + } Write { id, data } => { if let Some(s) = out.get(&id) { let b = gst::Buffer::from_slice(data); @@ -108,6 +137,6 @@ impl GstAudio { Err(e) => eprintln!("Audio thread error: {}", e), } }); - Ok(Self { thread }) + Ok(Self { out_thread }) } }