# 🎵 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.

