Compare commits

...

2 Commits

Author SHA1 Message Date
6554fa242b release: версия 0.0.36 2026-08-10 13:16:16 +03:00
1089d874af fix(room): замена фона в Safari и Firefox
Проверка поддержки была строже, чем требует библиотека, и молча отрезала два
браузера: кнопки выбора фона не было ни в превью, ни в комнате.

У `@livekit/track-processors` ДВА конвейера обработки кадров: современный
(`MediaStreamTrackProcessor`/`Generator`, только Chrome и производные) и
запасной — рисует кадры в canvas и отдаёт `canvas.captureStream()`. Проверка
требовала именно современный, хотя запасной путь доступен и в Safari, и в
Firefox. Заодно она проверяла `OffscreenCanvas`, но пропускала `VideoFrame`,
`createImageBitmap` и WebGL2, которые библиотеке реально нужны.

Теперь условие буквально повторяет `supportsBackgroundProcessors()` из самой
библиотеки: «умеет считать сегментацию» И «есть хоть какой-то конвейер».
При обновлении пакета сверять с ним.

Пробный WebGL2-контекст (иначе поддержку не определить) создаётся один раз на
жизнь страницы и сразу отпускается через `WEBGL_lose_context`: браузеры
держат ограниченное число живых контекстов.

Проверено: в Firefox 153 детект возвращает «поддерживается» (современного
конвейера нет, запасной есть), в Chrome регрессии нет — процессор
поднимается, трек живой.
2026-08-10 13:16:01 +03:00
6 changed files with 66 additions and 14 deletions

View File

@@ -128,7 +128,7 @@ SMTP_TIMEOUT_S=30
# --- Версия инстанса (релиз v0.0.1) --- # --- Версия инстанса (релиз v0.0.1) ---
# install.sh копирует значение из корневого файла VERSION при каждой # install.sh копирует значение из корневого файла VERSION при каждой
# установке/обновлении — руками менять не нужно. # установке/обновлении — руками менять не нужно.
VIDCONF_VERSION=0.0.35 VIDCONF_VERSION=0.0.36
# --- Профили compose. Дефолт ниже (`media,monitoring`) — только для ручного # --- Профили compose. Дефолт ниже (`media,monitoring`) — только для ручного
# `docker compose up` БЕЗ install.sh: медиа (LiveKit+coturn) + мониторинг, # `docker compose up` БЕЗ install.sh: медиа (LiveKit+coturn) + мониторинг,

1
.gitignore vendored
View File

@@ -61,3 +61,4 @@ frontend/public/mediapipe/wasm/
# Рабочая страница замера CPU (сессия 35), в репозиторий не идёт. # Рабочая страница замера CPU (сессия 35), в репозиторий не идёт.
frontend/bg-bench.html frontend/bg-bench.html
frontend/bg-support.html

View File

@@ -3,6 +3,18 @@
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/), Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/),
проект придерживается [семантического версионирования](https://semver.org/lang/ru/). проект придерживается [семантического версионирования](https://semver.org/lang/ru/).
## [0.0.36] — 2026-08-10
Исправление к 0.0.35: замена фона не появлялась в Safari и Firefox.
### Исправлено
- Проверка поддержки замены фона была строже, чем требует библиотека, и
молча отрезала два браузера — кнопки выбора фона не было ни в превью, ни
в комнате. У библиотеки два конвейера обработки кадров: современный
(только Chrome и производные) и запасной через `canvas.captureStream()`,
который работает и в Safari, и в Firefox; проверка требовала именно
современный. Теперь условие буквально повторяет проверку самой библиотеки.
## [0.0.35] — 2026-08-10 ## [0.0.35] — 2026-08-10
Замена фона видео на картинку — отключаемый модуль (по умолчанию выключен). Замена фона видео на картинку — отключаемый модуль (по умолчанию выключен).

View File

@@ -1 +1 @@
0.0.35 0.0.36

View File

@@ -89,7 +89,7 @@ services:
MEDIA_ROOT: ${MEDIA_ROOT:-/app/media} MEDIA_ROOT: ${MEDIA_ROOT:-/app/media}
# Версия инстанса (релиз v0.0.1) — install.sh копирует значение # Версия инстанса (релиз v0.0.1) — install.sh копирует значение
# из файла VERSION (корень репозитория) в .env; отдаётся в GET /api/health. # из файла VERSION (корень репозитория) в .env; отдаётся в GET /api/health.
VIDCONF_VERSION: ${VIDCONF_VERSION:-0.0.35} VIDCONF_VERSION: ${VIDCONF_VERSION:-0.0.36}
# Число процессов uvicorn (см. backend/Dockerfile). Дефолт 2 рассчитан # Число процессов uvicorn (см. backend/Dockerfile). Дефолт 2 рассчитан
# на 4-ядерный сервер, где ядра делятся с LiveKit. Поднимая значение, # на 4-ядерный сервер, где ядра делятся с LiveKit. Поднимая значение,
# проверьте бюджет соединений с БД: каждый воркер держит свой пул # проверьте бюджет соединений с БД: каждый воркер держит свой пул

View File

@@ -98,21 +98,60 @@ export function resolveBackgroundUrl(
} }
/** /**
* Поддерживает ли браузер сегментацию вообще. * Поддерживает ли браузер замену фона.
* *
* Проверяется по наличию API конвейера обработки кадров (Insertable Streams / * Проверка СИНХРОННАЯ и намеренно не трогает саму библиотеку: решение нужно
* `MediaStreamTrackProcessor`) — их нет, например, в Firefox. Проверка * ДО её загрузки, чтобы не показывать кнопку, которая не сработает, и не
* СИНХРОННАЯ и намеренно не трогает саму библиотеку: она нужна до её загрузки, * тянуть мегабайты впустую. Поэтому здесь буквально повторено условие
* чтобы не показывать кнопку, которая всё равно не сработает, и не тянуть * `supportsBackgroundProcessors()` из `@livekit/track-processors` — при
* мегабайты впустую. * обновлении пакета сверять с ним.
*
* ⚠️ Конвейеров у библиотеки ДВА, и требовать современный нельзя:
* - современный (`MediaStreamTrackProcessor`/`Generator`, Insertable Streams)
* есть только в Chrome и производных;
* - запасной рисует кадры в canvas и отдаёт `canvas.captureStream()` — он
* работает в Safari и Firefox.
*
* Первая версия (0.0.35) требовала именно современный конвейер — и фича
* молча отсутствовала в Safari и Firefox, хотя запасной путь там доступен.
* Условие ниже — «умеет считать сегментацию» И «есть хоть какой-то конвейер».
*/ */
export function isVirtualBackgroundSupported(): boolean { export function isVirtualBackgroundSupported(): boolean {
if (typeof window === 'undefined') return false if (typeof window === 'undefined') return false
return ( return canRunSegmentation() && hasAnyFramePipeline()
'MediaStreamTrackProcessor' in window && }
'MediaStreamTrackGenerator' in window &&
typeof OffscreenCanvas !== 'undefined' /**
) * Условие `BackgroundTransformer.isSupported`: чем библиотека считает маску и
* собирает кадр. WebGL2 проверяется созданием пробного контекста — иначе никак,
* но результат кэшируется на всю жизнь страницы: браузеры держат ограниченное
* число живых WebGL-контекстов, и создавать новый на каждый рендер нельзя.
*/
let segmentationSupport: boolean | null = null
function canRunSegmentation(): boolean {
if (segmentationSupport !== null) return segmentationSupport
const hasApis =
typeof OffscreenCanvas !== 'undefined' &&
typeof VideoFrame !== 'undefined' &&
typeof createImageBitmap !== 'undefined'
if (!hasApis) {
segmentationSupport = false
return false
}
const probe = document.createElement('canvas').getContext('webgl2')
// Пробный контекст сразу отпускаем — он больше не нужен, а слот в лимите
// браузера занимал бы до сборки мусора.
probe?.getExtension('WEBGL_lose_context')?.loseContext()
segmentationSupport = Boolean(probe)
return segmentationSupport
}
/** Условие `ProcessorWrapper.isSupported`: современный конвейер ЛИБО запасной на canvas. */
function hasAnyFramePipeline(): boolean {
const modern = 'MediaStreamTrackProcessor' in window && 'MediaStreamTrackGenerator' in window
const fallback =
typeof HTMLCanvasElement !== 'undefined' && 'captureStream' in HTMLCanvasElement.prototype
return modern || fallback
} }
/** /**