mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2024-09-20 02:30:58 +00:00
Handle playback volume
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
3b7f0c5793
commit
0f75905cc8
@ -20,11 +20,18 @@ pub struct PCMInfo {
|
|||||||
pub be: bool,
|
pub be: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Volume {
|
||||||
|
pub mute: bool,
|
||||||
|
pub volume: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AudioOutEvent {
|
pub enum AudioOutEvent {
|
||||||
Init { id: u64, info: PCMInfo },
|
Init { id: u64, info: PCMInfo },
|
||||||
Fini { id: u64 },
|
Fini { id: u64 },
|
||||||
SetEnabled { id: u64, enabled: bool },
|
SetEnabled { id: u64, enabled: bool },
|
||||||
|
SetVolume { id: u64, volume: Volume },
|
||||||
Write { id: u64, data: Vec<u8> },
|
Write { id: u64, data: Vec<u8> },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +40,7 @@ pub enum AudioInEvent {
|
|||||||
Init { id: u64, info: PCMInfo },
|
Init { id: u64, info: PCMInfo },
|
||||||
Fini { id: u64 },
|
Fini { id: u64 },
|
||||||
SetEnabled { id: u64, enabled: bool },
|
SetEnabled { id: u64, enabled: bool },
|
||||||
|
SetVolume { id: u64, volume: Volume },
|
||||||
Read { id: u64 },
|
Read { id: u64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +127,17 @@ impl<E: 'static + EventSender<Event = AudioOutEvent>> AudioOutListener<E> {
|
|||||||
self.send(AudioOutEvent::SetEnabled { id, enabled })
|
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
|
/// Write method
|
||||||
fn write(&mut self, id: u64, data: serde_bytes::ByteBuf) {
|
fn write(&mut self, id: u64, data: serde_bytes::ByteBuf) {
|
||||||
self.send(AudioOutEvent::Write {
|
self.send(AudioOutEvent::Write {
|
||||||
@ -191,6 +210,17 @@ impl<E: 'static + EventSender<Event = AudioInEvent>> AudioInListener<E> {
|
|||||||
self.send(AudioInEvent::SetEnabled { id, enabled })
|
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
|
/// Read method
|
||||||
fn read(&mut self, id: u64, size: u64) -> Vec<u8> {
|
fn read(&mut self, id: u64, size: u64) -> Vec<u8> {
|
||||||
dbg!((id, size));
|
dbg!((id, size));
|
||||||
|
@ -20,6 +20,7 @@ glib = { git = "https://github.com/gtk-rs/gtk-rs", optional = true }
|
|||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
gst = { package = "gstreamer", version = "0.16.7" }
|
gst = { package = "gstreamer", version = "0.16.7" }
|
||||||
gst-app = { package = "gstreamer-app", version = "0.16.5" }
|
gst-app = { package = "gstreamer-app", version = "0.16.5" }
|
||||||
|
gst-audio = { package = "gstreamer-audio", version = "0.16.5" }
|
||||||
|
|
||||||
[dependencies.gtk]
|
[dependencies.gtk]
|
||||||
package = "gtk4"
|
package = "gtk4"
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst_audio::StreamVolumeExt;
|
||||||
use qemu_display_listener::{Audio, PCMInfo};
|
|
||||||
use std::thread::{self, JoinHandle};
|
use std::thread::{self, JoinHandle};
|
||||||
use std::{collections::HashMap, error::Error};
|
use std::{collections::HashMap, error::Error};
|
||||||
|
|
||||||
|
use qemu_display_listener::{Audio, PCMInfo};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct OutStream {
|
struct OutStream {
|
||||||
pipeline: gst::Pipeline,
|
pipeline: gst::Pipeline,
|
||||||
src: gst_app::AppSrc,
|
src: gst_app::AppSrc,
|
||||||
|
sink: gst::Element,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pcminfo_as_caps(info: &PCMInfo) -> String {
|
fn pcminfo_as_caps(info: &PCMInfo) -> String {
|
||||||
@ -44,23 +46,28 @@ impl OutStream {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.dynamic_cast::<gst_app::AppSrc>()
|
.dynamic_cast::<gst_app::AppSrc>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let sink = pipeline.get_by_name("sink").unwrap();
|
||||||
Ok(Self { pipeline, src })
|
Ok(Self {
|
||||||
|
pipeline,
|
||||||
|
src,
|
||||||
|
sink,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GstAudio {
|
pub struct GstAudio {
|
||||||
thread: JoinHandle<()>,
|
out_thread: JoinHandle<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GstAudio {
|
impl GstAudio {
|
||||||
pub fn new(audio: Audio) -> Result<Self, Box<dyn Error>> {
|
pub fn new(audio: Audio) -> Result<Self, Box<dyn Error>> {
|
||||||
gst::init()?;
|
gst::init()?;
|
||||||
|
|
||||||
|
// TODO audio.listen_in() for capture.
|
||||||
let rx = audio.listen_out()?;
|
let rx = audio.listen_out()?;
|
||||||
let mut out = HashMap::new();
|
let mut out = HashMap::new();
|
||||||
let thread = thread::spawn(move || loop {
|
let out_thread = thread::spawn(move || loop {
|
||||||
match rx.recv() {
|
match rx.recv() {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
use qemu_display_listener::AudioOutEvent::*;
|
use qemu_display_listener::AudioOutEvent::*;
|
||||||
@ -95,6 +102,28 @@ impl GstAudio {
|
|||||||
eprintln!("Stream was not setup yet: {}", id);
|
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 } => {
|
Write { id, data } => {
|
||||||
if let Some(s) = out.get(&id) {
|
if let Some(s) = out.get(&id) {
|
||||||
let b = gst::Buffer::from_slice(data);
|
let b = gst::Buffer::from_slice(data);
|
||||||
@ -108,6 +137,6 @@ impl GstAudio {
|
|||||||
Err(e) => eprintln!("Audio thread error: {}", e),
|
Err(e) => eprintln!("Audio thread error: {}", e),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ok(Self { thread })
|
Ok(Self { out_thread })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user