Install ALSA on first run - #44
Open
Nicolas Palpacuer (NickPPC) wants to merge 4 commits into
Open
Conversation
On a host without ALSA the audio-module binary fails to start with
"libasound.so.2: cannot open shared object file" and exits 127. A desktop image
happens to ship it, so the gap only shows up on a server or minimal container
image -- and it surfaces as "model not registered" on every resource that
depends on the speaker or microphone, which reads like a config error rather
than a missing .so. The tarball already bundles JACK and libdb, but ALSA has to
come from the host.
Add a first_run.sh that installs it, and wire it into the packaging: meta.json
declares it, CMake installs it with PROGRAMS so it keeps its executable bit (the
RDK execs it directly), and the conan deployer copies it into module.tar.gz.
The script:
- checks whether libasound.so.2 is already present before touching a package
manager, so it is a no-op on a host that is already set up, and does nothing
on macOS
- supports apt, dnf/yum, zypper, pacman and apk, including the Debian/Ubuntu
64-bit time_t rename (libasound2t64 vs libasound2)
- looks the soname up through ldconfig, whose cache is architecture-aware, so
no /usr/lib/<triplet> paths are hardcoded
- re-verifies afterwards and, if it is still missing, logs the exact command
an operator should run by hand
It always exits 0, even when it cannot install anything. A non-zero exit from a
first_run script makes the RDK abort the whole machine's reconfiguration and
roll back to the previous config -- not just this module -- so a host we cannot
install on would take unrelated resources down with it. Exiting 0 leaves the
module to fail on its own, exactly as it does today, with actionable guidance in
the logs.
Tested in containers on ubuntu:24.04 (installs libasound2t64 and verifies),
twice over on the same host (idempotent), and as a non-root user with no sudo
(exits 0 and prints the manual command).
first_run.sh now exits non-zero when the required libraries are missing and could not be installed, instead of exiting 0 and leaving the module to fail on its own. That deliberately aborts the machine's reconfiguration. The RDK keeps the previous, working config, leaves already-running modules running, and marks this module's package as failed -- which is preferable to applying a config the machine cannot actually serve. Since no success marker is written on failure, first_run is retried automatically once the host is fixed. One consequence needs handling: the RDK only advances its stored config after the first_run phase succeeds (robot/impl/local_robot.go), and the cloud config watcher pushes a config every refresh interval, so an aborted reconfiguration re-runs this script roughly every 10 seconds. Re-running apt that often would hold the package-manager lock and fight an operator trying to fix the host by hand, so the install attempt is rate-limited to once per 10 minutes via a stamp file under /tmp. The diagnostic is still printed and the exit code is still non-zero on every run -- only the install attempt is skipped. The failure message now states the actual consequence: that the machine will keep its previous configuration until the libraries are installed, and that it retries by itself afterwards.
The install-attempt stamp lived under /tmp, which any local user can write to. That let an unprivileged user pre-create the path as a symlink and have this script truncate the target, since first_run normally runs as root. Record it as a sibling of the module directory instead, mirroring where the RDK keeps its own .first_run_succeeded marker -- that directory is root-owned. When VIAM_MODULE_ROOT is unset, which means someone is running the script by hand outside the RDK, throttling is disabled rather than falling back to an unsafe path; a manual run should attempt the install every time anyway.
The soname lookup table listed every library the OpenCV-based modules need across all five package managers, even though this module only ever asks about libasound.so.2. REQUIRED_SONAMES was already correct, so nothing was ever checked or installed that shouldn't be, but the dead rows made the table look like a shared list rather than this module's own dependency. Drop the rows this module cannot reach, and reword the two comments that used glib as their example. 46 lines lighter and the table now reads as exactly what the module requires.
Nicolas Palpacuer (NickPPC)
requested review from
Ale Paredes (ale7714),
Cheuk (cheukt) and
oliviamiller
August 3, 2026 22:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On a host without ALSA the
audio-modulebinary fails to start withlibasound.so.2: cannot open shared object fileand exits 127. Desktop images ship it and server or minimal container images do not, so the gap only appears on freshly provisioned machines — where it surfaces asmodel not registeredon every resource depending on the speaker or microphone, reading like a config error rather than a missing.so. The tarball already bundles JACK and libdb; this adds afirst_run.shthat installs ALSA the same way.Review guide
first_run.shis the entire change; everything else is packaging wiring. Start atmain()at the bottom.exports_sources→ CMakeinstall→ conandeploy(). Miss one and the script silently never reaches the machine.Changes
libasound.so.2vialdconfig, installs the right package for the distro, re-verifies, and prints a copy-pasteable command if it is still missingfirst_runkey, which the module did not previously declareinstall(PROGRAMS ...)rather thanFILES, so the script keeps its executable bit — the RDKexecs it directlymodule.tar.gzalongsiderun.shTesting
Verified in throwaway containers (all with empty package caches, i.e. the fresh-host case):
ubuntu:24.04— installslibasound2t64and re-verifies the sonameThe script handles the Debian/Ubuntu 64-bit
time_trename by tryinglibasound2t64thenlibasound2, so it works on noble and on jammy/bookworm without pinning a release. The soname is looked up throughldconfig, whose cache is architecture-aware, so no/usr/lib/<triplet>paths are hardcoded.The packaging is confirmed against this PR's own CI artifact rather than by inspection —
module-darwin-arm64from the build job unpacks to:i.e.
first_run.shlands at the tarball root next tometa.jsonwith its executable bit intact, which is what the RDK needs toexecit.Claude Code prompts used