feat: enhance LiveKit service URL handling and add clipboard support for Electron

This commit is contained in:
2026-02-22 03:41:07 +11:00
parent f5ba778e46
commit 42cc081d49
3 changed files with 35 additions and 10 deletions

View File

@@ -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');

View File

@@ -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(

View File

@@ -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 {