Repository navigation
Description
Summary
The Linux AppImage plays no sound at all. bundleMediaFramework (added in #8348) bundles a GStreamer plugin set that contains no AAC decoder, and 29 of the app's 33 audio assets are AAC-in-MP4. Because every SFX file is AAC, the frontend latches audio off entirely, so the four .mp3 music tracks never play either — even though their decoder is bundled.
Only the AppImage is affected. The .deb declares gstreamer1.0-libav in bundle.linux.deb.depends and is fine.
Environment
Phase-Desktop-Linux-x86_64.appimage, shell-v1.0.12, app v0.75.0- Nobara / Fedora 44 (host has
libgstlibav.so, but the AppImage cannot use it — see below)
Evidence
The app's own preflight already names the culprit exactly, on stderr at launch:
phase.rs: GStreamer plugins needed for audio are missing. Audio will be unavailable; the app still starts.
libgstlibav.so — provides avdec_aac (the .m4a codec every bundled track uses) — Debian/Ubuntu package: gstreamer1.0-libav
followed by 14 × :
** (WebKitWebProcess): WARNING **: Error: 12, Your GStreamer installation is missing a plug-in.
no suitable plugins found:
Missing decoder: MPEG-4 AAC (audio/mpeg, mpegversion=(int)4, ...)
Confirmed against the extracted AppDir:
- 105 bundled plugins in
usr/lib/gstreamer-1.0— gst-plugins-base + gst-plugins-good only - Scanning every bundled
.sofor an AAC decoder element (avdec_aac,faad,fdkaacdec): zero hits qtdemux(libgstisomp4.so) andaacparse(libgstaudioparsers.so) are present — only the decoder is missingclient/public/audio/: 29.m4a(AAC, verified withffprobe) and 4.mp3. Every SFX file is AAC.
Why all audio dies, not just AAC
libgstmpg123.so is bundled, so the four .mp3 music tracks are decodable. But preloadSfx() only loads SFX, all of which are AAC, so it returns "none". ensurePreload then treats that as a hard failure and latches audio off for the session:
audioManager.disable();
useAudioHealthStore.getState().setUnavailable("media-unavailable");The volume control correctly shows the muted state. The behaviour is right given the input — the input is just wrong.
Root cause
.github/workflows/shell-release.yml:236 installs only:
libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
with --no-install-recommends. gstreamer1.0-libav is a Recommends of libwebkit2gtk-4.1-0, so it never lands on the runner — and linuxdeploy-plugin-gstreamer can only copy plugins that are installed at build time. The runner happens to have plugins-base and plugins-good, which is exactly the set that shipped.
The AppRun hook pins the search path to the bundle, so the host's own plugins cannot fill the gap:
export GST_PLUGIN_SYSTEM_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0"
export GST_PLUGIN_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0"Dropping the host's libgstlibav.so into the bundle does not work either: the bundled GStreamer core is 1.24.2 and this host's is 1.28.6 — the version mismatch that caused #6744 in the first place.
Why CI didn't catch it
#8348 originally included a release smoke check that verified the shipped AppImage's plugin set actually registers avdec_aac and friends. It was removed before merge and is tracked in #8357. That check would have caught this exactly.
Suggested fix
- Install the plugin packages in the Linux job before
tauri-actionruns, so linuxdeploy has them to copy:(these need to bypassgstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-libav--no-install-recommends, or be listed explicitly as above) - Land Move the Linux release smoke probe into a no-secret job #8357's element-registration probe so a missing decoder fails the release rather than shipping silently.
Optionally, re-encoding the SFX to Vorbis or Opus would make the app's audio depend only on gst-plugins-base, which is always present — a belt to go with the braces.
Note
This does not affect playability, only sound. The AppImage also has an unrelated CPU regression from the same investigation — see #8614.
Diagnosed with Claude Code.
Activity
fix(release): install the GStreamer plugin packages the AppImage bund…