Build APIs for starting and stoping tracks

This commit is contained in:
Savanni D'Gerinel 2024-08-26 11:33:43 -04:00
parent 6cae7dbb0e
commit f8fdaf2892
2 changed files with 131 additions and 40 deletions

View File

@ -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());

View File

@ -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()
}
}