Голосовые ИИ-пайплайны в реальном времени поверх WebRTC SFU

• мин чтения
Голосовые ИИ-пайплайны в реальном времени поверх WebRTC SFU

Интеграция диалоговых голосовых моделей ИИ, таких как Gemini Live или OpenAI Realtime API, в живые многопользовательские звонки WebRTC обычно вынуждает команды разработчиков строить хрупкую архитектуру: поднимать headless-браузеры или тяжелые C++ воркеры GStreamer на бэкенде ИИ только ради передачи Opus поверх SRTP. При проектировании ИИ-шлюза внутри Slyber SFU Server я избавился от дублирования WebRTC на сервере, создав легковесный полнодуплексный бинарный WebSocket-конвейер (/ai/ws).

В сочетании с движком маршрутизации на Go без аллокаций этот шлюз позволяет любому оркестратору на Python, Node.js или Go транслировать сырые фреймы Opus в комнату WebRTC, сохраняя аппаратно-ускоренное воспроизведение в браузере и сквозное шифрование.

1. Отделение транспорта WebRTC от инференса ИИ (/ai/ws)

Вместо того чтобы обрабатывать ICE-кандидаты, рукопожатия DTLS и обратную связь RTCP внутри вашего ИИ-микросервиса, SFU предоставляет защищенный WebSocket-эндпоинт /ai/ws?room=room-id&mode=mux (документация шлюза):

  1. Извлечение аудио от человека к ИИ. Когда участники говорят в комнате, SFU снимает заголовки SRTP/RTP и пересылает сырые фреймы Opus по WebSocket с префиксом [len(speaker_id), rfc6464_audio_level, speaker_id...], чтобы ваш ИИ-бэкенд точно знал, кто именно из участников говорит.
  2. Мультиплексирование нескольких ботов (mode=mux). Одно WebSocket-соединение может динамически создавать до 6 независимых ИИ-агентов в одной комнате с помощью JSON-команд управления (spawn_agent и remove_agent); каждому агенту назначается собственный SSRC и идентификатор трека, чтобы клиенты отображали индивидуальные индикаторы речи для каждого бота.
  3. Инжект одиночных фреймов по HTTP. Для разовых голосовых уведомлений или объявлений бэкенд-сервисы могут отправить сырую полезную нагрузку Opus через POST /ai?room=room-id без поддержания постоянного сокета.

2. Выравнивание неравномерного аудио нейросети с помощью 20 мс RTP-пейсера

Мультимодальные LLM генерируют фрагменты речи неравномерно — часто отдавая 400–800 мс аудио одной пачкой, за которой следует сетевой джиттер. Прямая отправка таких пачек в WebRTC-сессию вызывает опустошение буфера джиттера в браузере и слышимые щелчки.

Внутри Slyber SFU Server за каждым запущенным слотом ИИ закреплен изолированный кольцевой буфер (до 600 фреймов / 12 секунд речи), управляемый строгим таймером на 20ms, который маркирует исходящие пакеты Opus монотонными порядковыми номерами и точным шагом RTP-таймстампа +960 при частоте 48 кГц.

3. Детекция перебивания (VAD Barge-In) быстрее 60 мс без расшифровки аудио

Естественный диалог человека с ИИ требует мгновенного прерывания: как только пользователь начинает говорить, бот должен немедленно замолчать. Расшифровка пакетов Opus на стороне SFU для запуска нейросетевого VAD сожгла бы ресурсы процессора и нарушила бы сквозное шифрование RFC 9605 SFrame.

Вместо этого SFU считывает открытое расширение RTP-заголовка RFC 6464 (urn:ietf:params:rtp-hdrext:ssrc-audio-level) из входящих аудиопакетов участников:

Code
// Когда энергия голоса человека превышает порог в течение 3 фреймов подряд (~60 мс):
1. Auto-flush мгновенно очищает все несказанные фреймы из очереди 20 мс пейсера бота
2. SFU отправляет {"type": "ai_vad_barge_in", "participant_id": "user-1"} в /ai/ws
3. После 360 мс тишины SFU отправляет событие {"type": "ai_vad_speech_end"}
Этап пайплайнаМеханизмПреимущество по задержке и масштабированию
Вход / выход ИИМультиплексированный бинарный WebSocket (/ai/ws?mode=mux)До 6 независимых голосов ИИ поверх 1 TCP-сокета
Устранение джиттераСерверный RTP-пейсер 20 мс (шаг таймстампа +960)Плавное воспроизведение в браузере при пачечном выводе LLM
Детекция перебиванияИнспекция заголовка RFC 6464 (порог в 3 фрейма)Сброс очереди <60 мс без расшифровки аудиопотока
Совместимость с Zero-TrustРаботает совместно с SFrame E2EE и ротацией ключей MLSПоддержка комнат с принудительным REQUIRE_E2EE=true

Поскольку уровень голоса считывается из расширения RTP-заголовка, детекция перебивания работает на скорости сетевого канала без криптографических накладных расходов — даже если в комнате принудительно включен режим REQUIRE_E2EE=true. Изучите полные бенчмарки развертывания на странице кейса Slyber SFU Server или начните работу на slyber.com.

Нужна высоконагруженная архитектура или индивидуальное инженерное решение?

Я проектирую и создаю отказоустойчивые Go-бэкенды, системы WebRTC-стриминга в реальном времени, кастомные протоколы и fullstack-приложения. Давайте обсудим ваши технические задачи и архитектуру.

Читайте также

Архитектура WebRTC SFU на Go без аллокаций

Написать базовый сервер селективной пересылки WebRTC (SFU) на Go с использованием библиотеки pion/webrtc/v4 можно за пару дней, однако при масштабировании до тысяч одновременных комнат всплывают серьезные узкие места: открытие десятков тысяч эфемерных UDP-портов ломает сеть контейнеров, выделение памяти в куче на каждый пакет вызывает паузы сборщика мусора, а стандартная ренегоциация SDP приводит к многосекундным черным экранам при переключении собеседников.

Как устроен SFU Server

Устройство высоконагруженного SFU сервера под капотом. Изоляция ядер, очереди SPSC, оценка канала TWCC и GCC, слои Simulcast и SVC, шлюзы WHIP и стек MoQ.

Почему я отказался от древнего Coturn для своего TURN сервера

Когда запускаешь WebRTC проект в локальной сети или тестируешь звонки между двумя домашними роутерами, прямое соединение через STUN работает идеально. Проблемы начинаются в продакшене. Около 15 или 20 процентов пользователей находятся за NAT, операторским CGNAT у мобильных провайдеров или жесткими корпоративными файрволами. Без надежного сервера посредника (TURN) такие клиенты видят бесконечный экран подключения и уходят.

Архитектура Slyber TURN Server

Написать базовый STUN и TURN сервер на Go с использованием библиотеки pion/turn/v4 можно за один вечер в сотню строк кода. Но как только такой прототип попадает на боевой сервер с сотнями одновременных медиапотоков, вскрываются системные проблемы очередь одного UDP сокета упирается в блокировки ядра Linux, мобильные клиенты при смене сети забивают пул портов мертвыми аллокациями, а открытый релей становится мишенью для сканирования внутренней облачной сети.