Files
AngePierreandClaude Opus 5 23b30ac1e8 Add the MKV recorder so a node can Record, not only preview
The recorder was the gap: it is FTF's own customised SDK example (a 1139-line
K4A MKV writer), not a stock sample, and it lived only in one machine's build
tree. Bring its source into the repo and build it as part of install.

It writes K4A-format MKV — the format the rest of Ithaca reads — so it stays,
and gets its libk4a from the Orbbec K4A wrapper rather than Microsoft's Azure
Kinect SDK, which is set aside. build_k4a_wrapper.sh builds that wrapper;
build_sdk.sh injects the recorder into the SDK examples tree and builds it there
against the wrapper (it depends on the SDK's own cmake targets). Found by rpath
at runtime, so no LD_LIBRARY_PATH.

install.sh now builds wrapper -> SDK+recorder -> preview server, each reusing an
existing build so the Nano is untouched. If the wrapper is unavailable the
install still completes preview-only and says so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 16:21:44 +02:00

119 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# One command, the same on every Jetson: installs the Ithaca capture node from this
# checkout. Detects the platform, installs dependencies, builds the C++ against a
# locally-built OrbbecSDK, generates a config and a service for the CURRENT user,
# and starts the bridge.
#
# Idempotent: safe to re-run after a git pull. It rebuilds the server, rewrites the
# config and unit, and restarts the service; it does not touch a working SDK build.
#
# Why a script and not a prebuilt image: the two Jetsons here have no common
# JetPack — tegra210 caps at 4, tegra234 needs 5+ — so nothing binary is portable
# between them. The source and this procedure are; the binaries are made locally.
set -euo pipefail
REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
USER_NAME=$(id -un)
HOME_DIR="$HOME"
echo "=============================================================="
echo " Ithaca node install"
eval "$("$REPO/scripts/detect_platform.sh")"
echo " modele : $MODEL"
echo " L4T : $L4T (JetPack $JETPACK, $SOC, $ARCH)"
echo " user : $USER_NAME home: $HOME_DIR"
echo " repo : $REPO"
echo "=============================================================="
if [[ "$ARCH" != "aarch64" ]]; then
echo "!! Cette install vise les Jetson (aarch64). Arch detectee: $ARCH." >&2
echo "!! Continue quand meme dans 3 s (Ctrl-C pour arreter)…" >&2
sleep 3
fi
# ---- 1. dependencies ------------------------------------------------------
"$REPO/scripts/install_deps.sh"
# ---- 2. the K4A wrapper, the SDK (with the recorder), then the server ------
# Three compiled pieces, in dependency order:
# - the Orbbec K4A wrapper provides libk4a, which the recorder needs;
# - the SDK builds the library AND the recorder example against that wrapper;
# - the preview server links the built SDK.
# Each script reuses an existing build, so a working node (the Nano) is untouched.
echo ">> Localisation / compilation du wrapper K4A (libk4a, Orbbec)…"
eval "$("$REPO/scripts/build_k4a_wrapper.sh")" || true
if [[ -n "${K4A_WRAPPER_DIR:-}" ]]; then
echo " K4A_WRAPPER_DIR = $K4A_WRAPPER_DIR"
export K4A_WRAPPER_DIR
else
echo " !! wrapper K4A indisponible — le nœud fera la PREVIEW mais pas le RECORD."
fi
echo ">> Localisation / compilation de l'OrbbecSDK (+ recorder)…"
eval "$("$REPO/scripts/build_sdk.sh")"
echo " OB_SDK_ROOT = $OB_SDK_ROOT"
echo " OB_SDK_BUILD = $OB_SDK_BUILD"
if [[ -n "${RECORDER_BIN:-}" ]]; then
echo " RECORDER_BIN = $RECORDER_BIN"
else
echo " !! recorder non produit — RECORD indisponible sur ce nœud."
fi
echo ">> Compilation du serveur de preview…"
SERVER_BIN=$("$REPO/scripts/build_server.sh")
echo " $SERVER_BIN"
# ---- 3. config, generated for this user -----------------------------------
# The tested bridge.py ships unchanged; portability lives here, in the config it
# reads. @PLACEHOLDERS@ become real paths for the current user.
CONFIG="$REPO/bridge/config.json"
if [[ -f "$CONFIG" ]]; then
echo ">> config.json existe deja — conserve (supprime-le pour regenerer)."
else
sed -e "s#@HOME@#$HOME_DIR#g" \
-e "s#@REPO@#$REPO#g" \
-e "s#@SDK_BUILD@#$OB_SDK_BUILD#g" \
"$REPO/bridge/config.template.json" > "$CONFIG"
echo ">> config.json genere: $CONFIG"
fi
mkdir -p "$HOME_DIR/IthacaRecordings"
# ---- 4. udev + usbfs (need root, affect the whole machine) ----------------
echo ">> Regles udev (acces camera sans root) + usbfs_memory…"
# Prefer the SDK's own installer when it is there — it is the maintained source of
# the rule set; fall back to the copy shipped here.
if [[ -x "$OB_SDK_ROOT/scripts/env_setup/install_udev_rules.sh" ]]; then
sudo bash "$OB_SDK_ROOT/scripts/env_setup/install_udev_rules.sh" || true
else
sudo install -m 0644 "$REPO/udev/99-obsensor-libusb.rules" \
/etc/udev/rules.d/99-obsensor-libusb.rules
fi
sudo udevadm control --reload-rules && sudo udevadm trigger || true
sudo install -m 0644 "$REPO/systemd/usbfs-memory.service" \
/etc/systemd/system/usbfs-memory.service
# So the camera is reachable without being root right now, not only after a
# reboot: the video group is what the udev rules grant to.
sudo usermod -aG video "$USER_NAME" || true
# ---- 5. the bridge service, generated for this user -----------------------
UNIT=/etc/systemd/system/ithaca-bridge.service
sudo sed -e "s#@REPO@#$REPO#g" -e "s#@USER@#$USER_NAME#g" \
"$REPO/systemd/ithaca-bridge.service.in" | sudo tee "$UNIT" >/dev/null
sudo systemctl daemon-reload
sudo systemctl enable --now usbfs-memory.service
sudo systemctl enable ithaca-bridge.service
sudo systemctl restart ithaca-bridge.service
echo "=============================================================="
echo " Installe. Etat du bridge :"
systemctl is-active ithaca-bridge.service || true
echo
echo " Journal en direct : journalctl -u ithaca-bridge -f"
echo " Si la camera n'est vue qu'apres reconnexion USB, c'est le"
echo " groupe 'video' qui vient d'etre ajoute — deconnecte/reconnecte"
echo " la session, ou rebranche la camera."
echo "=============================================================="