feat: build and bundle libmpv from source on Linux with full audio support#60
feat: build and bundle libmpv from source on Linux with full audio support#60
Conversation
Hardcoding "pipewire,pulse,alsa" prevented mpv from trying other compiled-in audio backends (sdl, oss, jack, sndio). Using ao=auto lets mpv try all available outputs, improving compatibility with different libmpv builds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pport Build libmpv from source in CI instead of using system libmpv-dev, ensuring ALSA + PulseAudio audio outputs are always compiled in. This prevents the "no audio output found" issue on systems with stripped libmpv packages. - build-libmpv.sh: explicitly enable alsa/pulse/pipewire audio when dev headers available - bundle-libmpv-linux.sh: prefer source build, recursively bundle transitive deps, set RPATH on all bundled .so files, verify audio libs are present - build.rs: prefer libs/linux/ (source build) over system pkg-config - CI (build.yml, release.yml): install audio/ffmpeg dev packages, build from source - tauri.conf.json: add audio (libpulse0|libasound2) and subtitle (libass) deps for deb/rpm - package_update: use apt-get install (resolves deps) instead of dpkg -i for deb updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR makes the Linux distribution more self-contained and reliable by building libmpv from source in CI with known audio backends enabled, bundling required shared libraries into the AppImage, and improving package dependency/install handling for .deb/.rpm distributions.
Changes:
- Build
libmpvfrom source on Linux CI with audio-related dev deps installed, and prefer linking againstlibs/linux/. - Enhance AppImage bundling to include
libmpvplus additional dependent.sofiles and set RPATH on bundled libraries. - Improve Linux packaging/runtime behavior: add audio/subtitle dependencies for deb/rpm, use
apt-get installfor deb updates, and set mpv audio output toao=auto.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/bundle-libmpv-linux.sh |
Prefer libs/linux/libmpv.so, bundle additional shared library deps, set RPATH on bundled .so files, and add a basic audio-lib presence check. |
scripts/build-libmpv.sh |
Add Linux audio dev-package detection and conditionally enable ALSA/PulseAudio/PipeWire in the Meson build args. |
crates/tauri-plugin-mpv/src/linux.rs |
Switch mpv audio option from a hardcoded backend list to ao=auto. |
crates/tauri-plugin-mpv/build.rs |
Prefer linking against libs/linux/ on Linux before falling back to system pkg-config. |
apps/desktop/src-tauri/tauri.conf.json |
Add runtime deps for audio (Pulse/ALSA) and subtitles (libass) to deb/rpm packaging config. |
apps/desktop/src-tauri/src/commands.rs |
For deb updates, prefer apt-get install (dependency resolution) with dpkg -i fallback. |
.github/workflows/release.yml |
Install build dependencies (meson/ninja/ffmpeg/audio/libass headers) and build libmpv from source in the Linux release job. |
.github/workflows/build.yml |
Install build dependencies and build libmpv from source in the Linux CI build job. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Collect all libs to bundle (deduplicated) | ||
| declare -A BUNDLED_LIBS | ||
|
|
||
| # bundle_deps: resolve and collect transitive dependencies of a shared library | ||
| bundle_deps() { | ||
| local lib="$1" | ||
| ldd "$lib" 2>/dev/null | grep "=> /" | awk '{print $3}' | while read -r dep; do | ||
| basename_dep=$(basename "$dep") | ||
| if echo "$basename_dep" | grep -qE "$SYSTEM_LIBS_RE"; then | ||
| continue | ||
| fi | ||
| if [[ ! -f "$BUNDLE_DIR/$basename_dep" ]]; then | ||
| cp "$dep" "$BUNDLE_DIR/" | ||
| echo " bundled: $basename_dep" | ||
| # Recursively resolve deps of this library too (one level deep for audio libs) | ||
| ldd "$dep" 2>/dev/null | grep "=> /" | awk '{print $3}' | while read -r subdep; do | ||
| sub_basename=$(basename "$subdep") | ||
| if echo "$sub_basename" | grep -qE "$SYSTEM_LIBS_RE"; then | ||
| continue | ||
| fi | ||
| if [[ ! -f "$BUNDLE_DIR/$sub_basename" ]]; then | ||
| cp "$subdep" "$BUNDLE_DIR/" | ||
| echo " bundled: $sub_basename (transitive)" | ||
| fi | ||
| done | ||
| fi | ||
| done |
There was a problem hiding this comment.
bundle_deps is described as collecting transitive dependencies, but the implementation only goes one level deep (direct deps + one nested ldd loop) and the declared BUNDLED_LIBS map is never used. This can miss deeper transitive dependencies and lead to an AppImage that runs on the CI runner but fails on a clean system. Consider implementing a true recursive walk to a fixpoint (using a visited set to avoid cycles) and either remove BUNDLED_LIBS or use it to dedupe/track visited libs.
| # Build with explicit audio + video output support. | ||
| # Audio: alsa/pulse/pipewire are auto-detected from dev headers; | ||
| # we enable them explicitly so the build fails if headers are missing | ||
| # rather than silently producing a libmpv without audio. | ||
| BUILD_DIR="$MPV_SRC/build-linux" | ||
| echo " Running meson setup..." | ||
| meson setup "$BUILD_DIR" "$MPV_SRC" \ | ||
| --buildtype=release \ | ||
| --wipe \ | ||
| -Dlibmpv=true \ | ||
| -Dgl=enabled \ | ||
| -Dvulkan=disabled \ | ||
| -Dwayland=enabled \ | ||
| -Dx11=enabled \ | ||
|
|
||
| MESON_ARGS=( | ||
| --buildtype=release | ||
| --wipe | ||
| -Dlibmpv=true | ||
| -Dgl=enabled | ||
| -Dvulkan=disabled | ||
| -Dwayland=enabled | ||
| -Dx11=enabled | ||
| -Degl=enabled | ||
| ) | ||
|
|
||
| # Enable audio outputs that have dev headers available | ||
| if pkg-config --exists alsa 2>/dev/null; then | ||
| MESON_ARGS+=(-Dalsa=enabled) | ||
| echo " Audio: ALSA enabled" | ||
| fi | ||
| if pkg-config --exists libpulse 2>/dev/null; then | ||
| MESON_ARGS+=(-Dpulse=enabled) | ||
| echo " Audio: PulseAudio enabled" | ||
| fi | ||
| if pkg-config --exists libpipewire-0.3 2>/dev/null; then | ||
| MESON_ARGS+=(-Dpipewire=enabled) | ||
| echo " Audio: PipeWire enabled" | ||
| fi |
There was a problem hiding this comment.
The comments say audio outputs are enabled explicitly so the build fails if headers are missing, but the actual Meson args only add -Dalsa/-Dpulse/-Dpipewire=enabled when pkg-config finds those dev packages. As written, the build will still succeed with zero audio backends (only a warning earlier), which contradicts the comment and can silently reintroduce the no-audio problem. Either update the comment to match the behavior, or enforce at least one required backend (and/or fail the build when none are detected).
| - name: Build libmpv from source | ||
| run: | | ||
| ./scripts/build-libmpv.sh linux | ||
| echo "LD_LIBRARY_PATH=$(pwd)/libs/linux:${LD_LIBRARY_PATH:-}" >> "$GITHUB_ENV" | ||
| echo "PKG_CONFIG_PATH=$(pwd)/libs/linux/pkgconfig:${PKG_CONFIG_PATH:-}" >> "$GITHUB_ENV" | ||
|
|
There was a problem hiding this comment.
release.yml exports PKG_CONFIG_PATH=$(pwd)/libs/linux/pkgconfig, but scripts/build-libmpv.sh linux currently only copies libmpv.so into libs/linux/ and does not create a pkgconfig/ directory or install a .pc file there. This env var looks unused/misleading; either drop it or add a step that actually generates/copies the mpv/libmpv pkg-config file into that directory if something depends on it.
…eanup - Add libplacebo-dev to CI deps (required by mpv 0.40.0); disable via meson flag when not available for local builds - Implement proper recursive dependency walk in bundle script (fixpoint loop using bundle dir as visited set) instead of one-level-deep nesting - Remove unused BUNDLED_LIBS declaration - Fix misleading comment about build failing without audio headers - Remove bogus PKG_CONFIG_PATH pointing to nonexistent pkgconfig/ dir Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
mpv 0.40.0 requires xscrnsaver, xext, xpresent, xrandr when X11 is enabled and wayland-egl when Wayland is enabled. Also disable optional features (lua, javascript, caca, sdl2, drm, jack, sndio, openal) to avoid auto-detection pulling in unneeded deps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
libplacebo is a hard requirement of mpv 0.40.0, not a toggleable meson option. libplacebo-dev is already in CI deps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pattern 'libmpv.so*' matched both the actual libmpv.so.2.5.0 file and the libmpv.so.2.5.0.p directory (meson per-target build dir). -not -type l only excluded symlinks, not directories, so cp failed with 'omitting directory'. Switch to -type f to match only regular files. Made-with: Cursor
…e_all_deps With 'set -euo pipefail', ldd|grep|awk|while fails silently when grep finds no '=> /' lines (libs with only linux-vdso/ld-linux deps). The pipeline's while loop also runs in a subshell, so queue+= updates were lost and the QUEUE_FILE workaround was needed. Switch to process substitution (< <(... || true)): - '|| true' suppresses grep exit-1 on zero matches - while body runs in the current shell so queue+= propagates directly - QUEUE_FILE and its trap are no longer needed Also add explicit error messages to patchelf calls so failures are visible in CI logs instead of being swallowed by set -e. Made-with: Cursor
Summary
libmpv-dev. Ensures AppImage ships fully self-contained with guaranteed audio support..sofileslibpulse0 | libasound2(deb) andpulseaudio-libs(rpm), pluslibassfor subtitle renderingapt-get install(resolves deps) withdpkg -ifallbackao=pipewire,pulse,alsatoao=autoContext
A user on Pop!_OS reported no audio — their system
libmpvwas compiled without audio output plugins. This is a packaging reliability issue: we can't control whatlibmpvdistros or users install. Building from source with known-good options solves this for AppImage, and explicit package deps solve it for deb/rpm.Changes
scripts/build-libmpv.shscripts/bundle-libmpv-linux.shcrates/tauri-plugin-mpv/build.rslibs/linux/over system pkg-config.github/workflows/{build,release}.ymlapps/desktop/src-tauri/tauri.conf.jsonapps/desktop/src-tauri/src/commands.rsapt-get installfor deb updatescrates/tauri-plugin-mpv/src/linux.rsao=autoinstead of hardcoded listTest plan
build-linuxjob passes with source-built libmpv🤖 Generated with Claude Code