//! 音頻播放模組 use anyhow::Result; use std::process::{Command, Stdio}; use std::io::Write; use std::sync::{Arc, Mutex}; #[derive(Debug, Clone)] pub struct AudioPlayer { process: Option, volume: f32, muted: bool, } impl AudioPlayer { pub fn new() -> Self { Self { process: None, volume: 1.0, muted: false, } } pub fn play(&mut self, path: &str, start_ms: u64) -> Result<()> { self.stop()?; let start_sec = start_ms as f64 / 1000.0; let volume_filter = if self.muted { "volume=0".to_string() } else { format!("volume={}", self.volume) }; let mut cmd = Command::new("ffplay"); cmd.args([ "-nodisp", "-autoexit", "-ss", &format!("{}", start_sec), "-af", &volume_filter, "-i", path, ]) .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn()?; self.process = Some(cmd); Ok(()) } pub fn stop(&mut self) -> Result<()> { if let Some(mut child) = self.process.take() { let _ = child.kill(); let _ = child.wait(); } Ok(()) } pub fn set_volume(&mut self, volume: f32) { self.volume = volume.clamp(0.0, 1.0); if !self.muted { self.restart_with_volume()?; } } pub fn toggle_mute(&mut self) -> bool { self.muted = !self.muted; self.muted } pub fn is_muted(&self) -> bool { self.muted } fn restart_with_volume(&mut self) -> Result<()> { Ok(()) } } impl Drop for AudioPlayer { fn drop(&mut self) { let _ = self.stop(); } }