Spec: Migrate to libmpv2 and declare the project licence
Status: Partially implemented — the LICENSE file has landed (part 2). The
libmpv → libmpv2 swap (part 1) is not done: src-tauri/Cargo.toml still
pins the abandoned crate to a git branch.
Requirements: UR-003 → IR-003 (revises the MPV integration); no new user-facing behaviour
UX spec: n/a
Supersedes / revises: dependency and licensing housekeeping identified in playback-backend-unification.md
Summary
Two related pieces of housekeeping that block or complicate later work:
- Replace the abandoned
libmpvcrate (pinned to a git branch) with the maintainedlibmpv2. - Add a
LICENSEfile. The project has none, which leaves its legal status undefined while it links GPL-licensed libmpv.
Neither changes user-visible behaviour. Both are prerequisites for windows-native-audio-backend.md.
Motivation
The dependency is dead
# src-tauri/Cargo.toml
libmpv = { git = "https://github.com/ParadoxSpiral/libmpv-rs.git", branch = "master" }
- crates.io
libmpv2.0.1 was published 2020-09-29. - The upstream repo's last commit was 2023-01-08; nothing since was released.
- We pin a git branch, so builds are not reproducible — the same lockfile-less checkout can resolve differently over time, and CI has no protection if the branch moves or the repo disappears.
libmpv2 (kohsine/libmpv2-rs) is a maintained fork of exactly this crate:
6.0.0 released 2026-05-12, ~23.5k recent downloads against the original's
~1.1k, releases roughly quarterly since 2024.
The project has no licence
There is no LICENSE/COPYING file and src-tauri/Cargo.toml has no license
field. The project is open source and will never be commercial, so this is purely
an omission — but it matters because we link libmpv, and "no licence" defaults to
all rights reserved, which is incompatible with distributing a GPL-derived
work.
Design
Part 1 — licence
Use GPLv3. This is forced, not chosen:
- mpv's default build is GPLv2-or-later, so the combined work must be GPL-compatible.
- Apache-2.0 is GPLv2-incompatible (patent-termination and indemnification clauses) but GPLv3-compatible.
- A scan of the dependency tree found Apache-2.0-only crates with no
alternative arm — most importantly
tao(Tauri's own windowing crate), plussync_wrapper,gethostname, andring(Apache-2.0 AND ISC).
tao is unavoidable in a Tauri app, so GPLv2 is unavailable. Exercising mpv's
"or later" option puts the combination at GPLv3.
Actions:
- Add
LICENSEcontaining the GPLv3 text. - Add
license = "GPL-3.0-or-later"tosrc-tauri/Cargo.tomlandlicensetopackage.json. - Note in the README that the binary links libmpv (GPLv2+) and FFmpeg.
Because the project is open source, we use mpv's default GPL build — no
-Dgpl=false, no LGPL FFmpeg build, and none of the LGPL §6 relinking analysis
that a proprietary app would need. We keep VAAPI/VDPAU/X11 and every GPL FFmpeg
filter.
🔴 Never build FFmpeg with --enable-nonfree — that produces a binary that is
unredistributable under any licence, open source or not.
Part 2 — libmpv → libmpv2
# Linux (and later Windows, per the Windows audio spec)
libmpv2 = "=6.0.0"
Pin exactly: libmpv2 has broken its API in every major release.
Breaking changes to expect, from the changelog:
| Version | Change | Impact here |
|---|---|---|
| 4.0.0 | Removed command helper methods — call mpv.command(...) directly | Low; we already use command/set_property |
| 5.0.0 | Removed mpv_node support entirely (properties return strings; parse JSON yourself); EventContext folded into Mpv; ProtocolContext → Protocol | Medium — start_event_loop uses create_event_context(); check whether that call still exists |
| 6.0.0 | RenderContext::new() → Mpv::create_render_context(); 'static bound on OpenGLInitParams; render context now borrows Mpv (fixes a use-after-free) | None — we do not use the render API |
The last row matters: we run mpv audio-only (video = no), so the entire render
surface is irrelevant to us. Consider disabling the default render feature to
reduce build surface.
The main porting work is the event loop in mpv_backend.rs — wait_event,
disable_deprecated_events, and the FileLoaded / PlaybackRestart /
PropertyChange / EndFile handling, given 5.0.0 folded EventContext into
Mpv.
Everything else — set_property calls, the af filter graph, the 250ms position
thread, the seek-suppression window — should port unchanged.
Layer assignment
No logic moves. This is a dependency swap plus a licence file; the
PlayerBackend trait boundary is untouched.
| Logic / responsibility | Layer | Why it belongs there |
|---|---|---|
mpv event → PlayerStatusEvent mapping | Rust (unchanged) | Already correct; only the binding API beneath it changes. |
Out of scope
- Any behaviour change. If playback behaves differently after this, that is a bug.
- Windows support — separate spec, but this must land first.
- Adopting the render API. We are audio-only on mpv.
- Re-licensing decisions beyond adding the file the project already implies.
Acceptance criteria
-
LICENSE(GPLv3) present;licensefield set inCargo.tomlandpackage.json. -
A full dependency-licence audit has been run (
cargo install cargo-license && cargo license) and confirms no GPLv3-incompatible dependency. (The scan behind this spec resolved 441 of 575 crates from the local registry cache; the remaining 134 are unverified.) -
libmpvgit dependency removed;libmpv2pinned to an exact version. - Linux audio playback works identically: play/pause/seek/volume, queue advance, gapless, EQ, normalization, sleep timer.
- Position updates still arrive at 250ms; the 150ms post-seek suppression still prevents the jump-to-zero glitch.
-
EndFilestill emitsPlaybackEndedonly for EOF (not STOP/QUIT/ERROR) — autoplay depends on this. - Builder image updated if the libmpv dev package requirement changed; no toolchain install added to any CI step.
-
bun run check,bun run test,bun run check:boundarypass. -
cargo fmtclean,cargo clippyclean,bun run test:rustpasses.
Testing
The existing mpv_backend_test.rs plus the build_af_filter,
eq_filter_entries, and normalize_filter_entry tests are the regression net —
they must pass unchanged, since none of them touch the binding API.
The event loop has no unit tests and is where the risk concentrates. Verify manually on Linux:
- Play → pause → play; confirm position does not flash to 0:00 (the known playing-event regression).
- Seek mid-track; confirm no jump-to-zero within 150ms.
- Let a track end naturally; confirm autoplay advances (exercises
EndFileEOF). - Press stop; confirm autoplay does not advance.
- Sleep-timer expiry; confirm it stops without triggering autoplay.
Cases 3–5 are the ones most likely to break silently, and each corresponds to a bug already fixed once in this codebase.
TRACES
MpvBackendconstruction / event loop → existing// TRACES: UR-003 | IR-003, unchanged- No new requirement IDs; this is a dependency migration.
Notes for the implementer
- Do this before the Windows audio backend.
- Read the 4.0/5.0/6.0 changelogs before writing code — the crate has broken API in every major release, most recently two months before this spec.
- The crates.io
repositoryfield forlibmpv2points atkohsine/libmpv-rs, but the repo was renamed tolibmpv2-rs; the old raw URLs 404. libmpv2-sysships pregenerated bindings and vendored headers, so no libclang is needed at build time — relevant to keeping the builder image thin.- A parallel Claude session may be active —
git diffbefore "repairing" unexpected changes.