Pipeline audio de bureau
La crate adk-audio fournit des entrées/sorties audio de bureau multiplateformes derrière l’indicateur de fonctionnalité desktop-audio. Trois composants — AudioCapture, AudioPlayback et VadTurnManager — permettent la capture au microphone, la lecture par les haut-parleurs et la gestion des tours de parole pilotée par la VAD pour créer des agents vocaux de bureau.
Vue d’ensemble
Le pipeline audio de bureau connecte le matériel audio du système au système de pipelines adk-audio existant :
Microphone → AudioCapture → AudioStream → [VAD → STT → Agent → TTS] → AudioPlayback → Speaker
Tous les composants utilisent la crate cpal pour l’audio multiplateforme (CoreAudio sur macOS, PipeWire/ALSA/PulseAudio sur Linux, WASAPI sur Windows) et produisent ou consomment le type AudioFrame standard.
Indicateurs de fonctionnalité
[dependencies]
# Cross-platform (macOS, Linux, Windows) via cpal
adk-audio = { version = "2.1.0", features = ["desktop-audio"] }
La fonctionnalité desktop-audio implique vad (pour VadProcessor) et ajoute cpal comme dépendance. Elle est intentionnellement exclue de la fonctionnalité all afin d’éviter d’introduire des dépendances audio spécifiques aux plateformes dans les compilations CI.
Prise en charge de PipeWire
Sur les distributions Linux modernes (Fedora 34+, Ubuntu 22.10+, Arch), PipeWire a remplacé PulseAudio et ALSA comme serveur audio par défaut. La fonctionnalité desktop-audio fonctionne de manière transparente avec PipeWire grâce à sa couche de compatibilité ALSA — aucune configuration supplémentaire n’est nécessaire.
Un backend PipeWire natif (desktop-pipewire) utilisant la crate pipewire (v0.9) est prévu dans une prochaine version. PipeWire natif offrirait une latence plus faible et une gestion directe des sessions. Son intégration est actuellement bloquée par un conflit de dépendances : redis-protocol 6.0.0 verrouille cookie-factory =0.3.2 tandis que le libspa de pipewire nécessite 0.3.3. Une fois que le projet amont assouplira ce verrouillage, le backend natif pourra être ajouté.
Démarrage rapide
Répertorier les périphériques audio
use adk_audio::{AudioCapture, AudioPlayback};
let inputs = AudioCapture::list_input_devices()?;
for device in &inputs {
println!("Mic: {} ({})", device.name(), device.id());
}
let outputs = AudioPlayback::list_output_devices()?;
for device in &outputs {
println!("Speaker: {} ({})", device.name(), device.id());
}
Capturer le son du microphone
use adk_audio::{AudioCapture, CaptureConfig};
use std::time::{Duration, Instant};
let mut capture = AudioCapture::new();
let devices = AudioCapture::list_input_devices()?;
let device = devices.first().expect("no input device");
let config = CaptureConfig::default(); // 16kHz, mono, 20ms frames
let mut stream = capture.start_capture(device.id(), &config)?;
let start = Instant::now();
while start.elapsed() < Duration::from_secs(3) {
if let Some(frame) = stream.recv().await {
// frame.data: PCM-16 LE bytes
// frame.sample_rate: 16000
// frame.channels: 1
// frame.duration_ms: 20
}
}
capture.stop_capture();
Lire du son sur les haut-parleurs
use adk_audio::{AudioFrame, AudioPlayback};
let mut playback = AudioPlayback::new();
let devices = AudioPlayback::list_output_devices()?;
let device = devices.first().expect("no output device");
let frame = AudioFrame::silence(16000, 1, 1000); // 1 second
playback.play(device.id(), &frame).await?;
playback.stop();
Gestion des tours de parole par VAD
use std::sync::Arc;
use adk_audio::{
AudioCapture, CaptureConfig, VadConfig, VadMode,
VadTurnManager, VoiceActivityEvent, VadProcessor,
};
let vad: Arc<dyn VadProcessor> = /* your VadProcessor impl */;
let config = VadConfig {
mode: VadMode::HandsFree,
silence_threshold_ms: 500,
speech_threshold_ms: 200,
};
let mut manager = VadTurnManager::new(vad, config)?;
let mut capture = AudioCapture::new();
let stream = capture.start_capture(device_id, &CaptureConfig::default())?;
manager.start(stream, |event| {
match event {
VoiceActivityEvent::SpeechStarted => println!("Speech started"),
VoiceActivityEvent::SpeechEnded { duration_ms } => {
println!("Speech ended ({duration_ms}ms)");
}
}
});
Composants
AudioDevice
Descripteur d’un périphérique audio système (entrée ou sortie). Contient un id opaque et un name lisible par l’utilisateur.
CaptureConfig
Configuration de la capture par microphone :
| Champ | Type | Valeur par défaut | Description |
|---|---|---|---|
sample_rate | u32 | 16000 | Fréquence d’échantillonnage en Hz |
channels | u8 | 1 | Nombre de canaux (1=mono, 2=stéréo) |
frame_duration_ms | u32 | 20 | Durée de chaque AudioFrame |
Appelez validate() avant utilisation — rejette les valeurs nulles avec AudioError::Device.
AudioCapture
Capture du microphone via cpal. La méthode start_capture() renvoie un AudioStream (mpsc::Receiver<AudioFrame> borné avec une capacité de 64). Les trames sont produites à des intervalles de frame_duration_ms au format PCM-16 LE.
AudioPlayback
Lecture sur haut-parleur via cpal. La méthode play() met en file les échantillons d'un AudioFrame dans une mémoire tampon partagée que le callback de sortie cpal vide. Appelez stop() pour libérer le périphérique.
VadTurnManager
Consomme un AudioStream, applique VadProcessor::is_speech() à chaque trame et émet des valeurs VoiceActivityEvent via un callback enregistré.
Deux modes :
- HandsFree — détection automatique des limites de la parole à l'aide de seuils configurables de durée du silence et de la parole
- PushToTalk — aucun événement automatique ; l'appelant contrôle le déclenchement en externe
VadConfig
| Champ | Type | Description |
|---|---|---|
mode | VadMode | HandsFree or PushToTalk |
silence_threshold_ms | u32 | Silence consécutif avant SpeechEnded |
speech_threshold_ms | u32 | Discours consécutif avant SpeechStarted |
Appelez validate() avant utilisation — rejette les seuils nuls avec AudioError::Vad.
Création d’un agent vocal
Le modèle complet d’un agent vocal conversationnel :
- Capturer l’audio depuis le microphone
- Détecter les limites de la parole avec VAD
- Transcrire la parole avec GeminiStt (ou tout autre
SttProvider) - Envoyer la transcription à un LlmAgent pour le raisonnement
- Synthétiser la réponse avec GeminiTts (ou tout autre
TtsProvider) - Lire l’audio synthétisé via le haut-parleur
Consultez examples/desktop_audio/src/voice_agent.rs pour un exemple complet fonctionnel utilisant de véritables fournisseurs cloud Gemini.
Sécurité des threads
Tous les types audio de bureau (AudioCapture, AudioPlayback, VadTurnManager) sont Send + Sync, ce qui permet de les partager en toute sécurité entre les tâches Tokio.
Gestion des erreurs
Les erreurs audio de bureau utilisent l’énumération AudioError existante :
| Composant | Variante d’erreur | Quand |
|---|---|---|
| AudioCapture | AudioError::Device | Périphérique introuvable, hôte indisponible, validation de la configuration |
| AudioPlayback | AudioError::Device | Périphérique introuvable, hôte indisponible, échec de l’ouverture/de l’écriture |
| VadTurnManager | AudioError::Vad | Validation de la configuration (seuils à zéro) |
Prise en charge de la plateforme
| Plateforme | Backend audio | Statut |
|---|---|---|
| macOS | CoreAudio | Pris en charge |
| Linux | PipeWire (via la compatibilité ALSA) | Pris en charge (installer libasound2-dev) |
| Linux | ALSA / PulseAudio (legacy) | Pris en charge (installer libasound2-dev) |
| Windows | WASAPI | Pris en charge |
Sur Linux moderne, PipeWire est le serveur audio par défaut et a remplacé PulseAudio et ALSA. La fonctionnalité desktop-audio fonctionne de manière transparente sur PipeWire grâce à sa couche de compatibilité ALSA. Un backend natif PipeWire utilisant le crate pipewire est prévu pour une prochaine version (actuellement bloqué par un conflit de dépendances en amont dans redis-protocol).
Exemples
Consultez examples/desktop_audio/ pour découvrir 6 exemples pratiques, dont un agent vocal conversationnel complet avec STT/TTS Gemini réels.