Beatsync Documentation
repository·main·Indexed 25 days ago
https://github.com/freeman-jiang/beatsyncA high-precision web audio player for synchronized multi-device playback using NTP-inspired time synchronization. Features include millisecond-accurate sync, spatial audio capabilities, and a self-hostable architecture consisting of a Bun-based server, a Next.js client, and a shared package for type-safe schemas.
What's inside beatsync
- Beatsync is a high-precision web audio player designed for multi-device playback. It features millisecond-accurate synchronization using NTP-inspired time synchronization primitives, spatial audio capabilities (controlling device volumes via a virtual listening source), and a polished UI. It is cross-platform and works on any modern browser, though Chrome is recommended for optimal performance. The project is self-hostable.
Quickstart: Set up and run Beatsync locally
mainBeatsync uses Turborepo for monorepo management. To run the project locally, follow these steps:
Configure Environment Variables: In
apps/client, create or update a.envfile with the following values:NEXT_PUBLIC_API_URL: The URL for the HTTP server.NEXT_PUBLIC_WS_URL: The URL for the WebSocket server.
Install Dependencies: Use
bun installto install dependencies for all workspaces.Start the Application: Use
bun devto start both the client (on port3000) and the server (on port8080).
# 1. Configure apps/client/.env NEXT_PUBLIC_API_URL=http://localhost:8080 NEXT_PUBLIC_WS_URL=ws://localhost:8080/ws # 2. Install and run bun install bun devRun the Beatsync client development server
mainTo start the development server for the Beatsync client, use one of the following package manager commands. Once running, the application will be available at http://localhost:3000.
npm run dev # or yarn dev # or pnpm dev # or bun devDeploy the Beatsync client to Vercel
mainThe Beatsync client can be deployed using the Vercel Platform. For detailed instructions, refer to the official Next.js deployment documentation.Install and run the Beatsync server
mainTo set up the Beatsync server locally, install the dependencies using
bunand then start the development server. Once running, the server will be accessible athttp://localhost:3000.bun install bun run devInstall and run the @beatsync/shared package
mainTo set up the
@beatsync/sharedpackage, usebunto install dependencies and execute the entry point. This project requires the Bun runtime (v1.2.2 or later recommended).bun install bun run index.tsImplement the 3-step R2 upload flow
mainThe upload process has changed from a single
multipart/form-dataPOST to a three-step coordination flow using presigned URLs. This reduces server bandwidth by allowing direct client-to-R2 uploads.- Request URL: Client requests a presigned upload URL from the server via
POST /api/upload-url. - Direct Upload: Client uploads the audio file directly to R2 using the provided presigned URL.
- Confirm Upload: Client notifies the server of the successful upload via
POST /api/upload-completeto trigger WebSocket room updates.
- Request URL: Client requests a presigned upload URL from the server via
Configure Cloudflare R2 for Beatsync Server
mainTo use the R2 integration, you must configure the following environment variables in
apps/server/.env. This setup replaces the previous filesystem-based storage with Cloudflare R2 for audio files.# Required environment variables in apps/server/.env CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id CLOUDFLARE_R2_ACCESS_KEY_ID=your_r2_access_key_id CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_r2_secret_access_key CLOUDFLARE_R2_BUCKET_NAME=beatsync-audioSynchronize client time using NTP-inspired probe pairs
mainThe
ntp.tsutility provides primitives for millisecond-accurate time synchronization between a client and server using a 'coded probe pair' (Huygens) method. This method sends two NTP requests with a known inter-departure gap to filter out measurements corrupted by network queuing, TCP head-of-line blocking, or garbage collection pauses.To perform synchronization:
- Call
sendProbePairto dispatch two requests via WebSocket. - Use
handleNTPResponseto process incoming server responses. handleNTPResponsewill return anNTPMeasurementonly when a complete, 'pure' pair (where the server inter-arrival gap matches the client inter-departure gap withinNTP_CONSTANTS.PROBE_GAP_TOLERANCE_MS) is validated.
- Call
Manage audio playback synchronization
mainThe
RoomManagerhandles synchronized audio playback by coordinating audio loading across all clients before execution.- Initiate Loading: Call
initiateAudioSourceLoadto broadcast aLOAD_AUDIO_SOURCEevent. This starts a 3-second timeout to ensure playback proceeds even if some clients are slow. - Process Client Readiness: As clients load the source, call
processClientLoadedAudioSource. - Execution: Once all clients have reported readiness (or the timeout is reached),
executeScheduledPlayis called to broadcast theSCHEDULED_ACTIONwith the calculated execution time.
- Initiate Loading: Call
Use the new R2-compatible server endpoints
mainThe server API has been updated to support the R2 architecture. Note that the original
/uploadendpoint is deprecated and will return a deprecation error message.Endpoint Method Description /api/upload-urlPOSTGenerates presigned upload URLs /api/upload-completePOSTConfirms successful uploads /audioPOSTRedirects to R2 public URLs (replaces direct file serving) /uploadPOSTDeprecated: Returns a helpful error message Configure PM2 for the Beatsync server
mainTo run the Beatsync server using PM2, use the following configuration in
pm2.config.js. This setup ensures the server runs from the correct directory using the bundled entry point and utilizes thebuninterpreter resolved viamiseshims to maintain version consistency with the repository'smise.tomlpin.module.exports = { name: "beatsync-server", // Name of your application cwd: "apps/server", script: "dist/index.js", // Bundled entry point // Resolve bun through mise shims so the version comes from this repo's // mise.toml pin, not a stale standalone install (~/.bun/bin/bun). interpreter: `${process.env.HOME}/.local/share/mise/shims/bun`, };