RoomCall

A real-time, peer-to-peer video calling application built with Next.js and WebRTC.

0
0
0
TypeScript
public

RoomCall

A real-time, peer-to-peer video calling application built with Next.js and WebRTC. Create or join rooms instantly โ€” no account required.

Features

  • Instant rooms โ€” Generate a unique room code and share it with anyone
  • HD video & audio โ€” Peer-to-peer media via WebRTC for low-latency calls
  • Mute / camera toggle โ€” Control your mic and video independently at any time
  • Screen sharing โ€” Share your screen with all participants in the room
  • Live in-call chat โ€” Real-time text chat via RTCDataChannel (no server relay)
  • Multi-participant โ€” Mesh topology supports multiple users in one room
  • No sign-up โ€” Enter a display name and join, thatโ€™s it

Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
UI React 19, Tailwind CSS v4, Lucide icons
Real-time WebRTC (RTCPeerConnection, RTCDataChannel)
Signaling Socket.io v4 (custom Node.js server)
Language TypeScript
Fonts Geist Sans / Geist Mono

Architecture

Browser A                    Signaling Server (server.js)           Browser B
   |                                    |                               |
   |โ”€โ”€ join-room โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>|                               |
   |<โ”€ room-users (empty) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€|                               |
   |                                   |<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ join-room โ”€โ”€โ”€โ”€โ”€โ”€โ”€|
   |<โ”€ user-joined โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ |โ”€โ”€โ”€ room-users ([A]) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>|
   |                                   |                               |
   |โ”€โ”€ offer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ >|
   |<โ”€ answer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ |
   |<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ICE candidates (both ways) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>|
   |                                                                   |
   |<โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• P2P media + data channel โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•>|
                         (no server involved)

Key Design Decisions

  • Mesh topology โ€” Every peer connects directly to every other peer. Best for small groups (2โ€“8 people). No SFU/MCU needed.
  • Signaling via Socket.io โ€” Used only to exchange SDP offers/answers and ICE candidates. Once the call is established, the signaling server is no longer in the media path.
  • In-call chat via RTCDataChannel โ€” Chat messages travel peer-to-peer. The server never sees message content.
  • Screen sharing via replaceTrack โ€” Swaps the video track on all existing peer connections without renegotiation.
  • Custom Next.js server โ€” server.js wraps Next.js with http.createServer, allowing Socket.io to share the same port.

Folder Structure

web-rtc/
โ”œโ”€โ”€ server.js                          # Custom Node.js server (Next.js + Socket.io)
โ”œโ”€โ”€ signaling-server/                  # Standalone signaling server (for split deployments)
โ”‚   โ”œโ”€โ”€ server.js
โ”‚   โ””โ”€โ”€ package.json
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ app/
โ”‚   โ”‚   โ”œโ”€โ”€ layout.tsx                 # Root layout (fonts, metadata)
โ”‚   โ”‚   โ”œโ”€โ”€ page.tsx                   # Home page (Create Room / Join Room)
โ”‚   โ”‚   โ”œโ”€โ”€ globals.css                # Global styles + Tailwind v4
โ”‚   โ”‚   โ””โ”€โ”€ room/
โ”‚   โ”‚       โ””โ”€โ”€ [roomId]/
โ”‚   โ”‚           โ”œโ”€โ”€ page.tsx           # Room route (async params)
โ”‚   โ”‚           โ””โ”€โ”€ _components/
โ”‚   โ”‚               โ”œโ”€โ”€ RoomClient.tsx # Main room orchestrator
โ”‚   โ”‚               โ”œโ”€โ”€ PreJoin.tsx    # Name entry screen before joining
โ”‚   โ”‚               โ”œโ”€โ”€ VideoTile.tsx  # Individual video/avatar tile
โ”‚   โ”‚               โ”œโ”€โ”€ Controls.tsx   # Bottom control bar
โ”‚   โ”‚               โ””โ”€โ”€ ChatPanel.tsx  # Slide-in chat panel
โ”‚   โ”œโ”€โ”€ hooks/
โ”‚   โ”‚   โ””โ”€โ”€ useWebRTC.ts               # Core WebRTC hook (connections, signaling, media)
โ”‚   โ”œโ”€โ”€ lib/
โ”‚   โ”‚   โ””โ”€โ”€ webrtc.ts                  # RTCConfiguration (STUN servers)
โ”‚   โ””โ”€โ”€ types/
โ”‚       โ””โ”€โ”€ index.ts                   # Shared TypeScript types
โ”œโ”€โ”€ .env.local                         # Local environment variables (gitignored)
โ”œโ”€โ”€ .env.example                       # Environment variable template
โ””โ”€โ”€ next.config.ts                     # Next.js config

Getting Started

1. Install dependencies

npm install

2. Configure environment

cp .env.example .env.local
# .env.local defaults work for local development โ€” no changes needed

3. Run the development server

npm run dev

Open http://localhost:3000.

Note: npm run dev runs node server.js, not next dev. This is required because Socket.io needs a persistent Node.js HTTP server.

Environment Variables

Variable Default Description
PORT 3000 Port for the Node.js server
NEXT_PUBLIC_SOCKET_URL (same origin) URL of the signaling server. Leave empty in dev. Set to your deployed signaling server URL in production.
FRONTEND_URL http://localhost:3000 (Signaling server only) Allowed CORS origin

Deployment

Option A โ€” Railway (recommended, everything in one)

Railway supports persistent Node.js processes. No changes needed to the code.

  1. Push your repo to GitHub
  2. Go to railway.app โ†’ New Project โ†’ Deploy from GitHub
  3. Set environment variable: NODE_ENV=production
  4. Railway auto-detects npm run build and npm run start

Option B โ€” Vercel (frontend) + Railway (signaling)

Vercel is serverless and cannot run Socket.io. Split the deployment:

  1. Deploy signaling-server/ to Railway as a separate service
    • Set FRONTEND_URL=https://your-app.vercel.app in Railway env vars
  2. Deploy the Next.js frontend to Vercel
    • Set NEXT_PUBLIC_SOCKET_URL=https://your-signal.railway.app in Vercel env vars
    • Build command: npm run build

Why not Vercel for everything? Vercelโ€™s serverless functions are stateless and terminate between requests. Socket.io requires a persistent process to maintain WebSocket connections and room state.

v0.3.3[beta]