import React, { useCallback, useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { IReduxState, IStore } from '../app/types'; import IconUserSVG from '../base/icons/svg/user.svg?raw'; import { browser } from '../base/lib-jitsi-meet'; import { IParticipant } from '../base/participants/types'; import { TILE_ASPECT_RATIO } from '../filmstrip/constants'; import { hidePiP, openDocumentPiP } from './actions'; import PiPTriggerButton from './components/web/PiPTriggerButton'; import { isDocumentPiPSupported, renderAvatarOnCanvas, shouldShowPiP, } from './functions'; import logger from './logger'; /** * Canvas dimensions for PiP avatar rendering. */ const CANVAS_WIDTH = 640; const CANVAS_HEIGHT = Math.floor(CANVAS_WIDTH / TILE_ASPECT_RATIO); /** * Frame rate 0 means capture on-demand when canvas changes. * We manually request frames after drawing to ensure capture. */ const CANVAS_FRAME_RATE = 0; const togglePiP = { key: 'toggle-pip', Content: PiPTriggerButton, group: 2 }; /** * Options for the useCanvasAvatar hook. */ interface IUseCanvasAvatarOptions { backgroundColor: string; customAvatarBackgrounds: string[]; displayName: string; displayNameColor: string; fontFamily: string; initialsColor: string; participant: IParticipant | undefined; shouldShowAvatar: boolean; } /** * Result returned by the useCanvasAvatar hook. * The stream ref is populated in an effect, while publishFrame lets consumers * explicitly deliver the current canvas after attaching it to a video element. */ interface IUseCanvasAvatarResult { canvasStreamRef: React.MutableRefObject; publishFrame: () => void; } /** * Internal refs managed by the hook. */ interface ICanvasRefs { canvas: HTMLCanvasElement | null; defaultIcon: HTMLImageElement | null; } /** * Loads and prepares the default user icon SVG as an Image element. * * @returns {HTMLImageElement} The prepared image element. */ function createDefaultIconImage(): HTMLImageElement { let svgText = IconUserSVG; if (!svgText.includes('fill=')) { svgText = svgText.replace('