-
Web App (React + Vite)
- Current: Mesh WebRTC (working for 2-4 users)
- Optimized: Noise suppression, audio pipeline
- Deployed: https://cruwellsvox.web.app
-
Desktop App (Electron)
- Windows + macOS native support
- Same React app wrapped
- Ready to build with
npm run build:electron
-
Cloud Functions Backend
- Room/participant management
- Stream registration & tracking
- Heartbeat & cleanup
- SFU-ready signaling layer
Mesh RTC Topology:
- 2 users: 1 connection ✓ (working)
- 3 users: 3 connections ✓ (working, deployed)
- 4 users: 6 connections ✓ (working with fixes)
- 10 users: 45 connections ✗ (CPU/bandwidth collapse)
Each connection requires:
- Audio encoding + transmission (up)
- Audio reception + decoding (down)
- Noise suppression processing × 9 streams
- = Exponential CPU + bandwidth growth
SFU Topology (for 10+ users):
- 10 users: 10 connections to server only
- Each sends 1 stream UP
- Receives 9 relayed streams DOWN
- Server handles routing, not clients
- = Linear scaling
- Electron setup (Windows + macOS)
- Native audio APIs ready
- Desktop app builds
- Next: Test 4-5 person call on desktop
You have 3 options:
1. Go to https://livekit.cloud
2. Sign up (free tier: 5 GB/month transcoding)
3. Get API key + wallet URL
4. Deploy to production in 5 minutes
Pros:
- Managed service (no ops)
- Proven 10-100 user scaling
- Free tier available
- TURN servers included
Cons:
- Pay-per-use when free tier exceeded
- 3rd-party dependency# Deploy on a VPS (DigitalOcean, Linode, AWS - $5-20/mo)
docker run --name livekit \
-e LIVEKIT_API_KEY=devkey \
-e LIVEKIT_API_SECRET=secret \
-p 7880:7880 \
-p 7881:7881 \
-p 7882:7882/udp \
livekit/livekit-server:latest
Cost: $5-20/month for VPS
Pros: Full control, no third-party, better latency
Cons: Need to manage server, backups, updates# Deploy Livekit on Cloud Run
# Persistent container + Firestore integration
Cost: $0.04 per 1 CPU-hour (typically $10-50/mo for 10 users)
Pros: Firebase ecosystem, auto-scaling, managed
Cons: More expensive than VPSCurrent VoiceContext.jsx needs changes for SFU:
// BEFORE (Mesh RTC):
// - Connect to N-1 peers
// - Send/receive audio to each peer
// - Manage N-1 RTCPeerConnections
// AFTER (SFU):
// - Connect to 1 SFU server
// - Send 1 audio stream
// - Receive N-1 remote streams (relayed by server)
// - Manage 1 RTCPeerConnection + N-1 remote tracks# 1. Build Electron
npm run build:electron
# 2. Test locally (dev mode with hot reload)
npm run dev:electron
# 3. Package for production
## macOS:
npm run build:electron
# Output: release/CruwellsVox-x.y.z.dmg
## Windows:
npm run build:electron
# Output: release/CruwellsVox-x.y.z.exe1. Test npm run dev:electron
2. Make a 4-person call on desktop
3. Report: Does it work better than web?
4. Decide: Use mesh or move to SFU?1. Choose SFU backend (Livekit Cloud recommended)
2. Deploy Cloud Functions to Firebase
3. Refactor VoiceContext for SFU signaling
4. Test 10-person call
5. Build + deploy desktop with SFU client1. Build + test desktop with current mesh (verify it helps)
2. If good at 4-5 users: proceed to SFU deployment
3. If struggling: SFU becomes higher priorityUser asks: "Can 10 people talk healthy?"
Q1: "What's your latency tolerance?"
→ <100ms required? → SFU essential (mesh = 200-500ms at 10 users)
→ >200ms ok? → Try desktop mesh first
Q2: "What's your deployment comfort?"
→ "Add line or two of code" → Livekit Cloud (managed SFU)
→ "Can manage VPS" → Self-hosted Livekit
→ "Prefer Firebase" → Google Cloud Run
Q3: "Budget?"
→ Free/minimal → Livekit free tier
→ $5-20/mo → Self-hosted Livekit on VPS
→ No limit → Livekit Cloud or Cloud Run
# Install functions dependencies
cd functions
npm install
# Deploy to Firebase
cd ..
npm run functions:deploy
# Check deployed functions
firebase functions:list// SFU connection flow
async joinRoom(roomId) {
// 1. Register with Cloud Functions
const { sfu, participants } = await fetch(
`/api/rooms/${roomId}/join`,
{ userId, displayName }
)
// 2. Get SFU connection details
const sfuServer = sfu.sfuServer // e.g., https://sfu.example.com
// 3. Create ONE connection to SFU
const pc = new RTCPeerConnection()
// 4. Add local audio stream
const stream = await getUserMedia()
stream.getTracks().forEach(track => pc.addTrack(track, stream))
// 5. Create offer to SFU
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)
// 6. Send offer to SFU via Cloud Functions
const { answer, iceCandidates } = await fetch(
`/api/rooms/${roomId}/streams/${userId}`,
{ offer, iceServers }
)
// 7. Set remote SDP (answer from SFU)
await pc.setRemoteDescription(new RTCSessionDescription(answer))
// 8. Handle incoming remote streams (from other participants)
pc.ontrack = (event) => {
// Play audio from each participant
attachRemoteStream(event.track)
}
}- ✅
src/electron/main.js- Electron main process - ✅
src/electron/preload.js- Secure IPC bridge - ✅
functions/src/index.js- SFU signaling backend - ✅
functions/package.json- Cloud Functions deps
- ✅
package.json- Electron + build scripts - ✅
vite.config.js- Build configuration - ✅
firebase.json- Functions config - ⏳
src/contexts/VoiceContext.jsx- Ready for SFU migration (not done yet)
- Builds for macOS (dmg)
- Builds for Windows (exe)
- Runs React app in Electron
- Has microphone permission request
- Test: 4-person call works smoothly
- Cloud Functions deployed to Firebase
- Endpoints tested via curl/Postman
- Room creation works
- Participant join/leave works
- Stream registration works
- VoiceContext refactored for SFU
- Client connects to SFU server
- Remote tracks received correctly
- Noise suppression still works
- Test: 10-person call works
Error: "Could not find native build tools"
# macOS
xcode-select --install
# Windows
# Download Visual Studio Build ToolsError: "Module not found (electron)"
npm install electron --legacy-peer-depsApp runs but audio not working
- Check: System → Privacy & Security → Microphone (app listed?)
- Check: Audio input device in SettingsModal
- Test: Mic test button
Cloud Functions failing
# Check logs
firebase functions:log --limit 50
# Redeploy
firebase deploy --only functions --forceSFU server unreachable
- CORS? Add
"cors": { "origin": true }(done - functions/src/index.js) - Firewall ports blocked? (ports depend on SFU choice)
- DNS not resolving? Check
sfuServerURL
Current state:
- ✅ Electron desktop app ready to build
- ✅ Cloud Functions SFU signaling ready to deploy
- ⏳ Need SFU media server (recommend Livekit)
- ⏳ Need VoiceContext migration to SFU
Next action: Build & test desktop with current mesh first, OR deploy SFU now?