ffmpeg implemented
This commit is contained in:
@@ -64,6 +64,17 @@ async fn player_set_volume(
|
||||
|
||||
#[tauri::command]
|
||||
async fn player_play(player: State<'_, PlayerRuntime>, url: String) -> Result<(), String> {
|
||||
// Fail fast if audio output or ffmpeg is not available.
|
||||
// This keeps UX predictable: JS can show an error without flipping to "playing".
|
||||
if let Err(e) = player::preflight_check() {
|
||||
{
|
||||
let mut s = player.shared.state.lock().unwrap();
|
||||
s.status = player::PlayerStatus::Error;
|
||||
s.error = Some(e.clone());
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
{
|
||||
let mut s = player.shared.state.lock().unwrap();
|
||||
s.error = None;
|
||||
|
||||
@@ -118,9 +118,20 @@ fn ffmpeg_command() -> OsString {
|
||||
let local_name = if cfg!(windows) { "ffmpeg.exe" } else { "ffmpeg" };
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(dir) = exe.parent() {
|
||||
let candidate = dir.join(local_name);
|
||||
if candidate.exists() {
|
||||
return candidate.into_os_string();
|
||||
// Common locations depending on bundler/platform.
|
||||
let candidates = [
|
||||
dir.join(local_name),
|
||||
// Some packagers place resources in a sibling folder.
|
||||
dir.join("resources").join(local_name),
|
||||
dir.join("Resources").join(local_name),
|
||||
// Or one level above.
|
||||
dir.join("..").join("resources").join(local_name),
|
||||
dir.join("..").join("Resources").join(local_name),
|
||||
];
|
||||
for candidate in candidates {
|
||||
if candidate.exists() {
|
||||
return candidate.into_os_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +139,36 @@ fn ffmpeg_command() -> OsString {
|
||||
OsString::from(local_name)
|
||||
}
|
||||
|
||||
pub fn preflight_check() -> Result<(), String> {
|
||||
// Ensure we have an output device up-front so UI gets a synchronous error.
|
||||
let host = cpal::default_host();
|
||||
let device = host
|
||||
.default_output_device()
|
||||
.ok_or_else(|| "No default audio output device".to_string())?;
|
||||
let _ = device
|
||||
.default_output_config()
|
||||
.map_err(|e| format!("Failed to get output config: {e}"))?;
|
||||
|
||||
// Ensure ffmpeg can be executed.
|
||||
let ffmpeg = ffmpeg_command();
|
||||
let status = Command::new(&ffmpeg)
|
||||
.arg("-version")
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.map_err(|e| {
|
||||
let ffmpeg_disp = ffmpeg.to_string_lossy();
|
||||
format!(
|
||||
"FFmpeg not available ({ffmpeg_disp}): {e}. Set RADIOPLAYER_FFMPEG, bundle ffmpeg next to the app, or install ffmpeg on PATH."
|
||||
)
|
||||
})?;
|
||||
if !status.success() {
|
||||
return Err("FFmpeg exists but returned non-zero for -version".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Pipeline {
|
||||
stop_flag: Arc<AtomicBool>,
|
||||
volume_bits: Arc<AtomicU32>,
|
||||
|
||||
Reference in New Issue
Block a user