Designing Group Video Calls That Gracefully Handle Mid-Call Join & Leave

Designing Group Video Calls That Gracefully Handle Mid-Call Join & Leave

Designing Group Video Calls That Gracefully Handle Mid-Call Join & Leave

A production-grade system-design walkthrough for a messaging platform’s group video calling feature — media routing architecture, signaling, renegotiation on participant churn, scaling, and reliability — with interview-style deep dives.

01

Introduction & History

Group video calling is one of the harder real-time systems problems in consumer software, because unlike a chat message or a poll vote, video and audio cannot tolerate retransmission-based reliability — a lost packet in a video frame that arrives 300 ms late is worse than useless, it is discarded, because by the time it could be retransmitted the moment it was meant to capture has already passed. Everything about this system is shaped by that one constraint: it must move a continuous, high-bitrate stream of perishable data between many participants with latency low enough to preserve natural conversation, while participants join and leave at arbitrary, unpredictable moments without the other participants noticing anything worse than a brief visual blip.

1.1 A Brief Lineage

The technical lineage here runs from early point-to-point VoIP and video conferencing hardware (dedicated conference room systems in the 1990s and 2000s using proprietary protocols and specialized hardware codecs), through enterprise software conferencing bridges, to the modern era defined by WebRTC — an open, browser-native, standardized real-time media stack that Google open-sourced and pushed through W3C / IETF standardization starting around 2011. WebRTC is what made it possible for any messaging app to add “click a button, start a video call” without every participant installing a plugin or dedicated client, and it is the near-universal foundation underneath the group calling feature this document designs.

1990s

Dedicated conference room hardware

Point-to-point video conferencing using proprietary protocols and specialized hardware codecs. The bar for connecting was owning the room; media routing was mostly a wiring problem.

2000s

Enterprise conferencing bridges

Software MCU-style bridges compose a single mixed stream per participant. Feasible for meeting rooms, still awkward for ad-hoc consumer usage.

2011

WebRTC open-sourced

Google open-sources a full browser-native real-time media stack; W3C / IETF standardization begins. “Click a button, start a call” becomes possible without plugins or dedicated apps.

Mid-2010s

SFU architecture becomes standard

Selective Forwarding Units replace mesh and MCU as the dominant routing pattern for group calls at anything beyond a handful of participants, trading server bandwidth for far better scale.

2020s

Casual, always-on group calling

Slack Huddles, Discord voice channels, and Teams / Meet make it normal to drop in and out of a live call at any moment. Non-disruptive join / leave is now a first-class product requirement, not a polish item.

1.2 Why the “Simple” Requirement Is Actually Hard

The specific challenge in this brief — participants joining and leaving mid-call without disrupting others — is deceptively simple to state and genuinely difficult to build well. A two-person call has exactly one media path to manage. A group call with a changing participant count has to solve a combinatorial routing problem (who sends media to whom) that must be re-solved, quickly and invisibly, every time someone joins or leaves, all while the participants who did not change anything continue talking without a hiccup. Getting this wrong is not a subtle failure — it shows up immediately as a pop in someone’s audio or a frozen frame every time a colleague drops into a standing group call, and it is exactly the kind of defect that erodes trust in a messaging product’s calling feature faster than almost any other class of bug.

🎤
What the interviewer may be probing for
  • Do you understand why video / audio is fundamentally different from a typical request / response or even a typical streaming data problem (loss-tolerant vs. loss-intolerant, latency-sensitive real-time media)?
  • Can you articulate the core media-routing architectural choice (mesh vs. MCU vs. SFU) and its consequences for how join / leave is handled?
  • Do you know WebRTC exists and roughly what problem it solves, without needing to reimplement codec / transport details from scratch?
02

Problem Framing & Requirements

Two coupled sub-problems with different characters — a signaling problem (who is in the call, negotiating how each participant’s media connects) and a media transport problem (actually moving audio / video bytes with minimal latency). Keeping them separate is what makes the design legible.

2.1 Functional Requirements

FR1

Start from an existing chat

Any participant can start a group video call from within an existing chat / conversation.

FR2

Join & leave any time

Other participants can join an in-progress call at any time and leave at any time, without ending the call for remaining participants.

FR3

Conversational latency

Each participant sees / hears audio and video from all (or a relevant subset of) other participants with natural conversational latency.

FR4

Adaptive quality

The system adapts video quality per participant based on their network conditions and device capability.

FR5

Mute / video / screen share

Participants can mute / unmute audio, enable / disable video, and share their screen.

FR6

Visible call state

Call state (who is in the call, who is speaking, connection quality) is visible to all participants.

FR7

Reconnect, not rejoin

Calls can be resumed if a participant’s connection briefly drops (reconnect without fully re-joining as a “new” participant from a UX perspective).

2.2 Non-Functional Requirements

Latency

150–250 ms end-to-end

Under roughly 150–250 ms for a natural conversational feel; anything approaching 400 ms+ becomes noticeably awkward (people start talking over each other).

Scale

Bounded call size

Group calls up to some bounded size (e.g., dozens to low hundreds of participants), as distinct from a broadcast / webinar product supporting tens of thousands of viewers.

Responsiveness

1–2 s to join

A joining participant should see / hear the call within 1–2 seconds; existing participants should experience no audible / visible disruption.

Loss

Loss tolerance

The media pipeline must degrade gracefully under packet loss and variable network conditions rather than freezing or failing outright.

Cost

Sub-quadratic scaling

Media routing cost (bandwidth and compute) must scale sub-quadratically with participant count — a naive full-mesh approach scales quadratically and becomes infeasible past a handful of participants.

Portability

Cross-platform

Works across mobile apps, desktop apps, and (ideally) web browsers, over a wide range of real-world network conditions (WiFi, cellular, corporate NAT / firewalls).

📜
Framing device for an interview

This system has two coupled sub-problems with different characters — a signaling problem (who is in the call, negotiating how each participant’s media connects to the system, a classic distributed-systems problem you can reason about with normal request / response and pub / sub tools) and a media transport problem (actually moving audio / video bytes with minimal latency, a UDP-based, loss-tolerant, real-time streaming problem governed by WebRTC and RTP, not HTTP). Keeping these two conceptually separate, and being explicit about which one you are addressing at any point in the design, is what makes the answer legible to an interviewer.

2.3 Sizing the Problem in Numbers

DimensionAssumptionImplication
Typical group call size2–50 participants (messaging-app group calls), with a long tail up to a few hundredSFU model needed well before the upper end of this range; mesh only viable at the very bottom
Per-stream video bitrate~150 kbps (low) to ~2.5 Mbps (high quality), plus ~30–50 kbps audioA 20-person call’s aggregate SFU forwarding load can reach tens of Mbps per node even with active-speaker limiting
Join / leave frequencyFrequent and organic — people drop in and out throughout the call’s duration, unlike a scheduled meeting with a fixed startChurn-handling logic is exercised constantly, not as an edge case, and must be a first-class design concern
Acceptable disruption on churnEffectively zero — no audible pop, no frozen frame, no dropped connectionRules out any approach requiring renegotiation of existing participants’ sessions on membership change
Network heterogeneityWide mix of WiFi, cellular, and NAT / firewall configurations across participants in the same callPer-participant adaptive quality (simulcast) and reliable TURN fallback are required, not optional
03

Architecture & Components

The architecture centers on a Selective Forwarding Unit (SFU) model — the industry-standard approach for group calls beyond a handful of participants — combined with a separate signaling layer that manages call membership and negotiation, decoupled from the media path itself.

CLIENTS Participant ALong-standing member Participant BLong-standing member Participant CJoins mid-call SIGNALING PLANE Load BalancerL7 / WebSocket Signaling Service ClusterWebSocket · SDP · ICE Call State Store (Redis)Members · SFU assignment Presence & MembershipPublishes join / leave events Call OrchestratorAssigns SFU node SFU Cluster RouterPlacement & inter-node relay MEDIA PLANE SFU Media Server 1Selective forwarding SFU Media Server 2Peer node (scale / geo) TURN / STUN RelaysNAT traversal fallback Media Router (per-call selective forwarding)Simulcast layer selection per receiver SUPPORTING SERVICES Push Notification SvcWake invited participants Recording / TranscriptionOptional participant on SFU TURN Credential ServiceShort-lived, scoped tokens

Figure 1 — SFU-centered architecture. Blue lines carry signaling (SDP offer / answer, ICE), red lines are RTP / SRTP media over UDP, purple dashed lines are TURN fallback for clients whose NAT / firewall blocks direct connectivity.

3.1 Component Breakdown

Signaling

Signaling Service Cluster

Stateless-ish WebSocket servers that carry call-control messages — join / leave requests, WebRTC session negotiation (SDP offer / answer), ICE candidate exchange — between clients and the rest of the system. Ordinary real-time messaging infrastructure, not media transport.

State

Call State Store (Redis)

Tracks which participants are currently in which call, which SFU node(s) they are connected to, and current mute / video-enabled state — the authoritative, low-latency source for “who is in this call right now.”

Membership

Presence & Membership Service

Publishes membership change events (participant joined / left) to all current call participants via the signaling layer, and to any other system (e.g., the parent messaging app) that needs to reflect call state in its UI.

Orchestrator

Call Orchestrator Service

Decides, for a new call or a newly joining participant, which SFU node(s) will host the call’s media, and coordinates the signaling handshake needed to connect a participant to that node.

SFU

SFU Media Server Nodes

The heart of the media plane. Each participant sends one upstream media connection to an SFU node; the SFU selectively forwards (without decoding / re-encoding) each participant’s stream to every other participant who needs it, based on current call membership and each receiver’s requested quality layer.

Router

SFU Cluster Router / Selector

Picks the best SFU node for a call (typically the one geographically closest to the majority of participants, with available capacity) and manages inter-node media relay when a single call’s participants are split across multiple SFU nodes for scale or geographic reasons.

Relay

TURN / STUN Relay Servers

STUN helps clients discover their public-facing network address for direct / efficient connectivity; TURN relays media for the substantial fraction of real-world clients sitting behind restrictive NATs / firewalls that block direct UDP connectivity to the SFU.

Credentials

TURN Credential Service

Issues short-lived, scoped credentials for TURN relay usage, since TURN relays are a shared, costly resource that must not be open to arbitrary abuse.

Recording

Recording / Transcription Service

Optional. A specialized “participant” that the SFU forwards media to like any other endpoint, decoupled from the live call path so recording load never affects live participants’ experience.

Notif

Push Notification Service

Notifies invited participants who are not actively in the app that a call has started or that they are being invited to join.

🎤
Interviewer follow-ups on architecture
  • “Why an SFU instead of a full mesh where every client connects directly to every other client?” — Full mesh requires each client to encode and upload its media N−1 times (once per other participant), which scales quadratically in total bandwidth and linearly in per-client upload bandwidth as participants grow — infeasible past roughly 4–6 participants on typical consumer upload bandwidth. An SFU centralizes forwarding so each client uploads once and downloads N−1 streams, a much more favorable scaling shape.
  • “Why an SFU instead of an MCU (Multipoint Control Unit) that mixes everyone into one combined stream?” — An MCU does the heavy lifting of decoding every stream and re-encoding a single composited stream per participant, which is CPU / GPU-intensive at the server and adds real encode / decode latency; an SFU just forwards packets without transcoding, which is far cheaper to scale and adds minimal latency, at the cost of pushing more of the compositing / layout work to each client.
  • “Why is signaling a separate system from media, when both are ‘real-time’?” — They have completely different reliability and transport needs: signaling is relatively low-volume, benefits from reliable, ordered delivery (a WebSocket / TCP-based channel is fine), while media is extremely high-volume, loss-tolerant, and latency-critical, needing UDP-based transport (RTP / SRTP) where an old, late packet is actively harmful to retransmit.
04

Internal Working

4.1 WebRTC Fundamentals in This System

Each participant’s client uses WebRTC to establish a media connection to the SFU. The negotiation follows the standard offer / answer model (SDP — Session Description Protocol) to agree on codecs, encryption keys, and network paths, and ICE (Interactive Connectivity Establishment) to find the best actual network path between client and SFU, trying direct UDP connectivity first and falling back to a TURN relay if NAT / firewall traversal fails. All media is encrypted end-to-end between client and SFU using SRTP (Secure RTP), and typically further protected with DTLS for the key exchange itself.

4.2 Simulcast and Scalable Video Coding

A single participant’s outgoing video is rarely sent as just one quality stream. Using simulcast, a sending client encodes and uploads two or three simultaneous quality layers (e.g., low, medium, high resolution / bitrate) of its own video. The SFU then selectively forwards whichever layer is appropriate to each individual receiver, based on that receiver’s current bandwidth, CPU, and UI layout (a participant shown as a tiny thumbnail does not need the high-resolution layer; the currently-speaking participant shown full-screen does). This is the key mechanism that lets the same call gracefully serve receivers with wildly different network conditions without the sender needing to know or care about each receiver’s individual situation — the SFU makes that decision per-receiver, per-layer, continuously.

4.3 Selective Forwarding Logic

The SFU does not necessarily forward every participant’s stream to every other participant at full quality, especially as call size grows. Common optimizations include forwarding only the audio of participants who are actually currently speaking (audio-only or muted “silent” streams for everyone else, driven by voice-activity detection), and forwarding video only for a bounded number of currently-visible participants (e.g., an “active speaker” plus whoever is pinned / visible in the current UI layout) rather than every single participant’s video to every single receiver — turning what would otherwise be O(N²) total forwarding work into something closer to O(N × visible_tiles), a materially better scaling shape for larger calls.

4.4 Codec Selection and Adaptation

Codec choice affects both quality-per-bit and CPU cost — modern deployments typically negotiate a codec like VP8 / VP9 or H.264 for broad compatibility, with newer, more bandwidth-efficient codecs like AV1 used where both ends support it. Because the SFU never decodes or re-encodes media in the selective-forwarding model, codec negotiation happens once per sender-receiver pair at connection time and stays fixed for that pair’s session — the SFU is simply forwarding whatever bytes it receives, agnostic to the codec inside them, which is part of why it is so much cheaper computationally than an MCU.

4.5 Congestion Control and Bandwidth Estimation

Each WebRTC connection continuously estimates available bandwidth (commonly via Google Congestion Control or similar algorithms built into the WebRTC stack) using signals like packet loss, delay, and jitter observed on that specific path. The sender uses this estimate to decide which simulcast layers to keep sending and at what encoded bitrate; the SFU uses its own per-receiver bandwidth estimate to decide which of the sender’s available layers to actually forward to that receiver. This dual-sided estimation — sender deciding what to produce, SFU deciding what to relay per receiver — is what allows the same call to serve a participant on gigabit fiber and a participant on a spotty 4G connection simultaneously, each getting a stream matched to their own real-time conditions.

4.6 Packet Loss Concealment and Jitter Buffering

Because retransmission is often not viable for real-time media (a retransmitted packet frequently arrives too late to be useful), receivers rely on loss-tolerant techniques: forward error correction (sending modest redundant data that allows reconstructing some lost packets without retransmission), packet loss concealment (audio codecs like Opus can synthesize a plausible continuation of speech across small gaps), and jitter buffers (a small, adaptive buffer on the receiving end that absorbs variable network delay and smooths playback, at the cost of a small amount of added latency). None of these live at the SFU — they are endpoint (sender / receiver) responsibilities — but the SFU’s job of forwarding packets promptly and without adding its own significant queuing delay is what keeps these endpoint mechanisms effective.

🎤
What an interviewer may ask
  • “How does the system handle a participant on a poor cellular connection in a call with people on fast WiFi?” — Simulcast lets that participant’s own uplink degrade to a lower-quality layer without affecting anyone else, and on the downlink side the SFU can independently send that participant lower-quality layers of everyone else’s video, adapting each direction independently rather than forcing the whole call down to the worst participant’s level.
  • “Why forward only active-speaker video / audio at scale rather than everyone’s?” — Because human attention and screen real estate are inherently limited (nobody’s UI meaningfully shows 50 full-motion video tiles at once), and forwarding streams nobody is actually looking at or listening to wastes bandwidth and server compute for zero perceptual benefit — this is essentially an application-level backpressure / relevance filter on top of the raw routing problem.
  • “Why does not the SFU just retransmit lost packets like TCP would?” — By the time a retransmitted packet could arrive, the moment of audio / video it represents has usually already passed and been either concealed or skipped by the receiver — retransmission optimizes for eventual completeness, which is the wrong goal for a live stream that only cares about “what can I play right now.”
05

Data Flow & Lifecycle

The join and leave flows follow the same underlying principle: the SFU changes the set of forwarded streams without disturbing anyone else’s active connection.

New Participant Signaling Svc Call Orchestrator SFU Node (existing call) Existing Participants 1. join_call(call_id, auth) 2. Resolve call, get assigned SFU node 3. SFU endpoint + ICE config 4. join_ack + current participant list 5. WebRTC offer (SDP) 6. WebRTC answer (SDP) 7. ICE candidates (both directions) DTLS / SRTP handshake, media flow begins — no renegotiation for existing participants 8. participant_joined event (metadata only) 9. Begin forwarding NewP’s media stream 10. Existing streams now also forwarded to NewP

Figure 2 — Mid-call join. Existing participants’ own WebRTC connections to the SFU are not torn down or renegotiated — the SFU simply begins forwarding one additional inbound stream to them.

The crucial detail is that existing participants’ own WebRTC connections to the SFU are not torn down or renegotiated when a new participant joins — the SFU simply begins forwarding an additional inbound stream to them (using modern WebRTC capabilities like a single negotiated transceiver that can carry a dynamic set of streams, or lightweight, non-disruptive renegotiation that does not interrupt existing media flow). This is precisely what prevents a join from being disruptive to people already on the call.

Leaving Participant Signaling Svc SFU Node Remaining Participants 1. leave_call OR connection-drop detected 2. Remove participant from forwarding set 3. Stop forwarding LeavingP’s media 4. participant_left event (UI removes tile) 5. Update call state store (membership, timestamps)

Figure 3 — Mid-call leave. Leaving mirrors joining: the SFU stops forwarding the departed participant’s stream and other participants simply stop receiving it — no teardown of anyone else’s connection is required.

A distinction worth calling out explicitly: a graceful leave (user taps “leave call”) and an ungraceful disconnect (network drop, app crash) are detected differently — the former is an explicit signaling message, the latter is inferred via WebRTC connection-state changes and / or a heartbeat timeout — but both converge on the same cleanup path once detected.

06

Handling Mid-Call Join & Leave Gracefully (Deep Dive)

This is the heart of the brief, so it is worth pulling the relevant mechanisms together explicitly rather than leaving them scattered across other sections.

6.1 Why Naive Approaches Break

A naive implementation might treat any membership change as “renegotiate the whole call” — tear down and rebuild the SDP / ICE session for every participant whenever anyone joins or leaves, since the “set of streams in the room” technically changed. This causes a visible / audible glitch (a brief black frame or audio pop) for every existing participant, every single time anyone else joins or leaves — clearly unacceptable for a group call in an active messaging app where people join and leave frequently.

6.2 The Fix: Decouple “Connection” from “Stream Set”

The mechanism that solves this is treating each participant’s WebRTC connection to the SFU as a stable, long-lived transport session whose set of actively flowing streams can change dynamically without renegotiating the underlying connection itself. Modern WebRTC (via the Unified Plan SDP semantics and dynamically added / removed transceivers, or an SFU’s proprietary lightweight signaling for stream subscription) supports adding or removing a forwarded stream to / from an existing peer connection without a full renegotiation round-trip — this is what allows the SFU to start or stop forwarding one participant’s media to another without disturbing anyone’s actual connection state.

6.3 Client-Side Smoothing

Beyond the transport-layer mechanism, the client UI itself absorbs churn gracefully: a joining participant’s video tile fades in once their stream stabilizes (rather than popping in mid-frame), a leaving participant’s tile is removed with a short transition, and the audio mixer applies a brief fade rather than an abrupt cut when a stream stops, so a leave does not sound like a click or pop in other participants’ ears.

6.4 Late-Joiner Bootstrap

A participant joining a call already in progress needs to quickly reach the current state of every other stream (video keyframes in particular — video decoding cannot start mid-frame). The SFU forces a fresh keyframe request to each existing sender specifically for the benefit of the new joiner (existing participants’ own decode state is unaffected, since they are still receiving whatever cadence of keyframes they were already getting) — this is a small, per-join server-side action that has no visible impact on anyone already in the call, but is what makes a new joiner’s video “snap in” quickly rather than showing a gray box for a few seconds.

6.5 Renegotiation Batching Under High Churn

In a large call where several participants join or leave within the same short window (e.g., a scheduled meeting starting, where a dozen people click join within a few seconds of each other), the orchestrator batches the resulting stream-set updates pushed to the SFU rather than processing and pushing an individual update per event — reducing the total number of small control messages and avoiding any risk of the SFU thrashing its forwarding tables under a burst of near-simultaneous membership changes.

🎤
What an interviewer may ask
  • “Walk me through, mechanically, why a new participant joining does not interrupt an existing participant’s audio.” — Existing participants’ peer connections to the SFU are never torn down; the SFU simply begins forwarding one additional inbound stream over infrastructure that is already flowing. There is no shared mutable session state between participant N and participant N+1’s connection that a join would need to touch.
  • “What is the very first thing a newly joined participant sees, and why might there be a brief delay before it is smooth?” — They typically see a placeholder / loading state for each other participant’s tile until that participant’s next video keyframe arrives (since mid-GOP frames are undecodable without a preceding keyframe) and the SFU-forced keyframe request resolves — this is normal and expected, on the order of a few hundred milliseconds, not a bug.
  • “How would you handle 20 participants all leaving a call at almost the same instant (e.g., a scheduled meeting ending)?” — Batch the membership-change processing rather than handling each leave as a fully independent event, and ensure the call-state store and presence broadcast can absorb a burst of near-simultaneous updates without becoming a serialization bottleneck.
07

Advantages, Disadvantages & Trade-offs

No single architectural choice here is free — every decision that makes join / leave graceful, or that makes the system scale to larger calls, trades away some simplicity, some cost, or some flexibility elsewhere. Laying these out explicitly is often exactly what separates a design that merely works from one that demonstrates real engineering judgment in an interview setting.

DecisionAdvantageTrade-off / Cost
SFU media routing (vs. mesh)Sub-quadratic bandwidth scaling; each client uploads onceRequires and pays for dedicated server-side media infrastructure; adds one network hop of latency vs. direct mesh
SFU (vs. MCU)Much lower server CPU / GPU cost, lower added latency (no transcode)Client devices must decode multiple incoming streams and handle layout / compositing themselves
Simulcast (multiple quality layers per sender)Each receiver gets a quality level suited to its own conditions, independentlyHigher sender-side upload bandwidth and encode CPU cost (encoding 2–3 layers instead of 1)
Non-renegotiating stream add / remove on join / leaveZero disruption to existing participants on membership changeMeaningfully more complex signaling / SFU logic than “just renegotiate everything”
Active-speaker / visible-tile-only forwarding at scaleBandwidth and compute scale with visible tiles, not total participantsRequires voice-activity detection and UI-aware subscription logic; a participant not currently “active” may have a brief lag when they do start speaking
08

Performance & Scalability

8.1 Bandwidth Scaling Comparison

TopologyPer-client uploadPer-client downloadServer bandwidth (N participants)
Full mesh(N−1) × stream bitrate(N−1) × stream bitrateNone (no server in media path)
SFU1 × stream bitrate (or a few with simulcast)(N−1) × stream bitrate (or fewer with active-speaker limiting)Roughly N × (N−1) × bitrate in aggregate forwarding, but distributed and horizontally scalable
MCU1 × stream bitrate1 × composited stream bitrateN × decode + N × encode — very CPU / GPU-intensive per call

The SFU model shifts the quadratic cost from clients’ scarce, asymmetric consumer upload bandwidth onto server infrastructure that can be horizontally scaled and is typically running on well-provisioned data center network links — which is precisely why it is the standard choice once group size exceeds what mesh can handle.

8.2 SFU Node Capacity Planning

A single SFU node’s capacity is bounded primarily by aggregate throughput (total Mbps of forwarding across all its hosted calls) and, secondarily, CPU for packet handling, RTCP processing, and simulcast layer selection logic. For calls exceeding a single node’s comfortable capacity (either one very large call, or many concurrent smaller calls), the cluster router distributes calls across nodes, and for a single call that is unusually large, participants can be split across multiple SFU nodes with an inter-node relay path forwarding between them — trading a small amount of extra latency for that cross-node hop against the ability to scale a single call beyond one machine’s limits.

8.3 Geographic Routing

The call orchestrator prefers assigning a call to the SFU node geographically closest to the majority of its participants (or, for a call whose participants are globally spread, potentially splitting across regional nodes) to minimize the median round-trip time, since latency for real-time media is a direct, felt quality factor rather than an abstract metric.

8.4 Concrete Capacity Example

2–3 GbpsAggregate forwarding per node
~16 MbpsPer 8-person call
150–180Concurrent 8-person calls per node
4Visible streams per receiver

Consider a single SFU node comfortably handling an aggregate forwarding throughput of roughly 2–3 Gbps. A mix of concurrent calls averaging 8 active participants each, with active-speaker-limited forwarding keeping each participant’s download to roughly 4 visible streams at medium quality (~500 kbps each, ~2 Mbps download per participant), works out to roughly 16 Mbps aggregate forwarding per 8-person call — meaning a single node could theoretically host on the order of 150–180 such calls concurrently before hitting the bandwidth ceiling, well before CPU typically becomes the binding constraint for straightforward forwarding (as opposed to any server-side compositing or transcoding, which would shift the bottleneck to CPU / GPU much sooner). Real deployments target meaningfully below this theoretical ceiling to preserve headroom for uneven load distribution and traffic spikes.

8.5 Cost of Non-Disruptive Join / Leave vs. Naive Renegotiation

It is worth quantifying why the non-renegotiating approach matters at scale, not just for UX polish: a full SDP renegotiation round-trip typically costs on the order of one to a few hundred milliseconds of signaling round-trip time, plus the encoder / decoder pipeline reset that causes the visible glitch. In a call with frequent organic churn — say, an average of one join or leave every 30 seconds sustained over a long-running call — naive renegotiation-on-every-change would impose that glitch on every existing participant roughly twice a minute, which very quickly becomes the single most complained-about aspect of the product. The non-renegotiating stream-set-update approach reduces the existing-participant-facing cost of each churn event to effectively zero, at the one-time architectural cost of building and maintaining the more sophisticated dynamic stream-subscription mechanism.

🎤
What an interviewer may ask
  • “At what participant count does mesh stop making sense, roughly, and why?” — Somewhere around 4–6 participants for typical consumer upload bandwidth (a few Mbps), since each added participant multiplies every existing participant’s upload requirement — the math simply does not work past a small group, which is why virtually every mainstream group-calling product uses SFU (or MCU) architecture, not mesh, even for relatively small default group sizes.
  • “How would you decide whether to add more SFU nodes globally or scale up existing ones?” — This is a classic scale-out vs. scale-up trade-off; scale-out (more, smaller nodes, geographically distributed) improves latency for a geographically spread user base and improves fault isolation (one node failing affects fewer calls), while scale-up simplifies operations for a smaller number of larger nodes — most production systems lean scale-out specifically because of the latency-sensitivity and blast-radius concerns unique to real-time media.
09

High Availability & Reliability

Failover

SFU node failure handling

If an SFU node hosting an active call fails, affected participants’ clients detect the connection loss and the orchestrator migrates the call to a healthy node, with clients re-establishing their media connections — a visible but brief (a few seconds) interruption, versus the alternative of the call ending entirely.

Signaling

Signaling layer redundancy

Horizontally scaled and stateless with respect to call membership (which lives in the shared Redis-backed call state store), so any signaling node can be lost without losing call state, and clients reconnect to any healthy signaling node.

Resume

Reconnect without “re-joining”

A participant’s brief network drop (e.g., switching from WiFi to cellular) is treated as a reconnect against the same call session rather than a full leave-then-rejoin, preserving their place in the call and avoiding a disruptive “participant left, participant joined” flicker over what was really just a few seconds of network hiccup.

Degrade

Graceful degradation under stress

If a participant’s bandwidth degrades severely, the system prefers to downgrade video quality (or drop video entirely, falling back to audio-only) before allowing the connection to drop entirely — preserving the core conversational experience as long as possible.

TURN

TURN relay redundancy

TURN infrastructure is deployed with enough geographic and capacity redundancy that TURN itself does not become a single point of failure for the meaningful fraction of participants who require it for connectivity.

🎤
What an interviewer may ask

“An SFU node hosting a 15-person call crashes mid-meeting. What do participants experience?” — A brief freeze / reconnect (typically a few seconds) as clients detect the dropped connection and the orchestrator reassigns the call to a healthy node; call membership and state survive because they live in the separate, replicated call state store, not on the SFU node itself.

9.1 Failover Runbook, Conceptually

  1. Clients detect connection loss to their SFU node via WebRTC connection-state change events (ICE connection state transitioning to “failed” or “disconnected” beyond a grace period).
  2. The signaling layer is separately notified (via health checks or the same connection-loss signal relayed through the client) and marks the affected SFU node unhealthy, triggering the orchestrator to select a replacement node.
  3. Call membership and each participant’s last-known state (mute status, active layout) are read from the replicated call state store — unaffected by the SFU node failure since they were never stored there.
  4. Each affected client re-establishes a fresh WebRTC connection to the new node, following essentially the same flow as an initial join.
  5. Once all affected clients have reconnected, normal forwarding resumes; unaffected calls on other, healthy nodes experience zero impact throughout.

The total user-visible interruption is bounded by connection-loss detection time plus reconnection time — typically a handful of seconds — versus the alternative of the entire call simply ending, which is why this failover path is considered a core reliability requirement rather than a nice-to-have.

10

Security

Encryption

Media encryption

All media is encrypted in transit via SRTP / DTLS between each client and the SFU; some products additionally support end-to-end encryption where the SFU forwards encrypted media it cannot itself decode, at the cost of losing server-side features that require access to raw media (like transcoding or certain recording features).

Access

Call access control

Joining a call requires a valid, scoped authorization token tied to the inviting conversation / group, preventing unauthorized participants from joining a call by guessing or leaking a call ID.

TURN

TURN credential scoping

TURN relay credentials are short-lived and scoped to a specific call / session, preventing abuse of relay infrastructure as an open proxy.

Signaling

Signaling channel integrity

The signaling WebSocket is authenticated per-connection and authorized per-action (e.g., only a call’s participants or an authorized admin can force-remove another participant), preventing signaling-layer spoofing of call control actions.

Abuse

Abuse prevention

Rate limiting on call creation and join attempts prevents automated abuse (e.g., call-bombing a user with rapid repeated call invitations).

10.1 Threat Model Summary

ThreatMitigation
Unauthorized participant joining via a leaked / guessed call IDServer-side authorization check against actual group / call membership at join time, not just possession of an ID
Eavesdropping on media in transitSRTP / DTLS encryption between every client and the SFU by default; optional end-to-end encryption for higher-sensitivity deployments
Malicious use of TURN relay as a general-purpose proxyShort-lived, call-scoped TURN credentials issued per session rather than static, long-lived credentials
Signaling spoofing (e.g., forging a “remove participant” action)Per-action authorization checks on the signaling channel, not just connection-level authentication
Denial of service via rapid call creation or join-floodRate limiting at the API gateway and signaling layer, scoped per user / account
Unwanted recording or screen captureExplicit, visible in-call indicators when recording is active; server-side enforcement that only authorized participants can start a recording
🎤
What an interviewer may ask

“How would you prevent someone from joining a call they were not invited to, if they somehow obtained the call ID?” — Authorization must be checked server-side against actual call / group membership at join time, not derived from possession of an opaque ID; the call ID alone should never be sufficient credential to join.

11

Monitoring, Logging & Metrics

QoS

Real-time quality metrics

Packet loss, jitter, round-trip time, and resolution / framerate actually delivered, collected continuously per participant via WebRTC’s built-in statistics API and aggregated for both live quality-adaptation decisions and post-call analysis.

Churn

Join / leave churn metrics

Rate of membership changes per call, and — critically — measured disruption to existing participants (e.g., any detectable audio glitch or freeze correlated with a join / leave event) as the direct signal of whether the “graceful” requirement is actually being met in production.

Nodes

SFU node health

CPU, memory, and aggregate forwarding bandwidth per node, used both for alerting and for the cluster router’s placement decisions.

Setup

Call setup success rate & TTFF

How often a join attempt actually succeeds in establishing media, and how long it takes from join request to the new participant seeing / hearing others — a key end-to-end UX metric.

Diagnostics

Client-side diagnostics upload

On call end (or on quality-degradation events), clients can upload a compact diagnostic bundle (connection stats, ICE candidate history) to aid debugging of hard-to-reproduce connectivity issues, particularly ones tied to specific network / NAT configurations.

11.1 Example SLOs

MetricTarget
Median end-to-end audio latency< 150 ms
Time from join request to first received media< 2 s (p95)
Detectable disruption to existing participants on others’ join / leave0 events (target); incident-worthy if nonzero at scale
Call setup success rate> 99.5%
SFU node failover recovery time< 5 s
12

Deployment & Cloud

Geo

Geographically distributed SFU fleet

SFU nodes are deployed across multiple regions / points of presence close to where users actually are, since media latency is directly tied to physical network distance in a way that is much less true for typical stateless web services.

Metal

Bare-metal or dedicated compute for media nodes

Given the sustained, predictable, high-throughput nature of media forwarding, SFU nodes are often run on dedicated or reserved compute rather than purely elastic serverless infrastructure, since the workload does not have the highly bursty, idle-most-of-the-time shape that makes serverless economically attractive.

Elastic

Autoscaling the signaling and orchestration tiers

These tiers are much more conventional stateless services and scale elastically with call-creation and signaling-message volume using standard container orchestration autoscaling.

Rollout

Careful staged rollout for media-path changes

Changes to SFU forwarding logic or codec handling are rolled out gradually (a small percentage of new calls at a time) with close quality-metric monitoring, since a subtle regression in media handling can degrade call quality in ways that are hard to catch in pre-production testing but very noticeable to real users.

12.1 Cost Considerations

Media server capacity (SFU nodes) is the dominant infrastructure cost for this feature, scaling roughly with aggregate concurrent call-minutes and average call size, not with total registered users — a platform with millions of users but modest concurrent call volume has a very different cost profile than one where video calling is the primary activity. TURN relay usage is a secondary but non-trivial cost driver, since a meaningful fraction of real-world connections (commonly cited industry figures put it at somewhere around 10–20% of sessions) require relaying rather than direct connectivity, and relayed media consumes real server bandwidth for the call’s full duration. Because both costs scale with usage rather than with a fixed infrastructure footprint, capacity planning and forecasting tie closely to product growth projections for the calling feature specifically, not just overall platform growth.

12.2 Multi-Region and Data Residency

For a global messaging platform, SFU placement also has to account for data residency requirements in some jurisdictions (media, and particularly recordings, may need to stay within a specific region’s infrastructure for regulatory reasons), which constrains the otherwise purely latency-driven geographic routing logic with an additional compliance-driven placement rule layered on top.

13

Databases, Caching & Load Balancing

DataStoreWhy
Live call membership and stateRedis (in-memory, replicated)Sub-millisecond reads / writes on every join / leave / state-change event; call state is inherently short-lived
Call / meeting metadata (scheduled calls, participant permissions)Relational DB (PostgreSQL)Structured, relatively low-volume data with strong consistency needs
Post-call analytics and quality metricsColumnar analytics store (ClickHouse / BigQuery-style)Optimized for large-scale aggregate quality reporting, decoupled from the live path
Recordings (if enabled)Object storage (S3-style)Large binary media files, accessed relatively infrequently post-call

Load balancing for the signaling tier is standard L4 / L7 balancing across stateless nodes. Load balancing for the media tier is a fundamentally different problem — it is really a placement decision (which SFU node should host this call) made once at call-start / first-join time by the orchestrator, based on geography and current node load, rather than a per-request balancing decision, since a call’s media path needs to stay pinned to a consistent node (or fixed set of nodes) for the call’s duration.

14

APIs & Microservices

Signaling

Signaling API (WebSocket)

join_call, leave_call, SDP offer / answer exchange, ICE candidate exchange, mute / video-toggle state updates, and membership-change event delivery — the full real-time call-control surface.

REST

Call Management REST API

Create a scheduled or ad-hoc call, fetch call metadata / participant list, manage permissions — conventional CRUD-style endpoints for anything not requiring millisecond-level real-time delivery.

Internal

SFU Control API (internal)

Used by the orchestrator to instruct an SFU node to add / remove a participant’s stream from another participant’s forwarding set — the internal mechanism underlying the non-disruptive join / leave behavior.

Boundaries

Service boundaries

Signaling, orchestration, and media (SFU) are separate services deliberately, mirroring the point that call-control and media-transport are different problems with different scaling and reliability characteristics — a bug or slowdown in call metadata handling should never be able to interrupt already-flowing media.

15

Design Patterns & Anti-patterns

15.1 Patterns Used

SFU

Selective Forwarding (SFU pattern)

The core media-routing pattern that makes group calls tractable at scale without server-side transcoding cost.

Split

Control Plane / Data Plane separation

Signaling (control plane) and media (data plane) are architecturally and operationally separate, mirroring the same pattern used in networking and many other distributed systems.

Degrade

Graceful Degradation

Quality adapts down (lower resolution, audio-only) before connectivity fails outright, preserving the core experience under adverse conditions.

Pub/Sub

Publish / Subscribe for membership events

Membership changes are broadcast to interested parties (other participants, the parent messaging app) rather than requiring polling.

Sticky

Sticky session / pinned placement

A call’s media stays pinned to its assigned SFU node(s) for the call’s duration, rather than being load-balanced per-request like a stateless web service.

15.2 Anti-patterns to Avoid

Anti-patterns
  • Full renegotiation on every membership change: Causes a visible / audible glitch for every existing participant on every join / leave — directly violates the “graceful” requirement and is the single most important anti-pattern to call out explicitly given this brief.
  • Full mesh for anything beyond a very small group: Quadratic bandwidth scaling makes this infeasible past a handful of participants; a common mistake in early prototypes that “work in the demo” with 3 people and then fail in production with 10.
  • Treating a brief network drop as a full leave: Causes unnecessary “participant left / participant joined” UI flicker and potential loss of in-call context for a hiccup that should have been a transparent reconnect.
  • Forwarding every stream to every participant regardless of visibility: Wastes bandwidth and compute on streams nobody is currently looking at or listening to, and scales worse than necessary as call size grows.
  • Coupling call metadata operations to the live media path: Making media flow depend synchronously on a database write for unrelated call metadata introduces unnecessary latency and a new failure mode into the most latency-sensitive part of the system.
16

Best Practices & Common Mistakes

Best practices

  • Design the join / leave path to never touch existing participants’ active connections — the single highest-leverage architectural decision for meeting this brief’s core requirement.
  • Force a keyframe for new joiners specifically, rather than waiting for the sender’s normal keyframe interval, to make new video “snap in” quickly.
  • Apply UI-level smoothing (fade in / out) for tile add / remove and audio mixing, since even a technically instantaneous stream change can look / sound abrupt without client-side polish.
  • Distinguish graceful leave from ungraceful disconnect explicitly, and give ungraceful disconnects a brief grace period before treating them as a full leave, to smooth over transient network blips.
  • Load test specifically for churn, not just steady-state call size — a call that is stable at a fixed 20 participants can still misbehave if 10 people join and leave within the same 30-second window; that is a distinct scenario worth its own test coverage.

Common mistakes

  • Over-indexing on the “steady state” call and under-testing the churn path, since it is the harder, less obvious scenario and easy to under-invest in relative to basic call setup and teardown.
  • Assuming WebRTC “just handles” NAT traversal — TURN relay capacity and reliability is a real, non-trivial operational concern for the meaningful fraction of real-world users behind restrictive networks, and under-provisioning it causes a specific, hard-to-diagnose class of “some users cannot connect” issues.
17

Real-World Industry Examples

The SFU-centric, control-plane / data-plane-separated architecture described here is the dominant pattern across the industry’s group calling products, converging from the same underlying constraints rather than any one company’s specific implementation.

Zoom

Proprietary media routing

Runs its own proprietary media routing infrastructure (conceptually SFU-like, with additional server-side optimizations) purpose-built to handle very large meetings, and has published extensively on techniques like simulcast and adaptive bitrate to handle heterogeneous participant network conditions gracefully.

Google Meet

Browser-native WebRTC + SFU

Built on WebRTC (which Google itself originated and open-sourced) with an SFU-based backend, benefiting directly from browser-native media support without requiring any plugin or app installation for basic participation.

Discord

Messaging-native group voice / video

Conceptually very close to this brief: calls start organically from existing chat / server contexts, participants join and leave voice channels constantly and casually, and the underlying media architecture is built to make that churn feel completely lightweight and disruption-free, which is core to the product’s whole voice-channel UX philosophy.

Microsoft Teams

Tiered SFU + server-side compositing

Handles both small ad-hoc group calls and large scheduled meetings on shared underlying media infrastructure, using tiered approaches (more SFU-like for smaller / interactive calls, additional server-side compositing for very large meetings with features like together-mode) depending on call characteristics.

Slack Huddles

Low-friction huddle model

A lightweight, low-friction group audio / video feature deliberately designed around exactly this brief’s spirit — starting and joining a huddle is meant to feel as casual and disruption-free as walking into a room, reflecting the same underlying non-disruptive join / leave engineering priority.

18

Frequently Asked Questions

Q1

Why not just use a full mesh for small messaging-app group calls, since group chats are often small anyway?

Even “small” group calls (5–8 participants) start to strain typical consumer upload bandwidth under full mesh, and a platform-wide feature needs to handle the tail of larger group calls too; starting with an SFU from the outset avoids a costly architectural rewrite later and keeps the join / leave behavior consistent regardless of call size.

Q2

Does adding a new participant to a call require any of the existing participants’ apps to do extra work?

Minimal — their existing WebRTC connection to the SFU stays intact, and their client simply starts receiving one additional inbound media stream (which their UI renders as a new tile) and requesting a keyframe-friendly decode start for it; there is no renegotiation-level work required on their end.

Q3

How is audio handled differently from video when someone joins or leaves?

Audio does not have the keyframe / decode-start complexity video does — a joining participant simply starts receiving the ongoing audio stream and it is immediately intelligible — so audio’s join experience is inherently a bit smoother / faster than video’s, and many products intentionally connect audio first, with video “catching up” a moment later, when a participant joins.

Q4

What happens if two participants join at almost exactly the same instant?

Each join is processed as an independent event against the shared call-state store, which serializes concurrent membership updates safely (e.g., via atomic Redis operations); as long as the orchestrator and SFU control path handle concurrent stream-set updates correctly, both joins succeed without interfering with each other or with already-connected participants.

Q5

Could this design support screen sharing without additional architecture?

Screen share is typically modeled as just another media stream from the sharing participant (often as a second video track alongside their camera), routed through the exact same SFU forwarding mechanism — no separate architecture is needed, though UI layout logic on receivers’ clients does need to prioritize the shared-screen stream appropriately.

Q6

Why is TURN relay needed at all if WebRTC already handles connectivity — is not direct peer-to-client-to-SFU connectivity always possible?

A meaningful fraction of real-world networks (corporate firewalls, certain carrier-grade NAT configurations, some public WiFi setups) block or restrict the direct UDP connectivity WebRTC prefers; TURN provides a relay fallback that looks like ordinary traffic to those networks, trading a bit of extra latency and server bandwidth cost for connectivity that would otherwise simply fail for those users.

Q7

How would you extend this design to support very large “webinar-style” calls where most participants are viewers rather than active speakers?

That is a meaningfully different workload — very high fan-out, very low fan-in — closer to the ingest / aggregate / fan-out shape of a live-streaming or polling system than a symmetric group call; a production platform typically routes such calls through a different, broadcast-optimized path (e.g., a “webinar mode” with a much higher viewer-to-speaker ratio and CDN-style fan-out for viewer-only participants) rather than stretching the peer-symmetric group-call SFU model to that scale.

19

Summary & Key Takeaways

The six ideas worth remembering

  • Group video calling is fundamentally shaped by the loss-intolerant, latency-critical nature of real-time media — design decisions follow from that constraint far more than from typical web-service scaling concerns.
  • An SFU-based media routing architecture is what makes group calls scale sub-quadratically, by having each client upload once and letting the server selectively forward to each receiver based on their own conditions.
  • The key to graceful mid-call join / leave is architecturally decoupling a participant’s underlying transport connection from the dynamic set of streams flowing over it, so membership changes never require disrupting anyone else’s already-established connection.
  • Signaling (call control) and media (transport) are deliberately separate systems with different reliability, consistency, and transport needs — conflating them is a common source of unnecessary complexity and coupling.
  • Simulcast and active-speaker-aware selective forwarding let the system serve heterogeneous network conditions and larger call sizes without forcing every participant down to the lowest common denominator.
  • Reliability leans on fast, largely invisible recovery — reconnect-not-rejoin for brief network drops, fast SFU node failover, and graceful quality degradation before outright connection failure.

Taken together, the join / leave-specific mechanisms — non-renegotiating stream add / remove, forced keyframes for new joiners, and client-side smoothing — are what turn a generically scalable media architecture into one that specifically satisfies this brief’s core requirement: participants coming and going should be an ordinary, unremarkable part of a live call, not an event anyone else even notices. The broader lesson generalizes well beyond video calling: whenever a system’s steady-state behavior is easy but its membership-change or state-transition behavior is hard, that transition path deserves the same deliberate architectural attention as the steady state itself, rather than being treated as an edge case bolted on after the fact.