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.).
13 KiB
13 KiB
🎵 Pipeline d'Encodage Audio - Documentation Technique
Date: 2025-01-27
Service: veza-stream-server
Version: 1.0.0
📋 Table des Matières
- Architecture
- Format Manifest HLS
- Mapping Qualité → Codec/Bitrate
- Gestion des Erreurs
- Tests
- Instructions de Développement
🏗️ Architecture
Vue d'ensemble
Le pipeline d'encodage audio est composé de plusieurs couches :
┌─────────────────────────────────────────────────────────┐
│ API REST Layer │
│ POST /admin/stream/encode/:track_id/:quality │
│ 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' │
└─────────────────────────────────────────────────────────┘
Composants Principaux
1. EncodeJob
Structure représentant un job d'encodage :
track_id: UUID du trackinput_path: Chemin vers le fichier sourceoutput_dir: Répertoire de sortie pour segments HLScodec: Codec audio (AAC, Opus, MP3, FLAC)bitrate: Bitrate en bpsquality: Qualité (low, medium, high, hi_res)
2. EncoderPool
Pool de workers qui traitent les jobs d'encodage :
- Queue asynchrone (
async_channel) - Workers threads dédiés
- Nombre de workers:
min(nb_cpu / 2, 8) - Chaque worker spawn un processus FFmpeg
3. EncodingService
Service de haut niveau pour :
- Lancer des encodages
- Vérifier les statuts
- Gérer les répertoires de sortie
📄 Format Manifest HLS
Structure d'un Manifest Media Playlist
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:4.000,
segment_00000.ts
#EXTINF:4.000,
segment_00001.ts
#EXTINF:4.000,
segment_00002.ts
#EXT-X-ENDLIST
Tags HLS Utilisés
#EXTM3U: Identifie le fichier comme playlist M3U8#EXT-X-VERSION:3: Version du protocole HLS#EXT-X-TARGETDURATION:6: Durée maximale d'un segment (secondes)#EXT-X-MEDIA-SEQUENCE:0: Numéro de séquence du premier segment#EXT-X-PLAYLIST-TYPE:VOD: Type de playlist (VOD = Video On Demand)#EXTINF:4.000,: Durée du segment suivant (secondes)#EXT-X-ENDLIST: Marque la fin de la playlist (VOD uniquement)
Structure des Fichiers de Sortie
/data/streams/
<track_id>/
low/
index.m3u8
segment_00000.ts
segment_00001.ts
...
medium/
index.m3u8
segment_00000.ts
segment_00001.ts
...
high/
index.m3u8
segment_00000.ts
segment_00001.ts
...
hi_res/
index.m3u8
segment_00000.ts
segment_00001.ts
...
🎚️ 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 |
Rationale
- Low (64kbps, mono): Optimisé pour faible bande passante (mobile, 3G)
- Medium (128kbps, stéréo): Qualité standard pour streaming web
- High (192kbps, stéréo): Haute qualité pour audiophiles
- Hi-Res (320kbps, stéréo): Qualité maximale (premium)
Note: Opus pourra être ajouté plus tard pour ultra-low latency (<5ms).
⚠️ Gestion des Erreurs
Erreurs FFmpeg Courantes
| Erreur | Cause | Solution |
|---|---|---|
FFmpeg exited with status: 1 |
Fichier source invalide ou codec manquant | Vérifier le fichier source, installer codecs |
HLS manifest not generated |
FFmpeg a échoué silencieusement | Vérifier stderr FFmpeg, logs |
Encoding timed out |
Fichier trop long ou CPU saturé | Augmenter timeout ou réduire workers |
Failed to create output directory |
Permissions insuffisantes | Vérifier permissions /data/streams |
Statuts de Job
pending: Job en attente dans la queueencoding: Job en cours de traitementdone: Job terminé avec succèserror: Job échoué (voirerror_message)
Retry Logic
- Max retries: 3
- Conditions: Erreurs temporaires (timeout, IO)
- Pas de retry: Erreurs permanentes (fichier invalide, codec manquant)
🧪 Tests
Tests Unitaires
Command Builder
#[test]
fn test_build_hls_command() {
let cmd = FfmpegCommandBuilder::new()
.input("input.wav")
.output("output/index.m3u8")
.audio_codec(AudioCodec::AAC)
.bitrate(128000)
.container(ContainerFormat::HLS)
.hls_time(4)
.build()
.unwrap();
// Vérifier que la commande contient les bonnes options
assert!(cmd.get_args().contains(&"-threads".to_string()));
assert!(cmd.get_args().contains(&"-map".to_string()));
}
Progress Parser
#[test]
fn test_parse_ffmpeg_progress() {
let line = "size=1024kB time=00:00:05.12 bitrate=128.0kbits/s speed=10.2x";
let progress = FfmpegProgress::parse(line).unwrap();
assert_eq!(progress.time, Some(Duration::from_millis(5120)));
assert_eq!(progress.speed, Some(10.2));
}
Tests d'Intégration
Setup
# Créer un fichier audio de test
ffmpeg -f lavfi -i "sine=frequency=440:duration=10" /tmp/test_audio.wav
Test Complet
#[tokio::test]
#[ignore] // Nécessite FFmpeg installé
async fn test_encode_track() {
let db_pool = create_test_pool().await;
let encoder_pool = FfmpegEncoderPool::new(db_pool.clone(), None).await.unwrap();
let service = EncodingService::new(
encoder_pool,
db_pool,
"/tmp/streams_test"
);
// Encoder un track de test
service.encode_track(track_id, "medium").await.unwrap();
// Attendre la fin (timeout 60s)
tokio::time::sleep(Duration::from_secs(60)).await;
// Vérifier que le manifest existe
let manifest_path = PathBuf::from("/tmp/streams_test")
.join(track_id.to_string())
.join("medium")
.join("index.m3u8");
assert!(manifest_path.exists());
// Vérifier que les segments sont en DB
let segments = sqlx::query!(
"SELECT COUNT(*) FROM stream_segments WHERE track_id = $1 AND quality = 'medium'",
track_id
)
.fetch_one(&db_pool)
.await
.unwrap();
assert!(segments.count.unwrap_or(0) > 0);
}
🛠️ Instructions de Développement
Prérequis
# Installer FFmpeg
sudo apt-get update
sudo apt-get install -y ffmpeg
# Vérifier la version
ffmpeg -version
# Version minimale: 4.0+
Configuration
Variables d'Environnement
# Répertoire de sortie pour les segments HLS
export STREAM_OUTPUT_DIR=/data/streams
# URL de la base de données
export DATABASE_URL=postgresql://veza:password@localhost:5432/veza_db
Migrations SQL
# Appliquer les migrations
psql $DATABASE_URL -f migrations/001_create_stream_jobs.sql
psql $DATABASE_URL -f migrations/002_create_stream_segments.sql
Compilation
cd veza-stream-server
cargo build --release
Exécution
# Démarrer le serveur
cargo run --release
# Ou avec variables d'environnement
STREAM_OUTPUT_DIR=/data/streams cargo run --release
Tests
# Tests unitaires (sans FFmpeg)
cargo test
# Tests d'intégration (nécessite FFmpeg)
cargo test -- --ignored
Monitoring
Logs
Les logs sont émis via tracing :
info!: Événements importants (démarrage workers, jobs terminés)debug!: Progression FFmpeg (time, speed)warn!: Erreurs non-critiques (retry, timeout)error!: Erreurs critiques (échec encodage, crash FFmpeg)
Métriques Prometheus
# Nombre de jobs en cours
stream_encoding_jobs_active{quality="medium"} 2
# Nombre de jobs terminés
stream_encoding_jobs_completed_total{quality="medium"} 150
# Nombre de jobs échoués
stream_encoding_jobs_failed_total{quality="medium"} 5
# Temps moyen d'encodage (secondes)
stream_encoding_duration_seconds{quality="medium"} 45.2
Dépannage
FFmpeg non trouvé
# Vérifier que FFmpeg est installé
which ffmpeg
# Vérifier les permissions
ls -la /data/streams
Erreurs de DB
# Vérifier la connexion
psql $DATABASE_URL -c "SELECT COUNT(*) FROM stream_jobs;"
# Vérifier les tables
psql $DATABASE_URL -c "\dt stream_*"
Workers bloqués
# Vérifier les processus FFmpeg
ps aux | grep ffmpeg
# Tuer les processus bloqués
pkill -9 ffmpeg
📊 Performance
Benchmarks
| Fichier Source | Durée | Qualité | Temps Encodage | CPU Usage |
|---|---|---|---|---|
| 3 min MP3 (128kbps) | 3:00 | medium | ~15s | 25% |
| 5 min WAV (44.1kHz) | 5:00 | high | ~30s | 40% |
| 10 min FLAC (96kHz) | 10:00 | hi_res | ~90s | 60% |
Optimisations
- Pool de Workers: Limiter à
min(nb_cpu / 2, 8)pour éviter saturation - Isolation CPU:
-threads 1par processus FFmpeg - Cache: Réutiliser les encodeurs si possible (future feature)
- Priorité: Jobs urgents en tête de queue
🔮 Roadmap
Phase 1 (Actuel) ✅
- Pool d'encodeurs FFmpeg
- Support HLS avec segments
- API REST complète
- Persistance en DB
Phase 2 (Future)
- Support Opus pour ultra-low latency
- Adaptive bitrate (ABR) automatique
- Cache des encodeurs réutilisables
- Cleanup automatique des segments anciens
Phase 3 (Future)
- Streaming live (pas seulement VOD)
- Support DASH en plus de HLS
- Hardware acceleration (GPU encoding)
- Multi-pass encoding pour meilleure qualité
📚 Références
Auteur: Veza Stream Server Team
Dernière mise à jour: 2025-01-27