From 42cc081d49d93912ea8cb2de6ea4bacd66404d18 Mon Sep 17 00:00:00 2001 From: Litruv Date: Sun, 22 Feb 2026 03:41:07 +1100 Subject: [PATCH] feat: enhance LiveKit service URL handling and add clipboard support for Electron --- src/app/features/call/CallService.ts | 28 ++++++++++++++++++++++------ src/app/features/call/useCall.ts | 10 ++++++---- src/app/utils/dom.ts | 7 +++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/app/features/call/CallService.ts b/src/app/features/call/CallService.ts index d3924ad..9bbc289 100644 --- a/src/app/features/call/CallService.ts +++ b/src/app/features/call/CallService.ts @@ -300,10 +300,26 @@ export class CallService { this.config.accessToken ); - // Step 2: Exchange OpenID token for LiveKit JWT + // Step 2: Determine LiveKit service URL (check room-level config first) + let livekitServiceUrl = this.config.livekitServiceUrl; + + // Check if room has a custom LiveKit config + const room = this.matrixClient.getRoom(roomId); + if (room) { + const livekitConfigEvent = room.currentState.getStateEvents('im.paarrot.room.livekit_config', ''); + if (livekitConfigEvent) { + const roomLivekitUrl = livekitConfigEvent.getContent()?.service_url; + if (roomLivekitUrl) { + console.log('Using room-level LiveKit URL:', roomLivekitUrl); + livekitServiceUrl = roomLivekitUrl; + } + } + } + + // Step 3: Exchange OpenID token for LiveKit JWT console.log('Requesting LiveKit JWT for Matrix room:', roomId); this.livekitJwt = await fetchLiveKitJWT( - this.config.livekitServiceUrl, + livekitServiceUrl, roomId, this.config.userId, this.config.deviceId, @@ -322,7 +338,7 @@ export class CallService { console.warn('WebRTC details:', JSON.stringify(webrtcCheck.details, null, 2)); } - // Step 3: Create and connect to LiveKit room + // Step 4: Create and connect to LiveKit room this.livekitRoom = new Room({ adaptiveStream: true, dynacast: true, @@ -351,7 +367,7 @@ export class CallService { console.log('Audio capture options:', audioCaptureOptions); - // Step 4: Publish local tracks based on call type with selected devices and processing + // Step 5: Publish local tracks based on call type with selected devices and processing if (callType === CallType.Video) { // For video calls, enable both camera and microphone await this.livekitRoom.localParticipant.setCameraEnabled(true); @@ -361,12 +377,12 @@ export class CallService { await this.livekitRoom.localParticipant.setMicrophoneEnabled(true, audioCaptureOptions); } - // Step 5: Send Matrix state event to announce participation + // Step 6: Send Matrix state event to announce participation // This state event will be rendered in the timeline as a "joined the call" notification await this.sendCallMemberEvent(roomId, callId, true); this.currentCallId = callId; - // Step 6: Start periodic membership refresh to prevent expiry after 1 hour + // Step 7: Start periodic membership refresh to prevent expiry after 1 hour this.startMembershipRefresh(roomId, callId); console.log('Announced call participation to Matrix room'); diff --git a/src/app/features/call/useCall.ts b/src/app/features/call/useCall.ts index 99547e2..e4a62e0 100644 --- a/src/app/features/call/useCall.ts +++ b/src/app/features/call/useCall.ts @@ -105,12 +105,14 @@ export function useCallService(options?: UseCallServiceOptions): CallContextValu console.log('Call service init - Using configured LiveKit URL:', livekitServiceUrl); } + // If still no URL, log warning but allow service to initialize + // Individual rooms may have their own LiveKit configs if (!livekitServiceUrl) { // eslint-disable-next-line no-console - console.log('Call service init - No LiveKit service found, calls not supported'); - setCallSupported(false); - setCallSupportLoading(false); - return; + console.log('Call service init - No global LiveKit URL found'); + console.log('Call service init - Will check for room-level configs when joining calls'); + // Use a placeholder URL - room-level config will override this + livekitServiceUrl = 'https://placeholder.invalid/livekit'; } service = new CallService( diff --git a/src/app/utils/dom.ts b/src/app/utils/dom.ts index 80db3ae..71e8e22 100644 --- a/src/app/utils/dom.ts +++ b/src/app/utils/dom.ts @@ -188,6 +188,13 @@ export const scrollToBottom = (scrollEl: HTMLElement, behavior?: 'auto' | 'insta }; export const copyToClipboard = (text: string) => { + // Try Electron clipboard first (if available) + if ('electron' in window && (window as any).electron?.clipboard?.writeText) { + (window as any).electron.clipboard.writeText(text); + return; + } + + // Fall back to standard web APIs if (navigator.clipboard) { navigator.clipboard.writeText(text); } else {