📡

Переговорка (ToshaStream): стрим-сервер и голосовая для команды

собственный продукт в продакшене, версия 1.50.0: голос, чаты и закрытый эфир

Закрытая площадка на своём сервере: трансляция по SRT с двумя качествами, просмотр в браузере, голосовая связь напрямую между участниками через WebRTC, чаты и роли доступа. Стрим-сервер и голосовая для команды.

В продакшене · собственный продукт
< 1 с
задержка просмотра через WebRTC (WHEP)
До 10
человек на голосовой канал, соединение напрямую
90 дней
история чатов в базе, переживает перезапуск сервиса
Переговорка DevUnit Lab: справка по чатам, голосу и эфиру и профиль пользователя в мобильном клиенте
Переговорка DevUnit Lab: справка по чатам, голосу и эфиру и профиль пользователя в мобильном клиенте

Задача

Прежняя схема была голым nginx-rtmp без настроек: трансляция периодически обрывалась, а подключиться к потоку и даже писать в него мог любой, кто знал адрес. Ролей и закрытых сессий не было. Для рабочего созвона такая связка не годится так же, как для трансляции.

Нужна была закрытая площадка для узкого круга людей: голосовые каналы, текстовые чаты и, когда нужно, трансляция игрового процесса с домашнего компьютера. Плюс два условия. Зритель с телефона на LTE и зритель на гигабитном канале должны получать разный поток, а не один компромиссный. А сервис не должен ронять соседей: раньше сервер стрима работал на одной машине с входным узлом VPN, и любой сбой стрима грозил VPN у всех клиентов.

Решение

В репозитории продукт называется «Переговорка» (прежнее имя — ToshaStream). Он открывается в браузере по секретной ссылке, а трансляцию можно смотреть ещё и в VLC. Страница работает в двух режимах: «Переговорка» (голос и чаты без плеера) и «Эфир» (плеер, чат эфира и голосовая рядом). Что сделано по README и журналу выпусков:

  • Приём потока по SRT с шифрованием и паролем, резервный приём по RTMP.
  • Два качества одновременно: родное 3440×1440 и облегчённое 1720×720 для мобильного интернета.
  • Просмотр в браузере через HLS и через WebRTC (WHEP) с задержкой меньше секунды, в VLC — по RTSP и SRT.
  • Голосовая на WebRTC-mesh со своим TURN: три общих канала, звонки в личных беседах, группы, режим «только голос».
  • Показ экрана через сервер: 1080p, 30 кадров в секунду, до 18 Мбит/с.
  • Чаты: три общих, личные, группы и чат эфира; реакции, ответы, опросы, закреп, поиск, предпросмотр ссылок, вложения, голосовые сообщения.
  • Роли гость, свой, админ и «только личка», аккаунты на время, журнал входов и кнопка «выйти везде».
  • Пуши на каждое устройство без дублей и настройка «без звука» по беседе.
  • Ночной снимок базы, проверка здоровья контейнеров и автоперезапуск залипшего сервиса.

Как это устроено

SRT вместо RTMP

SRT (Secure Reliable Transport) — протокол передачи видео поверх UDP, который повторно запрашивает потерянные пакеты. Поток с ПК стримера приходит на сервер по SRT под паролем и с ключом шифрования. RTMP оставлен запасным приёмом. Сам сервер видео не перекодирует, поэтому качество эфира целиком зависит от настроек на игровом ПК; инструкция по OBS собрана отдельно.

Два качества эфира без перекодирования на сервере

Оба потока, 3440×1440 и 1720×720, кодирует видеокарта на ПК, а сервер только раздаёт. Единственное, что перекодируется, — звуковая дорожка в AAC для Safari, и это единицы процентов ядра процессора. Обратная сторона: при выключенном ПК нет ни одного из потоков.

Просмотр: HLS для устойчивости, WHEP для скорости

HLS (потоковое видео сегментами) даёт 6–8 секунд задержки, но выдерживает нестабильную мобильную сеть, и в нём можно отмотать назад примерно на 16 секунд (8 сегментов по 2 секунды). WHEP — способ получить поток через WebRTC с задержкой меньше секунды. Зритель выбирает между обычным и «быстрым» режимом. Поток 1440p в браузере играют Chrome, Edge и Safari, а для Firefox есть 720p в H.264.

Голосовая на WebRTC-mesh со своим TURN

WebRTC-mesh означает, что каждый участник соединяется напрямую с каждым: голос через сервер не идёт вовсе, сервер лишь сводит участников и передаёт служебные пакеты. Отсюда задержка в десятки миллисекунд и почти нулевая нагрузка на сервер. Расплата — каждый шлёт голос каждому, поэтому предел стоит осознанно: 10 человек на канал. TURN — ретранслятор для тех, к кому нет прямого соединения. В coturn включены временные учётные данные на час, секрет наружу не выходит, а расшифровать разговор ретранслятор не может.

Закрытый доступ: auth_request в nginx и роли

Каждый запрос к HLS, WHEP и звуку проверяется через auth_request: nginx перед выдачей спрашивает у сервиса, вошёл ли человек. Для VLC и внешних плееров есть отдельный секрет. Роли живут в базе и меняются из админки на ходу, без перезапуска и обрыва чужого разговора. Роль «только личка» видит одну переписку с админом: общие чаты, каналы, эфир и чужие имена для неё закрыты на сервере. Изменяющие запросы принимаются только POST-ом с проверкой Sec-Fetch-Site.

Чаты, голосовые сообщения и история

История чатов лежит в SQLite и переживает перезапуск. Голосовое сообщение записывается прямо из поля ввода (до 5 минут), а сервер перекодирует его в mp3 через ffmpeg, чтобы его играли и iPhone, и Android, и компьютер. Ссылки получают предпросмотр, который собирает сервер, с защитой от SSRF: внутренние и частные адреса не открываются вовсе. Уведомления не дублируются: пока человек читает чат на одном устройстве, пуши не идут ни на какие другие.

Устойчивость сервиса

Контейнеры отвечают на проверку здоровья, а чат — на /healthz с чтением и записью базы. Сторожевой таймер поднимает залипший контейнер в течение минуты, но не чаще трёх раз в час. База снимается по ночам, а отдельная машина забирает снимки и проверяет восстановление; сбой приходит сообщением в Telegram. Сервис работает на отдельной машине, поэтому уронить VPN не может.

Результат

  • Задержка просмотра меньше секунды через WHEP, 6–8 секунд через HLS.
  • До 10 человек на голосовой канал напрямую, без нагрузки на сервер.
  • Рабочие созвоны и трансляции идут на собственной инфраструктуре, без сторонних мессенджеров.
  • История чатов хранится 90 дней и переживает перезапуск.
  • Голос защищён сквозным шифрованием между браузерами.

Технологии: что и зачем

  • Go — сервис чата, аккаунтов, ролей, сигналинга голосовой и счётчика зрителей.
  • MediaMTX — приём SRT и раздача HLS, WHEP, RTSP.
  • WebRTC и coturn — голос напрямую между участниками и собственный TURN.
  • SQLite — аккаунты, сообщения, состояние прочтения.
  • nginx — вход по HTTPS и проверка доступа на каждый запрос.
  • Docker Compose — запуск сервисов с потолком по процессору и памяти.

Статус

Версия 1.50.0 от 29 сентября 2026 года, в продакшене, собственный продукт. Рабочее название в README — «Переговорка»; внутренние имена путей и потоков пока прежние.

Известные ограничения по README: текстовый чат не сквозной, его читает тот, у кого есть root на машине; вход в эфир ограничен аккаунтом, но не ролью; групповой голос — mesh, а не SFU, поэтому больше 10 человек на канал потребует другой схемы; запись эфира сейчас выключена, включать её заново нужно вместе с настроенной ротацией. В планах: проверить эфир после правки задержки SRT, обкатать Telegram-бота управления аккаунтами, сменить пароль публикации SRT.

Вопросы по проекту

Почему для трансляции SRT, а не RTMP, и как это убирает обрывы?
SRT работает поверх UDP и переспрашивает потерянные пакеты. RTMP идёт по TCP и при потерях копит задержку, пока соединение не оборвётся, — именно так рвалась прежняя схема на голом nginx-rtmp. RTMP в сервисе остался только запасным приёмом на случай, если UDP где-то режут.
Какая задержка у трансляции в браузере?
Меньше секунды через WebRTC (WHEP) и 6–8 секунд через HLS. Второе — осознанный размен ради устойчивости на мобильной сети. В HLS можно отмотать назад примерно на 16 секунд. Поток в браузере играют Chrome, Edge и Safari; Firefox получает 720p в H.264.
Слышит ли сервер голосовые разговоры?
Нет. Голос идёт напрямую между участниками, до 10 человек на канал, и шифруется между браузерами. Собственный TURN-сервер нужен только как ретранслятор для тех, кому напрямую не пробиться, и расшифровать звук он не может. Текстовые чаты, в отличие от голоса, не сквозные: они лежат в базе на сервере.
Можно ли вести рабочие созвоны и чаты на своём сервере, а не в облачном мессенджере?
Да. В сервисе три общих голосовых канала, звонки в личных беседах, группы, показ экрана, чаты с историей и опросами. Чат можно вынести отдельным окном поверх игры в оконном режиме (Chrome и Edge от версии 116). Всё работает в браузере на компьютере и телефоне, без установки.
Какие данные хранятся и кто имеет доступ?
Пароли хранятся в виде bcrypt-хешей, аккаунты и история чатов — в SQLite на своём сервере, история 90 дней, журнал входов 180 дней. Доступ разделён ролями «гость», «свой», «админ» и «только личка». К эфиру и голосу каждый запрос проверяется через auth_request в nginx.
Можно ли развернуть такую систему для другой команды?
Да, такие развёртывания берутся под заказ. Сервис поднимается в Docker Compose, названия чатов и тексты интерфейса админ меняет из админки, оформление выбирается из 10 палитр и 10 шрифтов. Оба качества эфира кодирует видеокарта на ПК стримера, поэтому серверу не нужна мощная машина.

Ещё по этому направлению

Тестирование у заказчикаNDA

OshaVPN Router: своя прошивка для MikroTik — VPN на весь офис

прошили заказчику MikroTik с Авито: весь офис за VPN, российское напрямую, зарубежное через туннель, на устройствах ничего не нужно ставить

OpenWrtucode
В продакшене · собственный продукт

VPN-инфраструктура: входной узел в России, выход в Европе

собственный продукт: релей в России, постоянный туннель и узел в Нидерландах

ЗавершёнNDA

Корпоративный шлюз на Xray и nginx для IT-команды

заказ IT-компании: рабочие инструменты снова доступны на своих серверах

Нужно похожее?

Расскажите о задаче — покажем, как решали такое, и прикинем объём работ.