diff --git a/src/lib.rs b/src/lib.rs index 6975066..e81836e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ mod websocket; mod util; mod cot_router; mod cot_generator; +mod video_stream; #[arma] pub fn init() -> Extension { @@ -49,5 +50,11 @@ pub fn init() -> Extension { .command("send_digital_pointer_cot", cot_router::send_digital_pointer_cot) .command("stop", cot_router::stop) ) + .group( + "video_stream", + Group::new() + .command("start", video_stream::start_stream) + .command("stop", video_stream::stop_stream) + ) .finish() } diff --git a/src/video_stream.rs b/src/video_stream.rs new file mode 100644 index 0000000..b1c3951 --- /dev/null +++ b/src/video_stream.rs @@ -0,0 +1,84 @@ +use arma_rs::Context; +use lazy_static::lazy_static; +use std::process::Command; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::sync::Mutex; +use std::thread; + +lazy_static! { + static ref STREAM_CTRL: Mutex>> = Mutex::new(None); +} + +pub fn start_stream( + ctx: Context, + address: String, + port: String, + stream_path: String, + username: String, + password: String, +) -> &'static str { + let (tx, rx): (Sender<()>, Receiver<()>) = mpsc::channel(); + let rtsp_url = format!( + "rtsp://{}:{}@{}:{}/{}", + username, password, address, port, stream_path + ); + let rtsp_url_clone = rtsp_url.clone(); + + thread::spawn(move || { + let mut child = match Command::new("ffmpeg") + .args(&[ + "-f", + "gdigrab", + "-i", + "desktop", + "-f", + "rtsp", + "-rtsp_transport", + "tcp", + &rtsp_url_clone, + ]) + .spawn() + { + Ok(child) => child, + Err(e) => { + return ctx.callback_data("armatak_video_error", "Failed to Start FFmpeg", e.to_string()) + } + }; + + if rx.recv().is_err() { + return ctx.callback_null("armatak_video_error", "Error receiving stop signal"); + } + + Ok(if let Err(e) = child.kill() { + return ctx.callback_data("armatak_video_error", "Failed to Stop FFmpeg", e.to_string()) + }) + }); + + match STREAM_CTRL.lock() { + Ok(mut lock) => *lock = Some(tx), + Err(e) => { + eprintln!("Failed to acquire lock: {}", e); + } + } + + "starting video stream" +} + +pub fn stop_stream(ctx: Context) -> &'static str { + match STREAM_CTRL.lock() { + Ok(mut lock) => { + if let Some(tx) = lock.take() { + if let Err(e) = tx.send(()) { + let _ = ctx.callback_data("armatak_video_error", "Failed to send stop signal", e.to_string()); + } + } else { + let _ = ctx.callback_null("armatak_video_error", "Tried to stop an unexistant stream"); + } + } + Err(e) => { + let _ = ctx.callback_data("armatak_video_error", "Failed to acquire lock", e.to_string()); + } + } + + "starting video stream" +}