Refactoriser MusicRenderer pour un comportement stateful complet
Cette modification refactorise l'architecture pour que chaque `MusicRenderer` gère son propre thread de surveillance (watcher), au lieu de déléguer le polling au `ControlPoint` centralisé. - Ajout d'un module `watcher.rs` avec `WatchStrategy`, `WatchedState` et fonctions helper - Implémentation de `start_watching()` et `stop_watching()` dans `MusicRenderer` - Centralisation de la gestion du watcher dans le constructeur et les méthodes `has_been_seen_now()`/`mark_as_offline()` - Suppression du polling central (~140 lignes) dans `control_point.rs` - Simplification du `registry.rs` avec suppression des appels manuels `start/stop_watching()` - Correction du bug dans `refresh_device_presence()` pour le traitement offline→online - Préparation pour le support futur des notifications push (OpenHome, Chromecast) L'architecture est maintenant plus robuste avec une meilleure encapsulation, cohérence des événements et une gestion automatique du watcher.
This commit is contained in:
114
Blackboard/Done/stateful_music_renderer.md
Normal file
114
Blackboard/Done/stateful_music_renderer.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Tâche terminée : Rendre MusicRenderer complètement stateful
|
||||
|
||||
## Objectif
|
||||
|
||||
Refactoriser l'architecture pour que chaque `MusicRenderer` gère son propre thread de surveillance (watcher), au lieu de déléguer le polling au `ControlPoint` centralisé.
|
||||
|
||||
## Motivation
|
||||
|
||||
1. **Encapsulation** - Tout l'état et le comportement d'un renderer au même endroit
|
||||
2. **Cohérence** - Les événements sont émis là où l'état change
|
||||
3. **Adaptabilité par backend** - Chaque backend peut avoir sa propre stratégie de surveillance (polling vs push)
|
||||
4. **Auto-advance spécifique** - La logique d'auto-advance peut être adaptée par backend
|
||||
5. **Simplicité du ControlPoint** - Il devient un simple registry/coordinateur
|
||||
|
||||
---
|
||||
|
||||
## Résumé de l'implémentation
|
||||
|
||||
### Fichiers créés
|
||||
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| `pmocontrol/src/music_renderer/watcher.rs` | Module watcher avec `WatchStrategy`, `WatchedState` et fonctions helper |
|
||||
|
||||
### Fichiers modifiés
|
||||
|
||||
| Fichier | Modification |
|
||||
|---------|--------------|
|
||||
| `pmocontrol/src/music_renderer/musicrenderer.rs` | Champs watcher, méthodes `start/stop_watching()`, logique auto-advance, gestion automatique dans constructeur et `DeviceOnline` |
|
||||
| `pmocontrol/src/music_renderer/mod.rs` | Export du module `watcher` |
|
||||
| `pmocontrol/src/registry.rs` | Simplifié : plus d'appels manuels watcher |
|
||||
| `pmocontrol/src/control_point.rs` | Suppression polling central (~140 lignes), `RendererRuntimeSnapshot`, `handle_renderer_event()` |
|
||||
|
||||
---
|
||||
|
||||
## Architecture finale
|
||||
|
||||
### WatchStrategy
|
||||
|
||||
```rust
|
||||
pub enum WatchStrategy {
|
||||
Polling { interval_ms: u64 }, // UPnP, LinkPlay, Arylic (500ms)
|
||||
Push, // Futur : notifications push
|
||||
Hybrid { polling_interval_ms: u64 }, // OpenHome, Chromecast
|
||||
}
|
||||
```
|
||||
|
||||
### Gestion automatique du watcher
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ GESTION AUTOMATIQUE DU WATCHER │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Création MusicRenderer ──► constructeur ──► start_watching() │
|
||||
│ │
|
||||
│ has_been_seen_now() ──► si !was_online ──► start_watching() │
|
||||
│ │
|
||||
│ mark_as_offline() ──► stop_watching() ──► online = false │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Flux offline/online
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ FLUX ONLINE │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ SSDP Discovery ──► push_renderer() ──► constructeur │
|
||||
│ ──► start_watching() │
|
||||
│ │
|
||||
│ SSDP Alive (offline→online) ──► has_been_seen_now() │
|
||||
│ ──► start_watching() │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ FLUX OFFLINE │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ SSDP ByeBye / Timeout ──► mark_as_offline() │
|
||||
│ ──► stop_watching() │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Points techniques clés
|
||||
|
||||
- **Thread safety** : `AtomicBool` avec `Ordering::SeqCst` pour le signal d'arrêt
|
||||
- **Idempotence** : `start_watching()` et `stop_watching()` sont idempotents
|
||||
- **Nommage** : Thread nommé `watcher-{friendly_name}` pour debug
|
||||
- **Polling** : 500ms pour position/état, 1s pour volume/mute
|
||||
- **Auto-advance** : Géré dans `handle_state_change()` du MusicRenderer
|
||||
- **Compensation bugs** : `compute_logical_playback_state()` corrige les comportements Arylic/LinkPlay
|
||||
|
||||
---
|
||||
|
||||
## Rounds de vérification
|
||||
|
||||
| Round | Objectif | Résultat |
|
||||
|-------|----------|----------|
|
||||
| 1 | Implémentation initiale | OK |
|
||||
| 2 | Vérifier transition offline→online | Bug trouvé et corrigé dans `refresh_device_presence()` |
|
||||
| 3 | Audit complet des chemins offline/online | Tous les chemins vérifiés OK |
|
||||
| 4 | Centralisation dans `MusicRenderer` | Gestion automatique dans constructeur et `DeviceOnline` |
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
L'architecture est maintenant plus robuste :
|
||||
- Impossible d'oublier de démarrer/arrêter le watcher
|
||||
- Le `registry.rs` est simplifié
|
||||
- Préparation pour le support futur des notifications push (OpenHome, Chromecast)
|
||||
Reference in New Issue
Block a user