# Service Audio-in - Skull Pi

Service de capture audio en temps réel avec détection d'activité vocale (VAD) et calcul RMS pour le projet **Skull Pi**. Compatible avec le HAT ReSpeaker 2-Mic via I²S/ALSA.

## Fonctionnalités

- 🎤 **Capture audio** : ReSpeaker 2-Mic Pi HAT (16kHz mono, 16-bit)
- 📊 **RMS temps réel** : Énergie audio normalisée [0..1], publié toutes les 20ms
- 🎙️ **VAD (Voice Activity Detector)** : État machine avec hystérésis configurable
- 📡 **MQTT** : Publication des métriques et configuration dynamique
- 🔧 **Configuration à chaud** : Seuils VAD ajustables via MQTT
- 📝 **Logs JSON** : Statistiques et métriques détaillées

## Architecture

```
Micro ReSpeaker → ALSA → sounddevice → RMS Calculator
                                           ↓
                                       VAD Engine → MQTT Publisher
                                           ↑
                                   Config Subscriber (MQTT)
```

## Installation

### Prérequis

- Raspberry Pi Zero 2 W avec HAT ReSpeaker 2-Mic
- Python 3.9+
- ALSA configuré pour ReSpeaker
- Broker MQTT (ex. Mosquitto)

### Dépendances

```bash
pip install -r requirements.txt
```

### Déploiement

```bash
# Copier les fichiers
sudo cp -r audioin/ /opt/Skull/apps/
sudo cp skull-audioin.sh /opt/Skull/bin/
sudo cp skull-audioin.service /etc/systemd/system/

# Permissions
sudo chmod +x /opt/Skull/bin/skull-audioin.sh
sudo chown -R skull:skull /opt/Skull/apps/audioin

# Service systemd
sudo systemctl daemon-reload
sudo systemctl enable skull-audioin
sudo systemctl start skull-audioin
```

## Configuration

### Seuils VAD par défaut

```json
{
  "threshold": 0.3, // Seuil RMS d'activation [0..1]
  "attack_ms": 80, // Délai activation (ms)
  "release_ms": 200, // Délai désactivation (ms)
  "eos_ms": 800 // Silence pour fin de parole (ms)
}
```

### Variables d'environnement

```bash
export ALSA_CARD=sndrpirpspeaker  # Device ALSA
export PYTHONPATH=/opt/Skull/apps
```

## Utilisation

### Lancement manuel

```bash
cd /opt/Skull/apps/audioin
python -m audioin.main --log-file /opt/Skull/logs/audioin.log
```

### Monitoring MQTT

```bash
# Écouter toutes les métriques
mosquitto_sub -t 'audio/#' -v

# RMS en temps réel (20ms)
mosquitto_sub -t 'audio/rms'

# États VAD
mosquitto_sub -t 'audio/vad'

# Capacités du service (retained)
mosquitto_sub -t 'audio/capabilities'
```

### Configuration dynamique

```bash
# Modifier seuil VAD à chaud
mosquitto_pub -t audio/vad/config -m '{
  "threshold": 0.25,
  "attack_ms": 60,
  "release_ms": 150,
  "eos_ms": 600
}'
```

## Messages MQTT

### Publications du service

#### `audio/rms` (20ms)

```json
{
  "ts_ms": 1703123456789,
  "rms": 0.27
}
```

#### `audio/vad` (changements d'état)

```json
{
  "ts_ms": 1703123456789,
  "active": true,
  "rms": 0.41
}
```

#### `audio/vad` (fin de parole)

```json
{
  "ts_ms": 1703123456789,
  "active": false,
  "rms": 0.05,
  "end_of_speech": true
}
```

#### `audio/capabilities` (retained, au démarrage)

```json
{
  "mic": "respeaker-2mic",
  "rate": 16000,
  "vad": true,
  "channels": 1
}
```

### Souscriptions du service

#### `audio/vad/config` (configuration VAD)

```json
{
  "threshold": 0.3,
  "attack_ms": 80,
  "release_ms": 200,
  "eos_ms": 800
}
```

## Tests

### Tests unitaires

```bash
# Tous les tests
pytest

# Avec coverage
pytest --cov=audioin --cov-report=html

# Test spécifique
pytest tests/test_vad.py::TestVoiceActivityDetector::test_attack_transition
```

### Tests manuels

```bash
# Lister devices audio disponibles
python -m audioin.main --list-devices

# Mode verbose
python -m audioin.main --verbose
```

### Scénarios de test

1. **RMS constant** : `aplay sine_1khz.wav` → RMS stable ~0.3
2. **VAD activation** : Parler dans le micro → `active: true`
3. **VAD release** : Rester silencieux → `active: false`
4. **End of Speech** : Long silence → `end_of_speech: true`
5. **Config à chaud** : Publier nouveau seuil → VAD se reconfigure

## Métriques et logs

### Logs JSON (`/opt/Skull/logs/audioin.log`)

```json
{
  "timestamp": "2024-01-01T12:34:56Z",
  "level": "INFO",
  "module": "audioin",
  "message": "Statistiques RMS",
  "rms_avg": 0.23,
  "active_ratio": 0.15
}
```

### Statistiques périodiques (1 min)

- RMS moyen
- Ratio frames actives/totales
- État VAD courant
- Taille queue audio

## Performances

- **Latence** : < 50ms par frame (objectif)
- **CPU** : ~10-15% sur RPi Zero 2W
- **Mémoire** : ~30MB RSS
- **Réseau** : ~100 msg MQTT/seconde (pic)

## Dépannage

### Audio non détecté

```bash
# Vérifier devices ALSA
aplay -l
arecord -l

# Test capture
arecord -D plughw:sndrpirpspeaker -f S16_LE -r 16000 -c 1 test.wav

# Driver ReSpeaker
sudo dmesg | grep -i respeaker
```

### MQTT non connecté

```bash
# Test broker
mosquitto_pub -t test -m "hello"
mosquitto_sub -t test

# Logs service
journalctl -u skull-audioin -f
```

### Performances dégradées

```bash
# Monitoring ressources
htop
iotop -ao

# Queue audio élevée
tail -f /opt/Skull/logs/audioin.log | grep queue
```

## Développement

### Linting et formatage

```bash
# Ruff (linting + formatting)
ruff check audioin/
ruff format audioin/

# MyPy (type checking)
mypy audioin/
```

### Structure du code

```
audioin/
├── __init__.py          # Package init
├── main.py              # Point d'entrée CLI
├── service.py           # Service principal
├── config.py            # Configuration
├── audio_capture.py     # Capture ALSA
├── rms.py               # Calculateur RMS
├── vad.py               # Voice Activity Detector
├── mqtt_client.py       # Client MQTT
└── logger.py            # Logger JSON

tests/
├── test_rms.py          # Tests RMS
├── test_vad.py          # Tests VAD
├── test_config.py       # Tests configuration
└── test_integration.py  # Tests d'intégration
```

### Ajout de nouvelles métriques

1. Modifier `service.py` → `_process_audio_frame()`
2. Ajouter publication MQTT dans `mqtt_client.py`
3. Documenter nouveau topic MQTT
4. Ajouter tests unitaires

## Licence

MIT - Voir fichier LICENSE

## Support

- Documentation : https://skull-pi.local/docs/audioin
- Issues : Ouvrir un ticket GitLab
- Logs : `/opt/Skull/logs/audioin.log`
- Status : `systemctl status skull-audioin`
