A real-time, multi-camera live streaming application built with WebRTC and Socket.IO. A Director manages multiple camera feeds, selects which one is broadcast, and Viewers watch the selected stream live in their browser.
Cameraman(s) → Director (selects feed) → Viewers
- Each Cameraman joins a room and streams their camera via WebRTC peer connection to the Director.
- The Director sees all camera feeds simultaneously and clicks one to select it as the active broadcast.
- Viewers connect to the room and receive whichever feed the Director has selected. When the Director switches cameras, viewers are automatically redirected to the new feed.
The main watch page. Displays a live room list in the sidebar and streams the active camera feed in the main player.
- Connects to the server and fetches available rooms automatically
- Animated TV-noise canvas shown when no stream is active
- Auto-refreshes room list every 15 seconds
- Includes a link to join any room as a cameraman
The broadcast control interface. Auto-generates a room code on load.
- Displays all connected camera feeds in a responsive grid
- Click any feed to select it as the active stream for viewers
- Shows live counts of connected cameramen and viewers
- Auto-switches to another camera if the active one disconnects
The mobile-friendly camera interface. Reads the room code from the URL (?code=XXXXXX).
- Streams at up to 1080p with a 1:1 aspect ratio preview
- Supports switching between front/back cameras on mobile
- Mute/unmute audio toggle
- Wake lock prevents the screen from sleeping during a stream
public/
├── index.html # Viewer page
├── index.css # Viewer styles
├── index.js # Viewer logic (WebRTC + Socket.IO)
├── director.html # Director control panel
├── director.css # Director styles
├── director.js # Director logic (WebRTC + Socket.IO)
├── cameraman.html # Cameraman page
├── cameraman.css # Cameraman styles
└── cameraman.js # Cameraman logic (WebRTC + Socket.IO)
A Node.js server (not included here) is required to serve the files and handle Socket.IO signaling.
All peer connections use the following ICE server configuration:
- STUN:
stun.l.google.com:19302,stun1.l.google.com:19302 - TURN:
openrelay.metered.ca(ports 80, 443, 443/TCP)
| Event | Direction | Description |
|---|---|---|
create-room |
Client → Server | Director creates a room |
join-room |
Client → Server | Cameraman or viewer joins a room |
cameraman-joined |
Server → Director | Notifies director of a new camera |
offer |
Director → Cameraman / Viewer → Cameraman | WebRTC offer |
answer |
Cameraman → Director / Cameraman → Viewer | WebRTC answer |
ice-candidate |
Both directions | ICE candidate exchange |
select-cameraman |
Director → Server | Director picks active camera |
stream-started |
Server → Viewers | Tells viewers which camera to connect to |
cameraman-left |
Server → Director | Camera disconnected |
viewer-joined/left |
Server → Director | Viewer count updates |
get-room-list |
Viewer → Server | Request active rooms |
room-list |
Server → Viewer | List of active rooms with metadata |
Open /director.html — a room code is generated automatically and displayed on screen.
Open /cameraman.html?code=XXXXXX on any device (phone, tablet, laptop) with the room code. Grant camera/microphone permissions and tap Start Camera.
Open /index.html, find the room in the sidebar, and click it to start watching. The stream switches automatically when the director selects a different camera.
- Multi-camera support — unlimited cameramen per room
- Instant camera switching — director switches feeds with one click; viewers follow automatically
- Mobile-first cameraman UI — front/back camera toggle, wake lock, 1:1 crop preview
- Resilient connections — automatic reconnection with exponential backoff, TURN fallback
- Live room discovery — viewers see all active rooms without needing a room code
- Real-time stats — director sees connected cameraman and viewer counts live