veza/veza-stream-server/docs/DESIGN_STREAM_PIPELINE.md
okinrev b7955a680c P0: stabilisation backend/chat/stream + nouvelle base migrations v1
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.).
2025-12-06 11:14:38 +01:00

7 KiB

🎯 DESIGN - Pipeline d'encodage audio minimal mais robuste

Date: 2025-01-27
Mission: P0 - Rendre le stream-server fonctionnel


1. ARCHITECTURE

1.1 Vue d'ensemble

┌─────────────────┐
│   API Routes    │
│  /transcode     │
│  /job/{id}      │
│  /hls/{id}/...  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ TranscodingEngine│
│  - Queue         │
│  - JobManager    │
│  - WorkerPool    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Worker Pool    │
│  (N workers)    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  FFmpeg Process │
│  (HLS output)   │
└─────────────────┘

1.2 Composants principaux

TranscodingEngine

  • Responsabilité: Orchestrer le transcodage
  • Composants:
    • PriorityQueue: File d'attente des jobs
    • JobManager: Stockage et suivi des jobs
    • WorkerPool: Pool de workers parallèles

JobManager

  • Responsabilité: Stocker et suivre l'état des jobs
  • Stockage: HashMap<Uuid, TranscodingJob> (en mémoire pour P0)
  • Méthodes:
    • enqueue(job) -> Uuid
    • get_status(job_id) -> Option<JobStatus>
    • update_status(job_id, status)

WorkerPool

  • Responsabilité: Traiter les jobs en parallèle
  • Implémentation: Tokio tasks avec canal async
  • Workers: N workers (configurable, défaut: num_cpus())

Pipeline

  • Responsabilité: Exécuter FFmpeg et gérer les erreurs
  • Fonction: transcode_to_hls(input_path, output_dir, codec, bitrate) -> Result<TranscodeResult>

2. PIPELINE D'ENCODAGE

2.1 Fonction principale

async fn transcode_to_hls(
    input_path: &Path,
    output_dir: &Path,
    codec: AudioCodec,
    bitrate: u32,
    profile: &QualityProfile,
) -> Result<TranscodeResult, TranscodeError>

Étapes:

  1. Créer le répertoire de sortie {output_dir}/{job_id}/
  2. Construire la commande FFmpeg
  3. Exécuter FFmpeg avec timeout
  4. Vérifier que index.m3u8 et segments existent
  5. Retourner TranscodeResult avec chemins

2.2 Structure de sortie HLS

{output_dir}/
  {job_id}/
    index.m3u8          # Master playlist HLS
    segment_00001.ts
    segment_00002.ts
    segment_00003.ts
    ...

2.3 Format du manifest HLS

#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
...
#EXT-X-ENDLIST

3. COMMAND BUILDER FFMPEG

3.1 Arguments par codec

AAC

ffmpeg -i input.wav \
  -c:a aac \
  -b:a 192k \
  -ar 44100 \
  -ac 2 \
  -f hls \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename segment_%05d.ts \
  index.m3u8

MP3

ffmpeg -i input.wav \
  -c:a libmp3lame \
  -b:a 192k \
  -ar 44100 \
  -ac 2 \
  -f hls \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename segment_%05d.ts \
  index.m3u8

Opus

ffmpeg -i input.wav \
  -c:a libopus \
  -b:a 192k \
  -ar 48000 \
  -ac 2 \
  -f hls \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename segment_%05d.ts \
  index.m3u8

FLAC

ffmpeg -i input.wav \
  -c:a flac \
  -compression_level 5 \
  -ar 44100 \
  -ac 2 \
  -f hls \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename segment_%05d.ts \
  index.m3u8

3.2 Améliorations du builder

  • Ajouter -hls_list_size 0 pour VOD (liste complète)
  • Valider que FFmpeg est installé au démarrage
  • Gérer les erreurs de construction de commande

4. GESTION DES ERREURS

4.1 Types d'erreurs

#[derive(Debug, thiserror::Error)]
pub enum TranscodeError {
    #[error("Input file not found: {0}")]
    InputNotFound(PathBuf),
    
    #[error("FFmpeg execution failed: {0}")]
    FfmpegError(String),
    
    #[error("Transcoding timed out after {0} seconds")]
    Timeout(u64),
    
    #[error("Output directory creation failed: {0}")]
    OutputDirError(String),
    
    #[error("HLS manifest not generated")]
    ManifestMissing,
    
    #[error("Insufficient disk space")]
    DiskSpaceError,
}

4.2 Gestion du timeout

  • Timeout: 5 minutes par défaut
  • Action: Tuer le processus FFmpeg si timeout
  • Implémentation: Utiliser Command::kill() sur le child process

4.3 Retry logic

  • Max retries: 3
  • Conditions de retry:
    • Erreur temporaire (timeout, IO error)
    • Pas de retry sur erreur permanente (fichier corrompu)

5. API REST

5.1 POST /v1/stream/transcode

Request:

{
  "file": "<multipart file>",
  "codec": "aac",
  "bitrate": 192000,
  "quality_profile": "high"
}

Response:

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "message": "Job submitted successfully"
}

5.2 GET /v1/stream/job/{id}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "progress": 45.5,
  "created_at": "2025-01-27T10:00:00Z",
  "started_at": "2025-01-27T10:00:05Z",
  "completed_at": null,
  "error": null
}

5.3 GET /v1/stream/hls/{job_id}/index.m3u8

Response: Contenu du fichier index.m3u8 avec Content-Type: application/vnd.apple.mpegurl

5.4 GET /v1/stream/hls/{job_id}/{segment}

Response: Contenu binaire du segment .ts avec Content-Type: video/mp2t


6. INTÉGRATION DANS APPSTATE

6.1 Ajout de TranscodingEngine

pub struct AppState {
    // ... existing fields ...
    pub transcoding_engine: Arc<TranscodingEngine>,
}

6.2 Initialisation dans AppState::new()

let transcoding_engine = Arc::new(
    TranscodingEngine::new(num_cpus::get())
);
transcoding_engine.start();

7. LOGS STRUCTURÉS

7.1 Événements à logger

  • job_queued: Job soumis
  • job_started: Worker commence le traitement
  • job_progress: Progression (toutes les 10%)
  • job_completed: Job terminé avec succès
  • job_failed: Job échoué avec erreur

7.2 Format des logs

tracing::info!(
    job_id = %job.id,
    status = "queued",
    priority = ?job.priority,
    "Job queued for transcoding"
);

8. TESTS

8.1 Tests unitaires

  • Test command builder pour chaque codec
  • Test pipeline avec fichier WAV de test
  • Test job manager en mémoire

8.2 Tests d'intégration

  • Upload fichier → job → index.m3u8 généré
  • Vérification existence segments
  • Test timeout FFmpeg

9. LIMITATIONS P0

  • Pas de multi-bitrate adaptatif (ABR)
  • Pas de DRM
  • Pas de persistance en base de données (mémoire uniquement)
  • Pas de métriques Prometheus détaillées
  • Pas de cleanup automatique des anciens jobs

Prochaine étape: Phase 3 - Implémentation