316 lines
13 KiB
Markdown
316 lines
13 KiB
Markdown
|
|
# 🔍 AUDIT COMPLET - Moteur d'Encodage Audio
|
||
|
|
|
||
|
|
**Date**: 2025-01-27
|
||
|
|
**Service**: `veza-stream-server`
|
||
|
|
**Mission**: P0 - Implémentation complète du moteur d'encodage audio
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. ÉTAT ACTUEL DU CODE
|
||
|
|
|
||
|
|
### 1.1. Structures Existantes ✅
|
||
|
|
|
||
|
|
#### `src/core/encoder.rs`
|
||
|
|
- **`EncoderPool`** : Structure définie mais **VIDE** (ligne 253: `// TODO: Implémentation réelle des encodeurs`)
|
||
|
|
- Pool d'encodeurs par codec (Opus, AAC, MP3, FLAC)
|
||
|
|
- Métriques d'utilisation (`EncoderMetrics`)
|
||
|
|
- Configuration (`EncoderPoolConfig`)
|
||
|
|
- **PROBLÈME**: Les pools sont initialisés mais vides, aucun encodeur réel n'est créé
|
||
|
|
|
||
|
|
- **`EncoderPipeline`** : Structure pour pipeline d'encodage
|
||
|
|
- Support multi-sortie (`Vec<EncoderOutput>`)
|
||
|
|
- Chaîne d'effets audio
|
||
|
|
- **PROBLÈME**: `start_processing()` est un TODO (ligne 459)
|
||
|
|
|
||
|
|
- **`AudioCodec`** : Enum complet avec Opus, AAC, MP3, FLAC
|
||
|
|
- Configuration détaillée par codec
|
||
|
|
- ✅ Bien défini
|
||
|
|
|
||
|
|
- **`QualityProfile`** : Profils prédéfinis (Voice, Music Standard, High, Lossless)
|
||
|
|
- ✅ Fonctionnel
|
||
|
|
|
||
|
|
#### `src/transcoding/ffmpeg/command_builder.rs`
|
||
|
|
- **`FfmpegCommandBuilder`** : Builder pattern pour commandes FFmpeg
|
||
|
|
- ✅ Support HLS basique (`-f hls`, `-hls_time`, `-hls_playlist_type vod`)
|
||
|
|
- ✅ Support codecs audio (AAC, MP3, Opus, FLAC)
|
||
|
|
- ✅ Gestion bitrate, sample_rate, channels
|
||
|
|
- **MANQUE**: Option `-threads 1` pour isolation CPU
|
||
|
|
- **MANQUE**: Option `-map 0:a` pour forcer audio-only
|
||
|
|
- **MANQUE**: Pattern de nommage segments personnalisable
|
||
|
|
|
||
|
|
#### `src/transcoding/ffmpeg/progress_parser.rs`
|
||
|
|
- **`FfmpegProgress`** : Parser pour stderr FFmpeg
|
||
|
|
- ✅ Parse frame, fps, time, bitrate, speed
|
||
|
|
- ✅ Regex robuste
|
||
|
|
- ✅ Support audio-only (sans frame/fps)
|
||
|
|
|
||
|
|
#### `src/transcoding/pipeline/`
|
||
|
|
- **`TranscodingJob`** : Structure de job existante
|
||
|
|
- ✅ UUID, track_id, input_path, output_dir
|
||
|
|
- ✅ Status (Pending, Processing, Completed, Failed, Cancelled)
|
||
|
|
- ✅ Priority (Background, Normal, Urgent)
|
||
|
|
- ✅ Progress tracking
|
||
|
|
- **PROBLÈME**: Utilise `String` pour `track_id` au lieu de `Uuid`
|
||
|
|
|
||
|
|
- **`TranscodingWorker`** : Worker basique
|
||
|
|
- ✅ Exécute FFmpeg avec timeout (5 min)
|
||
|
|
- ✅ Gestion erreurs et retry
|
||
|
|
- ✅ Vérification manifest HLS généré
|
||
|
|
- **MANQUE**: Pas de parsing des segments produits
|
||
|
|
- **MANQUE**: Pas de capture stderr en streaming
|
||
|
|
- **MANQUE**: Pas de persistance en DB
|
||
|
|
|
||
|
|
- **`job_manager.rs`** et **`queue.rs`** : Gestion de queue
|
||
|
|
- ✅ Structure présente
|
||
|
|
- ⚠️ À vérifier l'intégration avec le nouveau système
|
||
|
|
|
||
|
|
#### `src/audio/pipeline.rs`
|
||
|
|
- **`AudioPipeline`** : Pipeline de traitement audio
|
||
|
|
- ✅ Décodage → Traitement → Encodage
|
||
|
|
- ✅ Support effets audio
|
||
|
|
- ✅ Normalisation
|
||
|
|
- **NOTE**: Conçu pour streaming temps réel, pas pour batch encoding
|
||
|
|
|
||
|
|
#### `src/routes/transcode.rs`
|
||
|
|
- Routes API existantes :
|
||
|
|
- ✅ `POST /v1/stream/transcode`
|
||
|
|
- ✅ `GET /v1/stream/job/:id`
|
||
|
|
- ✅ `GET /v1/stream/hls/:job_id/index.m3u8`
|
||
|
|
- ✅ `GET /v1/stream/hls/:job_id/:segment`
|
||
|
|
- **PROBLÈME**: Utilise `job_id` au lieu de `track_id` + `quality`
|
||
|
|
|
||
|
|
### 1.2. Ce Qui Manque Totalement ❌
|
||
|
|
|
||
|
|
1. **Pool d'encodeurs fonctionnel**
|
||
|
|
- Aucun worker thread réel
|
||
|
|
- Aucune queue async_channel
|
||
|
|
- Aucun spawn de processus FFmpeg
|
||
|
|
|
||
|
|
2. **Structure `EncodeJob`**
|
||
|
|
- Pas de structure dédiée pour encodage (utilise `TranscodingJob` qui est générique)
|
||
|
|
- Pas de mapping qualité → codec/bitrate automatique
|
||
|
|
|
||
|
|
3. **Pipeline d'encodage complet**
|
||
|
|
- Pas de vérification `track.source_path` en DB
|
||
|
|
- Pas de création répertoire `/data/streams/<track_id>/<quality>/`
|
||
|
|
- Pas de parsing des segments HLS produits
|
||
|
|
- Pas d'insertion en DB (`stream_segments`)
|
||
|
|
|
||
|
|
4. **Migrations SQL**
|
||
|
|
- Table `stream_jobs` n'existe pas
|
||
|
|
- Table `stream_segments` n'existe pas
|
||
|
|
- Pas d'index pour performance
|
||
|
|
|
||
|
|
5. **API REST manquante**
|
||
|
|
- `POST /admin/stream/encode/:track_id` (lance encodage)
|
||
|
|
- `GET /admin/stream/status/:track_id` (statut multi-qualité)
|
||
|
|
- `GET /stream/:track_id/:quality/index.m3u8` (playlist HLS)
|
||
|
|
- `GET /stream/:track_id/:quality/segment_*.ts` (segments)
|
||
|
|
|
||
|
|
6. **Monitoring FFmpeg**
|
||
|
|
- Pas de capture stderr en streaming
|
||
|
|
- Pas de logs tracing pour avancement
|
||
|
|
- Pas de détection crashes FFmpeg
|
||
|
|
|
||
|
|
7. **Parsing segments HLS**
|
||
|
|
- Pas de parsing du manifest `.m3u8` pour extraire segments
|
||
|
|
- Pas de calcul durée par segment
|
||
|
|
- Pas de validation segments générés
|
||
|
|
|
||
|
|
### 1.3. Incohérences / À Refactor ⚠️
|
||
|
|
|
||
|
|
1. **Duplication structures**
|
||
|
|
- `src/core/encoder.rs` : `EncoderPool`, `EncoderPipeline` (abstrait, traits)
|
||
|
|
- `src/transcoding/pipeline/` : `TranscodingJob`, `TranscodingWorker` (concret, FFmpeg)
|
||
|
|
- **SOLUTION**: Utiliser `TranscodingJob` comme base, créer `EncodeJob` wrapper si besoin
|
||
|
|
|
||
|
|
2. **Conventions MIME / Format**
|
||
|
|
- `AudioCodec` dans `core/encoder.rs` (enum avec variants)
|
||
|
|
- `AudioCodec` dans `transcoding/codecs/mod.rs` (enum simple)
|
||
|
|
- **SOLUTION**: Unifier vers `transcoding/codecs/mod.rs`
|
||
|
|
|
||
|
|
3. **Gestion CPU concurrency**
|
||
|
|
- `EncoderPoolConfig.max_parallel_encodes = num_cpus::get() * 2` (trop agressif)
|
||
|
|
- Pas de limite réelle dans `TranscodingWorker`
|
||
|
|
- **SOLUTION**: Pool avec `min(nb_cpu / 2, 8)` workers
|
||
|
|
|
||
|
|
4. **Handling erreurs FFmpeg**
|
||
|
|
- `TranscodingWorker` capture exit code mais pas stderr détaillé
|
||
|
|
- Pas de parsing erreurs spécifiques (codec manquant, file not found, etc.)
|
||
|
|
- **SOLUTION**: Parser stderr pour erreurs courantes
|
||
|
|
|
||
|
|
5. **Routes API incohérentes**
|
||
|
|
- Routes existantes: `/v1/stream/hls/:job_id/...`
|
||
|
|
- Besoin: `/stream/:track_id/:quality/...`
|
||
|
|
- **SOLUTION**: Garder les deux (rétrocompatibilité) ou migrer progressivement
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. DESIGN PROPOSÉ
|
||
|
|
|
||
|
|
### 2.1. Architecture
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ API REST Layer │
|
||
|
|
│ POST /admin/stream/encode/:track_id │
|
||
|
|
│ GET /admin/stream/status/:track_id │
|
||
|
|
│ GET /stream/:track_id/:quality/index.m3u8 │
|
||
|
|
│ GET /stream/:track_id/:quality/segment_*.ts │
|
||
|
|
└────────────────────┬────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ Encoding Service Layer │
|
||
|
|
│ - Vérifie track.source_path en DB │
|
||
|
|
│ - Crée répertoire /data/streams/<track_id>/<quality>/ │
|
||
|
|
│ - Crée EncodeJob et l'envoie dans la queue │
|
||
|
|
└────────────────────┬────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ Encoder Pool (Worker Threads) │
|
||
|
|
│ - Queue: async_channel::Receiver<EncodeJob> │
|
||
|
|
│ - Workers: Vec<EncoderWorker> (1 thread = 1 FFmpeg) │
|
||
|
|
│ - Nombre: min(nb_cpu / 2, 8) │
|
||
|
|
└────────────────────┬────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ FFmpeg Execution │
|
||
|
|
│ - Build command avec FfmpegCommandBuilder │
|
||
|
|
│ - Spawn processus FFmpeg │
|
||
|
|
│ - Capture stderr en streaming │
|
||
|
|
│ - Parse progression (FfmpegProgress) │
|
||
|
|
│ - Détecte crashes et erreurs │
|
||
|
|
└────────────────────┬────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ Post-Processing │
|
||
|
|
│ - Parse manifest .m3u8 pour extraire segments │
|
||
|
|
│ - Calcule durée par segment │
|
||
|
|
│ - Insère segments en DB (stream_segments) │
|
||
|
|
│ - Met à jour stream_jobs.status = 'done' │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2. Structures de Données
|
||
|
|
|
||
|
|
#### `EncodeJob` (nouveau)
|
||
|
|
```rust
|
||
|
|
pub struct EncodeJob {
|
||
|
|
pub track_id: Uuid,
|
||
|
|
pub input_path: PathBuf,
|
||
|
|
pub output_dir: PathBuf,
|
||
|
|
pub codec: AudioCodec,
|
||
|
|
pub bitrate: u32,
|
||
|
|
pub quality: String, // "low", "medium", "high", "hi_res"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `EncoderWorker` (nouveau)
|
||
|
|
```rust
|
||
|
|
pub struct EncoderWorker {
|
||
|
|
id: usize,
|
||
|
|
receiver: async_channel::Receiver<EncodeJob>,
|
||
|
|
db_pool: PgPool,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Tables SQL
|
||
|
|
- `stream_jobs`: id, track_id, status, created_at, updated_at, error_message
|
||
|
|
- `stream_segments`: id, track_id, quality, segment_index, path, duration, created_at
|
||
|
|
|
||
|
|
### 2.3. Mapping Qualité → Codec/Bitrate
|
||
|
|
|
||
|
|
| Qualité | Codec | Bitrate | Sample Rate | Channels | HLS Segment Time |
|
||
|
|
|---------|-------|---------|-------------|----------|------------------|
|
||
|
|
| `low` | AAC | 64kbps | 22.05kHz | 1 (mono) | 4s |
|
||
|
|
| `medium`| AAC | 128kbps | 44.1kHz | 2 (stereo) | 4s |
|
||
|
|
| `high` | AAC | 192kbps | 44.1kHz | 2 (stereo) | 4s |
|
||
|
|
| `hi_res`| AAC | 320kbps | 48kHz | 2 (stereo) | 4s |
|
||
|
|
|
||
|
|
**Note**: Opus pourra être ajouté plus tard pour ultra-low latency.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. PLAN D'IMPLÉMENTATION
|
||
|
|
|
||
|
|
### Phase 1: Infrastructure de Base
|
||
|
|
1. ✅ Créer migrations SQL (`stream_jobs`, `stream_segments`)
|
||
|
|
2. ✅ Créer `EncodeJob` dans `src/core/job.rs`
|
||
|
|
3. ✅ Améliorer `FfmpegCommandBuilder` (ajouter `-threads 1`, `-map 0:a`)
|
||
|
|
|
||
|
|
### Phase 2: Pool d'Encodeurs
|
||
|
|
4. ✅ Implémenter `EncoderWorker` avec queue async_channel
|
||
|
|
5. ✅ Implémenter `EncoderPool` avec spawn workers
|
||
|
|
6. ✅ Intégrer capture stderr FFmpeg en streaming
|
||
|
|
|
||
|
|
### Phase 3: Pipeline Complet
|
||
|
|
7. ✅ Service d'encodage (vérification track, création répertoires)
|
||
|
|
8. ✅ Parsing manifest HLS et insertion segments en DB
|
||
|
|
9. ✅ Mise à jour `stream_jobs` status
|
||
|
|
|
||
|
|
### Phase 4: API REST
|
||
|
|
10. ✅ Handlers API (encode, status, HLS manifest, segments)
|
||
|
|
11. ✅ Intégration dans router principal
|
||
|
|
|
||
|
|
### Phase 5: Tests & Documentation
|
||
|
|
12. ✅ Tests unitaires (command builder, progress parser)
|
||
|
|
13. ✅ Tests d'intégration (mini audio file, vérification HLS)
|
||
|
|
14. ✅ Documentation technique complète
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. DÉPENDANCES REQUISES
|
||
|
|
|
||
|
|
- ✅ `async-channel` : Queue async pour jobs
|
||
|
|
- ✅ `tokio::process::Command` : Spawn FFmpeg
|
||
|
|
- ✅ `sqlx` : DB operations
|
||
|
|
- ✅ `uuid` : IDs
|
||
|
|
- ✅ `tracing` : Logging
|
||
|
|
- ✅ `regex` : Parsing stderr FFmpeg (déjà présent)
|
||
|
|
|
||
|
|
**FFmpeg système**:
|
||
|
|
- Doit être installé: `sudo apt-get install ffmpeg`
|
||
|
|
- Version minimale: 4.0+
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. RISQUES IDENTIFIÉS
|
||
|
|
|
||
|
|
1. **Performance CPU**
|
||
|
|
- FFmpeg peut saturer CPU si trop de workers
|
||
|
|
- **MITIGATION**: Limiter à `min(nb_cpu / 2, 8)`
|
||
|
|
|
||
|
|
2. **Espace disque**
|
||
|
|
- Segments HLS peuvent être volumineux
|
||
|
|
- **MITIGATION**: Cleanup automatique après X jours (future feature)
|
||
|
|
|
||
|
|
3. **FFmpeg non disponible**
|
||
|
|
- Erreur si FFmpeg pas installé
|
||
|
|
- **MITIGATION**: Vérifier au démarrage, retourner erreur claire
|
||
|
|
|
||
|
|
4. **Concurrence DB**
|
||
|
|
- Plusieurs workers insèrent segments simultanément
|
||
|
|
- **MITIGATION**: Transactions, index sur (track_id, quality, segment_index)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. CRITÈRES DE SUCCÈS
|
||
|
|
|
||
|
|
- [ ] Pool d'encodeurs fonctionnel avec workers FFmpeg réels
|
||
|
|
- [ ] Segments HLS générés et accessibles via API
|
||
|
|
- [ ] API `/stream/:track_id/:quality/index.m3u8` opérationnelle
|
||
|
|
- [ ] Logs `tracing` complets (avancement, erreurs, temps)
|
||
|
|
- [ ] DB mise à jour correctement (`stream_jobs`, `stream_segments`)
|
||
|
|
- [ ] Worker pool robuste & stable (pas de leaks, gestion erreurs)
|
||
|
|
- [ ] Documentation complète (`docs/STREAM_ENCODING_PIPELINE.md`)
|
||
|
|
- [ ] TRIAGE.md mis à jour (P0 Streaming résolu)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Prochaine étape**: Implémentation Phase 1 (Infrastructure de Base)
|
||
|
|
|