perf(frontend): включить adaptiveStream и dynacast

Оба флага в LiveKit по умолчанию выключены: каждый клиент был подписан на
полное качество всех чужих треков независимо от размера плитки, а каждый
паблишер слал все слои симулкаста, даже если их никто не смотрит. На тесте
28.07 (19 участников, ~8 камер) это дало устойчивые 140–169 Мбит/с исходящего
трафика при пике 240, 662 события `remote bwe: channel congestion detected` и
146 переходов аллокатора STABLE → DEFICIENT — то есть видимый участникам лаг.

Замер на локальном стенде (9 участников, паблишеры 720p, одинаковый состав
комнаты, приращение bytesReceived по getStats клиента):

  без флагов   5 потоков 1280x720 @33 fps  — 11 110 кбит/с
  с флагами    4 потока   320x150 @17 fps  —    778 кбит/с

Заодно начинает экономить уже написанный код, который до сих пор не давал
выигрыша: «скрыть остальных» не рендерит карусель (TX контейнера LiveKit
0.76 → 0.03 Мбит/с), пагинация StageGrid рендерит только текущую страницу,
а pauseVideoInBackground (дефолт true) работает лишь при adaptiveStream.

Демонстрация экрана, режимы показа и листание страниц проверены — регрессий нет.
This commit is contained in:
2026-07-28 23:25:43 +03:00
parent b528785249
commit eb4e5ea83f

View File

@@ -187,6 +187,22 @@ export function RoomPage() {
const { userChoices } = usePersistentUserChoices()
const roomOptions = useMemo<RoomOptions>(
() => ({
// Оба флага в LiveKit по умолчанию выключены, и без них каждый клиент
// подписан на полное качество всех чужих треков независимо от размера
// плитки, а каждый паблишер шлёт все слои симулкаста, даже если их никто
// не смотрит. На тесте 28.07.2026 (19 участников, ~8 камер) это дало
// устойчивые 140169 Мбит/с исходящего трафика при пике 240, 662 события
// `remote bwe: channel congestion detected` и 146 переходов аллокатора
// STABLE → DEFICIENT — то есть видимый участникам лаг.
//
// adaptiveStream: подписка на слой по фактическому размеру плитки на
// экране + пауза треков, которые сейчас не отрисованы. Именно на нём
// начинает экономить уже написанный код: «скрыть остальных»
// (RoomStage) не рендерит карусель, а пагинация StageGrid рендерит
// только текущую страницу — неприаттаченные треки считаются невидимыми.
// dynacast: паблишер прекращает отдавать слои, на которые нет подписчиков.
adaptiveStream: true,
dynacast: true,
audioCaptureDefaults: { deviceId: userChoices.audioDeviceId || undefined },
videoCaptureDefaults: { deviceId: userChoices.videoDeviceId || undefined },
// Аудиовыход (колонки/наушники/bluetooth) — отдельный персист, не через