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 std::{
|
||||
net::{Ipv6Addr, SocketAddrV6},
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::net::{Ipv6Addr, SocketAddrV6};
|
||||
use tokio::task::spawn_blocking;
|
||||
use warp::{serve, Filter};
|
||||
|
||||
struct State_ {
|
||||
device_list: Vec<String>,
|
||||
}
|
||||
mod state;
|
||||
use state::State;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State {
|
||||
internal: Arc<RwLock<State_>>,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct PlayTrackParams {
|
||||
track_name: String,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 let Some(device_name) = props.get("node.description") {
|
||||
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