Lupyd.
Feature Real-Time Communication

How We Built Real-Time Audio and Video Calling in Lupyd

A look at how Lupyd brings together WebRTC, React, Tauri, Rust, Android, and Cloudflare RealtimeKit to support one-to-one and group calling.

G

Ganji Pranay Raj, Developer

Lupyd

Sept 28, 2026
•
5 min read
How We Built Real-Time Audio and Video Calling in Lupyd

LUPYD Real-Time Calling Flow

Signaling Plane

Call Invitation

Caller sends an invite with session metadata

Accept

Offer / Answer

ICE candidates and SDP exchanged

Connected

Lupyd servers relay signaling messages only, so a relay operator can start or end a call but cannot join the media path.

Media Plane (WebRTC)

Caller Endpoint

Captures audio and video

DTLS-SRTP media path

Direct peer to peer

Recipient Endpoint

Decodes and renders the stream

Group calls fan out one encrypted sender stream per participant, so every recipient holds its own keys.

Call signaling establishes the session while WebRTC handles the peer-to-peer audio and video connection.

Calling in LUPYD began with a simple goal: let people start a conversation without leaving the app. Delivering that experience meant coordinating real-time media, call signaling, and app state across WebRTC, React, Tauri, Rust, and Android.

Starting With 1-to-1 Calling

We started with one-to-one audio and video calls. WebRTC carries the media between participants; LUPYD handles the signaling and application state needed to start, update, and end each call.

A call passes through several connected stages: an invitation arrives, the recipient accepts, the peers establish a connection and negotiate media, then both sides clean up when the call ends. Each transition needs to be reflected consistently in the app.

Getting a call to connect is only the first milestone. The harder work is keeping every layer in sync as the call changes state, especially when events arrive close together or the user acts outside the call screen.

Beyond the Call Screen

A call should remain manageable when the app is no longer in the foreground. Users need to see that a call is active and take essential actions without reopening the call screen.

On Android, that experience depends on connecting the app to native support for ongoing call notifications and foreground call handling. Actions such as accepting, muting, unmuting, or ending a call need to pass between Android and LUPYD so the interface and call state stay aligned.

A single call can involve several parts of the stack, each with a distinct responsibility:

  • React: Call UI and application state
  • WebRTC: Real-time audio and video
  • Tauri: Application and native bridge
  • Rust: Native application logic
  • Android: Notifications and foreground call handling

Adding Group Calling

One-to-one calls were a starting point. Group conversations bring additional needs: a meeting model, participant management, and controls that work for everyone in the call.

For group calls, LUPYD uses Cloudflare RealtimeKit for the meeting infrastructure and calling interface. It provides microphone and camera controls, device settings, meeting controls, and a minimized meeting window. This lets people stay connected while continuing to use LUPYD.

The Real Challenge: Call State

The central challenge in real-time apps is keeping state consistent across the interface, the signaling flow, and the underlying connection.

An incoming call might be accepted, cancelled, rejected, or disconnected while other events are still in flight. The app has to manage active sessions, pending offers, ICE candidates, native actions, and cleanup without leaving a call in a contradictory state.

This work changed how I think about calling features. A WebRTC connection is one piece; the full experience depends on independent layers responding in a coordinated way.

What I Learned

The biggest lesson for me was that getting a call connected is only the beginning.

The experience is really tested when someone minimizes the app, responds to a notification, changes audio or video settings, joins a group meeting, or ends a call from outside the call screen. Those moments are where coordination across the stack matters most.

Building calling for LUPYD gave me hands-on experience across React, WebRTC, Tauri, Rust, and Android. More than anything, it showed me that a reliable calling experience comes from making those technologies work together as one system.

Key Takeaways
  • ✓ WebRTC handles peer-to-peer audio and video while Lupyd manages call signaling and application state.
  • ✓ Android foreground services and notifications keep calls usable when the app is minimized.
  • ✓ Group calling adds participant management and meeting controls through Cloudflare RealtimeKit.
  • ✓ Reliable calling depends on keeping call state synchronized across React, Tauri, Rust, and Android.
Open Source

Explore Lupyd on GitHub

Inspect our open-source repositories, cryptography libraries, and client tools on GitHub.

Explore Lupyd on GitHub