webrtc-tauri

WebRTC dans Tauri — LGB-037

Nature de ce document

Ce billet est explicitement un rapport d’investigation, pas une suite U/M/I/C/E complète (voir docs/projet/03-BACKLOG-LEGBA.md, section LGB-037). Ce fichier distingue, pour chaque plateforme, trois états possibles — jamais mélangés implicitement :

  • testé-fonctionne : exécuté réellement depuis cette session, avec la sortie de commande à l’appui.
  • testé-échoue (avec cause) : exécuté réellement, la cause technique exacte est identifiée et citée.
  • non testé : pas d’environnement disponible pour le vérifier depuis cette session ; jamais présenté comme un succès ou un échec supposé.

Le scaffold vérifié est examples/tauri-shell — exemple isolé, non publié (voir son README.md pour l’architecture et les commandes).


Résumé par plateforme

PlateformeBuildLancementConnexion signalisation LiveKitCaméra/micro réels
macOS (local, cette session)testé-fonctionnetesté-fonctionne (processus stable, sans crash)non testé visuellement (voir ci-dessous)non testé
Linux (conteneur ubuntu:24.04, cette session — mêmes étapes que le job CI)testé-fonctionne (après correction d’un conflit de paquets apt, cause exacte ci-dessous)testé-fonctionne (processus stable sous Xvfb, rendu logiciel faute de GPU)non testé dans cette vérification locale ; le job CI réel (tauri-shell-linux) le tentera, pas encore exécuté sur GitHub Actionsnon testé
Windowsnon testé — aucune machine Windows disponible dans cet environnement

macOS — testé localement, dans cette session

Environnement réel de cette session

Contrairement à l’hypothèse de départ du billet (environnement sandboxé sans affichage), l’exécution a eu lieu sur la machine macOS réelle de l’utilisateur (Wislys-MacBook-Pro, Apple M5, macOS 26.2, écran interne réel). Mais cette session est un job d’arrière-plan non interactif : pas de session graphique pilotable, pas d’accès caméra/micro accordé. Les outils shell (cargo, pnpm, tauri) fonctionnent normalement ; piloter une fenêtre réelle (capturer un écran, accorder une permission caméra) est délibérément resté hors de portée de cette vérification — voir « Ce qui n’a pas été tenté, et pourquoi » plus bas.

Build — testé-fonctionne

pnpm exec tauri build --no-bundle

A compilé les 415 crates Rust de la chaîne Tauri v2 (tauri 2.11.5, wry 0.55.1, WKWebView natif macOS) et produit un binaire réel :

Built application at: examples/tauri-shell/src-tauri/target/release/tauri-shell

file confirme : Mach-O 64-bit executable arm64, 9,2 Mo.

Un premier essai a échoué avec un message d’erreur exact (scénario 12) :

error: proc macro panicked
 --> src/main.rs:6:14
  = help: message: failed to open icon .../icons/icon.png: No such file or directory (os error 2)

tauri::generate_context!() exige une icône même avec bundle.active: false (pas de paquet .app produit, mais l’icône de fenêtre reste requise). Corrigé en ajoutant trois PNG minimaux (couleur unie, générés par script, pas de dépendance de design) dans examples/tauri-shell/src-tauri/icons/. Après correction, le build a réussi sans autre erreur.

--no-bundle a été choisi délibérément : produire un .app/.dmg distribuable est hors du périmètre de ce billet (qui vérifie la connexion WebRTC, pas la distribution) et aurait ajouté des exigences de signature/notarisation macOS non pertinentes ici. Documenté aussi dans examples/tauri-shell/README.md.

Lancement — testé-fonctionne (au sens : le processus démarre et reste stable)

Le binaire a été lancé directement (./src-tauri/target/release/tauri-shell) en arrière-plan shell, à deux reprises :

  1. Sans stack LiveKit démarrée : processus toujours actif après 3 s, aucune sortie stderr, arrêt propre au kill.
  2. Stack LiveKit démarrée (voir plus bas), jeton fraîchement signé : même résultat — processus stable 6 s, aucune erreur, arrêt propre.

Aucun crash, aucune exception Rust, aucun message d’erreur dans les deux cas. C’est une preuve réelle que le binaire s’exécute sur macOS, pas une supposition.

Ce qui n’a pas été tenté, et pourquoi — non testé

  • Confirmation visuelle que la fenêtre s’affiche et que la page HTML s’y charge. Tauri sur macOS ne redirige pas la console WKWebView vers stdout du processus par défaut (contrairement à Chrome/Playwright utilisé par les tests E2E existants) : il n’y a pas de journal exploitable depuis le shell. La vérification visuelle nécessiterait de piloter l’écran réel de la machine de l’utilisateur (capture d’écran, clics) depuis une tâche d’arrière-plan non surveillée — délibérément évité ici : le binaire n’est pas un .app enregistré (build --no-bundle), donc les outils d’automatisation d’applications macOS ne le reconnaissent même pas comme cible pilotable (list_apps avec le nom du binaire renvoie une liste vide) — confirmé en essayant.
  • Connexion réelle au serveur de signalisation LiveKit observée avec succès. Un serveur LiveKit de développement était réellement joignable pendant l’essai n°2 (curl http://localhost:7880OK, provenant du stack docker-compose d’un autre chantier en parallèle sur la même machine — même docker-compose.yml, mêmes clés devkey/secret, jamais dupliquées ni modifiées). Le jeton a été signé avec succès (signature JWT locale, aucun appel réseau nécessaire — voir scripts/mint-dev-token.mjs). Mais faute de journal WKWebView ou de capture d’écran, l’issue réelle de room.connect() (succès, échec, timeout) n’a pas été observée. Absence de crash n’est pas la preuve d’une connexion réussie — ce rapport ne prétend pas ce qu’il n’a pas vu.
  • Capture caméra/micro réelle. Nécessite une permission macOS accordée interactivement (boîte de dialogue système) : accorder cette permission au nom de l’utilisateur, sans lui, depuis une tâche d’arrière-plan non surveillée, active la caméra/le micro réels de sa machine — jugé inapproprié à faire seul. Documenté comme non testé, pas comme un échec.

Pourquoi ce n’est pas maquillé en succès : le scénario 13 du billet exige de ne jamais glisser implicitement d’un état à l’autre. « Le processus ne crashe pas » et « la salle a été rejointe avec succès » sont deux affirmations différentes ; seule la première est prouvée ici.


Linux (CI, ubuntu-latest) — job isolé + vérification locale par conteneur

Le job CI

.github/workflows/ci.yml gagne un nouveau job, tauri-shell-linux, volontairement isolé :

  • Aucun needs: — ne dépend d’aucun autre job, et aucun autre job ne dépend de lui.
  • continue-on-error: true au niveau du job entier : un échec ici ne fait jamais échouer le workflow global, donc ne bloque jamais la fusion des autres billets (scénario 14). Une régression y reste visible (une annotation ::warning:: est émise si le lancement échoue autrement que par timeout), sans jamais devenir bloquante.
  • N’installe/ne construit que examples/tauri-shell — aucune des huit portes de qualité existantes n’est modifiée.

Ce job n’a pas encore tourné sur GitHub Actions au moment de la rédaction (il tourne à la prochaine ouverture de PR). Pour ne pas se contenter d’un fichier YAML non vérifié, les mêmes étapes ont été reproduites dans un vrai conteneur ubuntu:24.04 (image de base de ubuntu-latest au moment de ce billet) depuis cette session — résultats ci-dessous, avec la sortie de commande réelle à l’appui.

Vérification par conteneur — résultats réels

Exécuté depuis cette session : docker run --rm -v <dépôt>:/src:ro ubuntu:24.04 bash … — le dépôt est copié dans le conteneur avant pnpm install (jamais écrit dans le node_modules macOS monté). Mêmes versions que le job CI : Node 22 (nodesource, v22.23.2 installé), pnpm@12.4.2 (corepack), Rust stable (rustc 1.98.1, cargo 1.98.1, via rustup).

Dépendances système — testé-échoue puis corrigé (cause exacte). Premier essai avec libappindicator3-dev et libayatana-appindicator3-dev dans la même commande apt-get install :

The following packages have unmet dependencies:
 libappindicator3-dev : Depends: libappindicator3-1 (= 12.10.1+20.10.20200706.1-0ubuntu5)
 libayatana-appindicator3-dev : Conflicts: libappindicator3-dev
E: Unable to correct problems, you have held broken packages.

Les deux paquets sont mutuellement exclusifs sur Ubuntu 24.04 (noble) — libappindicator3-dev vient d’une doc Tauri plus ancienne. Corrigé en ne gardant que libayatana-appindicator3-dev (le job CI et examples/tauri-shell n’installent plus que celui-ci). Après correction, apt-get install réussit sans erreur.

Build — testé-fonctionne. pnpm exec tauri build --no-bundle a compilé les mêmes ~415 crates que sur macOS, cette fois avec le backend WebKitGTK (webkit2gtk, gdk, soup3, cairo-rs, tao…) au lieu de WKWebView :

Finished `release` profile [optimized] target(s) in 1m 26s
Built application at: /work/examples/tauri-shell/src-tauri/target/release/tauri-shell

Aucune erreur de compilation Rust, aucun contournement.

Lancement — testé-fonctionne (processus stable), avec une limite matérielle réelle documentée. Lancé sous xvfb-run --auto-servernum -- timeout 8 ./tauri-shell (même motif Xvfb que la Porte 7 E2E) :

libEGL warning: DRI3 error: Could not get DRI3 device
libEGL warning: Ensure your X server supports DRI3 to get accelerated rendering
launch exit code (124 = timeout, i.e. it was still running): 124

Code de sortie 124 = timeout a dû tuer le processus après 8 s parce qu’il tournait encore — même signal de stabilité que sur macOS, pas un crash. L’avertissement DRI3/EGL est réel et attendu : Xvfb ne fournit aucun GPU, WebKitGTK bascule sur un rendu logiciel. Non bloquant ici (le processus continue de tourner), mais documenté comme limite connue pour un futur test visuel (un rendu logiciel peut suffire pour une capture d’écran automatisée, mais serait plus lent qu’un rendu accéléré).

Ce que cette vérification locale ne couvre pas, par rapport au job CI réel. Ce conteneur local n’a pas démarré le stack docker-compose.yml (Docker-dans-Docker non configuré pour cette vérification rapide) : la tentative de connexion réelle au serveur de signalisation LiveKit n’a donc pas été exercée ici, contrairement au job tauri-shell-linux dans .github/workflows/ci.yml, qui lance docker compose up -d avant de construire et lancer le scaffold. Le job CI lui-même n’a pas encore tourné sur GitHub Actions au moment de la rédaction — il tournera à la prochaine exécution du workflow sur cette PR.

Capture caméra/micro — non testé. Même limite que macOS : aucune tentative de getUserMedia/getDisplayMedia observée. De plus, le motif Chrome existant (--use-fake-device-for-media-stream, --use-fake-ui-for-media-permissions) est spécifique à Chromium — il ne s’applique pas à WebKitGTK, le moteur utilisé par la WebView Tauri sur Linux. WebKitGTK a son propre mécanisme de périphérique factice (GStreamer videotestsrc/audiotestsrc), non mis en place ni testé ici — documenté comme un écart réel entre l’infrastructure E2E existante (Chromium) et ce scaffold (WebKitGTK), pas une simple hypothèse.

Matrice de compatibilité Linux — causes exactes

AspectÉtatCause exacte
Dépendances système (apt)testé-échoue → corrigélibappindicator3-dev et libayatana-appindicator3-dev sont en conflit direct sur Ubuntu 24.04 (noble) ; seul libayatana-appindicator3-dev s’installe
Compilation Rust (cargo/tauri build --no-bundle)testé-fonctionneAucune, compile proprement avec WebKitGTK
Lancement du binaire sous Xvfbtesté-fonctionne (stable)
Rendu accéléré (GPU)testé-échoue (non bloquant)Xvfb n’expose aucun périphérique DRI3 ; WebKitGTK bascule sur un rendu logiciel
Connexion réelle au serveur de signalisation LiveKitnon testé (vérification locale) / prévu en CINon exercé dans cette vérification locale (pas de Docker-dans-Docker) ; le job CI réel démarre docker-compose.yml avant de lancer le scaffold, mais n’a pas encore tourné sur GitHub Actions
Capture caméra/micro facticenon testéLe motif Chrome --use-fake-device-for-media-stream ne s’applique pas à WebKitGTK ; équivalent GStreamer non mis en place

Windows — non testé

Aucune machine Windows n’est disponible dans cet environnement d’exécution. Ni build, ni lancement, ni aucune autre vérification n’ont été tentés. Documenté explicitement comme non testé — ni comme un succès supposé, ni comme un échec (scénario 5).


Ce qui a été délibérément laissé de côté

  • Empaquetage distribuable (.app/.dmg sur macOS, .deb/.AppImage/.rpm sur Linux) : hors périmètre — ce billet vérifie la connexion WebRTC dans une WebView Tauri, pas un pipeline de distribution. bundle.active: false partout.
  • Commandes IPC Tauri : aucune définie. La WebView parle directement à LiveKit en WebSocket/WebRTC ; src-tauri n’ouvre qu’une fenêtre.
  • Intégration aux portes de qualité existantes : examples/tauri-shell ne définit aucun script build/lint/typecheck/testturbo l’ignore silencieusement dans tous les jobs existants. Seul le nouveau job isolé le touche.