Содержание статьи +
- Кратко
- Почему это важно
- Число, которое решает всё: кто кого слышит
- Режим первый – до ~50 человек: пересылаем всё
- Режим второй – от 50 до ~500 человек: пересылаем только говорящих
- Режим третий – от 500 до 5 000+ человек: смешиваем немногих, раздаём один
- Три режима рядом
- Частая ошибка: проектировать под среднее, платить за пик
- Где здесь Фора Софт
- Ключевые выводы
- Что почитать дальше
Кратко
Групповой звонок, который идеально работает на десяти участниках, может начать сбоить на пятидесяти, упасть на пятистах и превратиться в систему совсем другого рода на пяти тысячах – и первым обычно ломается именно аудио, а не видео. Причина проста и арифметична: если каждый микрофон отправлять каждому слушателю, объём работы растёт как квадрат числа участников, поэтому удвоение комнаты примерно учетверяет нагрузку. Выход – перестать обращаться со всеми голосами одинаково: пересылать только тех немногих, кто реально говорит, а на самых больших масштабах ещё и смешивать этих немногих в один поток на сервере, чтобы каждый слушатель по-прежнему получал лишь один. Эта статья проходит три режима – маленькая комната, где пересылается всё, большая комната, где пересылаются только активные говорящие, и массовая трансляция, где говорящих смешивают и раздают результат – и даёт цифры, чтобы понять, в каком режиме находится ваш продукт.
Почему это важно
Если вы планируете виртуальный класс, инструмент для общих собраний компании, вебинар-тауунхолл, лайв-шопинг или экстренный мост связи, то число, которое вы впишете в поле «максимум участников» в спецификации продукта, тихо определяет всю вашу аудиоархитектуру и счёт за серверы. Команды регулярно проектируют под демо – двенадцать человек в сетке – а потом обнаруживают, что собрание на 300 человек либо плавит сервер, либо звучит как стадион. Эта статья – для продакт-менеджера, основателя или инженерного руководителя, которому нужно понять, почему стоимость аудио взрывается с масштабом и что меняется на каждом пороге размера, чтобы честно оценить инфраструктуру и задать инженерам правильный вопрос до запуска, а не во время инцидента. Старший инженер найдёт здесь каждое утверждение со ссылкой на статью Jitsi про Last-N, соответствующие IETF RFC и опубликованное поведение Janus, mediasoup и LiveKit. К концу вы будете знать для вашего конкретного целевого числа участников, что делать – пересылать, выбирать или смешивать, – и сколько стоит каждый выбор.
Число, которое решает всё: кто кого слышит
Прежде чем переходить к архитектуре, удержите в голове один арифметический факт, потому что из него следует каждое решение по масштабированию в этой статье. В звонке каждый говорящий производит один поток аудио, и каждый слушающий должен его получить. Если все могут одновременно и говорить, и слышать всех остальных, и в комнате K человек, то общее число доставок голоса, которое система должна обработать, равно: K человек, каждый получает остальные K−1 голосов – то есть K × (K − 1) доставок.
Подставим числа, потому что форма роста и есть вся суть. Формула – на первой строке, умножение – на второй, результат – на третьей.
- 5 человек: 5 × 4 = 20 доставок голоса.
- 50 человек: 50 × 49 = 2 450 доставок.
- 500 человек: 500 × 499 = 249 500 доставок.
- 5 000 человек: 5 000 × 4 999 = 24 995 000 доставок.
Обратите внимание, что произошло. Переход от 5 к 50 участникам – в десять раз больше людей – дал не в десять, а примерно в 122 раза больше доставок. Это квадратичный рост: работа растёт как квадрат числа людей, поэтому удвоение комнаты почти учетверяет нагрузку. Инженеры Jitsi в статье 2015 года о масштабе конференций сформулировали ту же мысль прямо: в системе, где каждая точка отправляет медиа всем остальным, «требуемые ресурсы (CPU, пропускная способность сети) растут квадратично с числом точек», и такая архитектура «плохо масштабируется, когда число участников значительно (≈ 50)». Пятьдесят – это число, на котором наивный подход начинает болеть; в заголовке этой статьи оно не случайно.
Полезный образ. Представьте ужин. С шестью гостями каждый успевает следить за каждым – шесть человек, тридцать возможных отношений «слушаю-говорю», и это работает. Теперь представьте банкетный зал на пятьсот человек, где все пытаются говорить со всеми сразу: это не разговор, это рёв, и никакая хитрая проводка не отменит того, что одновременных отношений слушания тут четверть миллиона. Решение – не лучшая проводка. Решение – признать, что большинство этих отношений не нужны в любой конкретный момент, потому что в любой реальной встрече одновременно говорят лишь несколько человек. Это единственное осознание – пересылать только то, что человек реально произносит – и есть рычаг, который превращает невозможное число обратно в управляемое.
«О различии «активный» и «пассивный». В этой статье активный участник – тот, чей микрофон включён и может быть услышан; пассивный – только слушает. У тауунхолла на 5 000 человек обычно 3 активных и 4 997 пассивных. Стоимость аудио задаёт число активных, а не общее число – и разделение этих двух величин первое, что делает грамотно спроектированный большой звонок.»
Семейство протоколов, которым браузеры передают живое аудио, WebRTC, не решает за вас проблему масштабирования. Оно даёт трубу; решать, какое аудио по ней течёт на каждом масштабе, – работа вашей архитектуры. Чтобы понять три кирпичика, которые мы комбинируем ниже – отправлять напрямую, пересылать и смешивать, – начните с сопутствующей статьи Аудио в SFU, MCU и P2P, где каждый из них разобран по отдельности. Эта статья – о том, что происходит, когда вы доводите их до 50, 500 и 5 000.
Режим первый – до ~50 человек: пересылаем всё
Первый режим – это малый и средний групповой звонок: дейли команды, класс, заседание совета. Здесь правильный ответ – Selective Forwarding Unit, SFU: сервер, который принимает голос каждого участника и пересылает его дальше, ни разу не декодируя звук. Каждый участник загружает один поток и скачивает по одному потоку на каждого, кого слушает. Работа сервера лёгкая, потому что он никогда не декодирует аудио; его основная стоимость – шифрование, к которому мы вернёмся.
Вот аудиоспецифичный факт, который удивляет даже опытных видеоинженеров: в этом режиме всё аудио пересылается всем и всегда. Знаменитый приём масштабирования Last-N, при котором сервер пересылает лишь несколько самых релевантных видеопотоков, а остальные ставит на паузу, придуман для видео, и в исходной статье Jitsi прямо сказано: «схема Last N применяется только к пересылке видеопотоков, но не аудио; аудио со всех точек пересылается всегда». Причина в том, что аудио дёшево и чувствительно к задержке. Голосовой поток на кодеке Opus занимает около 24–32 тысяч бит в секунду – доля от размера видеопотока, – и если придержать чьё-то аудио, решая, «релевантен» ли он, вы срежете первое слово. Поэтому в звонке на 50 человек сервер пересылает каждый голос каждому слушателю, и это нормально: потоки маленькие, и клиент способен декодировать пару десятков.
Куда же тогда уходит стоимость? В два места. Первое – нагрузка шифрования на сервере. WebRTC требует шифровать каждый медиапакет на участке до сервера, поэтому SFU должен расшифровать каждый входящий пакет и заново зашифровать его для каждой исходящей копии. Замеры Jitsi показали рост CPU примерно в шаге с общим битрейтом, «в основном за счёт расшифровки и повторного шифрования RTP-пакетов» – а не самого аудио, которое никогда не декодируется. Второе – нагрузка декодирования и микширования на клиенте. Ваше устройство декодирует каждый входящий голос и сводит их для динамиков, и эта работа растёт с числом активных говорящих.
Приём, который масштабирует аудио, не ломая его
Если бы в комнате на 50 человек все 50 сидели с включёнными микрофонами и открытыми «открытыми» микрофонами, результатом стала бы неслушаемая каша фонового шума – пятьдесят комнат вентиляторов, клавиатур и улицы, сложенных вместе. Два механизма не дают этому случиться, и оба – чистая аудиоинженерия.
Первый – прерывистая передача (DTX): тихий микрофон фактически перестаёт отправлять данные. Opus DTX роняет молчащего участника с ~24–32 kbit/s до примерно 1 kbit/s, отправляя лишь крошечную подсказку «комфортного шума» раз в несколько сотен миллисекунд. Поэтому в звонке на 50 человек, где говорят трое, полноскоростное аудио шлют только эти трое; остальные 47 на проводе почти молчат. Реальную аудионагрузку комнаты задают активные говорящие, а не общее число. (Как работают DTX и комфортный шум, см. Детектор речевой активности (VAD) и прерывистая передача (DTX).)
Второй – осведомлённость об активном говорящем. Каждый отправитель проставляет громкость каждого аудиопакета в маленькое поле RTP-заголовка, определённое в IETF RFC 6464 – число от 0 до 127 в децибелах ниже полной шкалы, – и сервер читает его без декодирования звука. Хотя сервер пересылает всё аудио, он использует эти числа, чтобы сообщить каждому клиенту, кто доминирующий говорящий, – так UI может подсветить его, а клиент может выбрать отрисовку только самых громких. Это фундамент, на котором строится следующий режим.
Режим второй – от 50 до ~500 человек: пересылаем только говорящих
После примерно пятидесяти человек меняются две вещи. Комната почти всегда становится асимметричной – несколько докладчиков и большая, в основном замьюченная аудитория, – и даже пересылка аудио только активных говорящих каждому слушателю начинает накапливаться, потому что число слушателей теперь велико. Голос одного докладчика, идущий к 499 слушателям, – это 499 исходящих копий, которые сервер должен зашифровать. С тремя докладчиками это почти 1 500 операций «зашифровать-и-отправить» на каждый аудиокадр, каждые 20 миллисекунд. Аудио всё ещё дёшево маршрутизировать, но стоимостью становится веерная раздача (fan-out).
Архитектура этого режима – по-прежнему SFU, но теперь он пересылает только аудио активных говорящих, а не всех. Сервер ранжирует участников по их числам громкости RFC 6464, определяет тех немногих, кто реально держит слово, и пересылает только эти потоки. Общее собрание на 200 человек, где докладывает один VP, пересылает по сути один аудиопоток 199 слушателям; когда кто-то задаёт вопрос, его поток добавляется в набор пересылаемых, а поток VP может выпасть. Решение о том, кто активный говорящий, – сердце этого режима, и принять его правильно сложнее, чем «кто громче прямо сейчас».
Как выбрать активного говорящего и не ошибиться
Кашель, упавший телефон, одно громкое «ага» в знак согласия – ничто из этого не должно отбирать слово у докладчика. Отраслевой стандарт – алгоритм идентификации доминирующего говорящего, опубликованный Иланой Волфин и Израилем Коэном, который статья Jitsi адаптировала для работы исключительно на уровнях громкости RFC 6464 без декодирования аудио. Вместо реакции на один громкий пакет он оценивает речевую активность каждого участника сразу в трёх временных окнах – мгновенном окне нескольких фонем, среднем окне слова-двух и длинном окне короткого предложения – и объявляет смену говорящего, только когда все три вместе растут на одном канале. Авторы задали явные цели поведения: переходный шум и однословные реплики не должны вызывать смену, смену может запустить только начало настоящего речевого всплеска, а допустимая задержка перехода между говорящими – «до одной секунды». Относительная громкость голоса не должна влиять на шанс быть выбранным – тихого докладчика определяют так же надёжно, как громкого.
Этот алгоритм работает внутри ActiveSpeakerObserver в mediasoup, логики доминирующего говорящего в Jitsi Videobridge и эквивалента в каждом серьёзном SFU. Результат – стабильный сигнал «активного говорящего», который делает сразу две работы: сообщает SFU, какое аудио пересылать, и сообщает каждому клиенту, какую плитку подсветить.
Арифметика выигрыша
Выигрыш – это разница между квадратичным и линейным ростом. Замеры Jitsi оценили её для видео: в конференции на 30 участников пересылка фиксированного числа потоков вместо всех сокращала исходящий битрейт на 72–89% в зависимости от того, сколько пересылалось, превращая квадратичный рост в линейный по числу участников. Для аудио действует та же логика, как только вы пересылаете только активных говорящих: стоимость масштабируется с числом говорящих (которое в любой реальной встрече держится около 1–5), умноженным на число слушателей, а не с квадратом общего числа. Конкретно: в вебинаре на 500 человек с 3 активными говорящими вы пересылаете порядка 3 × 500 = 1 500 доставок аудио вместо 500 × 499 = 249 500, которых потребовала бы «пересылка всего» – сокращение в 166 раз, достигнутое целиком за счёт того, что вы не пересылаете тишину.
Оставшийся потолок этого режима – на стороне клиента. Даже когда пересылаются только активные говорящие, у одного SFU есть конечное число исходящих соединений, которые он способен шифровать и обслуживать, а у одного клиента, принимающего несколько аудиопотоков плюс UI плюс видео, есть свой предел. Около нескольких сотен – пары тысяч участников на одном сервере вы упираетесь в один из них. Этот потолок и определяет третий режим.
Режим третий – от 500 до 5 000+ человек: смешиваем немногих, раздаём один
На нескольких тысячах участников стеной становится сама веерная раздача. Отправить аудио трёх говорящих 5 000 слушателям – это 15 000 зашифрованных исходящих потоков на каждый аудиокадр, а один клиент, который ещё и отрисовывает видео, не может комфортно принимать и декодировать несколько отдельных аудиопотоков на фоне всего остального. Выход – перестать слать отдельные потоки и смешать активных говорящих в один общий поток на сервере, а затем отправить этот единственный поток всем. Это подход Multipoint Control Unit – MCU, – применённый хирургически только к аудио и только к активным говорящим.
Механика важна. Сервер декодирует только аудио немногих активных говорящих (не всех 5 000 – остальные молчат и исключены логикой активного говорящего), складывает их в один микс, заново кодирует его один раз и отправляет этот единственный поток каждому слушателю. Слушатель теперь скачивает ровно один аудиопоток независимо от того, 500 в комнате человек или 50 000. Плагин AudioBridge в Janus – производственный пример именно этого: это «аудио-MCU», и «все аудиопотоки смешиваются, а не ретранслируются», поэтому «создаётся единственное PeerConnection независимо от того, сколько участников войдёт в комнату», каждый получает «микс остальных» участников. Стоимость решительно смещается с веерной раздачи в сети на CPU сервера на микширование – но поскольку декодируются только активные немногие, а микс производится один раз, этот CPU ограничен числом говорящих, а не числом слушателей.
Правило N-минус-1 и почему вы никогда не складываете все 5 000
Две детали аудиоинженерии заставляют серверное микширование работать. Первая: микс, отправляемый каждому говорящему, должен исключать его собственный голос – иначе он услышит себя с задержкой в долю секунды. Для N участников каждый получает сумму остальных контрибьюторов – микс N-минус-1. Для чистых слушателей это тривиально (они ничего не вносят, поэтому получают полный микс), а для горстки активных говорящих сервер производит слегка разный микс на каждого. Вторая – и это правило делает масштаб возможным – сервер смешивает только несколько самых громких каналов, а не все. Сложение 5 000 аудиосигналов нагромоздит 5 000 шумовых порогов в шипение громче любого голоса и обойдётся в 5 000 декодирований. Масштабируемый микшер конференции выбирает несколько верхних активных каналов по их уровню аудио и смешивает только их – обычно от трёх до шести голосов. Те же числа громкости RFC 6464, что управляли пересылкой в режиме два, теперь управляют отбором для микширования в режиме три.
Когда одного сервера мало: каскадирование
У одного сервера есть потолок по числу участников независимо от архитектуры. Чтобы выйти за него – в десятки тысяч – производственные системы каскадируют: они запускают много медиасерверов, ретранслирующих друг другу, так что участник, подключённый к серверу во Франкфурте, слышит говорящего, подключённого к серверу в Сан-Паулу, без того, чтобы любой из серверов обслуживал всех участников напрямую. Опубликованная архитектура LiveKit – проработанный пример: пограничные серверы образуют распределённую сетку, координируются через общий слой состояния (Redis) и ретранслируют дорожки между регионами – так платформа заявляет поддержку сессий до 100 000 участников с задержкой между ними менее 100 миллисекунд. Каскадирование не меняет логику аудио внутри комнаты – вы всё так же пересылаете активных говорящих или смешиваете самых громких немногих – оно лишь распределяет веерную раздачу по многим машинам, чтобы ни одна не упёрлась в свой потолок.
Честный финал: на масштабе трансляции это перестаёт быть «звонком»
Есть порог, за которым правильный ответ – признать, что вы больше не ведёте разговор. Запуск продукта на 50 000 зрителей с тремя докладчиками – это трансляция, а не групповой звонок. Стандартный производственный приём – гибрид: несколько докладчиков и приглашённые «на сцену» участники аудитории работают на реальном SFU/MCU для настоящего двустороннего взаимодействия, а пассивная аудитория получает смешанную программу по стримингу вроде Low-Latency HLS через CDN – ровно как живой видеопоток. Интерактивное ядро остаётся маленьким и реальным; массовый пассивный ярус обслуживается инфраструктурой, построенной под массовые пассивные ярусы. Понять, где провести эту черту – сколько людей действительно должны иметь возможность ответить, – самое важное решение по масштабированию, и это продуктовое решение прежде, чем инженерное. Стриминговая половина – отдельная дисциплина; см. Аудио в HLS, DASH, CMAF и Аудио в стриминге с низкой задержкой.
Три режима рядом
Три режима по-разному распределяют одни и те же ресурсы – CPU сервера, пропускную способность веерной раздачи, нагрузку декодирования на клиенте и задержку – по мере роста комнаты. Таблица – это решение в одном виде. Читайте число участников как мягкие пороги, а не жёсткие границы; ваши реальные числа зависят от настроек кодека, железа и того, сколько человек говорят одновременно.
| Свойство | ~50 человек | ~500 человек | 5 000+ человек |
|---|---|---|---|
| Архитектура | SFU, пересылка всего | SFU, пересылка активных | MCU-микс громких; каскад/гибрид |
| Сервер декодирует аудио? | Никогда | Никогда | Только активных немногих |
| Что получает каждый слушатель | Каждый голос | Голоса активных говорящих | Один смешанный поток |
| Главная стоимость | Декод на клиенте + шифрование на сервере | Веерная раздача (шифрование на копию) | CPU микса (ограничен говорящими) |
| Потоков скачивает слушатель | По одному на активного говорящего | По одному на активного говорящего | Ровно один (микс) |
| Добавленная задержка | Наименьшая (только пересылка) | Низкая (только пересылка) | Выше (декод + микс + перекодирование) |
| Контроль по говорящему (mute, уровни) | Полный | Полный | Теряется при микшировании |
| Запись одним файлом | Нужен отдельный микс | Нужен отдельный микс | Микс уже существует |
| Пример из реальности | Комната Jitsi, mediasoup, LiveKit | SFU-вебинар в режиме активного говорящего | Janus AudioBridge; каскад LiveKit; гибрид SFU+LL-HLS |
Узор читается ясно, когда вы его видите. По мере роста комнаты стоимость мигрирует с клиента (декодирование многих потоков) на сеть сервера (раздача копий) на CPU сервера (микширование). Каждая миграция покупает вам ещё порядок масштаба и каждая чего-то стоит – обычно контроля по говорящему и немного задержки. Мастерство – менять режим в нужный момент: не слишком рано (теряя простоту пересылки) и не слишком поздно (после инцидента).
Частая ошибка: проектировать под среднее, платить за пик
Вот ловушка, в которую попадает больше всего команд, и она специфична для аудио на масштабе. Аудионагрузку встречи задаёт не общее число участников и даже не среднее число говорящих – её задаёт наихудшее число одновременно говорящих, и это число скачет ровно в неподходящий момент. Общее собрание на 500 человек сидит на одном-двух активных говорящих 55 минут, а потом CEO говорит «есть вопросы?» – и сорок человек размьючиваются разом. Если ваша логика активного говорящего пересылает или смешивает всех, кто на миг стал громким, этот один момент может потребовать в двадцать раз больше аудиоресурсов, чем устойчивое состояние, – и именно в этот момент звонок деградирует на глазах вашей самой важной аудитории.
Лекарство – жёсткий предел на число одновременно пересылаемых или смешиваемых говорящих – обычно от трёх до шести, – обеспеченный ранжированием доминирующего говорящего, плюс элемент UI, делающий предел понятным (очередь «поднять руку» или управляемая модератором сцена). Правило Волфин–Коэна о том, что «при одновременной речи на более чем одном канале доминирующий говорящий – тот, кто начал говорить первым», как раз и не даёт размьючиванию сорока человек превратиться в сорок пересылаемых потоков: система выбирает тех немногих, кто начал первым, и держит остальных. Проектируйте предел осознанно; не позволяйте ему быть случайностью того, что выставлено в вашем SFU по умолчанию.
Вторая, более тихая ловушка: разрывы DTX путают наивную логику активного говорящего. Поскольку тихий микрофон под Opus DTX перестаёт слать пакеты, читатель уровня, ожидающий пакет каждые 20 миллисекунд, может принять тишину за «этот говорящий ушёл» и заставить подсветку активного говорящего мигать. Если ваша подсветка дёргается, когда люди делают паузу между предложениями, первым делом смотрите на тайминг DTX, а не на алгоритм. Это задокументированное поведение в реальных SFU, и лекарство – в том, как читатель уровня обрабатывает отсутствующие пакеты, а не в самих числах громкости.
Где здесь Фора Софт
Мы встраиваем аудио реального времени в видеоконференции, e-learning, телемедицину и продукты для живых событий с 2005 года, и вопрос «сколько участников?» мы фиксируем до того, как написать строку медиакода, потому что он определяет архитектуру сильнее любого другого требования. Виртуальный класс на 30 студентов – это простой SFU, пересылающий преподавателя и тех, кто размьючится; общее собрание компании на 400 человек – это SFU в режиме активного говорящего с лимитом на число говорящих и модерируемой очередью вопросов; запуск продукта на 10 000 участников – это маленькая интерактивная сцена, питающая смешанную программу по стримингу с низкой задержкой для пассивной аудитории. Мы проектируем под пиковый момент одновременных говорящих, а не под комфортное среднее, потому что видели, что делает спайк «есть вопросы?» с системой, рассчитанной на устойчивое состояние. Когда продукту нужны и настоящая интерактивность на масштабе, и чистые записи, мы планируем CPU микширования и путь записи заранее, а не обнаруживаем их под нагрузкой.
Ключевые выводы
- Стоимость аудио растёт как квадрат размера комнаты, если каждый голос идёт всем.
- До ~50 человек: SFU пересылает всё аудио; DTX держит молчащие микрофоны почти бесплатными.
- 50–500 человек: пересылайте только активных говорящих по уровням громкости RFC 6464.
- 5 000+ человек: смешивайте самых громких немногих в один поток; каскадируйте или идите в гибрид.
- Никогда не складывайте все каналы – смешивайте только верхние три-шесть активных говорящих.
- Проектируйте под пиковое число одновременно говорящих, а не под среднее.