Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(silo/native): add MediaMTX streaming relay on silo

Every ac-native device can now broadcast to silo.aesthetic.computer.
MediaMTX relay accepts SRT push and serves RTMP/HLS for viewers.

- silo/stream/: MediaMTX config + deploy script
- stream.conf only needs CHANNEL=name to enable broadcasting
- Default SRT_LATENCY bumped to 120ms for internet (vs 40ms LAN)
- Viewers pull: rtmp://silo:1935/<channel> or HLS at :8888/<channel>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+185 -19
+27 -19
fedac/nixos/configuration.nix
··· 175 175 } 176 176 ''; 177 177 178 - # SRT streamer: pushes notepat framebuffer over WiFi to OBS on Windows, 179 - # which then forwards to TikTok Live. 178 + # SRT streamer: pushes notepat video + audio to silo.aesthetic.computer 179 + # via MediaMTX relay. Viewers pull RTMP/SRT/HLS from silo. 180 180 # 181 181 # Opt-in: only starts if /mnt/stream.conf exists on the USB config partition. 182 - # Create /mnt/stream.conf with: 183 - # HOST=192.168.1.100 # Windows host IP on LAN 184 - # PORT=9000 # SRT port (OBS Media Source listens here) 185 - # BITRATE=6M # encode bitrate 186 - # FRAMERATE=60 # capture fps 187 - # SRT_LATENCY=40 # ms — lower = less latency, more fragile on bad WiFi 188 - # WIDTH=1280 # output width (scale from native) 189 - # HEIGHT=720 # output height 182 + # Minimal stream.conf (just enable with defaults): 183 + # CHANNEL=my-device 184 + # 185 + # Optional overrides in stream.conf: 186 + # HOST=silo.aesthetic.computer # relay server (default: silo) 187 + # PORT=9000 # SRT port 188 + # BITRATE=6M # encode bitrate 189 + # FRAMERATE=60 # capture fps 190 + # SRT_LATENCY=120 # ms — tuned for internet (not LAN) 191 + # WIDTH=1280 # output width 192 + # HEIGHT=720 # output height 193 + # AUDIO_BITRATE=128k # audio encode bitrate 190 194 systemd.services.ac-native-stream = { 191 - description = "AC Native SRT streamer (to OBS → TikTok)"; 195 + description = "AC Native SRT streamer (to silo relay)"; 192 196 after = [ "ac-native-kiosk.service" "mount-usb-config.service" ]; 193 197 wants = [ "ac-native-kiosk.service" ]; 194 198 wantedBy = [ "multi-user.target" ]; ··· 206 210 serviceConfig = { 207 211 Type = "simple"; 208 212 Restart = "on-failure"; 209 - RestartSec = 3; 213 + RestartSec = 5; 210 214 EnvironmentFile = "/mnt/stream.conf"; 211 215 212 216 ExecStartPre = pkgs.writeShellScript "ac-native-stream-wait" '' 213 217 # Give the kiosk a moment to grab DRM master and start rendering 214 - sleep 2 218 + sleep 3 215 219 216 220 for _ in $(seq 1 40); do 217 221 ls /dev/dri/card* >/dev/null 2>&1 && break ··· 227 231 ExecStart = pkgs.writeShellScript "ac-native-stream" '' 228 232 set -u 229 233 230 - HOST="''${HOST:?HOST not set in /mnt/stream.conf}" 234 + # Defaults tuned for internet relay via silo 235 + HOST="''${HOST:-silo.aesthetic.computer}" 231 236 PORT="''${PORT:-9000}" 237 + CHANNEL="''${CHANNEL:-$(hostname)}" 232 238 BITRATE="''${BITRATE:-6M}" 233 239 FRAMERATE="''${FRAMERATE:-60}" 234 - SRT_LATENCY="''${SRT_LATENCY:-40}" 240 + SRT_LATENCY="''${SRT_LATENCY:-120}" 235 241 WIDTH="''${WIDTH:-1280}" 236 242 HEIGHT="''${HEIGHT:-720}" 243 + AUDIO_BITRATE="''${AUDIO_BITRATE:-128k}" 237 244 238 245 CARD="$(ls /dev/dri/card* 2>/dev/null | head -n1)" 239 246 [ -n "$CARD" ] || { echo "[stream] no DRM card"; exit 1; } 240 247 241 - URL="srt://''${HOST}:''${PORT}?mode=caller&latency=''${SRT_LATENCY}&pkt_size=1316&tlpktdrop=1" 242 - echo "[stream] capturing $CARD at ''${FRAMERATE}fps → $URL" 248 + STREAMID="publish:/''${CHANNEL}" 249 + URL="srt://''${HOST}:''${PORT}?mode=caller&streamid=''${STREAMID}&latency=''${SRT_LATENCY}&pkt_size=1316&tlpktdrop=1" 250 + echo "[stream] channel: ''${CHANNEL}" 251 + echo "[stream] capturing $CARD at ''${FRAMERATE}fps" 243 252 echo "[stream] encode: h264_vaapi ''${WIDTH}x''${HEIGHT} @ ''${BITRATE}" 244 - 245 - AUDIO_BITRATE="''${AUDIO_BITRATE:-128k}" 253 + echo "[stream] → $URL" 246 254 247 255 exec ${pkgs.ffmpeg-full}/bin/ffmpeg \ 248 256 -hide_banner -loglevel warning \
+125
silo/stream/deploy.fish
··· 1 + #!/usr/bin/env fish 2 + # Deploy MediaMTX streaming relay to silo.aesthetic.computer 3 + # 4 + # Usage: 5 + # fish deploy.fish # Full deploy (download binary + config + systemd) 6 + # fish deploy.fish --config # Config-only update (no restart unless binary changed) 7 + 8 + set RED '\033[0;31m' 9 + set GREEN '\033[0;32m' 10 + set YELLOW '\033[1;33m' 11 + set NC '\033[0m' 12 + 13 + set SCRIPT_DIR (dirname (status --current-filename)) 14 + set VAULT_DIR "$SCRIPT_DIR/../../aesthetic-computer-vault" 15 + set SSH_KEY "$VAULT_DIR/home/.ssh/id_rsa" 16 + set SILO_HOST "silo.aesthetic.computer" 17 + set SILO_USER "root" 18 + set REMOTE_DIR "/opt/mediamtx" 19 + set MEDIAMTX_VERSION "1.12.2" 20 + set MEDIAMTX_URL "https://github.com/bluenviron/mediamtx/releases/download/v$MEDIAMTX_VERSION/mediamtx_v{$MEDIAMTX_VERSION}_linux_amd64.tar.gz" 21 + 22 + set CONFIG_ONLY false 23 + if contains -- --config $argv 24 + set CONFIG_ONLY true 25 + end 26 + 27 + if not test -f $SSH_KEY 28 + echo -e "$RED x SSH key not found: $SSH_KEY$NC" 29 + exit 1 30 + end 31 + 32 + echo -e "$GREEN-> Testing SSH connection to $SILO_HOST...$NC" 33 + if not ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=10 $SILO_USER@$SILO_HOST "echo ok" &>/dev/null 34 + echo -e "$RED x Cannot connect to $SILO_HOST$NC" 35 + exit 1 36 + end 37 + 38 + # Upload config 39 + echo -e "$GREEN-> Uploading mediamtx.yml...$NC" 40 + ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "mkdir -p $REMOTE_DIR" 41 + scp -i $SSH_KEY -o StrictHostKeyChecking=no \ 42 + $SCRIPT_DIR/mediamtx.yml \ 43 + $SILO_USER@$SILO_HOST:$REMOTE_DIR/ 44 + 45 + if test $CONFIG_ONLY = true 46 + echo -e "$GREEN-> Config-only: reloading mediamtx...$NC" 47 + ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "systemctl reload mediamtx 2>/dev/null || systemctl restart mediamtx" 48 + echo -e "$GREEN Done.$NC" 49 + exit 0 50 + end 51 + 52 + # Download + install binary on remote 53 + echo -e "$GREEN-> Installing MediaMTX v$MEDIAMTX_VERSION on $SILO_HOST...$NC" 54 + ssh -i $SSH_KEY $SILO_USER@$SILO_HOST " 55 + cd $REMOTE_DIR 56 + if test -f mediamtx && ./mediamtx --version 2>&1 | grep -q '$MEDIAMTX_VERSION'; then 57 + echo 'Already at v$MEDIAMTX_VERSION, skipping download' 58 + else 59 + curl -fsSL '$MEDIAMTX_URL' -o /tmp/mediamtx.tar.gz 60 + tar -xzf /tmp/mediamtx.tar.gz -C $REMOTE_DIR mediamtx 61 + rm /tmp/mediamtx.tar.gz 62 + chmod +x $REMOTE_DIR/mediamtx 63 + echo 'Installed MediaMTX v$MEDIAMTX_VERSION' 64 + fi 65 + " 66 + 67 + # Create systemd service 68 + echo -e "$GREEN-> Setting up systemd service...$NC" 69 + ssh -i $SSH_KEY $SILO_USER@$SILO_HOST " 70 + cat > /etc/systemd/system/mediamtx.service << 'UNIT' 71 + [Unit] 72 + Description=MediaMTX streaming relay (AC Native) 73 + After=network-online.target 74 + Wants=network-online.target 75 + 76 + [Service] 77 + Type=simple 78 + ExecStart=/opt/mediamtx/mediamtx /opt/mediamtx/mediamtx.yml 79 + ExecReload=/bin/kill -HUP \$MAINPID 80 + Restart=on-failure 81 + RestartSec=5 82 + LimitNOFILE=65536 83 + 84 + [Install] 85 + WantedBy=multi-user.target 86 + UNIT 87 + 88 + systemctl daemon-reload 89 + systemctl enable mediamtx 90 + systemctl restart mediamtx 91 + sleep 2 92 + systemctl is-active mediamtx 93 + " 94 + 95 + set STATUS $status 96 + if test $STATUS -eq 0 97 + echo -e "$GREEN MediaMTX is running.$NC" 98 + else 99 + echo -e "$RED x MediaMTX failed to start. Check logs:$NC" 100 + echo -e "$YELLOW ssh -i $SSH_KEY $SILO_USER@$SILO_HOST journalctl -u mediamtx -n 30$NC" 101 + exit 1 102 + end 103 + 104 + # Open firewall ports 105 + echo -e "$GREEN-> Opening firewall ports (9000/udp SRT, 1935/tcp RTMP, 8888/tcp HLS)...$NC" 106 + ssh -i $SSH_KEY $SILO_USER@$SILO_HOST " 107 + if command -v ufw >/dev/null 2>&1; then 108 + ufw allow 9000/udp comment 'MediaMTX SRT' 109 + ufw allow 1935/tcp comment 'MediaMTX RTMP' 110 + ufw allow 8888/tcp comment 'MediaMTX HLS' 111 + elif command -v firewall-cmd >/dev/null 2>&1; then 112 + firewall-cmd --permanent --add-port=9000/udp 113 + firewall-cmd --permanent --add-port=1935/tcp 114 + firewall-cmd --permanent --add-port=8888/tcp 115 + firewall-cmd --reload 116 + else 117 + echo 'No firewall tool found — ports may already be open' 118 + fi 119 + " 120 + 121 + echo "" 122 + echo -e "$GREEN Done. MediaMTX relay deployed to $SILO_HOST$NC" 123 + echo -e "$GREEN SRT push: srt://$SILO_HOST:9000?streamid=publish:/<channel>$NC" 124 + echo -e "$GREEN RTMP pull: rtmp://$SILO_HOST:1935/<channel>$NC" 125 + echo -e "$GREEN HLS view: http://$SILO_HOST:8888/<channel>$NC"
+33
silo/stream/mediamtx.yml
··· 1 + # MediaMTX relay config for AC Native live streaming. 2 + # Accepts SRT push from ac-native devices, serves RTMP/HLS for viewers. 3 + # 4 + # Stream paths are channel names (e.g. /jeffrey, /notepat-001). 5 + # Push: srt://silo.aesthetic.computer:9000?streamid=publish:/<channel> 6 + # Pull: rtmp://silo.aesthetic.computer:1935/<channel> 7 + # srt://silo.aesthetic.computer:9000?streamid=read:/<channel> 8 + # HLS: http://silo.aesthetic.computer:8888/<channel> 9 + 10 + logLevel: info 11 + logDestinations: [stdout] 12 + 13 + # Allow any path — each ac-native device picks its own channel name. 14 + paths: 15 + all_others: 16 + 17 + # SRT: ac-native devices push here 18 + srt: yes 19 + srtAddress: :9000 20 + 21 + # RTMP: OBS / TikTok Studio pulls from here 22 + rtmp: yes 23 + rtmpAddress: :1935 24 + 25 + # HLS: browser preview 26 + hls: yes 27 + hlsAddress: :8888 28 + hlsAlwaysRemux: yes 29 + 30 + # Disable unused protocols 31 + rtsp: no 32 + webrtc: no 33 + srtpEnabled: no