feat(player): webview audio backend for platforms without a native one

Adds WebviewAudioBackend, used on non-Linux/non-Android targets (e.g.
Windows) where there is no libmpv/ExoPlayer. Instead of decoding, it
emits a WebviewAudioLoad event with the stream URL; a frontend <audio>
element (WebviewAudioAdapter + webviewAudio service) plays it and reports
state/position back through the existing player_report_* round-trip, so
the Rust PlayerController stays the single source of truth. Play/pause/
seek reach the element via the existing ControlCommand event.

All video already renders in the webview on every platform, so this
completes audio-only playback for Windows (video via WebView2, audio via
<audio>). Pure Rust + Tauri events, so it still cross-compiles from Linux.

Regenerates bindings.ts (adds webview_audio_load; also carries the
equalizer EQ bindings).

TRACES: UR-003, UR-004, UR-005 | DR-004
This commit is contained in:
2026-07-24 23:49:23 +02:00
parent c543f90ad3
commit d4e2cd120c
8 changed files with 643 additions and 5 deletions
+19 -3
View File
@@ -121,6 +121,7 @@ use commands::{
player_get_audio_settings,
player_get_autoplay_settings,
player_get_cache_config,
player_get_eq_presets,
player_get_queue,
// Session management commands
player_get_session,
@@ -515,6 +516,12 @@ fn emit_backend_init_failed(app_handle: &tauri::AppHandle, backend: &'static str
}
/// Create the appropriate player backend for the current platform.
// playback_reporter/position_throttler are consumed only by the native audio
// backends (mpv/exo); on platforms using the webview audio backend they're unused.
#[cfg_attr(
not(any(target_os = "linux", target_os = "android")),
allow(unused_variables)
)]
fn create_player_backend(
app_handle: tauri::AppHandle,
playback_reporter: Arc<tokio::sync::Mutex<Option<playback_reporting::PlaybackReporter>>>,
@@ -615,11 +622,19 @@ fn create_player_backend(
}
}
// Fallback for other platforms
// Platforms with no native audio backend (e.g. Windows): render audio-only
// playback through a webview <audio> element (all video already renders in
// the webview). Falls back to NullBackend only if the backend can't init.
#[cfg(not(any(target_os = "linux", target_os = "android")))]
{
warn!("WARNING: No audio backend available for this platform");
Box::new(NullBackend::new())
info!("No native audio backend for this platform - using webview <audio> backend");
match player::WebviewAudioBackend::new(_event_emitter) {
Ok(backend) => Box::new(backend),
Err(e) => {
emit_backend_init_failed(&app_handle, "webview-audio", e.to_string());
Box::new(NullBackend::new())
}
}
}
}
@@ -666,6 +681,7 @@ fn specta_builder() -> Builder<tauri::Wry> {
player_skip_to,
player_set_audio_settings,
player_get_audio_settings,
player_get_eq_presets,
player_set_video_settings,
player_get_video_settings,
// Sleep timer and autoplay commands