Skip to content
 
 

Repository files navigation

vacuumstreamer

Stream video from the AVA-based robot vacuum's camera. video_monitor drives the on-board Cedar H264 encoder via libtrecorder.so and feeds frames to vacuumstreamer.so, an LD_PRELOAD shim that intercepts the Agora RTC SDK calls and re-serves the raw H264 stream over TCP port 6969. A client such as go2rtc (on the robot or on a separate host) turns that into RTSP/WebRTC.

Tested on: Dreame L10s Ultra (r2338 firmware).

video_monitor is built entirely from source — see Build. The camera powers on only when a TCP client connects to port 6969.

Build

Both vacuumstreamer.so (the shim) and video_monitor (the camera bridge) cross-compile for AArch64 inside a Docker toolchain image. build.sh fetches the device libraries it links against directly from the robot — nothing binary is checked in.

# 1. Build the toolchain image (once)
docker build -t vacuumstreamer .

# 2. Fetch device libs + build both artifacts
VACUUM_ROBOT_IP=192.168.x.y ./build.sh
# non-default SSH key/options:
VACUUM_ROBOT_IP=192.168.x.y SSH_OPTS="-i ~/.ssh/id_robot" ./build.sh

build.sh pulls these from /usr/lib on the robot into ./libs/ (gitignored, cached between builds) and links against them — they only satisfy the linker; at runtime the on-device copies are used via rpath=/usr/lib:

Library Purpose
libc.so.6 pins entry point to GLIBC_2.17
libpthread.so.0 pthread
libtrecorder.so Cedar H264 recorder API (TRecorder)
libMemAdapter.so CedarX DMA-memory ops
libawrecorder.so AW encoder (AwEncoderCreate) + Cedar encoder chain

Because they are fetched from the target, the build automatically matches your robot firmware. The remaining transitive dependencies (libVE, libvencoder, libcdc_base, …) are resolved at runtime from /usr/lib. To re-fetch after a firmware update, delete ./libs/ and rebuild.

How video_monitor works

video_monitor.c is a stripped-down reimplementation of the stock binary, reverse-engineered from its oneChannelTest/CallbackFromTRecorder. The verified TRecorder setup sequence is:

CreateTRecorder → TRreset → TRSetRecorderCfgPath(path,len) → TRsetCamera(0)
→ TRsetOutput → TRsetMaxRecordTimeMs → TRsetRecorderCallback(cb) → TRprepare → TRstart(.,2)

The callback receives H264 (what == 2; info->[0] = buffer, info->[8] = size) and forwards it via agora_rtc_send_video_data, which vacuumstreamer.so redirects to TCP clients. Three device quirks are handled in source: the GetMemAdapterOpsSMemAdapterGetOpsS rename (shimmed), linking libawrecorder.so for AwEncoderCreate, and prepending a fixed 22-byte SPS/PPS to every IDR (the encoder emits none in-band).

Install

Copy vacuumstreamer.so, the freshly built video_monitor, start.sh, and the configuration files to the robot:

ssh root@${VACUUM_ROBOT_IP} "mkdir -p /data/vacuumstreamer"
scp -O vacuumstreamer.so   root@${VACUUM_ROBOT_IP}:/data/vacuumstreamer/vacuumstreamer.so
scp -O video_monitor       root@${VACUUM_ROBOT_IP}:/data/vacuumstreamer/video_monitor
scp -O start.sh            root@${VACUUM_ROBOT_IP}:/data/vacuumstreamer/start.sh
scp -Or dist/ava/conf/video_monitor/ root@${VACUUM_ROBOT_IP}:/data/vacuumstreamer/ava_conf_video_monitor
ssh root@${VACUUM_ROBOT_IP} "chmod +x /data/vacuumstreamer/video_monitor /data/vacuumstreamer/start.sh"

Autostart on boot

start.sh bind-mounts the encoder config and launches video_monitor (detached via setsid) under the shim. Hook it into the robot's user boot script, /data/_root_postboot.sh (run by /etc/rc.sysinit):

ssh root@${VACUUM_ROBOT_IP} 'grep -q vacuumstreamer/start.sh /data/_root_postboot.sh ||
  printf "\n# vacuumstreamer camera bridge\nif [ -x /data/vacuumstreamer/start.sh ]; then\n\t/data/vacuumstreamer/start.sh\nfi\n" >> /data/_root_postboot.sh'

Start it now without rebooting:

ssh root@${VACUUM_ROBOT_IP} "/data/vacuumstreamer/start.sh"

The raw H264 stream is then available at tcp://${VACUUM_ROBOT_IP}:6969 (Annex-B, with SPS/PPS on every keyframe). Verify with:

ffprobe -v error -select_streams v -show_entries stream=codec_name,width,height \
  tcp://${VACUUM_ROBOT_IP}:6969

go2rtc

Run go2rtc on the robot, or on a separate host (e.g. your Frigate box) to keep the robot idle. On the robot:

curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.9/go2rtc_linux_arm64 \
  -o /data/vacuumstreamer/go2rtc
chmod +x /data/vacuumstreamer/go2rtc
/data/vacuumstreamer/go2rtc -c '{"streams": {"vacuum_cam": "tcp://127.0.0.1:6969"}}'

From another host, point the source at the robot instead: tcp://${VACUUM_ROBOT_IP}:6969.

Credits to @Uberi, source: https://anthony-zhang.me/blog/offline-robot-vacuum/

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages