Includes: - Extended caption styling (font, shadow, dimmed color, bg toggle) - Media server, subtitle downloader, VTT parser, processing modal - Waveform tiers, thumbnail/timeline improvements, transport controls - Hybrid download model, dependency management, clip export enhancements - 21 chat summaries, 2 implementation plans, 2 design specs Co-authored-by: Cursor <cursoragent@cursor.com>
4.5 KiB
4.5 KiB
Fix Audio Playback + Dynamic Waveform Resolution
Task Description
- Fix missing audio on preview playback — Video plays but with no sound in WKWebView.
- Dynamic waveform resolution — Waveform should increase in detail as the user zooms in.
Root Cause Analysis (Audio)
The preview file is correctly muxed (H.264 640x360 + AAC 128kbps, moov atom at offset 24 — fast-start). WKWebView config analysis:
- wry 0.55.1 defaults
autoplay: true→ setsmediaTypesRequiringUserActionForPlayback = None - tauri-runtime-wry uses
WebViewBuilder::new_with_web_context()which inherits this default - Tauri v2.11.6 doesn't expose or override
autoplay - So WKWebView SHOULD be configured for audio playback
Despite correct configuration, WKWebView's Tauri asset protocol (https://asset.localhost/...) appears to silently drop audio tracks when streaming local files — possibly due to range request handling or MIME type issues in the custom protocol handler.
Fix: Load the video file as a blob: URL instead of using the asset protocol. This bypasses the asset protocol entirely and uses WKWebView's native blob URL handling, which reliably plays both audio and video tracks.
Changes Made
Audio Fix: Blob URL Video Loading (src/lib/components/VideoPlayer.svelte)
- Added a
$effectthat fetches the preview file viaconvertFileSrcURL, converts it to a Blob, then creates ablob:URL - Video element now uses the blob URL instead of the asset protocol URL
- Added
playsinlineattribute to the video element - Added explicit
volume = 1andmuted = falseonloadeddata - Added
.play()Promise error handling (catches and logs rejections) - Shows "Preparing video…" state while blob is loading
- Falls back to asset protocol URL if blob creation fails
- Properly revokes old blob URLs on session change
Dynamic Waveform: Backend (src-tauri/src/services/waveform_generator.rs)
- Added
extract_waveform_range(file_path, start_time, end_time, peak_count)function - Uses
ffmpeg -ss {start} -t {duration}with 44100 Hz sample rate for high-resolution extraction - Computes peaks for just the specified time range
Dynamic Waveform: Command (src-tauri/src/commands/media_analysis.rs)
- Added
extract_waveform_rangeTauri command - Registered in
lib.rs
Dynamic Waveform: Frontend Binding (src/lib/bindings/mediaAnalysis.ts)
- Added
extractWaveformRange(filePath, startTime, endTime, peakCount)binding
Dynamic Waveform: Session State (src/lib/stores/videoSession.svelte.ts)
- Added
waveformDetailPeaks,waveformDetailStart,waveformDetailEndto session state - Increased initial waveform extraction from 8,000 to 50,000 peaks (good for most zoom levels)
- Detail fields cleared on session reset
Dynamic Waveform: Renderer (src/lib/timeline/waveformRenderer.ts)
- Refactored
drawWaveformto accept aWaveformDataobject with both overview and detail peaks - Renderer automatically uses detail peaks when they cover the visible viewport
- Falls back to overview peaks when detail is not available
Dynamic Waveform: Timeline Component (src/lib/components/Timeline.svelte)
- Added auto-fetch
$effectthat monitors zoom level and viewport - When overview peaks per pixel drops below 2, triggers a 300ms-debounced detail extraction
- Detail extraction pads visible range by 50% on each side to avoid re-fetching on small pans
- Requests 4 peaks per pixel for crisp detail
- Passes
WaveformDatato both main timeline and minimap renderers
Renderer Types Updated (src/lib/timeline/renderer.ts)
drawTimelinenow acceptsWaveformDatainstead ofnumber[]
Lessons Learned
- WKWebView's custom protocol handlers (like Tauri's
https://asset.localhost/) can have subtle audio issues even when video plays fine. Blob URLs are a reliable workaround. - For waveform LOD (level of detail), a two-tier approach (high-count overview + on-demand range extraction) provides the best UX: fast initial display with detail on demand.
- Debouncing the detail waveform fetch prevents spamming ffmpeg during rapid zoom/pan.
- Padding the extraction range by 50% on each side significantly reduces re-fetch frequency during small viewport adjustments.
Follow-Up Items
- Investigate if Tauri's asset protocol can be configured to properly serve audio (may be a wry bug)
- Consider pre-computing multiple LOD levels for the waveform instead of on-demand extraction
- The blob approach loads the entire preview file into memory (~97MB for a 54-min video at 360p) — acceptable for desktop but may need optimization for very long videos