From 359f9fd1f5565964a9226e950b35d7cd78cfa170 Mon Sep 17 00:00:00 2001 From: Max Ronzhin Date: Tue, 11 Aug 2026 02:03:24 +0300 Subject: [PATCH] =?UTF-8?q?fix(room):=20=D0=BF=D0=BE=D1=87=D0=B8=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=87=D0=B5=D1=80=D0=BD=D0=B5=D1=8E=D1=89?= =?UTF-8?q?=D0=B5=D0=B5=20=D1=81=D0=B2=D0=BE=D1=91=20=D0=B2=D0=B8=D0=B4?= =?UTF-8?q?=D0=B5=D0=BE=20=D0=B2=20Safari=20=D0=BF=D1=80=D0=B8=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B8=20=D1=84?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Safari гасил собственный обходной путь для чёрного кадра — охрана от мерцания в livekit-client сравнивает srcObject с тем же объектом MediaStream, а detach/attach внутри библиотеки промахивался мимо обработанного трека и мутировал поток на месте. Переприцепляем элементы вручную после stopProcessor(), чтобы пересоздать MediaStream и дать защите сработать штатно. --- frontend/src/hooks/useVirtualBackground.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frontend/src/hooks/useVirtualBackground.ts b/frontend/src/hooks/useVirtualBackground.ts index 8d10e0b..9e589fb 100644 --- a/frontend/src/hooks/useVirtualBackground.ts +++ b/frontend/src/hooks/useVirtualBackground.ts @@ -103,6 +103,22 @@ export function useVirtualBackground( if (!track || !desiredUrl) { if (track && processorRef.current) { await track.stopProcessor() + // Safari-обход: `stopProcessor` внутри livekit-client меняет трек + // в элементе «на месте», переиспользуя тот же объект `MediaStream` + // (внутренний `detach` промахивается мимо обработанного трека, + // который реально висел в элементе). Из-за этого собственная + // защита библиотеки от мерцания (`srcObject !== mediaStream` в + // `attachToElement`) не даёт сработать её же обходному пути для + // чёрного кадра в Safari. Пересоздаём `MediaStream` вручную — + // detach обнулит `srcObject`, attach создаст новый объект, защита + // пропустит штатный `play()`. Элемент остаётся в своём документе, + // никуда не переезжает. Копия массива обязательна: `detach` + // правит `attachedElements` по ходу перебора. Уберётся, если + // библиотека когда-нибудь починит эту защиту. + for (const el of [...track.attachedElements]) { + track.detach(el) + track.attach(el) + } await processorRef.current.destroy() processorRef.current = null }