monorepo/gm-dash/server/src/audio_control.rs

151 lines
4.3 KiB
Rust

use gstreamer::{prelude::*, ClockTime, MessageType, MessageView};
use std::sync::{Arc, RwLock};
pub struct AudioControl {
bus: gstreamer::Bus,
pipeline: gstreamer::Pipeline,
mixer: gstreamer::Element,
audio_sink: gstreamer::Element,
bus_monitor: std::thread::JoinHandle<()>,
playing: Arc<RwLock<bool>>,
}
impl Default for AudioControl {
fn default() -> Self {
let pipeline = gstreamer::Pipeline::new();
let bus = pipeline.bus().unwrap();
let mixer = gstreamer::ElementFactory::find("audiomixer")
.unwrap()
.load()
.unwrap()
.create()
.build()
.unwrap();
pipeline.add(&mixer).unwrap();
let audio_sink = gstreamer::ElementFactory::find("pulsesink")
.unwrap()
.load()
.unwrap()
.create()
.build()
.unwrap();
pipeline.add(&audio_sink).unwrap();
mixer.link(&audio_sink).unwrap();
let playing = Arc::new(RwLock::new(false));
let bus_monitor = std::thread::spawn({
let pipeline_object = pipeline.clone().upcast::<gstreamer::Object>();
let playing = playing.clone();
let bus = bus.clone();
move || loop {
if let Some(msg) = bus.timed_pop_filtered(
ClockTime::NONE,
&[
MessageType::Error,
MessageType::Eos,
MessageType::StateChanged,
],
) {
match msg.view() {
MessageView::StateChanged(st) => {
if msg.src() == Some(&pipeline_object) {
*playing.write().unwrap() = st.current() == gstreamer::State::Playing;
}
}
MessageView::Error(err) => {
println!("error: {:?}", err);
}
MessageView::Eos(_) => {
println!("EOS");
}
_ => {
unreachable!();
}
}
}
}
});
Self {
bus,
pipeline,
mixer,
audio_sink,
bus_monitor,
playing,
}
}
}
impl AudioControl {
pub fn playing(&self) -> bool {
*self.playing.read().unwrap()
}
pub fn play(&self) {
let mut playing = self.playing.write().unwrap();
if !*playing {
// self.pipeline.set_state(gstreamer::State::Playing).unwrap();
*playing = true;
}
}
pub fn stop(&self) {
let mut playing = self.playing.write().unwrap();
if *playing {
// self.pipeline.set_state(gstreamer::State::Paused).unwrap();
*playing = false;
}
}
pub fn add_track(&mut self, path: String) {
let source = gstreamer::ElementFactory::find("filesrc")
.unwrap()
.load()
.unwrap()
.create()
.property("location", path)
.build()
.unwrap();
self.pipeline.add(&source).unwrap();
let decoder = gstreamer::ElementFactory::find("decodebin")
.unwrap()
.load()
.unwrap()
.create()
.build()
.unwrap();
self.pipeline.add(&decoder).unwrap();
source.link(&decoder).unwrap();
let volume = gstreamer::ElementFactory::find("volume")
.unwrap()
.load()
.unwrap()
.create()
.property("mute", false)
.property("volume", 0.75)
.build()
.unwrap();
self.pipeline.add(&volume).unwrap();
volume.link(&self.mixer).unwrap();
decoder.connect_pad_added(move |_, pad| {
let next_pad = volume.static_pad("sink").unwrap();
pad.link(&next_pad).unwrap();
});
}
pub fn remove_track(&mut self, path: String) {
/* Need to run EOS through to a probe on the trailing end of the volume element */
}
}