A lightweight real-time voice call application to explore WebRTC, Socket.IO, and real-time system design.
PepTalk focuses on creating temporary voice rooms with minimal friction. Hosts authenticate to create and moderate rooms, while guests can join directly using a room link.
- Temporary voice rooms
- Authenticated hosts (Clerk)
- Guest join via room link
- Waiting room with host approval
- Host moderation (mute, kick)
- Automatic host reassignment
- Real-time room updates using Socket.IO
- WebRTC peer-to-peer media architecture
| Layer | Technology |
|---|---|
| Frontend | Next.js, React, TypeScript, Tailwind CSS |
| Authentication | Clerk |
| Realtime Signaling | Socket.IO |
| Media Transport | WebRTC |
| Runtime | Node.js |
┌─────────────────────────┐
│ Next.js Client │
│ React + Tailwind UI │
└────────────┬────────────┘
│
Socket.IO Events
│
┌────────────▼────────────┐
│ Socket.IO Server │
│ │
│ • Room lifecycle │
│ • Waiting room │
│ • Host moderation │
│ • Host reassignment │
│ • State sync │
└────────────┬────────────┘
│
In-memory Room Store
The Socket.IO server acts as the authoritative source of truth for room state. Every room operation (join, leave, admit, mute, kick, etc.) is performed on the server before being broadcast to connected clients.
Host Browser Guest Browser
┌─────────────────┐ ┌─────────────────┐
│ │ │ │
│ RTCPeerConnection│ │ RTCPeerConnection│
│ │ │ │
└────────┬────────┘ └────────┬────────┘
│ │
│ Peer-to-Peer Audio │
└────────────────────────────────┘
PepTalk uses a mesh WebRTC topology, where every participant establishes a direct connection with every other participant. This keeps the architecture simple for small rooms while avoiding additional media infrastructure.
WebRTC does not define how peers discover each other or exchange connection information. PepTalk reuses the existing Socket.IO server as its signaling server.
Host Socket.IO Server Guest
│ │ │
│────── Offer ─────────────>│ │
│ │────── Offer ───────────>│
│ │<───── Answer ───────────│
│<───── Answer ─────────────│ │
│ │ │
│──── ICE Candidates ──────>│──── ICE Candidates ────>│
│<─── ICE Candidates ───────│<─── ICE Candidates ─────│
│ │ │
└──────────── Peer Connection Established ────────────┘
Once signaling is complete, the media stream flows directly between browsers without passing through the server.
Socket.IO is responsible only for signaling and synchronizing room state. Once peers negotiate a connection, media is exchanged directly between browsers using WebRTC.
Guest joins room
│
▼
Waiting Room
│
▼
Host approves
│
▼
Added to room
│
▼
Offer / Answer
│
▼
ICE Exchange
│
▼
Peer Connection
This project intentionally keeps the frontend lightweight. Next.js provided built-in routing and server capabilities without requiring additional project setup.
Rooms are temporary and the application targets a single server with a maximum of six participants. Introducing Redis would have added infrastructure complexity without much benefit for the MVP.
Guests should be able to join with minimal friction, while privileged actions (creating rooms, admitting users, kicking participants, muting participants) require authentication.
PepTalk uses a mesh WebRTC topology where every participant maintains a direct connection with every other participant. This is simple to implement for small rooms but does not scale well. Larger rooms would require an SFU-based architecture.
- Redis-backed room storage
- TURN server support
- SFU for larger rooms
- Video and screen sharing
- Persistent chat
- Production deployment hardening
git clone <repo-url>
cd peptalk
npm install
npm run devThe Socket.IO signaling server should also be started before creating or joining rooms.
MIT