Skip to content

fix(desktop): check libVLC candidates without a recursive search - #520

Open
veryCrunchy wants to merge 9 commits into
mainfrom
fix/linux-desktop-test-hang
Open

veryCrunchy wants to merge 9 commits into
mainfrom
fix/linux-desktop-test-hang

Conversation

@veryCrunchy

@veryCrunchy veryCrunchy commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Outcome

Fixes the Linux CI build job, which has stopped producing output in :ui:desktopTest until the 45 minute job limit since desktop video playback landed (#511). The same root cause also delayed the desktop video fallback at app startup on machines without libVLC.

vlcj's default NativeDiscovery searches each candidate directory recursively and follows symbolic links, with no depth bound. When libVLC is absent, it walks every tree under /usr/lib, /usr/local/lib and every PATH entry. On GitHub's ubuntu-24.04 runner that includes the Android SDK and NDKs under /usr/local/lib/android/sdk. DesktopLibVlcPlaybackTest runs discovery once per test method, before it can skip, and the test task logs only failures, so nothing was printed.

In the app, warmDesktopVideoPlayback() runs the same walk at startup. While discovery was pending, the media viewer hid its "Play video" external-player fallback. Windows and macOS packages find their bundled libVLC first. This behavior is unreleased (changes/unreleased).

Changes:

  • DesktopLibVlcRuntime uses desktopLibVlcDiscoveryStrategies(). These wrap vlcj's Linux, macOS and Windows strategies with the same candidate directories, order, and per-OS library loading and plugin path handling. Each candidate is checked directly for both libraries and is never searched below. Trade-off: a libVLC nested inside a subdirectory of a candidate is no longer found. JNA's default library path still applies.
  • :ui test tasks log Test still running after 3 minutes: <class> > <test> and stop after 30 minutes. A future hang then fails with a name, well inside the CI job limit. The slowest desktop test takes about 12 s.

Main's Linux CI had stopped at desktopTest since #511, which hid two further failures that this PR also fixes:

  • DesktopSystemMediaControlsTest.theWindowsButtonHandlerAnswersComAndDispatchesTheButton builds the Windows SMTC COM handler, whose stdcall JNA callbacks cannot be created on Linux ("Invalid calling convention 63"). The test now runs only on Windows. Production already opens the Windows integration only when os.name is Windows.
  • :ui:lintAnalyzeRelease crashed inside lint ("findFirCompiledSymbol only works on compiled declarations"). Android lint 9.3.1 crashes while analysing any Kotlin script applied with apply(from = ...), whatever its content or location. Reproduced locally on main. The libVLC packaging tasks from ui/desktop-libvlc.gradle.kts now live unchanged in ui/build.gradle.kts, with a comment explaining why they must not be split out again. The two path-filter entries for the removed file are dropped from ci.yml. Lint is not disabled, baselined or suppressed.

Review follow-up: vlcj 4.12.1 checks only /usr/lib/x86_64-linux-gnu, /usr/lib64, /usr/local/lib64, /usr/lib/i386-linux-gnu, /usr/lib and /usr/local/lib (then PATH), with no default-path fallback. Removing the recursive walk would therefore have hidden Debian/Ubuntu multiarch installs on other architectures. Discovery now adds /usr/lib/<triplet> for the JVM's own architecture before vlcj's directories. The other known triplets (x86_64, aarch64, arm-linux-gnueabihf, i386, riscv64, powerpc64le, s390x) come last, so a foreign-architecture copy is never chosen first. Versioned runtime names (libvlc.so.5, libvlccore.so.9) are accepted, and the plugin path still resolves to <dir>/vlc/plugins.

Verification

  • Every check relevant to the changed scope passes, or each unrun check is listed below with a reason

  • bash tools/check-repository.sh passes

  • A new changes/unreleased/ fragment records the change

  • No credentials, private server data, machine-local paths, or generated output are included

  • New DesktopLibVlcDiscoveryTest (4 tests):

    • the first candidate directly holding both libraries wins, and a nested copy is never found;
    • incomplete, misnamed, missing, plain-file and empty candidates are skipped;
    • a symbolic link loop is not followed (skipped where the host cannot create symlinks);
    • exactly one platform strategy applies on any host.
  • DesktopLibVlcPlaybackTest still plays real libVLC on a Windows machine with VLC installed, found through the new discovery.

  • Full :ui:desktopTest --rerun :androidApp:testDebugUnitTest --rerun on Windows with JDK 21: desktop 4056 tests (70 skipped), Android 1183 tests, 0 failures. The slow-test log never fired. The new log line was confirmed with a temporary 2 s threshold, then reverted.

  • bash tools/check-kotlin-architecture.sh and bash tools/check-repository.sh pass.

  • Timing evidence: vlcj's recursive search over one Windows machine's 63 PATH entries took 192.5 s per walk, which matches the roughly six minute Windows desktopTest slowdown after Play Photos videos and add desktop in-app video playback #511. A shell reproduction of the search in Ubuntu 24.04 under WSL followed /usr/bin/X11 -> . 40 levels deep.

Not verified locally: a full Linux run of the suite. This PR's Linux CI job is the confirmation. If any other test still hangs, the new log names it after 3 minutes.

  • Follow-up tests: DesktopLibVlcDiscoveryTest (8 tests, now including a runtime-only aarch64 tree, native-triplet preference, candidate order, and no walking below system directories), DesktopLibVlcPlaybackTest (2, real libVLC), DesktopSystemMediaControlsTest (6; the Windows handler test runs on Windows).
  • :ui:lintAnalyzeRelease :androidApp:verifyReleaseLintGate passes locally. On main it crashes before the fix.
  • CI on 41d6592: Linux build passed in 10m18s, including the lint gate and assembleDebug. Linux desktopTest executed and passed in about 4m38s at 6099a09, and was restored from the build cache at the final head because only build-script code moved.

Compatibility and risk

Desktop only. Packaged builds keep finding their bundled libVLC in the first candidate. Linux and source runs find a system libVLC in the standard and Debian multiarch library directories. Only nested, non-standard layouts are no longer discovered. The packaging tasks are unchanged and only moved into ui/build.gradle.kts.

Visual changes

Not applicable.

vlcj's default discovery searches every candidate directory recursively
and follows symbolic links. Without libVLC it walks all of /usr/lib,
/usr/local/lib, and every PATH entry. On the Linux CI runner that tree
includes the Android SDK, which is the most likely reason the desktop
test task stopped producing output until the 45 minute job limit after
DesktopLibVlcPlaybackTest was added. The Windows desktop tests also grew
by about six minutes. In the app, the same walk ran at startup and hid
the external-player fallback until it finished.

Keep vlcj's candidate directories, order, and per-OS loading, but check
each candidate itself and never search below it.
The ui test tasks log only failures, so a stuck test printed nothing
until CI cancelled the job. Log the name of any test still running after
3 minutes and stop a test task after 30 minutes, well inside the CI job
limit. The slowest desktop test takes about 12 seconds and the full
desktop run about 6 minutes of test time.
@obiente-cloud
obiente-cloud Bot temporarily deployed to Obiente Preview / PR #520 / NC Native October 19, 2026 10:57 Destroyed
@obiente-cloud

obiente-cloud Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Obiente preview

NC Native · 41d6592d74fd · Ready

Open preview

View in Obiente

Obiente updates this comment as the preview changes.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T13:47:21.619458Z e672909 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0644604abf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread changes/unreleased/desktop-libvlc-bounded-discovery.md Outdated
@obiente-cloud
obiente-cloud Bot temporarily deployed to Obiente Preview / PR #520 / NC Native October 19, 2026 11:05 Destroyed
The SMTC COM handler's JNA callbacks use the Windows stdcall convention, which JNA cannot create on Linux or macOS, so its class initializer failed there. Production opens the handler only on Windows.
@obiente-cloud
obiente-cloud Bot temporarily deployed to Obiente Preview / PR #520 / NC Native October 19, 2026 12:11 Destroyed
vlcj names only the x86_64 and i386 triplet directories, so on arm64 and other architectures the distribution libVLC in /usr/lib/<triplet> was reachable only through the recursive search removed earlier. Check the JVM's own triplet directory before vlcj's first system directory, and the other known triplets after all of vlcj's candidates, because vlcj stops at the first copy it finds even when that copy cannot load. Each directory is still checked directly.
@obiente-cloud
obiente-cloud Bot temporarily deployed to Obiente Preview / PR #520 / NC Native October 19, 2026 12:43 Destroyed
Android lint 9.3.1 visits a Kotlin script applied with apply(from = ...) and crashes analysing it (findFirCompiledSymbol only works on compiled declarations), which failed :ui:lintAnalyzeRelease on main as well. The crash occurs whatever the applied script contains and wherever it lives, and disappears without the apply call. The download and staging tasks now live in ui/build.gradle.kts unchanged; the CI path filters and docs point there.
@obiente-cloud
obiente-cloud Bot temporarily deployed to Obiente Preview / PR #520 / NC Native October 19, 2026 13:43 Destroyed

This branch was successfully deployed

1 active deployment
Obiente Preview / PR #520 / NC Native — 41d6592d Deployed Oct 19, 2026 by obiente-cloud[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant