Files
ox_speak_old/readme_audio.md
2025-06-13 18:10:27 +02:00

106 lines
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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** laudio 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 sattend à des données audio **continues et naturelles**.
---
## ⏱️ Pas de timer à 20ms
- Ne jamais baser lenvoi des paquets audio sur une **horloge ou un cycle fixe**.
- Lencodage doit être déclenché **uniquement** par la disponibilité dune 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 dallocation après init,
- Idéal pour de l'audio pro mais limité à 1 producer / 1 consumer.
---
## 📊 Latence et performance
- Encodage Opus dune 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 dor
- 🎧 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).