handle call room swapping better

This commit is contained in:
Gigiaj 2025-04-17 02:26:50 -05:00
parent cb9e4ffe86
commit 14206dbb96

View file

@ -24,7 +24,7 @@ interface PersistentCallContainerProps {
}
export function PersistentCallContainer({ isVisible }: PersistentCallContainerProps) {
const { activeCallRoomId, setActiveCallRoomId } = useCallState();
const { activeCallRoomId, setActiveCallRoomId, registerActiveTransport } = useCallState();
const mx = useMatrixClient();
const room = useSelectedRoom();
const clientConfig = useClientConfig();
@ -39,10 +39,19 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
const cleanupRoomId = smallWidgetRef.current?.roomId;
logger.debug(`PersistentCallContainer effect running. activeCallRoomId: ${activeCallRoomId}`);
/**
* TODO:
* Need proper shutdown handling. Events from the previous widget can still come through it seems. Might need
* to queue the events and then allow the join to actually occur. This will *work* for now as it does handle switching technically.
* Need to look closer at it.
*
* Might also be able to keep the iframe alive and instead navigate to a new "room" to make the transition smoother
*/
const cleanup = () => {
logger.error(`PersistentCallContainer: Cleaning up for previous room: ${cleanupRoomId}`);
if (smallWidgetRef.current) {
smallWidgetRef.current.stopMessaging();
// smallWidgetRef.current.stopMessaging();
}
// Potentially call widgetApi.stop() or similar if the API instance has it
if (widgetApiRef.current) {
@ -50,94 +59,80 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
}
widgetApiRef.current = null;
smallWidgetRef.current = null;
iframeRef.current.src = 'about:blank';
};
if (activeCallRoomId && mx?.getUserId()) {
const newUrl = getWidgetUrl(mx, activeCallRoomId, clientConfig.elementCallUrl ?? '');
const userId = mx.getUserId() ?? '';
const app = createVirtualWidget(
mx,
`element-call-${activeCallRoomId}`,
userId,
'Element Call',
'm.call',
newUrl,
false,
getWidgetData(mx, activeCallRoomId, {}, { skipLobby: true }),
activeCallRoomId
);
if (cleanupRoomId !== activeCallRoomId) {
const newUrl = getWidgetUrl(mx, room, clientConfig.elementCallUrl ?? '');
if (iframeRef.current && iframeRef.current.src !== newUrl.toString()) {
logger.info(
`PersistentCallContainer: Updating iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
);
iframeRef.current.src = newUrl.toString();
} else if (iframeRef.current && !iframeRef.current.src) {
logger.info(
`PersistentCallContainer: Setting initial iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
);
iframeRef.current.src = newUrl.toString();
}
const iframeElement = iframeRef.current;
if (!iframeElement) {
logger.error('PersistentCallContainer: iframeRef is null, cannot setup API.');
return cleanup;
}
logger.debug(`PersistentCallContainer: Creating new SmallWidget/API for ${activeCallRoomId}`);
const smallWidget = new SmallWidget(app);
smallWidgetRef.current = smallWidget;
try {
const widgetApiInstance = smallWidget.startMessaging(iframeElement);
widgetApiRef.current = widgetApiInstance;
widgetApiInstance.once('ready', () => {
logger.info(`PersistentCallContainer: Widget for ${activeCallRoomId} is ready.`);
});
/* Default handling seems bugged on this. Element does not need this in their driver or codebase, but
we do. I believe down the road update_state will be used by element-call and this can be removed.
*/
widgetApiInstance.on(
'action:org.matrix.msc2876.read_events',
(ev: CustomEvent<IWidgetApiRequest>) => {
logger.info(`PersistentCallContainer: Widget requested 'read_events':`, ev.detail.data);
ev.preventDefault();
widgetApiRef.current?.transport?.reply(ev.detail, { approved: true });
}
);
widgetApiInstance.on('action:im.vector.hangup', () => {
if (iframeRef.current && iframeRef.current.src !== newUrl.toString()) {
logger.info(
`PersistentCallContainer: Received hangup action from widget in room ${activeCallRoomId}.`
`PersistentCallContainer: Updating iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
);
if (smallWidgetRef.current?.roomId === activeCallRoomId) {
setActiveCallRoomId(null);
}
});
} catch (error) {
logger.error(
`PersistentCallContainer: Error initializing widget messaging for ${activeCallRoomId}:`,
error
cleanup();
iframeRef.current.src = newUrl.toString();
} else if (iframeRef.current && !iframeRef.current.src) {
logger.info(
`PersistentCallContainer: Setting initial iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
);
iframeRef.current.src = newUrl.toString();
}
const iframeElement = iframeRef.current;
if (!iframeElement) {
logger.error('PersistentCallContainer: iframeRef is null, cannot setup API.');
return cleanup;
}
const userId = mx.getUserId() ?? '';
const app = createVirtualWidget(
mx,
`element-call-${activeCallRoomId}`,
userId,
'Element Call',
'm.call',
newUrl,
false,
getWidgetData(mx, activeCallRoomId, {}, { skipLobby: true }),
activeCallRoomId
);
logger.debug(
`PersistentCallContainer: Creating new SmallWidget/API for ${activeCallRoomId}`
);
const smallWidget = new SmallWidget(app);
smallWidgetRef.current = smallWidget;
try {
const widgetApiInstance = smallWidget.startMessaging(iframeElement);
widgetApiRef.current = widgetApiInstance;
registerActiveTransport(activeCallRoomId, widgetApiRef.current.transport);
widgetApiInstance.once('ready', () => {
logger.info(`PersistentCallContainer: Widget for ${activeCallRoomId} is ready.`);
});
} catch (error) {
logger.error(
`PersistentCallContainer: Error initializing widget messaging for ${activeCallRoomId}:`,
error
);
cleanup();
}
} else {
if (iframeRef.current && iframeRef.current.src !== 'about:blank') {
logger.info('PersistentCallContainer: No active call, setting src to about:blank');
iframeRef.current.src = 'about:blank';
}
cleanup();
}
} else {
if (iframeRef.current && iframeRef.current.src !== 'about:blank') {
logger.info('PersistentCallContainer: No active call, setting src to about:blank');
iframeRef.current.src = 'about:blank';
}
cleanup();
}
return cleanup;
}, [activeCallRoomId, mx, setActiveCallRoomId]);
const containerStyle: React.CSSProperties = {
width: '100%',
height: '100%',
top: '1',
left: '1',
display: isVisible ? 'flex' : 'none',
flexDirection: 'row',
};
@ -149,10 +144,8 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
<Box
shrink="No"
style={{
width: '250px',
height: '100%',
overflowY: 'auto',
borderRight: '1px solid #ccc',
}}
>
<RouteSpaceProvider>