Backend Go: - Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN. - Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError). - Sécurisation de config.go, CORS, statuts de santé et monitoring. - Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles). - Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés. - Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*. Chat server (Rust): - Refonte du pipeline JWT + sécurité, audit et rate limiting avancé. - Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing). - Nettoyage des panics, gestion d’erreurs robuste, logs structurés. - Migrations chat alignées sur le schéma UUID et nouvelles features. Stream server (Rust): - Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core. - Transactions P0 pour les jobs et segments, garanties d’atomicité. - Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION). Documentation & audits: - TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services. - Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3). - Scripts de reset et de cleanup pour la lab DB et la V1. Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
365 lines
7.8 KiB
Markdown
365 lines
7.8 KiB
Markdown
# 🎵 Pipeline de streaming audio - Documentation
|
|
|
|
**Date**: 2025-01-27
|
|
**Version**: 0.2.0
|
|
|
|
---
|
|
|
|
## Vue d'ensemble
|
|
|
|
Le pipeline de transcodage audio de Veza permet de convertir des fichiers audio en format HLS (HTTP Live Streaming) pour le streaming web. Il utilise FFmpeg pour l'encodage et un système de workers asynchrones pour le traitement parallèle.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Composants principaux
|
|
|
|
1. **TranscodingEngine**: Orchestrateur principal
|
|
- Gère la file d'attente des jobs
|
|
- Lance et supervise les workers
|
|
- Stocke l'état des jobs via JobManager
|
|
|
|
2. **JobManager**: Stockage en mémoire des jobs
|
|
- Enregistre les jobs soumis
|
|
- Met à jour l'état des jobs
|
|
- Permet de récupérer l'état d'un job
|
|
|
|
3. **PriorityQueue**: File d'attente prioritaire
|
|
- 3 niveaux: Urgent, Normal, Background
|
|
- Capacité: 1000 jobs par défaut
|
|
- Backpressure si queue pleine
|
|
|
|
4. **TranscodingWorker**: Worker de traitement
|
|
- Traite un job à la fois
|
|
- Exécute FFmpeg avec timeout
|
|
- Gère les erreurs et retry
|
|
|
|
5. **FfmpegCommandBuilder**: Construction de commandes FFmpeg
|
|
- Support AAC, MP3, Opus, FLAC
|
|
- Génération HLS avec segments
|
|
- Validation des paramètres
|
|
|
|
---
|
|
|
|
## Workflow
|
|
|
|
### 1. Soumission d'un job
|
|
|
|
```
|
|
Client → POST /v1/stream/transcode
|
|
↓
|
|
Routes::transcode_handler
|
|
↓
|
|
TranscodingEngine::submit()
|
|
↓
|
|
JobManager::enqueue() → PriorityQueue::submit()
|
|
↓
|
|
Worker récupère le job et traite
|
|
```
|
|
|
|
### 2. Traitement d'un job
|
|
|
|
```
|
|
Worker::process()
|
|
↓
|
|
Créer répertoire de sortie
|
|
↓
|
|
FfmpegCommandBuilder::build()
|
|
↓
|
|
Command::spawn() → FFmpeg process
|
|
↓
|
|
Timeout (5 min) ou completion
|
|
↓
|
|
Vérifier manifest HLS généré
|
|
↓
|
|
JobManager::update_job()
|
|
```
|
|
|
|
### 3. Récupération de l'état
|
|
|
|
```
|
|
Client → GET /v1/stream/job/{id}
|
|
↓
|
|
Routes::get_job_status()
|
|
↓
|
|
JobManager::get_status()
|
|
↓
|
|
Retour JSON avec état
|
|
```
|
|
|
|
### 4. Streaming HLS
|
|
|
|
```
|
|
Client → GET /v1/stream/hls/{job_id}/index.m3u8
|
|
↓
|
|
Routes::serve_hls_manifest()
|
|
↓
|
|
Lire index.m3u8 depuis output_dir
|
|
↓
|
|
Retour avec Content-Type: application/vnd.apple.mpegurl
|
|
```
|
|
|
|
---
|
|
|
|
## Structure des fichiers de sortie
|
|
|
|
```
|
|
{output_dir}/
|
|
transcode_{uuid}/
|
|
index.m3u8 # Master playlist HLS
|
|
segment_00001.ts # Segment 1
|
|
segment_00002.ts # Segment 2
|
|
segment_00003.ts # Segment 3
|
|
...
|
|
```
|
|
|
|
### Format du manifest HLS
|
|
|
|
```m3u8
|
|
#EXTM3U
|
|
#EXT-X-VERSION:3
|
|
#EXT-X-TARGETDURATION:6
|
|
#EXT-X-MEDIA-SEQUENCE:0
|
|
#EXTINF:6.0,
|
|
segment_00001.ts
|
|
#EXTINF:6.0,
|
|
segment_00002.ts
|
|
#EXTINF:6.0,
|
|
segment_00003.ts
|
|
#EXT-X-ENDLIST
|
|
```
|
|
|
|
---
|
|
|
|
## API REST
|
|
|
|
### POST `/v1/stream/transcode`
|
|
|
|
Soumet un fichier audio pour transcodage.
|
|
|
|
**Request** (multipart/form-data):
|
|
- `file`: Fichier audio (WAV, MP3, FLAC, etc.)
|
|
- `codec`: Codec cible (aac, mp3, opus, flac) - optionnel
|
|
- `bitrate`: Bitrate en bps - optionnel
|
|
- `quality_profile`: Profil (hi_res, high, medium, low) - optionnel
|
|
- `priority`: Priorité (urgent, normal, background) - optionnel
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"status": "queued",
|
|
"message": "Job submitted successfully"
|
|
}
|
|
```
|
|
|
|
### GET `/v1/stream/job/{id}`
|
|
|
|
Récupère l'état d'un job.
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"track_id": "my_track",
|
|
"status": "processing",
|
|
"progress": 45.5,
|
|
"created_at": "SystemTime { tv_sec: 1737979200, tv_nsec: 0 }",
|
|
"started_at": "Some(SystemTime { tv_sec: 1737979205, tv_nsec: 0 })",
|
|
"completed_at": null,
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
**Statuts possibles**:
|
|
- `Pending`: Job en attente
|
|
- `Processing`: Job en cours de traitement
|
|
- `Completed`: Job terminé avec succès
|
|
- `Failed(String)`: Job échoué avec message d'erreur
|
|
- `Cancelled`: Job annulé
|
|
|
|
### GET `/v1/stream/hls/{job_id}/index.m3u8`
|
|
|
|
Sert le manifest HLS pour un job terminé.
|
|
|
|
**Response**: Contenu du fichier `index.m3u8` avec `Content-Type: application/vnd.apple.mpegurl`
|
|
|
|
### GET `/v1/stream/hls/{job_id}/{segment}`
|
|
|
|
Sert un segment HLS (.ts).
|
|
|
|
**Response**: Contenu binaire du segment avec `Content-Type: video/mp2t`
|
|
|
|
---
|
|
|
|
## Profils de qualité
|
|
|
|
### hi_res
|
|
- Bitrate: 320 kbps
|
|
- Sample rate: 48 kHz
|
|
- Channels: 2 (stéréo)
|
|
- Codec: AAC
|
|
- Segment time: 6 secondes
|
|
|
|
### high
|
|
- Bitrate: 192 kbps
|
|
- Sample rate: 44.1 kHz
|
|
- Channels: 2 (stéréo)
|
|
- Codec: AAC
|
|
- Segment time: 6 secondes
|
|
|
|
### medium (défaut)
|
|
- Bitrate: 128 kbps
|
|
- Sample rate: 44.1 kHz
|
|
- Channels: 2 (stéréo)
|
|
- Codec: AAC
|
|
- Segment time: 6 secondes
|
|
|
|
### low
|
|
- Bitrate: 64 kbps
|
|
- Sample rate: 22.05 kHz
|
|
- Channels: 1 (mono)
|
|
- Codec: AAC
|
|
- Segment time: 6 secondes
|
|
|
|
---
|
|
|
|
## Gestion des erreurs
|
|
|
|
### Types d'erreurs
|
|
|
|
1. **InputNotFound**: Fichier d'entrée introuvable
|
|
2. **FfmpegError**: Erreur d'exécution FFmpeg
|
|
3. **Timeout**: Transcodage dépassant 5 minutes
|
|
4. **OutputDirError**: Échec création répertoire de sortie
|
|
5. **ManifestMissing**: Manifest HLS non généré
|
|
|
|
### Retry logic
|
|
|
|
- **Max retries**: 3
|
|
- **Conditions**: Erreurs temporaires uniquement (timeout, IO)
|
|
- **Pas de retry**: Fichier corrompu, erreur permanente
|
|
|
|
### Timeout
|
|
|
|
- **Durée**: 5 minutes par défaut
|
|
- **Action**: Processus FFmpeg tué automatiquement
|
|
- **État**: Job marqué comme `Failed("Transcoding timed out")`
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Variables d'environnement
|
|
|
|
- `COMPRESSION_OUTPUT_DIR`: Répertoire de sortie (défaut: `/tmp`)
|
|
- `FFMPEG_PATH`: Chemin vers FFmpeg (optionnel, cherche dans PATH)
|
|
|
|
### Workers
|
|
|
|
- **Nombre**: `num_cpus()` par défaut
|
|
- **Capacité queue**: 1000 jobs
|
|
- **Timeout**: 5 minutes par job
|
|
|
|
---
|
|
|
|
## Limitations P0
|
|
|
|
- ❌ Pas de multi-bitrate adaptatif (ABR)
|
|
- ❌ Pas de DRM
|
|
- ❌ Pas de persistance en base de données (mémoire uniquement)
|
|
- ❌ Pas de cleanup automatique des anciens jobs
|
|
- ❌ Pas de métriques Prometheus détaillées
|
|
- ❌ Pas de validation FFmpeg installé au démarrage
|
|
|
|
---
|
|
|
|
## Exemples d'utilisation
|
|
|
|
### cURL
|
|
|
|
```bash
|
|
# Soumettre un job
|
|
curl -X POST http://localhost:8082/v1/stream/transcode \
|
|
-F "file=@audio.wav" \
|
|
-F "quality_profile=high"
|
|
|
|
# Récupérer l'état
|
|
curl http://localhost:8082/v1/stream/job/{job_id}
|
|
|
|
# Servir le manifest HLS
|
|
curl http://localhost:8082/v1/stream/hls/{job_id}/index.m3u8
|
|
|
|
# Servir un segment
|
|
curl http://localhost:8082/v1/stream/hls/{job_id}/segment_00001.ts
|
|
```
|
|
|
|
### JavaScript (fetch)
|
|
|
|
```javascript
|
|
// Soumettre un job
|
|
const formData = new FormData();
|
|
formData.append('file', audioFile);
|
|
formData.append('quality_profile', 'high');
|
|
|
|
const response = await fetch('http://localhost:8082/v1/stream/transcode', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const { job_id } = await response.json();
|
|
|
|
// Poller l'état
|
|
const statusResponse = await fetch(`http://localhost:8082/v1/stream/job/${job_id}`);
|
|
const status = await statusResponse.json();
|
|
|
|
if (status.status === 'Completed') {
|
|
// Charger le manifest HLS
|
|
const manifestUrl = `http://localhost:8082/v1/stream/hls/${job_id}/index.m3u8`;
|
|
// Utiliser un player HLS (hls.js, video.js, etc.)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
### Coûts CPU/RAM
|
|
|
|
- **CPU**: ~1 core par worker actif
|
|
- **RAM**: ~50-100 MB par job en cours
|
|
- **Disque**: ~10-20 MB par minute d'audio (selon bitrate)
|
|
|
|
### Recommandations
|
|
|
|
- **Workers**: 1-2x nombre de CPUs
|
|
- **Queue capacity**: 1000 jobs (ajustable selon charge)
|
|
- **Timeout**: 5 minutes (ajustable selon longueur fichiers)
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Job reste en "Pending"
|
|
|
|
- Vérifier que les workers sont démarrés (`TranscodingEngine::start()`)
|
|
- Vérifier les logs pour erreurs de workers
|
|
- Vérifier que FFmpeg est installé et accessible
|
|
|
|
### Job échoue avec "ManifestMissing"
|
|
|
|
- Vérifier que le répertoire de sortie est accessible en écriture
|
|
- Vérifier les logs FFmpeg pour erreurs d'encodage
|
|
- Vérifier l'espace disque disponible
|
|
|
|
### Timeout fréquents
|
|
|
|
- Augmenter le timeout dans `worker.rs` (const `JOB_TIMEOUT`)
|
|
- Vérifier la charge CPU
|
|
- Vérifier la taille des fichiers d'entrée
|
|
|
|
---
|
|
|
|
**Prochaine étape**: Voir `FFMPEG_COMMANDS.md` pour les détails techniques des commandes FFmpeg.
|
|
|