Архитектура кольцевого буфера и маршрутизация в памяти
Кольцевой буфер (internal/buffer/ring.go) — центральный узел маршрутизации данных в RUSEON Core. Он выполняет роль высокопроизводительной шины в общей оперативной памяти, раздавая входящие видеокадры всем потребителям (WebRTC, HLS, fMP4-архиватор, gRPC ИИ) без дублирования видеобуферов.
1. Раздельная синхронизация Split-Lock
Для устранения взаимных блокировок между высокочастотным потоком записи кадров и динамическим подключением/отключением зрителей используются два независимых мьютекса sync.RWMutex:
- Storage Mutex (
mu sync.RWMutex): Защищает кольцевой массив указателей*Frameи курсоры чтения/записи. - Subscriber Mutex (
subMu sync.RWMutex): Защищает список зарегистрированных каналов подписчиков.
Результат: Подключение новых WebRTC-зрителей не блокирует горутину приёма RTSP.
2. Параметры кодека без блокировок (atomic.Pointer[CodecParams])
Потоки H.264 и H.265 периодически передают наборы параметров (SPS, PPS, VPS), необходимые для инициализации видеодекодеров.
- При получении кадров параметров RingBuffer сохраняет их в
atomic.Pointer[CodecParams]. - Любой новый HLS-трансмуксер или WebRTC-пир считывает актуальные параметры без блокировок.
3. Мгновенный старт видео через подпитку ключевого кадра (KeyFrame Backfill)
При подключении нового зрителя ожидание следующего I-кадра с камеры (интервал GOP может составлять 2–4 секунды) приводило бы к неприятной паузе.
При вызове Subscribe():
- Буфер сканирует назад до ближайшего опорного I-кадра (KeyFrame).
- Мгновенно передает в канал подписчика все кадры, начиная с опорного до текущего момента.
- Плеер браузера начинает показ за миллисекунды.
4. Защита от медленных клиентов и флаг NeedsIFrame
Если клиент не успевает вычитывать видеоданные:
- Неблокирующая отправка: Кадры отправляются через
select ... default. - Дроп кадра: Если канал переполнен, кадр отбрасывается без замедления других потребителей.
- Метрика: Увеличивается счётчик
ruseon_ringbuffer_drops_total. - Флаг
NeedsIFrame: Подписчику выставляется флагNeedsIFrame = true. - Безопасное восстановление: Все промежуточные P-кадры отбрасываются до прихода следующего чистого I-кадра, предотвращая артефакты ("зелёный экран" и рассыпание картинки).