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

3.3 KiB
Raw Blame History

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)

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).