# Plan: pmowebrenderer - Améliorations et Multi-client avec DSP

## Objectifs

1. **Améliorer l'intégration UPnP Control** - Meilleur fonctionnement des commandes Play/Pause/Seek
   - Contrôle piloté près de la sortie (streaming) plutôt qu'au début du pipeline
   - Pour Pause: latence actuelle trop importante
   - Play/Pause/Seek doivent fonctionner simultanément sur tous les clients

2. **Améliorer la performance - Latence** - Réduire le délai entre l'envoi et la lecture

3. **Ajouter le support multi-client avec DSP** - Chaque client peut avoir son propre pipeline DSP

## Comportement UPnP Control

### Mode Radio (flux infini)
- Pas de pause possible, hanya next ou stop
- Seek n'a pas de sens


### Architecture
```
PlayerSource → ResamplingNode → ToI24Node
                                           ├──→ [DSP Client 1] → StreamingOggFlacSink 1
                                           ├──→ [DSP Client 2] → StreamingOggFlacSink 2
                                           └──→ ... (dynamique)
```

Le control point UPnP voit UN seul Media Renderer. Les commandes Play/Pause/Seek affectent TOUTES les sorties client simultanément.

## État Actuel

Le pipeline actuel est linéaire pour un seul client:
```
PlayerSource → ResamplingNode (96kHz) → ToI24Node → StreamingOggFlacSink
```

**Note importante:** Utiliser les crates pmoaudio et pmoaudio-ext existantes. Il est possible d'avoir plusieurs `StreamingOggFlacSink` consommant le même flux. Après ToI24Node, brancher en étoiles les différents DSP pour les différents clients.

## Plan d'Implémentation

### Phase 1: Amélioration UPnP Control

1. **Analyser les handlers existants** dans `handlers.rs`
2. **Identifier les problèmes** avec Play/Pause/Seek:
   - Timing des transitions d'état
   - Gestion des erreurs
   - Synchronisation entre clients HTTP et état UPnP
3. **Améliorer la fiabilité** des commandes
   - Piloter le contrôle près de la sortie (streaming)
   - Différerencier le comportement radio vs piste finie

### Phase 2: Amélioration Latence

1. **Réduire le buffer** dans `StreamingOggFlacSink`
2. **Optimiser le pacing** (actuellement max 0.5s ahead)
3. **Améliorer la directité** du chemin audio

### Phase 3: Architecture Multi-client avec DSP

1. **Refactorer le pipeline** pour supporter plusieurs clients comme décrit ci-dessus

2. **Créer un système de DSP** dans pmoaudio ou pmoaudio-ext:
   - Interface commune pour les effets audio
   - Config des DSP via PMOconfig
   - Room correction: equalizer, FIR filter, delay, gain

3. **Gérer le cycle de vie**:
   - Création du pipeline par client
   - Nettoyage lors de la déconnexion
   - Partage de la source commune entre clients

## Fichiers à Modifier

- `pipeline.rs` - Refactoring pour multi-client
- `handlers.rs` - Amélioration UPnP control
- `stream.rs` - Gestion multi-client
- `state.rs` - État par client
- pmoaudio ou pmoaudio-ext pour les mécanismes DSP

## Défis Potentiels

- Performance CPU avec plusieurs clients
- Synchronisation des clients avec le même contenu
- Gestion du gapless entre les pistes avec multi-client

### Gestion de la Pause

**Option recommandée: Silence (zéros)**
- Pendant la pause, continuer à envoyer des zéros encodés en FLAC
- Le client HTTP maintient sa connexion TCP alive
- Pas de reconnexion nécessaire quand on reprend la lecture
- Avantage: Seamless pour le client

**Pourquoi pas réduction du sample rate:**
- Le header FLAC définit le sample rate en固定entête
- Changer le sample rate en cours de flux invalidate le flux entier
- Rebuild du flux serait plus complexe que le gain obtenu
- FLAC compresse très bien les zéros de toute façon (beaucoup de répétitions)

**Autre option envisagée mais non recommandée:**
- Suspendre l'envoi: Le client HTTP va timeout et se déconnecter
- Segment OGG avec metadata: Complexe à implémenter, nécessite modification du client

### Phase 0: StreamingOggFlacSink avec contrôle Pause

**Distinction Radio vs Pistes finies:**

| Mode | Comportement pendant Pause |
|------|---------------------------|
| **Radio (flux infini)** | Les chunks qui arrivent sont ignorés/perdus. On envoie du silence. La source continue à produire mais on n'en tient pas compte. |
| **Pistes finies** | On bloque la consommation des chunks. Par backpressure, le pipeline en amont s'arrête (TimerBufferNode arrête d'envoyer). La lecture est truly arrêtée. |

**Architecture actuelle analysée:**
```
AudioSegment → StreamingOggFlacSink → FLAC encoder → OGG wrapper → timed_broadcast → clients
```

**Implémentation suggérée:**

1. **État de lecture distingué:**
   - `PlaybackMode::Radio` - ignore les chunks entrants pendant pause
   - `PlaybackMode::Track` - bloque la consommation (backpressure)

2. **Dans SharedSinkContext:**
   ```rust
   pub enum PlaybackMode {
       Radio,  // Flux infini - ignore chunks pendant pause
       Track,  // Piste finie - block par backpressure
   }
   
   pub playback_mode: PlaybackMode,
   pub is_paused: Arc<AtomicBool>,
   ```

3. **Traitement différent selon le mode:**
   - **Radio**: Si `is_paused`, envoyer silence (zéros) mais perdre les chunks entrants
   - **Track**: Si `is_paused`, ne pas consommer les chunks → backpressure → arrêt du pipeline en amont

4. **Transition automatique:**
   - Détecter le type de contenu via les métadonnées du TrackBoundary
   - **Enrichir TrackBoundary** avec un champ `stream_type`:
     ```rust
     pub enum StreamType {
         Continuous,  // Radio/webcast - flux infini
         Finite,       // Piste/album - flux avec fin définie
     }
     
     pub stream_type: StreamType,
     ```
   - Si durée inconnue = Radio (Continuous), si durée connue = Track (Finite)
