diff --git a/src/app/pages/call/PersistentCallContainer.tsx b/src/app/pages/call/PersistentCallContainer.tsx index e750801b..32a25d80 100644 --- a/src/app/pages/call/PersistentCallContainer.tsx +++ b/src/app/pages/call/PersistentCallContainer.tsx @@ -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) => { - 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