Handle playback volume

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-03-07 18:26:08 +04:00
parent 3b7f0c5793
commit 0f75905cc8
3 changed files with 67 additions and 7 deletions

View File

@ -20,11 +20,18 @@ pub struct PCMInfo {
pub be: bool,
}
#[derive(Debug)]
pub struct Volume {
pub mute: bool,
pub volume: Vec<u8>,
}
#[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<u8> },
}
@ -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<E: 'static + EventSender<Event = AudioOutEvent>> AudioOutListener<E> {
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<E: 'static + EventSender<Event = AudioInEvent>> AudioInListener<E> {
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<u8> {
dbg!((id, size));

View File

@ -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"

View File

@ -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::<gst_app::AppSrc>()
.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<Self, Box<dyn Error>> {
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::<gst_audio::StreamVolume>()
.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 })
}
}