Serveur Streaming Rust (veza-stream-server)
Architecture du serveur audio haute performance basé sur Axum.
Source : veza-stream-server/src/
Vue d'ensemble
Le stream server est un service Rust autonome qui gère :
- Streaming audio HLS adaptatif multi-bitrate
- WebSocket temps réel pour la lecture synchronisée
- Transcoding audio via FFmpeg (WAV → MP3, HLS)
- Métriques Prometheus pour le monitoring
Il communique avec le backend Go via RabbitMQ (événements asynchrones) et des callbacks REST internes.
Stack technique
| Composant |
Technologie |
| Framework HTTP |
Axum (async Rust) |
| Runtime |
Tokio |
| Auth |
JWT (validation) |
| Audio |
FFmpeg (transcoding), HLS.js (côté client) |
| Messaging |
RabbitMQ (consommateur) |
| Cache |
In-memory (playlists HLS) |
| Monitoring |
Prometheus |
| Stockage |
S3/MinIO |
| Base de données |
PostgreSQL (requêtes directes) |
Structure des modules
veza-stream-server/src/
├── main.rs # Point d'entrée, initialisation Axum
├── routes/
│ └── api.rs # Définition de toutes les routes
├── streaming/
│ ├── websocket.rs # Handler WebSocket avec protocole de sync
│ ├── hls.rs # Génération de playlists HLS
│ └── adaptive.rs # Sélection adaptative du bitrate
├── transcoding/
│ └── mod.rs # Orchestration transcoding FFmpeg
├── codecs/
│ └── mod.rs # Wrappers FFmpeg
├── audio/
│ └── mod.rs # Utilitaires audio
├── middleware/
│ ├── logging.rs # Logs structurés
│ ├── security.rs # Headers de sécurité
│ └── rate_limit.rs # Rate limiting par IP
├── auth/
│ └── mod.rs # Validation JWT
├── config/
│ └── mod.rs # Configuration depuis env
├── health/
│ └── mod.rs # Health checks
├── monitoring/
│ └── mod.rs # Métriques Prometheus
├── cache/
│ └── mod.rs # Cache mémoire playlists
└── database/
└── mod.rs # Requêtes PostgreSQL
Routes
Santé & monitoring
| Méthode |
Route |
Description |
| GET |
/ |
Message racine (info serveur) |
| GET |
/health |
Health check détaillé |
| GET |
/healthz |
Liveness probe (Kubernetes) |
| GET |
/readyz |
Readiness probe |
| GET |
/metrics |
Métriques Prometheus |
Streaming audio
| Méthode |
Route |
Description |
Auth |
| GET |
/stream/{filename} |
Stream fichier audio |
Signature URL |
| GET |
/hls/{track_id}/master.m3u8 |
Playlist master HLS |
JWT |
| GET |
/hls/{track_id}/{quality}/playlist.m3u8 |
Playlist par qualité |
JWT |
| GET |
/hls/{track_id}/{quality}/{segment} |
Segment HLS |
JWT |
| WS |
/ws |
WebSocket streaming temps réel |
JWT (query param) |
Transcoding
| Méthode |
Route |
Description |
Auth |
| POST |
/internal/jobs/transcode |
Lancer job transcoding |
Clé API interne |
| POST |
/v1/stream/transcode |
Initier transcoding |
JWT |
| GET |
/v1/stream/job/{id} |
Statut du job |
JWT |
| GET |
/v1/stream/hls/{job_id}/index.m3u8 |
Playlist du job |
JWT |
| GET |
/v1/stream/hls/{job_id}/{segment} |
Segment du job |
JWT |
| GET |
/api/streams/jobs/{id}/status |
Statut détaillé |
JWT |
Protocole WebSocket
Le WebSocket (/ws?track_id=...) utilise un protocole personnalisé pour la lecture synchronisée.
Commandes client → serveur
| Commande |
Payload |
Description |
play |
{ position: float } |
Démarrer la lecture à la position |
pause |
— |
Mettre en pause |
seek |
{ position: float } |
Sauter à une position |
sync |
{ position: float } |
Synchroniser (co-écoute) |
heartbeat |
— |
Maintenir la connexion |
error |
{ message: string } |
Signaler une erreur client |
Réponses serveur → client
| Réponse |
Payload |
Description |
ready |
{ duration, bitrates } |
Serveur prêt à streamer |
chunk |
{ data, position, bitrate } |
Chunk audio avec métadonnées |
sync_ack |
{ position } |
Accusé de réception sync |
error |
{ code, message } |
Erreur serveur |
Cycle de vie d'une connexion
Client Serveur
│ │
│── WS Connect ─────────────────▶│
│ (track_id, JWT en query) │
│ │── Validation JWT
│ │── Chargement playlist HLS
│◀── ready ──────────────────────│
│ (duration, bitrates) │
│ │
│── play { position: 0 } ──────▶│
│ │── Sélection bitrate adaptatif
│◀── chunk ──────────────────────│
│◀── chunk ──────────────────────│
│◀── chunk ──────────────────────│
│ │
│── heartbeat ──────────────────▶│ (toutes les 30s)
│ │
│── seek { position: 120 } ────▶│
│◀── chunk ──────────────────────│
│ │
│── pause ──────────────────────▶│
│ │
│── WS Close ───────────────────▶│
Streaming HLS adaptatif
Le serveur génère et sert des playlists HLS multi-bitrate avec sélection adaptative.
Qualités disponibles
Le transcoding produit plusieurs qualités à partir du fichier source :
| Qualité |
Bitrate |
Usage |
| low |
64 kbps |
Mobile / réseau faible |
| medium |
128 kbps |
Standard |
| high |
256 kbps |
Haute qualité |
| lossless |
Original |
Audiophile |
Fonctionnement
- Upload : Le backend Go reçoit le fichier audio et le stocke sur S3
- Événement :
track.uploaded publié sur RabbitMQ
- Transcoding : Le stream server consomme l'événement, transcode via FFmpeg
- Stockage : Les segments HLS et playlists sont stockés sur S3
- Callback :
POST /internal/tracks/:id/stream-ready vers le backend
- Lecture : Le client demande le master playlist, le serveur sert les segments
Structure des fichiers HLS sur S3
hls/{track_id}/
├── master.m3u8 # Master playlist (liste les qualités)
├── low/
│ ├── playlist.m3u8 # Playlist 64 kbps
│ ├── segment_000.ts # Segments audio
│ ├── segment_001.ts
│ └── ...
├── medium/
│ ├── playlist.m3u8 # Playlist 128 kbps
│ └── ...
├── high/
│ ├── playlist.m3u8 # Playlist 256 kbps
│ └── ...
└── lossless/
├── playlist.m3u8
└── ...
Pile de middlewares
Appliqués dans l'ordre à toutes les routes :
- CORS — Restrictif par défaut, origines configurables
- Timeout — 30 secondes par requête
- Compression — gzip
- Security Headers — X-Content-Type-Options, X-Frame-Options, etc.
- Rate Limiting — Par IP
- Request Logging — Logs JSON structurés
Configuration
pub struct Config {
port: u16, // PORT (default: 18082)
database_url: String, // DATABASE_URL
rabbit_mq: RabbitMQConfig, // RABBITMQ_URL
s3_bucket: String, // S3_BUCKET
s3_region: String, // S3_REGION
log_level: String, // LOG_LEVEL
allowed_origins: Vec<String>, // ALLOWED_ORIGINS
}
Toute la configuration provient des variables d'environnement (voir CONFIGURATION_ENVIRONNEMENT).
Communication inter-services
Événements RabbitMQ consommés
| Événement |
Action |
track.uploaded |
Lance le transcoding HLS |
track.deleted |
Supprime les segments HLS de S3 |
Callbacks REST vers le backend Go
| Callback |
Description |
POST /internal/tracks/:id/stream-ready |
Notifie que le transcoding est terminé |
POST /internal/stream-events |
Envoie des événements de streaming |
Header d'authentification : X-Stream-Secret
Dockerfiles
| Fichier |
Base |
Usage |
Dockerfile |
rust:latest |
Développement (avec debug symbols) |
Dockerfile.production |
debian:bookworm-slim |
Production (binaire optimisé, minimal) |
Documents liés