# 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 `cpal` en **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`) 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) ```rust 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_channel` vs `ringbuf` dans 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).