Build APIs for starting and stoping tracks
This commit is contained in:
parent
6cae7dbb0e
commit
f8fdaf2892
|
@ -1,45 +1,15 @@
|
||||||
use pipewire::{context::Context, main_loop::MainLoop};
|
use pipewire::{context::Context, main_loop::MainLoop};
|
||||||
use std::{
|
use serde::Deserialize;
|
||||||
net::{Ipv6Addr, SocketAddrV6},
|
use std::net::{Ipv6Addr, SocketAddrV6};
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
use warp::{serve, Filter};
|
use warp::{serve, Filter};
|
||||||
|
|
||||||
struct State_ {
|
mod state;
|
||||||
device_list: Vec<String>,
|
use state::State;
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Deserialize)]
|
||||||
struct State {
|
struct PlayTrackParams {
|
||||||
internal: Arc<RwLock<State_>>,
|
track_name: String,
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn new() -> State {
|
|
||||||
let internal = State_ {
|
|
||||||
device_list: vec![],
|
|
||||||
};
|
|
||||||
State {
|
|
||||||
internal: Arc::new(RwLock::new(internal)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_audio(&self, device: String) {
|
|
||||||
let mut st = self.internal.write().unwrap();
|
|
||||||
(*st).device_list.push(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn audio_devices(&self) -> Vec<String> {
|
|
||||||
let st = self.internal.read().unwrap();
|
|
||||||
(*st).device_list.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for State {
|
|
||||||
fn default() -> State {
|
|
||||||
State::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn server_main(state: State) {
|
async fn server_main(state: State) {
|
||||||
|
@ -55,13 +25,58 @@ async fn server_main(state: State) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let routes = root.or(list_output_devices);
|
let list_tracks = warp::path!("tracks").map({
|
||||||
|
let state = state.clone();
|
||||||
|
move || serde_json::to_string(&state.tracks()).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let play_track = warp::put()
|
||||||
|
.and(warp::path!("playing"))
|
||||||
|
.and(warp::body::json())
|
||||||
|
.map({
|
||||||
|
let state = state.clone();
|
||||||
|
move |params: PlayTrackParams| {
|
||||||
|
state.play(params.track_name);
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop_track = warp::delete()
|
||||||
|
.and(warp::path!("playing"))
|
||||||
|
.and(warp::body::json())
|
||||||
|
.map({
|
||||||
|
let state = state.clone();
|
||||||
|
move |params: PlayTrackParams| {
|
||||||
|
state.stop(params.track_name);
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop_all_tracks = warp::delete().and(warp::path!("playing")).map({
|
||||||
|
let state = state.clone();
|
||||||
|
move || {
|
||||||
|
state.stop_all();
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let now_playing = warp::path!("playing").map({
|
||||||
|
let state = state.clone();
|
||||||
|
move || serde_json::to_string(&state.playing()).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let routes = root
|
||||||
|
.or(list_output_devices)
|
||||||
|
.or(list_tracks)
|
||||||
|
.or(play_track)
|
||||||
|
.or(stop_track)
|
||||||
|
.or(stop_all_tracks)
|
||||||
|
.or(now_playing);
|
||||||
|
|
||||||
serve(routes).run(server_addr).await;
|
serve(routes).run(server_addr).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_add_audio_device(state: State, props: &pipewire::spa::utils::dict::DictRef)
|
fn handle_add_audio_device(state: State, props: &pipewire::spa::utils::dict::DictRef) {
|
||||||
{
|
|
||||||
if props.get("media.class") == Some("Audio/Sink") {
|
if props.get("media.class") == Some("Audio/Sink") {
|
||||||
if let Some(device_name) = props.get("node.description") {
|
if let Some(device_name) = props.get("node.description") {
|
||||||
state.add_audio(device_name.to_owned());
|
state.add_audio(device_name.to_owned());
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
use std::{collections::HashSet, sync::{Arc, RwLock}};
|
||||||
|
|
||||||
|
struct State_ {
|
||||||
|
device_list: Vec<String>,
|
||||||
|
track_list: Vec<String>,
|
||||||
|
currently_playing: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct State {
|
||||||
|
internal: Arc<RwLock<State_>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new() -> State {
|
||||||
|
let internal = State_ {
|
||||||
|
device_list: vec![],
|
||||||
|
track_list: vec![
|
||||||
|
"/home/savanni/Music/Travis Savoie/RPG Toolkit Volume II/01 - A Day to Rebuild.mp3.mp3".to_owned(),
|
||||||
|
"/home/savanni/Music/Travis Savoie/RPG Toolkit Volume II/05 - Books and Spellcrafting.mp3.mp3".to_owned(),
|
||||||
|
],
|
||||||
|
currently_playing: HashSet::default(),
|
||||||
|
};
|
||||||
|
State {
|
||||||
|
internal: Arc::new(RwLock::new(internal)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_audio(&self, device: String) {
|
||||||
|
let mut st = self.internal.write().unwrap();
|
||||||
|
st.device_list.push(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audio_devices(&self) -> Vec<String> {
|
||||||
|
let st = self.internal.read().unwrap();
|
||||||
|
st.device_list.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tracks(&self) -> Vec<String> {
|
||||||
|
let st = self.internal.read().unwrap();
|
||||||
|
st.track_list.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(&self, track: String) -> Result<(), String> {
|
||||||
|
let mut st = self.internal.write().unwrap();
|
||||||
|
if st.track_list.contains(&track) {
|
||||||
|
st.currently_playing.insert(track);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&self, track: String) -> Result<(), String> {
|
||||||
|
let mut st = self.internal.write().unwrap();
|
||||||
|
st.currently_playing.remove(&track);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_all(&self) -> Result<(), String> {
|
||||||
|
let mut st = self.internal.write().unwrap();
|
||||||
|
st.currently_playing = HashSet::new();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn playing(&self) -> Vec<String> {
|
||||||
|
let st = self.internal.read().unwrap();
|
||||||
|
st.currently_playing.iter().cloned().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for State {
|
||||||
|
fn default() -> State {
|
||||||
|
State::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue