Files
cinny/src/app/hooks/useCallSpeakers.ts
Ajay Bura 55e8306576 Display call member speaking status on bottom bar (#2742)
* add mutation observer hok

* add hook to read speaking member by observing iframe content

* display speaking member name in call status bar and improve layout

* fix shrining
2026-03-08 22:00:35 +11:00

61 lines
1.9 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState } from 'react';
import { CallEmbed } from '../plugins/call';
import { useMutationObserver } from './useMutationObserver';
import { isUserId } from '../utils/matrix';
import { useCallMembers, useCallSession } from './useCall';
import { useCallJoined } from './useCallEmbed';
export const useCallSpeakers = (callEmbed: CallEmbed): Set<string> => {
const [speakers, setSpeakers] = useState(new Set<string>());
const callSession = useCallSession(callEmbed.room);
const callMembers = useCallMembers(callEmbed.room, callSession);
const joined = useCallJoined(callEmbed);
const videoContainers = useMemo(() => {
if (callMembers && joined) return callEmbed.document?.querySelectorAll('[data-video-fit]');
return undefined;
}, [callEmbed, callMembers, joined]);
const mutationObserver = useMutationObserver(
useCallback(
(mutations) => {
const s = new Set<string>();
mutations.forEach((mutation) => {
if (mutation.type !== 'attributes') return;
const el = mutation.target as HTMLElement;
const style = callEmbed.iframe.contentWindow?.getComputedStyle(el, '::before');
if (!style) return;
const tileBackgroundImage = style.getPropertyValue('background-image');
const speaking = tileBackgroundImage !== 'none';
if (!speaking) return;
const speakerId = el.querySelector('[aria-label]')?.getAttribute('aria-label');
if (speakerId && isUserId(speakerId)) {
s.add(speakerId);
}
});
setSpeakers(s);
},
[callEmbed]
)
);
useEffect(() => {
videoContainers?.forEach((element) => {
mutationObserver.observe(element, {
attributes: true,
attributeFilter: ['class', 'style'],
});
});
return () => {
mutationObserver.disconnect();
};
}, [videoContainers, mutationObserver]);
return speakers;
};