Skip to content

daemon-001/ChronoBeat-IO

Repository files navigation

ChronoBeat-IO

Internet-Based Synchronized Audio Playback — Beat-level sync across multiple devices without WebSockets.

Status License Version

Live Demo — Try it now!


Table of Contents


Overview

ChronoBeat-IO enables synchronized music playback between multiple devices without WebSockets, by anchoring audio playback to a global server time instead of relying on real-time message delivery.

The goal is perceptual beat-level sync (like an add-on speaker), not sample-perfect hardware sync. All connected devices play the same track at the same global timestamp, creating seamless multi-device listening experiences.

Key Innovation

Instead of synchronizing play / pause events, all devices synchronize time.

Every device plays the same track at the same global timestamp.


Visuals

b1 b2 b3 b4

Features

[+] Multi-Device Synchronization — Sync music playback across unlimited devices in real-time
[+] WebSocket-Free — Uses stateless REST HTTP APIs for maximum compatibility
[+] NTP-Style Time Sync — Client clocks auto-calibrate for accuracy
[+] Drift Correction — Automatic periodic correction for clock drift
[+] Room-Based Architecture — Create multiple independent listening rooms
[+] Leader/Follower Model — One user controls playback, others follow seamlessly
[+] Audio Upload & Streaming — Upload MP3/WAV files or stream from URLs
[+] User Management — Track connected users with avatars and IDs
[+] Volume Control & Muting — Individual device volume control
[+] Real-Time User List — See who's connected in your room
[+] Progressive Web App — Works on desktop and mobile
[+] Dark Mode UI — Beautiful Material Design interface


Technology Stack

Frontend

  • React 19.2 — UI framework
  • Vite 7.2 — Fast build tool
  • Material-UI 7.3 — Component library
  • React Router 7.10 — Routing
  • Tailwind CSS 4.1 — Utility-first styling

Backend

  • Node.js + Express 5.2 — REST API server
  • Multer 2.0 — File upload handling
  • CORS 2.8 — Cross-origin requests

Infrastructure


System Architecture

Time Synchronization (Critical Step)

Client clocks are not trusted directly. Each device estimates its offset from server time using an NTP-style exchange:

offset = serverTime - clientLocalTime

This offset is stored locally and applied to all playback calculations.

Playback Anchor Model

When a leader starts playback, the system creates a playback anchor:

{
  "trackUrl": "song.mp3",
  "songPositionMs": 4534,
  "serverTimeMs": 1723456789267,
  "isPlaying": true
}

This anchor is the single source of truth for all connected devices.

Playback Calculation (Follower Device)

When a device receives the playback anchor later than the leader:

nowServerTime = Date.now() + offset
elapsed = nowServerTime - anchor.serverTimeMs
startPositionSec = (anchor.songPositionMs + elapsed) / 1000

Playback starts from the calculated position:

audio.currentTime = startPositionSec
audio.play()

This ensures beat alignment, even if playback begins mid-track.

Drift Correction (Maintaining Sync)

Clock drift and decoding differences are corrected periodically.

Every 2–3 seconds:

expected = (Date.now() + offset - serverStartTime) / 1000
drift = audio.currentTime - expected

if (Math.abs(drift) > 0.12) {
  audio.currentTime = expected
}

Small corrections keep devices perceptually synchronized over long sessions.


Getting Started

Prerequisites

  • Node.js 16+ and npm
  • Modern web browser with Web Audio API support

Installation

  1. Clone the repository
git clone https://github.com/yourusername/ChronoBeat-IO.git
cd ChronoBeat-IO
  1. Install dependencies
# Frontend dependencies
npm install

# Backend dependencies
cd server
npm install
cd ..
  1. Start development servers

Open two terminals:

Terminal 1 - Frontend (Vite)

npm run dev

Frontend runs on http://localhost:5173

Terminal 2 - Backend (Express)

cd server
npm start

Backend runs on http://localhost:3000

  1. Open in browser Navigate to http://localhost:5173 and start creating rooms!

Live Deployment

The application is deployed and accessible at:

You can start using it immediately without local setup!

Build for Production

# Frontend build
npm run build

# Outputs to dist/ directory

Project Structure

ChronoBeat-IO/
├── src/
│   ├── components/
│   │   ├── AudioSelector.jsx      # Audio file/URL selection UI
│   │   └── UserList.jsx            # Connected users display
│   ├── hooks/
│   │   ├── useTimeSync.js          # NTP-style time synchronization
│   │   ├── useAudioPreloader.js    # Audio file preloading
│   │   ├── useSyncedAudio.js       # Core playback sync logic
│   │   ├── useRoom.js              # Room state management
│   │   ├── useScheduledAudio.js    # Scheduled playback
│   │   └── useWebRTC.js            # WebRTC signaling (future)
│   ├── pages/                       # Route pages
│   ├── App.jsx                      # Main React component
│   ├── main.jsx                     # Entry point
│   └── assets/                      # Static assets
├── server/
│   ├── index.js                     # Express REST API server
│   └── package.json                 # Server dependencies
├── public/                          # Static files
├── index.html                       # HTML entry point
├── vite.config.js                   # Vite configuration
├── eslint.config.js                 # Linting rules
├── package.json                     # Frontend dependencies
└── README.md                         # This file

How It Works

1. Create or Join a Room

  • Leader creates a room (gets a room ID)
  • Followers join using the room ID
  • Server tracks all connected users

2. Upload or Select Audio

  • Upload an MP3/WAV file, or
  • Provide a URL to stream audio
  • Audio is stored on the server and accessible to all users in the room

3. Time Synchronization

  • Each device pings the /api/time endpoint
  • Calculates clock offset from server
  • Stores offset for playback calculations

4. Playback Synchronization

  • Leader clicks play → sends playback anchor to server
  • Server broadcasts anchor state to all devices
  • Each device calculates playback position based on:
    • Server timestamp
    • Audio position at anchor time
    • Their clock offset
  • All devices start playing at the same calculated position

5. Drift Correction

  • Every 2-3 seconds, devices check audio drift
  • If drift > 120ms, resync to calculated position
  • Keeps all devices in perceptual sync

6. User Management

  • Users ping server with heartbeat every 10 seconds
  • Server removes inactive users after 30 seconds
  • If leader leaves, next user becomes new leader

API Reference

Time Synchronization

GET /api/time

Returns current server timestamp in milliseconds.

Response:

{ "time": 1723456789267 }

Room Management

Join Room

POST /api/rooms/:roomId/join
Content-Type: application/json

{
  "userId": "user123",
  "username": "Alice",
  "isLeader": false
}

Leave Room

POST /api/rooms/:roomId/leave
Content-Type: application/json

{ "userId": "user123" }

Get Room State

GET /api/rooms/:roomId/state

Ping (Heartbeat)

POST /api/rooms/:roomId/ping
Content-Type: application/json

{ "userId": "user123" }

Audio Management

Upload Audio

POST /api/rooms/:roomId/audio/upload
Content-Type: multipart/form-data

[binary audio file]

Set Current Audio

POST /api/rooms/:roomId/audio/current
Content-Type: application/json

{
  "url": "https://example.com/song.mp3",
  "filename": "song.mp3"
}

Get Current Audio

GET /api/rooms/:roomId/audio/current

Playback Control

Start Playback

POST /api/rooms/:roomId/playback/start
Content-Type: application/json

{
  "userId": "user123",
  "audioOffset": 0,
  "speed": 1.0
}

Pause Playback

POST /api/rooms/:roomId/playback/pause
Content-Type: application/json

{ "userId": "user123" }

Seek Position

POST /api/rooms/:roomId/playback/seek
Content-Type: application/json

{
  "userId": "user123",
  "position": 45000
}

Deployment

Live Production URL

Frontend: https://chronobeat-frontend.onrender.com

Production Deployment on Render

See RENDER_DEPLOYMENT.md for complete setup instructions.

Quick Summary:

  1. Deploy backend Express server to Render Web Service
  2. Set PUBLIC_URL and ALLOWED_ORIGINS environment variables
  3. Deploy frontend to Render Static Site with build command npm run build
  4. Configure frontend to point to backend URL

Environment Variables

Backend (.env file):

PORT=3000
NODE_ENV=production
PUBLIC_URL=https://your-backend.onrender.com
ALLOWED_ORIGINS=https://your-frontend.onrender.com,http://localhost:5173

Frontend (.env file):

VITE_API_URL=https://your-backend.onrender.com

Troubleshooting

Issue: Audio sync is drifting

  • Solution: Check network latency. Large latency (>500ms) can affect sync precision.
  • Solution: Restart the room to reinitialize time sync.
  • Solution: Ensure all devices have system time set correctly.

Issue: Users disconnecting unexpectedly

  • Solution: Check browser console for network errors.
  • Solution: Ensure ALLOWED_ORIGINS in backend includes your frontend domain.
  • Solution: Check if devices are behind strict firewalls.

Issue: Audio file won't play

  • Solution: Verify file format is MP3 or WAV.
  • Solution: Check file size (max 50MB).
  • Solution: Ensure CORS headers are correctly configured.

Issue: "Cannot connect to server"

  • Solution: Verify backend is running and accessible.
  • Solution: Check browser network tab for failed requests.
  • Solution: Ensure PUBLIC_URL environment variable matches your deployment URL.

Performance Considerations

  • Sync Precision: Typically ±100-200ms perceptual sync
  • Max Users Per Room: Tested with 50+ users per room
  • Audio Quality: Limited by client's audio playback decoder
  • Latency Tolerance: Works best with <500ms network latency
  • Server Memory: ~1-2MB per active room

Future Enhancements

  • WebRTC audio streaming for lower latency
  • Playlist management
  • User authentication & persistent profiles
  • Advanced audio visualization
  • Voice chat integration
  • Mobile app (React Native)
  • Offline mode with sync on reconnect

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit changes (git commit -m 'Add AmazingFeature')
  4. Push to branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

This project is licensed under the ISC License - see the LICENSE file for details.


Support & Contact


Communication Model (No WebSockets)

This system uses stateless HTTP APIs:

Action Method
Create room POST
Play POST
Pause POST
Seek POST
Sync state GET (polling)

Clients poll the playback state every 2–5 seconds.


Expected Accuracy

Network Conditions Sync Accuracy
Good broadband ±50–100 ms
Mobile / average ±150 ms
Cross-region ±200 ms

This level of sync is sufficient for music listening and shared playback.


Why Perfect Sync Is Impossible

Even with timestamp anchoring, sample-perfect sync cannot be achieved due to:

  • Different audio decoding latencies
  • Browser audio buffering
  • Hardware clock differences
  • Mobile power management

This limitation applies to all internet-based playback systems.


Advantages of This Approach

  • Works over the public internet
  • No WebSockets required
  • Compatible with serverless platforms (Vercel)
  • Scales easily
  • Mobile browser friendly

Ideal Use Cases

  • Shared music listening
  • Add-on speaker behavior across devices
  • Watch / listen together apps
  • Lightweight real-time audio sync

Summary

Timestamp-anchored playback is the best achievable method for synchronized audio over the internet.

By synchronizing time instead of events, devices can play the same song in perceptual sync, even when joining late or experiencing network latency.

This approach mirrors the techniques used by major streaming platforms and is production-proven.

About

Perfect Music Synchronization for the Web

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages