151 lines
4.3 KiB
Rust
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 */
|
|
}
|
|
}
|