MediaMTX accepte l'ingestion WebRTC montante et sert une page de
publication. Trois proprietes qu'aucune application ne reunit : rien a
installer donc aucune limite de duree imposee par un editeur, tout passe
par le 443 donc ca traverse un reseau qui ne laisse sortir que HTTPS, et
WebRTC de bout en bout donc la latence minimale sans transcodage.
Contrepartie assumee : iOS suspend la capture des que l'ecran se
verrouille. Acceptable pour un capteur fixe et alimente, insuffisant pour
du 24/7 autonome - ou une application native reste preferable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Larix Broadcaster refuse une URL RTMP a un seul niveau : il impose le
schema rtmp://serveur/application/streamkey et affiche "Can't find rtmp
app and stream". Le chemin passe donc de "biblio" a "live/biblio", ce qui
satisfait cette contrainte sans rien changer pour SRT.
Au passage, un defaut mis en evidence par ce renommage : les ressources
statiques etaient servies sans directive de cache. Un navigateur laisse
ouvert continuait d'appeler l'ancien chemin, et la panne etait invisible
cote serveur - il ne voyait que des requetes vers une route disparue.
max-age=0 + must-revalidate : avec ETag, la revalidation coute un 304.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le domaine connaissait deja CAMERA_OFFLINE, classe CRITICAL, mais rien ne
l'emettait. CameraLivenessProbe interroge l'API du serveur media et comble
ce trou.
Elle passe par le meme port IngestSensorEventUseCase que l'endpoint REST
et le simulateur : trois producteurs de natures tres differentes, un seul
contrat d'entree, et le meme trajet Kafka -> agregat ensuite. Si l'alarme
est desarmee, une coupure video ne reveille personne - c'est l'agregat qui
tranche, pas la sonde.
Le seuil est la partie qui compte. Sur un lien 4G le flux tombe
regulierement sans que personne n'ait touche au telephone : tunnel,
bascule d'antenne, congestion. Alerter des la premiere sonde ratee
produirait plusieurs CRITICAL par jour, et on apprend vite a ignorer des
alertes qui crient pour rien - y compris le jour ou elles ont raison.
Trois sondes consecutives, soit une minute d'absence reelle. Six tests
couvrent ce comportement, dont la remise a zero du compteur au retour du
flux.
Utilisateur d'API dedie cote MediaMTX, restreint au reseau Docker interne.
41 tests au vert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ouvrir 1935/8890/8189 dans ufw ne suffit pas : le projet Hetzner Cloud
a son propre pare-feu en amont de la machine. tcpdump sur l'hote ne voit
aucun paquet sur 1935 alors que 2222, autorise des deux cotes, apparait
normalement - le trafic est jete avant d'atteindre le serveur.
Piege particulier sur 8189/udp : sans lui, la signalisation WebRTC
aboutit (elle passe par Caddy en 443) mais aucun media ne circule. La
console bascule en HLS sans rien signaler, et la panne se deguise en
simple latence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'iPhone n'est joignable depuis nulle part - CGNAT operateur en 4G, NAT
de la box sur le WiFi du studio, UPnP indisponible. Le serveur RTSP de
l'application camera est donc inutilisable de l'exterieur. Seule une
connexion sortante traverse les deux NAT : c'est le telephone qui pousse.
- MediaMTX en conteneur : SRT/RTMP en entree, WebRTC (WHEP) et HLS en
sortie. La video ne traverse jamais la JVM - 800 kbps continus dans
Spring Boot couteraient un thread par spectateur sans rien apporter.
- SRT privilegie sur RTMP : RTMP est du TCP, un paquet perdu sur un lien
mobile bloque tout le flux. SRT retransmet selectivement en UDP.
- Lecture publique (choix assume), publication authentifiee : sans ca
n'importe qui pousserait sa propre video sur le flux "biblio".
- Console : client WHEP maison avec repli HLS automatique, et mise en
pause quand l'onglet passe en arriere-plan.
Correction d'un bug trouve en deployant : le @ExceptionHandler(Exception)
avalait les exceptions que Spring sait deja traduire, si bien que toute
URL inconnue renvoyait 500 au lieu de 404 - ce qui noyait les vraies
pannes au milieu des 500 provoques par les crawlers. Test de regression
ajoute.
35 tests au vert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- deploy/deploy.sh : rsync + build distant + attente du healthcheck.
Le build tourne sur le serveur, la machine de dev n'a pas besoin d'un
JDK 21 et la difference d'architecture arm64/x86_64 disparait.
- .env.example : la procedure recommandait un `sed -i s/CHANGEME/.../`
global. Le motif apparaissant aussi dans le commentaire au-dessus, le
mot de passe genere s'y recopiait en clair. Remplace par un append
cible sur la seule ligne DB_PASSWORD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Backend d'un systeme de video-surveillance dont le capteur est un iPhone
recycle. Le probleme est simple, la structure est le sujet :
- domain/ sans aucun import de framework (verifie par 7 regles ArchUnit
qui tournent aussi pendant le docker build)
- CQRS strict : write et read ne partagent ni modele ni port
- AlarmDecision en sealed interface -> switch exhaustif verifie a la
compilation, plutot qu'une chaine de if
- Kafka en KRaft (Zookeeper est supprime depuis Kafka 4.0), cle de
partition = deviceId pour garantir l'ordre par capteur
- ErrorHandlingDeserializer + DLQ : un message malforme ne bloque pas
le flux des evenements suivants
- notification WebSocket differee apres commit, pour ne jamais afficher
une intrusion qui partirait en rollback
31 tests au vert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>