---
title: Video/Voice Calls in Team Chat (LiveKit WebRTC, in development)
---

# Video/Voice Calls in Team Chat (LiveKit WebRTC, in development)

## What it is

**Status:** In-development (gated behind `video-calls` unreleased feature). Reveal via **Settings -> Lab -> Video Calls**, or launch with `AMC_SHOW_VIDEO_CALLS=1`.

Channel-scoped voice and video calls inside Team Chat, powered by LiveKit (a WebRTC SFU). A call is a Firestore document with a status state machine (ringing -> active -> ended); the renderer manages call state through a Zustand store and connects to LiveKit for peer-to-peer media. Up to 50 participants per call.

## Where to find it

The call UI lives inside **Team Chat** — the call button sits in the channel header, and an incoming call arrives as an overlay. Because the feature is still in development, none of it is visible until you reveal it in **Settings -> Lab -> Video Calls**.

## How it behaves

### How it works

1. **Start a call** -- click the call button in the channel header. This creates a Firestore call doc (status `ringing`) and obtains a LiveKit token + URL.
2. **Ring** -- other channel members see an incoming call overlay. Declining suppresses re-ring for the session. Ring timeout is 30 seconds.
3. **Join** -- accepting transitions the call to `active` and returns a LiveKit token. The LiveKit room connection is renderer-side (no main-process relay).
4. **In-call** -- presence heartbeats every 30 seconds; participant count updates from Firestore snapshots.
5. **End** -- sets status to `ended`, records duration, posts a system message summarizing the call.

### In-call features

- **Controls toolbar** -- mute (M), camera toggle (V), screen share (S), virtual background (B), end call (Escape). All keyboard-accessible with ARIA labels.
- **Virtual backgrounds** -- blur (light/medium/heavy) or a custom image (JPEG/PNG/WebP). The track processor is lazy-loaded (not in the critical call-join path). Custom images are stored locally in `{userData}/video-backgrounds/`.
- **Participant grid** -- LiveKit-powered grid layout for multiple participants.

### What's built vs deployment blockers

**Built (renderer-side complete):**

- Zustand store with full call state machine (single active call, declined call tracking, connection state)
- UI components: CallButton, InCallView, IncomingCallOverlay, LiveKitCallGrid, CallControls, BackgroundPicker
- IPC schemas and channels: `TEAM_CHAT_CALL_START`, `TEAM_CHAT_CALL_JOIN`, `TEAM_CHAT_CALL_END`
- LiveKit room hook with presence heartbeat
- Virtual background processor with blur and custom image support
- Main-process IPC handlers (wired)

**Deployment blockers (must be resolved before shipping):**

- **Cloud Functions not deployed** -- `callStart`, `callJoin`, `callEnd` functions are referenced in `team-chat-call-relay-client.ts` but are NOT deployed to Firebase. These create/join/end call documents and obtain LiveKit tokens.
- **LiveKit DPA (Data Processing Agreement)** -- pending; required before enabling the feature.
- **Server-side call presence cleanup** -- stale heartbeat expiry is not yet implemented.

### Scope and limits

- **Desktop only** -- the call UI is a renderer-side feature inside Team Chat.
- **One active call at a time** -- the store enforces single-call; starting a second ends the first.
- **50-participant cap** -- enforced by Zod schema validation on the participants record.
- **$0 AI spend** -- no Claude tokens used; media is peer-to-peer via LiveKit.

## For agents

### Architecture (for agents / engineers)

| Piece                    | Location                                                                 |
| ------------------------ | ------------------------------------------------------------------------ |
| Zustand store            | `src/renderer/src/features/team-chat/video-call/call-store.ts`           |
| IPC client               | `src/renderer/src/features/team-chat/video-call/call-client.ts`          |
| Firestore call listener  | `src/renderer/src/features/team-chat/video-call/use-call-listener.ts`    |
| LiveKit room + heartbeat | `src/renderer/src/features/team-chat/video-call/use-livekit-room.ts`     |
| Controls toolbar         | `src/renderer/src/features/team-chat/video-call/CallControls.tsx`        |
| Background picker        | `src/renderer/src/features/team-chat/video-call/BackgroundPicker.tsx`    |
| Background processor     | `src/renderer/src/features/team-chat/video-call/video-bg-processor.ts`   |
| Background storage       | `src/main/services/team-chat/video-backgrounds.ts`                       |
| In-call view             | `src/renderer/src/features/team-chat/video-call/InCallView.tsx`          |
| Incoming call overlay    | `src/renderer/src/features/team-chat/video-call/IncomingCallOverlay.tsx` |
| Participant grid         | `src/renderer/src/features/team-chat/video-call/LiveKitCallGrid.tsx`     |
| Call button              | `src/renderer/src/features/team-chat/video-call/CallButton.tsx`          |
| Zod schemas + constants  | `src/shared/ipc-schemas/team-chat-calls.ts`                              |

## Related

- [team-chat.md](team-chat.md) -- the Team Chat feature that hosts calls
- Contract: [team-chat-video-call-contract.md](../../.claude/memory/contracts/team-chat-video-call-contract.md)













| Zod schemas + constants  | `src/shared/ipc-schemas/team-chat-calls.ts`                              |

| Piece | Location |
| --- | --- |
| Zustand store | `src/renderer/src/features/team-chat/video-call/call-store.ts` |
| IPC client | `src/renderer/src/features/team-chat/video-call/call-client.ts` |
| Firestore call listener | `src/renderer/src/features/team-chat/video-call/use-call-listener.ts` |
| LiveKit room + heartbeat | `src/renderer/src/features/team-chat/video-call/use-livekit-room.ts` |
| Controls toolbar | `src/renderer/src/features/team-chat/video-call/CallControls.tsx` |
| Background picker | `src/renderer/src/features/team-chat/video-call/BackgroundPicker.tsx` |
| Background processor | `src/renderer/src/features/team-chat/video-call/video-bg-processor.ts` |
| Background storage | `src/main/services/team-chat/video-backgrounds.ts` |
| In-call view | `src/renderer/src/features/team-chat/video-call/InCallView.tsx` |
| Incoming call overlay | `src/renderer/src/features/team-chat/video-call/IncomingCallOverlay.tsx` |
| Participant grid | `src/renderer/src/features/team-chat/video-call/LiveKitCallGrid.tsx` |
| Call button | `src/renderer/src/features/team-chat/video-call/CallButton.tsx` |
| Zod schemas + constants | `src/shared/ipc-schemas/team-chat-calls.ts` |




