
Привет, друзья! Долго думал, с чего начать. Может, забить промт в нейросеть — от которой уже все устали — и, махнув рукой, сказать «и так сойдёт» или накалякать самому, но от души? И надумал! В общем, если будет нудно — извиняйте, я не писатель и не копирайтер технических статей. Поэтому не удивляйтесь, если текст окажется технически грамотным, а где надо — с длинным тире, это всё проделки DeepSeek и его форматирования.
Начну с того самого вечера, когда мне пришла мысль создать свой аналог голосового и текстового чата. В тот день мы играли с друзьями в Зов Припяти онлайн, да да если кто не знал есть и такой, а связь держали через уже сейчас лагающий Discord. Тогда я поймал себя на мысли, глядя на КПК в игре: почему бы не сделать что‑то подобное — но с примесью Discord, TeamSpeak и RaidCall?

Идея взять интерфейс у раций пришла не на пустом месте. Я очень люблю электронику, рации и всё, что с этим связано, поэтому у меня в наличии есть не одна пара всеми известных Baofeng UV-5R, Quansheng UV‑K5(8) и Baofeng UV-5RH. По ламповости мне ближе всего Quansheng UV‑K5 — с его оранжевым дисплеем. Я взял именно эту палитру за основу, но инвертировал: чтобы яркий оранжевый свет от дисплея не бил по глазам ночью. Шрифт и элементы управления сделал в оттенках оранжевого, а фон — тёмным. Конечно в финальной версии моей голосовой рации, от Quansheng UV‑K5 не осталось и следа, но изначально я вдохновлялся именно ей.
Про WebRTC и почему P2P — это не так просто, как кажется
Очень давно, когда я только начинал изучать веб‑программирование, мне очень сильно зашла технология WebRTC. Эти P2P‑звонки просто завораживали: пара строк кода — и вот ты уже говоришь по видеосвязи в браузере, пишешь мгновенные сообщения, отправляешь файлы. Что может быть круче — такая технология и у тебя в руках, в свободном доступе!
Но с очень большими оговорками. Как я понял позже.
Строгий NAT
Строгий NAT для P2P‑соединения почти как приговор, так как P2P устанавливается напрямую между двумя устройствами. Но если у одного из них «строгий» NAT — а это сплошь и рядом в корпоративных сетях и у мобильных операторов — соединение просто не поднимется. Даже если вы в одном здании с одним интернет кабелем, но подключились к разным точкам доступа WiFi, это уже «Великая китайская стена» для P2P! Нужен STUN‑сервер, чтобы определить внешний адрес, и TURN‑сервер‑релей, чтобы пустить трафик через себя если p2p «уперся в стену». А TURN — это, по сути, тот же медиасервер, только тупой. И трафик через него идёт в обход экономии, ради которой P2P и придумывали.
Mesh в P2P соединении
Mesh в P2P — это реальная проблема. Если у вас в комнате 10 человек и вы используете чистый P2P Mesh — каждый клиент подключается к каждому. Это N×(N−1) соединений, и каждое устройство одновременно кодирует 9 исходящих потоков и декодирует 9 входящих. Мобильный процессор скажет до свидания, а батарея сядет за час. Связь рассыпается при первом же лаге на любом узле.
NAT и Mesh — две основные причины, почему идея «сделать всё на P2P» ушла в долгий ящик. Вернулась моя идея спустя года в тот вечер, когда мы в очередной раз катали в мою любимую игру Сталкер — «Зов Припяти»…
P2P, SFU, MCU — что выбрать и почему
А теперь давайте углубимся в саму инфраструктуру трех технологий, у которых есть свои плюсы и свои огромные минусы! К тому моменту, как я начал разрабатывать первый прототип голосового чата, у меня уже был небольшой опыт работы с командной строкой Linux, имелся опыт поднятия своего сервера и его настройки. Думаю, многим, кто этим занимался, знакомы iptables, dnsmasq, HestiaCP, Janus и прочие спутники серверной системы. В тонкости их использования я углубляться не буду — статья не об этом, но эти знания мне очень пригодились. Поговорим о том, почему я выбрал MCU, а не SFU и уж тем более не P2P.
Три архитектуры в двух словах
P2P (Mesh). Каждый с каждым. Никакого сервера между ними (кроме сигналинга и STUN/TURN). Просто в реализации. Ужасно масштабируется.
SFU (Selective Forwarding Unit). Появляется сервер, но он не микширует звук. Он просто принимает один поток от клиента и раздаёт его каждому — по отдельности. Discord, насколько я понял, работает именно так, а для малых групп и отдельных сценариев задействуются элементы P2P.
MCU (Multipoint Control Unit). Сервер принимает потоки от всех, микширует их в один и отдаёт каждому клиенту единственный готовый поток. Именно эта архитектура используется в большинстве телефонных конференций и в VoIP‑мостах.
Сравнение на примере комнаты в 10 человек
Опус‑кодек, 32 kbps на поток. Плюс оверхед RTP/UDP — примерно 20% сверху, но для чистоты сравнения возьмём только полезную нагрузку. Это подсчеты только для аудио потока, про видео я даже не стал затрагивать таблицу, там в разы все хуже. Считаем трафик и количество потоков на одного клиента (не на сервер, а на устройство игрока):
Параметр |
P2P (Mesh) |
SFU |
MCU |
|---|---|---|---|
Исходящих потоков у клиента |
9 |
1 |
1 |
Входящих потоков у клиента |
9 |
9 |
1 |
Итого потоков на клиента |
18 |
10 |
2 |
Трафик на отдачу (1 клиент) |
288 kbps |
32 kbps |
32 kbps |
Трафик на приём (1 клиент) |
288 kbps |
288 kbps |
32 kbps |
Суммарный трафик клиента |
576 kbps |
320 kbps |
64 kbps |
Трафик на сервере |
0 |
~3200 kbps |
~640 kbps |
Нагрузка на CPU клиента |
Высокая |
Средняя |
Низкая |
Нагрузка на CPU сервера |
Нет |
Низкая |
Высокая |
Связь рвётся, если у одного лаг |
Да |
Частично |
Практически нет |
Здесь важно понимать три вещи.
Первое — трафик. Клиент на MCU получает 32 kbps независимо от размера комнаты. Хоть 2 человека, хоть 10 — он скачивает ровно один поток. У клиента на SFU при 10 участниках — уже 288 kbps, и это растёт линейно. У клиента на P2P Mesh — 576 kbps и растёт квадратично: при 20 участниках это уже 2.3 Mbps только на голос.
Второе — нагрузка. SFU и P2P перекладывают микширование на устройство игрока. MCU — на сервер. Это ключевое различие. У игрока может быть старый телефон, слабый ноутбук, или он в момент матча запускает ещё и стрим — и голосовая связь начинает «плавать». Да по идее нас не должно это волновать, многих учат что нагрузку надо перебрасывать на клиента, минимум на сервер, это с одной стороны правильно, что бы обработать больше пользователей, но с другой стороны это не решает глобальную проблему в лице NAT. MCU такое исключает: устройство игрока получает готовый микс и просто играет его, при этом NAT и огромный исходящий трафик нас уже не заботят.
Третье — стабильность. В P2P при проблемах у одного участника страдают все. В SFU — почти все, потому что каждый клиент собирает потоки со всех. В MCU — только тот, у кого проблемы. Все остальные слышат чистый микс сервера.
Итог: MCU — это архитектура, где жертвуешь сервером ради игрока и ради тех плюсов которые она дает, при этом закрывая глаза на минусы!
Сервер, который выдержит MCU
Раз уж я выбрал самую «тяжёлую» архитектуру для сервера, пришлось позаботиться и о железе. Пока большинство инди‑сервисов живут на VPS в 2 ядра, MCU там просто не заведётся. Микширование десяти голосовых потоков в реальном времени требует мощностей CPU, и это не то, что можно посадить на копеечный тариф. Поэтому было решено собрать свой на первое время. Да это не топовая сборка, но и не из серии «Я его слепила из того что было», был и Intel Xeon E5-2667 и E5-2673 v3, первый меня не устроил по TDP 120W, а под второй не было наличии материнки, поэтому выбор пал на третий вариант с TDP 95W E5-2650 v2 отсюда на этом всё пока и крутится:
Компонент |
Характеристики |
|---|---|
Процессор |
Intel Xeon E5-2650 v2, 2.60 GHz, 8 ядер 16 потоков |
Оперативная память |
16 GiB, DDR3 ECC, 4 канала |
Основной диск |
NVMe SSD Silicon Power, 1 ТБ |
Резервный диск |
SATA SSD, 1 ТБ |
Операционная система |
Ubuntu 24.04 LTS |
Сеть |
1 Гбит/с |
У Xeon E5-2650 v2: 8 ядер и 16 потоков, хорошая пропускная способность шины и достаточно холодный из всех имеющихся в этой линейке. Крепкий рабочий конь для медиасерверов, для начала пока сойдет.
NVMe от Silicon Power на 1 ТБ — под хот‑данные: база чата, сессии, логи. Текстовый чат пишет в БД каждое сообщение, и разница между 0.1 мс и 5 мс на SATA становится заметна при тысячах сообщений в час.
Настройка сервера — отдельный квест, длиной в месяц. За это время было много всего: то тут что‑то отваливается, то там конфиг не применяется, то ищешь очевидную с точки зрения документации вещь, а она работает совсем не так. Единой инструкции, как поднять всё это с нуля, увы, нет. Каждый проект — своя мозаика и пазл. Но если кому‑то будет интересно — напишу статью о своем опыте.
Janus: сердце голосовой связи
В основе Setсhat лежит Janus Gateway — открытый медиасервер для WebRTC. Я использую его через плагины:
janus.plugin.audiobridge— для голоса. Микширует аудио от всех участников в комнате.Документация: janus.conf.meetecho.com/docs/audiobridge.html.
janus.plugin.textroom— для текстового чата. Это отдельный канал поверх WebRTC DataChannel, работает независимо от AudioBridge.Документация: janus.conf.meetecho.com/docs/textroom.html.
Что интересного выяснилось по ходу работы.
AudioBridge не умеет отправлять клиенту кастомные системные сообщения. Он умеет доставлять события о talking / stopped‑talking, уведомления о входе/выходе участников, но произвольный текст — нет. Возможно, я плохо покопался в документации — если что, поправьте меня. Поэтому для моих нужд — модальных окон, мгновенной синхронизации действий в комнате — пришлось городить свои, так сказать, костыли.
System message
Решение оказалось простым: раз у нас уже есть TextRoom, давайте использовать его как транспорт для системных команд. AudioBridge отвечает за звук, TextRoom — за то, чтобы мгновенно синхронизировать UI у всех участников. Одна архитектура обслуживает две задачи. Технически сигнал от одного клиента доходит до другого без обращений к серверу БД, через тот же DataChannel, по которому летят обычные сообщения, — это как раз то, что нам и надо.
Если коротко объяснить суть system message, то представьте, что мы отправляем команду в общий чат, которую никто не увидит, кроме скрипта на клиенте. Скрипт отсеивает это сообщение и смотрит, что там написано. Например, system:kick:id:1 — системе надо показать пользователю с id 1, что его только что кикнули. Пользователь при этом увидит модальное окно о кике. Это утрированно, но работает примерно так, как я описал, — и что самое главное, идеально! Результат мгновенный: задержка в десятки миллисекунд, нагрузка на сервер минимальна.
Да в этом есть один уязвимый момент, что пользователи сами могут рассылать системные сообщения, через форму отправки сообщений, но и это можно поправить, просто фильтруя его данные, что он отправляет. Почему system message удобно — увидите дальше, в разделе про фишки.

Что в итоге получилось
SetChat — голосовой и текстовый чат в стиле рации, работающий прямо в браузере без установки. В планах — APK‑версия для Android: она уберёт браузерный интерфейс, который сжимает UI рации на телефоне. Основные фишки — по порядку.

Тюнер частот
Настоящий цифровой тюнер, как на рации. Шкала с делениями, прицел по центру, эффект барабана при прокрутке. Диапазоны FM, AM (MW), SW, PMR. На пустой волне шипит — причём и звуком, и визуальным шумом на экране, весь шум синтезирован в js и canvas. При заходе — другой пользователь слышит своеобразный бип рации, при выходе короткое шипение, на сообщение и закреп тоже свои сигналы. Шкалу тюнера можно крутить пальцем, колесом мыши, стрелками или ввести частоту вручную.
Все зарегистрированные комнаты и гостевые видны в одном общем эфире. Открываешь тюнер — видишь, кто где вещает. Одна частота — одна комната, никаких пересечений.
Гостевой режим
Заходишь без регистрации, занимаешь свободную частоту, говоришь. Всё. Через минуту после выхода последнего участника комната автоматически освобождается, и частоту может занять кто‑то другой. Это как взять рацию на вечер: пришёл, поговорил, ушёл — слот вернулся в пул. Вот сравнительная таблица для гостя и зарега.
Возможность |
Гость |
Зарег |
|---|---|---|
Голос и текст в комнате |
✅ |
✅ |
Тюнер, эквалайзер, телеметрия |
✅ |
✅ |
Усиление микрофона, шумодав |
✅ |
✅ |
Пароль на комнату |
? при создании |
✅ в любой момент |
Модерация (кик, бан, мьют) |
❌ |
✅ |
Редактирование комнаты |
❌ |
✅ |
До 10 комнат + 1 радио |
❌ |
✅ |
Бессрочное существование |
❌ |
✅ |
История чата |
❌ |
✅ |
Привязка к кнопкам 1–10 + radio |
❌ |
✅ |
Подписки и уведомления |
❌ |
✅ |
Стоимость |
0 ₽ |
0 ₽ |

UI Setchat кнопки нижней панели
Лицевая сторона (когда controls‑inner не перевёрнут) слева направо:
Кнопка |
Иконка |
Действие |
Доступна когда |
|---|---|---|---|
Микрофон |
|
Включить/выключить свой микрофон |
Только когда в комнате и соединение установлено |
BBCode |
|
Открыть модалку разметки (жирный, ссылки, иконки, спойлеры) |
Только когда композер открыт |
Эмодзи |
|
Открыть модалку эмодзи |
Только когда композер открыт |
Написать (ручка) |
|
Открыть композер для сообщения |
Только когда в комнате |
Отправить (самолётик) |
|
Отправить сообщение или закрыть пустой композер |
Появляется только когда композер открыт, вместо «ручки» |
Ручка и самолётик — одна и та же позиция. Они меняются местами через hidden:
Композер закрыт → видна ручка.
Композер открыт → виден самолётик, ручка скрыта.
Задняя сторона (после клика на кнопку меню)
Слева направо:
Кнопка |
Иконка |
Действие |
|---|---|---|
Логи |
|
Открыть/закрыть панель логов ( |
Настройки |
|
Открыть модалку настроек: микрофон, усиление, отображение |
Аккаунт |
|
Открыть модалку авторизации или профиля (если залогинен) |
Поделиться |
|
Открыть модалку шаринга — копирование ссылки и кнопки соцсетей |
Кнопка «Аккаунт» использует иконку «выход из двери», но зеркально отражённую (transform: scaleX(-1)) — визуально это «вход». При смене состояния .enter / .exit иконка меняет направление.
Кнопка меню (переворот)
Состояние |
Иконка |
Действие |
|---|---|---|
Не перевёрнуто |
4 оранжевых кружка в сетке 2×2, повёрнутых на 45° |
Переворачивает панель — показывает «заднюю» сторону |
Перевёрнуто |
Те же 4 кружка повёрнуты на 135°, залиты оранжевым |
Возвращает «лицевую» сторону |
У кнопки меню есть приветственная анимация: пока она ни разу не нажата, кружки «дышат» — пульсируют вразнобой. После первого клика анимация снимается (класс .welcome удаляется).

Привязка к кнопкам 1–10 + radio
Под тюнером — полоска из десяти кнопок‑пресетов и слота radio. Каждая кнопка — запомненный канал, как на настоящей рации. Один раз настроил — переключаешься между каткой, клановым сбором и эфиром одним нажатием, а задается в настройках комнаты.
Отдельно стоит рассказать про слот radio. Это не просто одиннадцатая кнопка для ещё одной комнаты — это слот для твоей эфирной комнаты, режима вещания. По умолчанию он ведёт в комнату, помеченную как радио, где ты «вещаешь»: микрофон у ведущего открыт, остальным участникам можно приглушить микрофон из панели администрирования в один клик. Получается режим «один рассказывает — остальные слушают», как на настоящей радиостанции.
Зачем это нужно? Кроме атмосферы (включил «радио» и слушаешь, будто поймал эфир), это ещё и рабочий режим для брифингов и координации. Игрок может собрать команду на брифинг, объяснить план и разойтись по комнатам — не нужно выключать микрофоны по очереди, приглушение делает это за тебя.

Мгновенные закрепы и удаление сообщений
Закрепил сообщение — у всех в комнате оно подсветилось мгновенно. Удалил — у всех исчезло. Не «обновите страницу, пожалуйста», а прямо сейчас. На закреп играет короткий звуковой сигнал в стиле рации — все слышат, что‑то важное произошло. На снятие закрепа — тихо, без сигнала. Это и делает как раз система «system massage» о которой мы говорили чуть выше. Действие закрепа доступно всем кто в комнате.
Закреплённое сообщение выглядит не как пузырь сбоку, а как широкая плашка по центру потока с акцентной рамкой. Остаётся на своём месте в хронологии, но сразу заметно.

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

Бегущая строка под тюнером показывает, кто находится в комнате и кто говорит в эту секунду. У каждого ника — иконка динамика. Говорит — динамик яркий, молчит — приглушённый. Открыл комнату, посмотрел на строку — сразу видно, кто в эфире активен, а кто просто слушает.
Это пришло из атмосферы «Зова Припяти». Там в КПК есть визуальный ряд, который показывает разные состояния и тд. В SetChat я сделал то же самое — но уже не ради атмосферы, а ради пользы. Эквалайзер — для собственного самоконтроля, бегущая строка — для понимания, что происходит в эфире, исходящий и входящий трафик, пинг и потерянные пакеты, все это так же работает и показывает реальные данные, о которых подробнее мы поговорим ниже.

Телеметрия канала
В левом верхнем углу — живые данные: уровень соединения, входящий и исходящий битрейт, задержка (RTT), потери пакетов. Не «пропал звук и непонятно почему», а конкретные цифры. Если что‑то не так с каналом — видишь сразу и понимаешь, что происходи, зеленый индикатор с права говорит об успешном соединении, желтый о переподключение и красный о разрыве соединения.

Что задаётся в личных настройках клиента (не комнаты)
Настройка |
Где |
Значения |
|---|---|---|
Усиление микрофона |
Настройки → Микрофон |
x0.5 — x3.0 |
Эхоподавление |
Настройки → Микрофон |
Вкл / выкл |
Шумоподавление |
Настройки → Микрофон |
Вкл / выкл |
Автогромкость |
Настройки → Микрофон |
Вкл / выкл |
Сетка децибел |
Настройки → Отображение |
Вкл / выкл |
Эквалайзер |
Настройки → Отображение |
Вкл / выкл |
Визуальный шум |
Настройки → Отображение |
Вкл / выкл |

Модерация над пользователем в комнате владельца
Действие |
Что делает |
|---|---|
Кик |
Мгновенно выкидывает участника из эфира |
Мут |
Глушит микрофон участника (до отмены) |
Unmute |
Возвращает голос |
Бан |
Блокирует вход: 5 мин / 30 мин / 1 час / 1 день / 1 неделя / 1 месяц / 1 год / навсегда |
Разбан |
Снимает бан со списка |

Редактируемые параметры (владелец комнаты)
Настройка |
Где правится |
Ограничения |
|---|---|---|
Имя |
Плитка «Имя» |
Латиница, цифры, — только |
Описание |
Плитка «Описание» |
До 2000 символов |
Число мест |
Плитка «Мест» |
От 1 до 10 |
Битрейт |
Плитка «Битрейт» |
От 8 до 320 kbps, список из |
Пароль |
Плитка «Пароль» |
4–64 символа, bcrypt‑хеш. Опционально |
Частота |
При редактировании |
Валидная частота в рамках выбранного диапазона |
Диапазон |
При редактировании |
SW / AM / FM / PMR |
Привязка к кнопкам |
Плитка «Привязка» |
Кнопки 1–10 + слот radio |
Количество участников |
Просмотр и модерация |
10 человек |
Количество забаненных |
Просмотр и удаление |
Не ограничено |
Действие |
Что делает |
Удаление комнаты |
Освобождает слот и частоту, стирает историю, подписки, привязки |
Вход/Выход |
Быстрое подключение или отключение от своей комнаты |
Что задаётся при создании (и не меняется потом)
Настройка |
Где задаётся |
Ограничения |
|---|---|---|
Тип комнаты |
При создании |
Обычная или радио ( |
Владелец |
При создании |
Один раз — привязан к аккаунту |

Станции
Во вкладке «Станции», можно добавлять или удалять станции в избранное. Удаляется либо иконкой в правом нижнем углу, либо длительным нажатием на плитку станции. Собственные станции добавляются в избранное автоматически и не удаляются от туда, пока вы не освободите станцию.

Логи
Тоже очень важная вещь для отладки, и для того что бы была возможность просматривать ошибки соединения и прочего. Удобно для того, что бы вы могли отправить логи разработчику если вдруг возникнут какие ошибки.
Блокировка засыпания экрана на мобильных и сброс соединения
Что это
На мобильных устройствах (Android, iOS) экран автоматически гаснет через 30–60 секунд бездействия. Для голосового чата это критично: если экран погас — браузер уходит в фон, WebRTC‑соединение рвётся, микрофон отключается, и человек выпадает из эфира.
Как это работает
Чтобы не происходило дисконнектов, я решил пофиксить это костылем скрытого видео. Это просто небольшой фрагмент видео, вставленный в тег video, играющий на фоне зациклено, идея пришла спонтанно, но она на удивление работает.
При выходе из комнаты (или при сворачивании вкладки/переключении на другое приложение) — блокировка снимается автоматически, чтобы не жрать батарею зря. Потом, при возврате на вкладку, все восстанавливается.
Как я подошёл к защите
Пароли хранятся только в виде необратимого bcrypt‑хеша. Ни в базе, ни в логах, ни в бэкапах нет открытого пароля. Даже я его не знаю — только могу заменить.
Весь трафик шифруется через HTTPS (обычные запросы) и WSS (WebSocket‑соединение с Janus). Голос внутри WSS идёт поверх SRTP с DTLS‑ключами — то есть зашифрован дважды.
Защита от подбора пароля — двойная, по IP и по email отдельно. Алгоритм ее я не буду описывать по понятным причинам.
Активация аккаунта — по email, через письмо со ссылкой. Токен одноразовый, 64 hex‑символа. До перехода аккаунт не работает. Это отсекает регистрации на чужой email и спам.
Изоляция сессий. При каждом входе ID сессии меняется. Смена пароля сбрасывает все старые сессии на других устройствах.
Приватность. Никаких продаж данных третьим лицам. Ни рекламным сетям, ни аналитике, ни «партнёрам». Что храним: email (для входа), ник (публичный), bcrypt‑хеш пароля, технические логи с IP. Не собираем: паспортные данные, карты, адреса, геолокацию.
Резервные копии данных делаются регулярно.
Кому это может зайти
Я не ищу многомиллионной аудитории. И это не скромность. Больше скажу — многомиллионная аудитория моему проекту была бы даже вредна. MCU не выдержит серьёзного веб‑сервера с миллионами: это совсем другие нагрузки и другая инфраструктура. Запусти завтра на SetChat тысячу человек одновременно — сервер ляжет, и я об этом прекрасно знаю.
Мне нужна скромная, но живая аудитория. Человек тридцать активных участников — этого было бы достаточно, чтобы:
Понять реальную нагрузку на сервер в живом режиме, а не в синтетических тестах.
Посмотреть, что отваливается при массовом использовании, а что держится уверенно.
Найти узкие места в архитектуре и починить их до того, как нагрянет большая волна.
Оценить, где настройки MySQL, PHP‑FPM или Janus просят больше ресурсов, а где я их по глупости недодал.
Это второй этап моего опыта: собрать MVP — он уже собран. Теперь — проверить его на небольшой, но настоящей нагрузке. Для этого нужны не миллионы, а пара десятков живых пользователей, которые каждый вечер заходят, общаются, балуются и иногда находят странные баги.
Эта статья не для рекламы своего детища. Она для поиска единомышленников. Для тех, кому по душе такая ламповость. Кто тоже любит Сталкера, тихие вечера за тактикой, оранжевые дисплеи раций и голос в эфире с характерными для рации звуками... Добро пожаловать!
Послесловие
Для меня SetChat стал не только простенькой голосовой рацией и мгновенным текстовым чатом. Он стал огромным опытом. Местами — первым знакомством с множеством переплетений технологий связи. Linux‑сервер, настройка сервисов, отладка сети, работа с медиасерверами — всё это собралось в один проект, где каждая деталь должна работать в правильном тандеме.
Но первый этап — сборка и запуск — это только полдела. Второй этап — эксплуатация. И вот здесь мне нужны единомышленники, потому что настоящая нагрузка от живых людей всегда отличается от того, что я мог бы смоделировать в тестах. Кто‑то зайдёт с телефона в метро, кто‑то с ноутбука в деревне, кто‑то с планшета с хитрым браузером, кто‑то забанит себя случайно, кто‑то откроет три вкладки одновременно. Все эти сценарии я в теории знаю. А на практике — впервые столкнусь с ними только тогда, когда они действительно произойдут.
Поэтому и говорю: 30 человек для меня сейчас — идеальный размер аудитории. Не больше и не меньше. Не «хайпа ради», а ради того, чтобы проект стал крепче!
Моя радиоволна FM107.777 |
mahaone
На мобилках можно скрыть интерфейс нативной функцией добавления на главный экран. Называется по-разному, но суть одна – появляется ярлык, который запускает веб-приложение без интерфейса браузера.
Технология PWA