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
4.2 KiB
Parfait. Voici un schéma fonctionnel minimal pour un MediaRenderer UPnP privé par navigateur avec token. L’idé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
-
Le navigateur se connecte via WebSocket ou HTTP.
-
Rust génère un token unique pour ce client :
use uuid::Uuid; let token = Uuid::new_v4().to_string(); -
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
- Device description XML :
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
- Token unique = session privée + sécurité
- Pas besoin de SSDP / annonce : le renderer est dédié à un navigateur connu
- Control Point Vue.js sait exactement quel renderer utiliser
- Rust backend reste seul responsable de l’implémentation UPnP
- 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.