Files
jellytau/docs/build/build-windows.md
T
dtourolle 4daf172834 feat(windows): mpv plays audio on Windows, with libmpv shipped in the installer
libmpv on Windows (DR-237):
- The builder image carries zhongfly's LGPL libmpv-2.dll, pinned by
  asset name and sha256, plus an MSVC mpv.lib generated from the DLL's
  own mpv_* exports (the archive ships only a MinGW .dll.a). LGPL, not
  the GPL builds: no x264/x265, mpv -Dgpl=false; FFmpeg is version3, so
  LGPL-3.0. THIRD_PARTY_NOTICES.md records it.
- build-windows-cross.sh stages both files into src-tauri/windows-libs/;
  build.rs links mpv.lib from there and tauri.windows.conf.json bundles
  the DLL beside jellytau.exe from there, with the licence texts under
  licenses/. One directory, so the DLL shipped is the one linked.
- Workflows move to builder image 2026.09.1.

Windows audio:
- MpvBackend replaces WebviewAudioBackend on Windows (ao=wasapi), so
  volume, EQ, normalization and gapless work there as on Linux. Local
  files are passed to mpv as native paths, not file:// URLs.

Fixes found on the way:
- player_play_item decided "does the backend render video" with
  cfg!(not(linux)), true on Windows, while get_player_status sent
  Windows video to the <video> element. With mpv as the backend that
  would decode every film's soundtrack twice. All three callers now
  ask video_renders_natively() (UT-273).
- confine_queued_path rebuilt paths with PathBuf::push, so on Windows
  a queued `downloads/x` was stored as `downloads\x`, no longer the
  spelling the app built. It now keeps the caller's separator (UT-205,
  which only ever ran on Linux, failed under Windows).

Verified: jellytau.exe imports libmpv-2.dll; the full unit suite
cross-compiled for Windows passes under wine against the shipped DLL
(943/943, including the mpv injection and TLS tests); the NSIS
installer contains the DLL and licence texts. Not yet run on real
Windows hardware.
2026-09-24 22:25:31 -04:00

91 lines
4.2 KiB
Markdown

# Windows build
JellyTau targets Linux and Android primarily, but a working Windows build —
including an **NSIS installer cross-compiled from Linux** — is produced by the
Docker tooling. It is not yet a first-class release target (no code signing / CI
job / SMTC lockscreen), but it runs and plays media.
## How playback works on Windows
- **Video** — renders through the webview HTML5 `<video>` element (hls.js); on
Windows that is WebView2 (Chromium/Edge), which plays HLS + h264 fine. mpv
takes this over in DR-237's video phase; Linux already made that move.
- **Audio** — **libmpv**, the same `MpvBackend` Linux uses, with `ao=wasapi`.
Volume, EQ, normalization and gapless all go through mpv's filter graph as on
Linux. `libmpv-2.dll` ships beside `jellytau.exe` in the installer.
### libmpv on Windows
- **Which build:** zhongfly/mpv-winbuild's *LGPL* dev asset, pinned by name and
sha256 in [Dockerfile.builder](../../Dockerfile.builder), which unpacks it to
`/opt/libmpv-win64`. Licence terms: [THIRD_PARTY_NOTICES.md](../../THIRD_PARTY_NOTICES.md).
The same release also carries a GPL asset (x264/x265) — do not switch to it
casually, it moves the installer onto GPL-3.0 terms.
- **Import library:** the archive only ships a MinGW `libmpv.dll.a`. The image
generates an MSVC `mpv.lib` from the DLL's own `mpv_*` exports
(`llvm-readobj --coff-exports` → `.def` → `llvm-lib /def:`), so it cannot name
a symbol the DLL lacks.
- **One directory:** `scripts/build-windows-cross.sh` copies both files into
`src-tauri/windows-libs/` (gitignored) before building. `build.rs` links
`mpv.lib` from there and `tauri.windows.conf.json` bundles the DLL from there,
so the DLL shipped is the one linked against. Outside the image, point
`LIBMPV_WIN_DIR` at a directory holding `libmpv-2.dll` and `mpv.lib`.
- **Bumping it:** change the three `LIBMPV_WIN_*` values together, rebuild and
push the image, bump the image tag the workflows pin.
## Cross-compiling from Linux (MSVC + cargo-xwin)
We use the [official Tauri cross-compile path](https://v2.tauri.app/distribute/windows-installer/):
the **MSVC** target (`x86_64-pc-windows-msvc`) driven by
[`cargo-xwin`](https://github.com/rust-cross/cargo-xwin), which downloads the MSVC
CRT / Windows SDK headers and links with `lld`. MSVC is the target Tauri
officially supports for Windows (mingw/GNU is not), and — unlike GNU — it lets the
Tauri CLI bundle the **NSIS installer from a Linux host**.
> Why not mingw/GNU? The GNU target *does* link a valid `.exe`, but the Tauri CLI
> gates `--bundles` by the host OS unless it recognizes a real Windows build.
> `--runner cargo-xwin --target x86_64-pc-windows-msvc` is what flips it into
> Windows mode and enables the `nsis`/`msi` bundlers on Linux.
The builder image ([../Dockerfile.builder](../../Dockerfile.builder)) bakes in the
whole toolchain: the `x86_64-pc-windows-msvc` rust target, `cargo-xwin`, `lld`,
`llvm`, `nsis`, and the pinned Windows libmpv.
```bash
bun run docker:build:windows # NSIS installer + .exe -> ./dist
WIN_BUNDLES=none bun run docker:build:windows # exe only, skip bundling
```
Or directly on a host that has the toolchain:
```bash
scripts/build-windows-cross.sh # nsis installer + exe
WIN_BUNDLES=none scripts/build-windows-cross.sh # exe only
```
Under the hood the build runs:
```bash
tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis
```
Outputs:
- `.exe` — `src-tauri/target/x86_64-pc-windows-msvc/release/jellytau.exe`
- NSIS installer — `.../release/bundle/nsis/*-setup.exe`
(both copied to `./dist` when `OUTPUT_DIR` is set).
## Caveats
- **Cross-compilation is a last resort** per Tauri's own docs — it's less tested
than building on Windows. If it misbehaves, a `windows-latest` CI job or a
Windows VM building natively (`tauri build --bundles nsis`) is the fallback.
- **Code signing is not wired up** — the installer is unsigned, so Windows
SmartScreen will warn on first run.
## Outstanding for a first-class Windows release
1. SMTC (lockscreen / media keys) — not wired on Windows.
2. Code signing — the installer is unsigned.
3. Video through mpv (DR-237) — needs a WebView2-side surface.