3.3 KiB
3.3 KiB
Audio Capture & Processing — Architecture Notes
Ce document résume les décisions techniques et bonnes pratiques concernant la capture, l'encodage, et la transmission de la voix en temps réel dans un logiciel de type Discord/TeamSpeak, basé sur cpal (Rust) et Opus.
🎤 Capture audio avec cpal
✅ Bonnes pratiques
- Utiliser
cpalen mode callback pour une capture audio fiable et efficace. - Ne jamais traiter l’audio directement dans le callback.
- Le callback doit être minimaliste : uniquement pousser les échantillons dans un buffer partagé/thread-safe.
❌ Mauvaises pratiques
- Encoder dans le callback → risque de décrochage audio.
- Loguer ou dormir dans le callback → clics, perte de données.
🎯 Taille des frames : 960 samples, pas 960 ms
- Pour un encodage Opus en 20 ms à 48 kHz mono, il faut 960 samples par frame.
- Les chunks reçus de CPAL ne garantissent jamais d’être exactement de cette taille.
🧱 Bufferisation : découpage rigide
- Mettre en place un buffer circulaire (ex :
VecDeque<i16>) pour accumuler les samples reçus. - Dès que
buffer.len() >= 960:- Extraire les 960 premiers samples,
- Encoder via Opus,
- Transmettre immédiatement.
Pourquoi ne pas compléter avec des zéros ?
- Cela introduit des artefacts audio,
- L'encodeur Opus s’attend à des données audio continues et naturelles.
⏱️ Pas de timer à 20ms
- Ne jamais baser l’envoi des paquets audio sur une horloge ou un cycle fixe.
- L’encodage doit être déclenché uniquement par la disponibilité d’une frame complète.
🧵 Architecture multithread recommandée
[ CPAL Callback ]
↓
[ Channel / Ring Buffer ]
↓
[ Encode Thread (Opus) ]
↓
[ Network Sender (UDP) ]
- Le callback ne fait que
send(samples)dans un channel rapide. - L'encodage Opus est fait dans un thread séparé dès qu'une frame de 960 samples est disponible.
🔄 Communication entre threads
Option 1 – Crossbeam channel (recommandé au départ)
use crossbeam_channel::{bounded, Receiver, Sender};
- Solide, rapide, facile à intégrer.
- Peut être remplacé plus tard si besoin de plus de performance.
Option 2 – ringbuf (optimisé audio)
- Ultra rapide, pas d’allocation après init,
- Idéal pour de l'audio pro mais limité à 1 producer / 1 consumer.
📊 Latence et performance
- Encodage Opus d’une frame 960 mono ≈ 0.1 à 0.5 ms sur PC moderne.
- Aucun besoin d'ajouter de délai artificiel.
- Pas de risque de “fractionner la voix” si le buffer est bien géré.
✅ Récapitulatif des règles d’or
- 🎧 Ne pas encoder dans le callback CPAL.
- 🔁 Accumuler les samples dans un buffer jusqu'à 960.
- ✂️ Ne jamais compléter une frame incomplète avec des zéros.
- 🚫 Ne pas timer les envois → laisser le flux audio dicter le tempo.
- 🧵 Utiliser des channels ou buffers inter-threads pour le découplage.
📌 TODO futur
- Comparer performance
crossbeam_channelvsringbufdans ton usage réel. - Implémenter détection de silence (VAD) pour ne pas encoder à vide.
- Ajouter sequence number + timestamp (RTP-like) dans les paquets réseau.
- Implémenter jitter buffer côté client (récepteur).