Files
cinny/docs/handoff/features/voice-calls/HANDOFF.md
Max Litruv Boonzaayer e058165830 feat: upgrade toolchain and soften sync recovery after network blips
Bump Vite 8, matrix-js-sdk, and related deps; fix immer/vanilla-extract imports for new majors. Replace blocking sync error dialog with background recovery on wake/offline, and disable Vite auto-open in dev. Add feature handoff documentation index.
2026-07-09 01:55:09 +10:00

3.4 KiB

Voice & video calls — handoff

Summary

Paarrot supports Matrix RTC voice/video calls via MSC3401 (org.matrix.msc3401.call.member) and LiveKit. Calls can be docked in the sidebar, support screen share, remote cursors, mute/deafen, and are wired to the local HTTP API for external control.

User-facing behavior

  • Join/start calls from room UI (when homeserver exposes RTC/LiveKit via .well-known)
  • Docked call panel in sidebar; full overlay mode
  • Mute, deafen, camera, screen share controls
  • Call participants shown in room nav (CallParticipantsIndicator)

Architecture

useCallService (CallProvider)
  → CallService (LiveKit room, Matrix call member state)
    → useRtcConfig: .well-known m.rtc + LiveKit focus
  → UI: CallOverlay, DockedCallPanel, SidebarDockedCallPanel
  → getCallService() global ref for Electron API (paarrot-api.ts)

Key files

Path Role
cinny/src/app/features/call/useCall.ts React context, global CallService ref
cinny/src/app/features/call/CallService.ts Core call logic
cinny/src/app/features/call/types.ts CallState, ActiveCall, events
cinny/src/app/features/call/useRtcConfig.ts Homeserver RTC / LiveKit discovery
cinny/src/app/features/call/CallOverlay.tsx Full-screen call UI
cinny/src/app/features/call/DockedCallPanel.tsx Docked UI
cinny/src/app/features/call/SidebarDockedCallPanel.tsx Sidebar variant
cinny/src/app/features/call/useRemoteCursor.ts Screen-share cursor sync
cinny/src/app/features/call/CallSounds.ts Join/leave sounds
cinny/src/app/features/room-nav/CallParticipantsIndicator.tsx Nav badge
cinny/src/types/matrix/room.ts StateEvent.CallMember

Data model

Key Scope Notes
org.matrix.msc3401.call.member Room state Call membership
LiveKit JWT / room Ephemeral From homeserver RTC focus

Call mute/deafen/video state lives in CallService memory, not Matrix account data.

Dependencies

  • livekit-client (verify in package.json)
  • Homeserver .well-known RTC configuration
  • Browser/Electron media permissions (mic, camera, screen capture)
  • Electron desktopCapturer for screen share (main process)

Integration points

  • local-api: mute/deafen/status endpoints
  • Stream Deck: uses call mute/deafen via API
  • Room nav: participant indicators
  • Electron main: screen capture IPC if applicable

Testing

Manual

  1. Use a homeserver with Matrix RTC + LiveKit configured.
  2. Start voice call in a room; verify audio both ways.
  3. Toggle mute/deafen; verify API /status reflects state.
  4. Screen share; verify remote cursor if enabled.
  5. Dock/undock call panel.

Automated

  • None identified

Known issues & gotchas

  • callSupported false until .well-known RTC fetch completes — UI should hide call buttons when unsupported
  • getCallService() must be set before API mute actions work
  • Platform differences: screen capture APIs differ Electron vs browser vs Android

Future work

  • Call recording, noise suppression settings
  • Better reconnection / call transfer
  • MSC3401 spec tracking as it stabilizes

Add your extra things here

  • fetchWellKnownWithRTC, getLiveKitFocus, getLiveKitHomeserverPriority in useRtcConfig.ts
  • Global singleton: globalCallServiceInstance in useCall.ts for non-React consumers