Files
pmomusic/Blackboard/ToThinkAbout/webrenderer.md
Eric Coissac 1e882ba6c3 feat: implémentation du WebRenderer UPnP privé par navigateur
Ajout de la fonctionnalité WebRenderer permettant à chaque navigateur connecté de devenir un MediaRenderer UPnP privé.

- Création du crate pmowebrenderer avec l'architecture complète
- Implémentation des handlers SOAP → WebSocket pour les services AVTransport, RenderingControl et ConnectionManager
- Intégration avec le ControlPoint pour l'enregistrement dynamique des renderers
- Gestion des sessions avec timeout et cleanup automatique
- Support des commandes de transport (play, pause, stop, seek) et du contrôle du volume
- Mise à jour des dépendances dans Cargo.toml et Cargo.lock
- Documentation de l'architecture dans Blackboard/Architecture/webrenderer.md
2026-02-19 16:15:18 +01:00

4.2 KiB
Raw Blame History

Parfait. Voici un schéma fonctionnel minimal pour un MediaRenderer UPnP privé par navigateur avec token. Lidée est de rester fidèle à ton backend Rust existant et à la webapp Vue.js. En s'appuyant sur l'architecture de PMOMusic, j'aimerais que tu proposes un plan détaillé pour implémenter un tel système de Média Renderer.

  • L'application web se trouve dans: @webapp
  • Tu as un prototype de Média Renderer dans: @pmomediarenderer
  • Le contrôle point est dans : @pmocontrol
  • Tu implémenteras ce nouveau système de Média Renderer dans la CRATe pmowebrenderer

Tu mettras une version du plan en Markdown dans le répertoire @Architecture .


1. Flow général

Browser (Vue.js Control Point)
 ┌───────────────┐
 │   UI / audio  │
 │  WebSocket    │
 └───────▲───────┘
         │ token
         │
         ▼
Rust backend (UPnP MediaRenderer)
 ┌───────────────────────────┐
 │ Token → Renderer mapping  │
 │ Device XML / SOAP endpoints│
 │ Play/Pause/Stop → WS → Browser │
 └───────────────────────────┘

2. Étapes détaillées

a) Création du renderer

  1. Le navigateur se connecte via WebSocket ou HTTP.

  2. Rust génère un token unique pour ce client :

    use uuid::Uuid;
    let token = Uuid::new_v4().to_string();
    
  3. Rust crée une instance MediaRenderer privée, associée à ce token :

    • Device description XML : /renderer/<token>/desc.xml
    • AVTransport SOAP : /renderer/<token>/avtransport
    • RenderingControl SOAP : /renderer/<token>/renderingcontrol

b) Control Point

  • La webapp Vue.js reçoit le token et la “déclare” au Control Point :
const renderer = {
  token: "abcd-1234-efgh",
  name: "Browser Renderer"
};

// Ajout au control point local
controlPoint.addRenderer(renderer);
  • Toutes les commandes Play/Pause/Stop incluent ce token :
ws.send(JSON.stringify({
  token: renderer.token,
  action: "play",
  uri: "http://localhost:8080/media.mp3"
}));

c) Backend Rust : dispatcher les commandes

  • Rust reçoit le JSON avec le token.
  • Vérifie que le token correspond à un renderer actif.
  • Transmet la commande au navigateur via WebSocket (ou HTTP push) :
match msg.action.as_str() {
    "play" => send_ws_to_browser(&token, format!("play:{}", msg.uri)),
    "pause" => send_ws_to_browser(&token, "pause".to_string()),
    "stop" => send_ws_to_browser(&token, "stop".to_string()),
    _ => (),
}
  • Rust met à jour létat du renderer (AVTransport/RenderingControl) pour le Control Point.

d) Lecture côté navigateur

  • Le navigateur reçoit la commande via WebSocket et pilote <audio> :
ws.onmessage = (evt) => {
  const msg = evt.data;
  if(msg.startsWith("play:")) {
    audio.src = msg.split(":")[1];
    audio.play();
  } else if(msg === "pause") {
    audio.pause();
  } else if(msg === "stop") {
    audio.pause();
    audio.currentTime = 0;
  }
};

e) Fermeture / cleanup

  • Quand le navigateur se déconnecte :

    • Rust supprime le renderer associé au token
    • Émet un byebye virtuel pour le Control Point (si nécessaire)
    • Libère toutes les ressources

3. Points clés

  1. Token unique = session privée + sécurité
  2. Pas besoin de SSDP / annonce : le renderer est dédié à un navigateur connu
  3. Control Point Vue.js sait exactement quel renderer utiliser
  4. Rust backend reste seul responsable de limplémentation UPnP
  5. Lecture réelle = navigateur via <audio> ou <video>

💡 Ce modèle est très proche de ce que font Mopidy avec Iris, Kodi Remote, ou Chromecast / local cast : le device est connu et dédié, pas besoin de découverte réseau.