Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

heimdallr-sense

"Hearing the voice before the storm"

Voice Activity Detection на Go с микрофона через PipeWire (pw-cat). Чистый Go, без CGO.

Захватывает аудио с микрофона, прогоняет через WebRTC VAD, печатает [VOICE START] / [VOICE END] и записывает аудио в WAV-файлы или отправляет на сервер.

Зависимости

  • Linux с PipeWire (pw-cat)
  • Go 1.25+

Сборка

make                    # собрать все архитектуры
make all                # то же самое
make clean              # удалить бинарники

Собранные бинарники в build/:

Бинарник Архитектура
heimdallr-sense-linux-amd64 x86_64
heimdallr-sense-linux-arm64 ARM64 (Raspberry Pi 4+, Rock5)
heimdallr-sense-linux-armv7 ARMv7 (Tinker Board, RPi 2/3)

Локальная сборка:

go build -o heimdallr-sense ./cmd/vad

Запуск

./heimdallr-sense

Пример вывода (log_enabled: true):

{"time":"2026-07-23T15:30:45Z","level":"INFO","msg":"config loaded from ./config.yaml"}
{"time":"2026-07-23T15:30:45Z","level":"INFO","msg":"listening","rate":8000,"frame_ms":30,"frames":5,"voice_threshold":4,"silence_threshold":3,"record_mode":"file"}
{"time":"2026-07-23T15:30:46Z","level":"INFO","msg":"voice start"}
{"time":"2026-07-23T15:30:46Z","level":"INFO","msg":"recording started","pre_buffer_chunks":3}
{"time":"2026-07-23T15:30:48Z","level":"INFO","msg":"voice end"}
{"time":"2026-07-23T15:30:48Z","level":"INFO","msg":"recording saved","chunks":8,"duration_s":"1.2"}
{"time":"2026-07-23T15:30:48Z","level":"INFO","msg":"file saved","path":"./recordings/2026-07-23_15-30-46.000.wav"}

Ctrl+C для остановки.

Конфигурация

Все параметры задаются в config.yaml. Конфиг ищется в порядке:

  1. /etc/heimdallr-sense/config.yaml
  2. ./config.yaml (текущая директория)

Если файл не найден — используются дефолты.

sample_rate: 8000
vad_frame_ms: 30
frames_per_chunk: 5
voice_threshold: 4
silence_threshold: 3
vad_mode: 3

# audio_source: pw-cat, arecord, custom
audio_source: pw-cat
audio_command: ""

# recording: none, file, http, https, both
record_mode: file
record_dir: ./recordings
pre_buffer_chunks: 3
https_url: ""
http_timeout: 10
min_chunks: 3
tls_skip_verify: false
log_enabled: true

Параметры VAD

Параметр Описание Дефолт
sample_rate Частота дискретизации микрофона (Hz) 16000
vad_frame_ms Длительность фрейма VAD (мс) 30
frames_per_chunk Сколько фреймов анализировать за раз 5
voice_threshold Мин. фреймов с голосом для START 4
silence_threshold Мин. чанков без голоса для END 3
vad_mode Агрессивность VAD (0-3) 3

Параметры аудио

Параметр Описание Дефолт
audio_source Источник аудио: pw-cat, arecord, custom pw-cat
audio_command Кастомная команда (при audio_source: custom) ""

Примеры:

# PipeWire (по умолчанию)
audio_source: pw-cat

# ALSA
audio_source: arecord

# Кастомная команда (например, через SSH)
audio_source: custom
audio_command: "ssh remote-host arecord -f S16_LE -r 8000 -c 1 -t raw -"

Параметры записи

Параметр Описание Дефолт
record_mode Режим записи: none, file, http, https, both none
record_dir Каталог для WAV-файлов ./recordings
pre_buffer_chunks Чанков в кольцевом буфере (запись до голоса) 3
https_url URL для POST-запроса (multipart/form-data), поддерживаются http:// и https:// ""
http_timeout Таймаут HTTP-запроса (сек) 10
min_chunks Мин. чанков для сохранения записи (отсекает короткие шумы) 3
tls_skip_verify Игнорировать проверку TLS-сертификата false
log_enabled Включить JSON-логи (slog) true

Расчёт окна

  • Длительность чанка = vad_frame_ms * frames_per_chunk (по умолчанию 150мс)
  • Задержка VOICE START = 1 чанк (150мс)
  • Задержка VOICE END = silence_threshold чанков (450мс)
  • Pre-buffer = pre_buffer_chunks чанков (450мс) — аудио до начала голоса

Режимы VAD

Значение Режим Описание
0 Quality Максимальная чувствительность
1 LowBitrate Средняя
2 Aggressive Снижает ложные срабатывания
3 VeryAggressive Минимальная чувствительность, только явная речь

Режимы записи

Значение Описание
none Запись отключена
file Сохранение WAV в record_dir
http POST на https_url по HTTP
https POST на https_url по HTTPS
both И файл, и POST

Формат WAV-файлов

  • 16-bit PCM, mono
  • Имя файла: YYYY-MM-DD_HH-MM-SS.mmm.wav (время начала записи)
  • Запись включает pre-buffer (аудио до детекции голоса)

HTTPS/HTTP-загрузка

Режимы http, https и both отправляют WAV-файл на https_url методом POST в формате multipart/form-data. Адрес может начинаться с http:// или https:// — протокол определяется схемой URL, а не значением record_mode.

Запрос содержит:

  • поля формы: filename, sample_rate, duration
  • файл file (WAV, 16-bit PCM mono)
  • query-параметр filename в URL

Примеры конфигурации:

# HTTP-отправка на локальный сервис
record_mode: http
https_url: http://127.0.0.1:8080/api/transcribe

# HTTPS с игнорированием проверки сертификата
record_mode: https
https_url: https://example.com/upload
tls_skip_verify: true

tls_skip_verify применяется только к https:// URL, на http:// он не влияет.

При ошибке загрузки (недоступный сервер, таймаут, HTTP-статус >= 400) ошибка выводится в stderr и в JSON-лог. Если включён режим both, запись при этом не теряется — файл сохраняется в record_dir.

Пример серверного обработчика:

@app.post("/upload")
async def upload(file: UploadFile):
    data = await file.read()
    # data — WAV-файл

Запуск как сервис

systemd

Файл сервиса: systemd/heimdallr-sense.service

Установка:

# бинарник
sudo cp build/heimdallr-sense-linux-amd64 /usr/local/bin/heimdallr-sense
sudo chmod +x /usr/local/bin/heimdallr-sense

# конфиг
sudo mkdir -p /etc/heimdallr-sense
sudo cp config.yaml /etc/heimdallr-sense/config.yaml

# сервис
sudo cp systemd/heimdallr-sense.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable heimdallr-sense
sudo systemctl start heimdallr-sense

Управление:

sudo systemctl start heimdallr-sense     # запустить
sudo systemctl stop heimdallr-sense      # остановить
sudo systemctl restart heimdallr-sense   # перезапустить
sudo systemctl status heimdallr-sense    # статус
sudo systemctl disable heimdallr-sense   # отключить автозапуск

Логи:

journalctl -u heimdallr-sense -f              # следить в реальном времени
journalctl -u heimdallr-sense --since today    # за сегодня
journalctl -u heimdallr-sense -n 50            # последние 50 строк

Доступ к микрофону:

Если сервис запускается от root, доступ к PipeWire/ALSA может потребовать дополнительных настроек:

# добавить в [Service] если нужен доступ к PulseAudio/PipeWire
Environment="PULSE_SERVER=unix:/run/user/1000/pulse/native"
# или запускать от пользователя, у которого есть доступ к микрофону
User=sb
Group=sb

SystemV (init.d)

Файл скрипта: systemd/heimdallr-sense.init

Установка:

# бинарник
sudo cp build/heimdallr-sense-linux-amd64 /usr/local/bin/heimdallr-sense
sudo chmod +x /usr/local/bin/heimdallr-sense

# конфиг
sudo mkdir -p /etc/heimdallr-sense
sudo cp config.yaml /etc/heimdallr-sense/config.yaml

# init-скрипт
sudo cp systemd/heimdallr-sense.init /etc/init.d/heimdallr-sense
sudo chmod +x /etc/init.d/heimdallr-sense

# регистрация в автозагрузке
sudo update-rc.d heimdallr-sense defaults

Управление:

sudo service heimdallr-sense start     # запустить
sudo service heimdallr-sense stop      # остановить
sudo service heimdallr-sense restart   # перезапустить

Логи:

tail -f /var/log/heimdallr-sense.log

Деинсталляция:

sudo update-rc.d -f heimdallr-sense remove
sudo rm /etc/init.d/heimdallr-sense
sudo rm /etc/heimdallr-sense/config.yaml
sudo rm /usr/local/bin/heimdallr-sense

Архитектура

pw-cat (микрофон)
  → raw S16LE PCM
    → ring buffer (pre-buffer)
      → WebRTC VAD → [VOICE START/END]
        → recording buffer → WAV file / HTTPS POST

Программа запускает pw-cat -r --format s16 --rate <rate> --channels 1 -, читает сырые PCM-данные, разбивает на фреймы и прогоняет через WebRTC VAD (реализация rolandhe/go-vad — чистый Go порт libfvad).

При обнаружении голоса буфер pre-buffer сбрасывается в начало записи, аудио копится пока голос есть, и после silence_threshold чанков тишины запись финализируется.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages