diff --git a/Cargo.lock b/Cargo.lock index 5898871..f8282e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,14 +134,13 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alsa" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" +checksum = "37fe60779335388a88c01ac6c3be40304d1e349de3ada3b15f7808bb90fa9dce" dependencies = [ "alsa-sys", - "bitflags 1.3.2", + "bitflags 2.5.0", "libc", - "nix 0.24.3", ] [[package]] @@ -177,7 +176,7 @@ dependencies = [ "bitflags 2.5.0", "cc", "cesu8", - "jni 0.21.1", + "jni", "jni-sys", "libc", "log", @@ -1124,27 +1123,25 @@ dependencies = [ [[package]] name = "cpal" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" dependencies = [ "alsa", "core-foundation-sys 0.8.4", "coreaudio-rs", "dasp_sample", - "jni 0.19.0", + "jni", "js-sys", "libc", "mach2", - "ndk 0.7.0", + "ndk 0.8.0", "ndk-context", "oboe", - "once_cell", - "parking_lot 0.12.1", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.46.0", + "windows 0.54.0", ] [[package]] @@ -1306,24 +1303,24 @@ dependencies = [ ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "dirs" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", + "dirs-sys", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "dirs-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1371,6 +1368,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + [[package]] name = "ecolor" version = "0.27.2" @@ -2407,34 +2410,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - [[package]] name = "jni" version = "0.21.1" @@ -2865,12 +2840,13 @@ dependencies = [ [[package]] name = "muda" -version = "0.12.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40c16e25abca53b401d2972e8ad344820e318cf7e00ea8a951a5ca265590295" +checksum = "86b959f97c97044e4c96e32e1db292a7d594449546a3c6b77ae613dc3a5b5145" dependencies = [ "cocoa 0.25.0", "crossbeam-channel", + "dpi", "gtk", "keyboard-types", "libxdo", @@ -2913,20 +2889,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys 0.4.1+23.1.7779620", - "num_enum 0.5.11", - "raw-window-handle 0.5.2", - "thiserror", -] - [[package]] name = "ndk" version = "0.8.0" @@ -2982,15 +2944,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - [[package]] name = "ndk-sys" version = "0.5.0+25.2.9519653" @@ -3024,17 +2977,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", - "libc", -] - [[package]] name = "nix" version = "0.26.4" @@ -3074,13 +3016,13 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -3335,12 +3277,12 @@ dependencies = [ [[package]] name = "oboe" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ - "jni 0.20.0", - "ndk 0.7.0", + "jni", + "ndk 0.8.0", "ndk-context", "num-derive", "num-traits", @@ -3349,9 +3291,9 @@ dependencies = [ [[package]] name = "oboe-sys" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" dependencies = [ "cc", ] @@ -3371,6 +3313,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orbclient" version = "0.3.47" @@ -3838,15 +3786,16 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "rodio" -version = "0.17.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa" +checksum = "d1fceb9d127d515af1586d8d0cc601e1245bdb0af38e75c865a156290184f5b3" dependencies = [ "claxon", "cpal", "hound", "lewton", "symphonia", + "thiserror", ] [[package]] @@ -4568,14 +4517,14 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.12.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454035ff34b8430638c894e6197748578d6b4d449c6edaf8ea854d94e2dd862b" +checksum = "3ad8319cca93189ea9ab1b290de0595960529750b6b8b501a399ed1ec3775d60" dependencies = [ "cocoa 0.25.0", "core-graphics 0.23.1", "crossbeam-channel", - "dirs-next", + "dirs", "libappindicator", "muda", "objc", @@ -5034,7 +4983,7 @@ checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" dependencies = [ "core-foundation 0.9.3", "home", - "jni 0.21.1", + "jni", "log", "ndk-context", "objc", @@ -5182,15 +5131,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows" version = "0.48.0" @@ -5212,6 +5152,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.5", +] + [[package]] name = "windows" version = "0.56.0" @@ -5231,6 +5181,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets 0.52.5", +] + [[package]] name = "windows-core" version = "0.56.0" diff --git a/Cargo.toml b/Cargo.toml index b4a94a2..db41dcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ minijinja = { version = "1.0.3", features = ["loader"] } minimp3 = "0.5.1" mp3-duration = "0.1.10" regex = "1.9.0" -rodio = "0.17.1" +rodio = "0.18.1" serde = { version = "1.0.171", features = ["derive"] } tokio = { version = "1.29.1", features = ["full"] } xxhash-rust = { version = "0.8.6", features = ["xxh3", "const_xxh3"] } @@ -26,7 +26,7 @@ eframe = "0.27.2" tray-item = "0.10" winit = "0.25" once_cell = "1.19.0" -tray-icon = "0.12" +tray-icon = "0.14.3" raw-window-handle = "0.6.2" [build-dependencies] diff --git a/src/main.rs b/src/main.rs index 2b94bc7..f16d74c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,13 @@ -use axum::extract::State; -use axum::{routing, routing::get, Router}; -use axum_template::{engine::Engine, Key, RenderHtml}; +use axum_template::engine::Engine; use minijinja::{path_loader, Environment}; -use state::{AppState, TemplateEngine}; +use state::AppState; -use log::info; -use serde::{Deserialize, Serialize}; use std::env; -use std::{ - net::SocketAddr, - sync::{Arc, Mutex}, - thread, -}; +use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; use dotenvy::dotenv; -use vbplay::{example_handler, AudioThread, DeviceSelection, PlaybackAction, SoundDecoder}; +use vbplay::{example_handler, DeviceSelection, SoundDecoder}; mod handlers; mod server; @@ -24,9 +16,9 @@ mod state; mod ui; mod vbplay; -#[tokio::main] -async fn main() { +fn main() { dotenv().ok(); + let rt = tokio::runtime::Runtime::new().unwrap(); let device_pattern = env::var("DEVICE_PATTERN").expect("Need a device pattern"); let folder = env::var("DIRECTORY").expect("Need a directory in env file."); @@ -60,19 +52,24 @@ async fn main() { let (ui_to_server_tx, ui_to_server_rx) = mpsc::channel(32); - // Run the server in a separate thread - let server_thread = thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - server::run_server(app_state, ui_to_server_rx).await; - }); + let server_handle = rt.spawn(async move { + server::run_server(app_state, ui_to_server_rx).await; }); // Run the UI on the main thread ui::run_ui(server_settings, should_run, ui_to_server_tx); - // Wait for the server thread to finish - server_thread.join().unwrap(); + if let Err(e) = rt.block_on(server_handle) { + eprintln!("Server task error: {:?}", e); + } else { + println!("Server task completed successfully"); + } + + rt.shutdown_timeout(tokio::time::Duration::from_secs(5)); + audio.lock().unwrap().exit(); + drop(audio); + eprintln!("Reached end of program."); + std::process::exit(0); } diff --git a/src/server.rs b/src/server.rs index fa4cc25..8042b22 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,12 +2,8 @@ use crate::handlers; use crate::state::AppState; use axum::{routing, Router}; use serde::{Deserialize, Serialize}; -use std::{ - net::SocketAddr, - sync::{Arc, Mutex}, -}; +use std::net::SocketAddr; use tokio::sync::mpsc; -use tokio::task::JoinHandle; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ServerSettings { @@ -19,93 +15,82 @@ pub enum ServerMessage { UpdateSettings(ServerSettings), Interact, Shutdown, - // Add other message types here } pub async fn run_server(app_state: AppState, mut rx: mpsc::Receiver) { - let mut server_handle = start_server(&app_state); - loop { + let should_run = { + let guard = app_state.should_run.lock().unwrap(); + *guard + }; + + if !should_run { + eprintln!("Should run is false."); + break; + } + + let addr = { + let settings = app_state.settings.lock().unwrap(); + let port: u16 = settings.port.parse().unwrap_or(3311); + SocketAddr::from(([0, 0, 0, 0], port)) + }; + + let server_app_state = app_state.clone(); + + println!("listening on {}", addr); + + let server_handle = tokio::spawn(async move { + let app = Router::new() + .route("/", routing::get(handlers::home)) + .route("/play/:hash", routing::get(handlers::play_handler)) + .route("/stop", routing::get(handlers::stop_handler)) + .with_state(server_app_state.clone()); + + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + }); + let server_abort_handle = server_handle.abort_handle(); + tokio::select! { - _ = &mut server_handle => { + _ = server_handle => { // Server has stopped eprintln!("Server stopped."); + let mut should_run_guard = app_state.should_run.lock().unwrap(); + *should_run_guard = false; + drop(should_run_guard); break; }, Some(message) = rx.recv() => { match message { - // This is the message type that actually restarts the server. ServerMessage::UpdateSettings(new_settings) => { println!("Received new settings: {:?}", new_settings); let mut settings_guard = app_state.settings.lock().unwrap(); *settings_guard = new_settings; - + drop(settings_guard); // Ensure the lock is released before starting the new server // Restart the server with new settings println!("Aborting current server..."); - server_handle.abort(); // Cancel the previous server task - println!("Starting new server..."); - drop(settings_guard); // Ensure the lock is released before starting the new server - server_handle = start_server(&app_state); - println!("Server started."); + server_abort_handle.abort(); }, ServerMessage::Shutdown => { // Handle server shutdown println!("Shutting down server..."); let mut should_run_guard = app_state.should_run.lock().unwrap(); *should_run_guard = false; - server_handle.abort(); + drop(should_run_guard); + server_abort_handle.abort(); println!("Server shutdown."); break; }, - // Handle other message types here ServerMessage::Interact => { // Example interaction: print current settings let settings_guard = app_state.settings.lock().unwrap(); println!("Current settings: {:?}", *settings_guard); + server_abort_handle.abort(); }, } } } } -} - -fn start_server(app_state: &AppState) -> JoinHandle<()> { - // Compute the address before entering the async block - let addr = { - let settings = app_state.settings.lock().unwrap(); - let port: u16 = settings.port.parse().unwrap_or(3311); - SocketAddr::from(([0, 0, 0, 0], port)) - }; - - let server_app_state = app_state.clone(); - - println!("listening on {}", addr); - - tokio::spawn(async move { - let app = Router::new() - .route("/", routing::get(handlers::home)) - .route("/play/:hash", routing::get(handlers::play_handler)) - .route("/stop", routing::get(handlers::stop_handler)) - .with_state(server_app_state.clone()); - - let server = axum::Server::bind(&addr).serve(app.into_make_service()); - - // Run the server and monitor the should_run flag - tokio::select! { - _ = server => { - eprintln!("Server..."); - }, - _ = monitor_shutdown(server_app_state.should_run.clone()) => { - println!("Server shutdown signal received"); - } - } - }) -} - -async fn monitor_shutdown(should_run: Arc>) { - eprintln!("Monitoring shutdown..."); - while *should_run.lock().unwrap() { - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - } - eprintln!("Shutdown completed."); + eprintln!("Exiting run_server."); } diff --git a/src/ui.rs b/src/ui.rs index ffda055..3f02b25 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -24,7 +24,7 @@ pub fn run_ui( let window_handle = cc.window_handle().unwrap(); let window_handle = window_handle.as_raw(); let mut tray = - TrayItem::new("App Name", tray_item::IconSource::Resource("icon-red")).unwrap(); + TrayItem::new("Soundboard", tray_item::IconSource::Resource("icon-red")).unwrap(); if let RawWindowHandle::Win32(handle) = window_handle { // Windows Only. use windows::Win32::Foundation::HWND; @@ -59,8 +59,10 @@ pub fn run_ui( println!("Unsupported platform for tray icon."); } + let my_tx = tx.clone(); tray.add_menu_item("Quit", move || { - std::process::exit(0); + my_tx.try_send(ServerMessage::Shutdown).unwrap(); + //std::process::exit(0); }) .unwrap(); @@ -119,6 +121,7 @@ impl eframe::App for NativeApp { eprintln!("Failed to send shutdown message"); } } + drop(settings); }); } diff --git a/src/vbplay.rs b/src/vbplay.rs index f6f53a5..e457a41 100644 --- a/src/vbplay.rs +++ b/src/vbplay.rs @@ -182,6 +182,10 @@ pub fn audio_thread( match command { Command::Exit => { eprintln!("Exiting Soundloop."); + if let Ok(sink) = sink_mutex.lock() { + sink.stop(); + } + drop(stream_handle); break; } Command::Play(file_name) => { @@ -224,6 +228,7 @@ pub fn audio_thread( } } } + eprintln!("Exiting audio_thread"); }); tx