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 }