# 🔍 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`) - 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///` - 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/// │ │ - Crée EncodeJob et l'envoie dans la queue │ └────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Encoder Pool (Worker Threads) │ │ - Queue: async_channel::Receiver │ │ - Workers: Vec (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, 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)