npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@axsnull/audio-sync-engine

v1.1.0

Published

Production-grade client-side audio synchronization engine for distributed playback systems

Readme

@axsnull/audio-sync-engine

Production-grade client-side audio synchronization engine for distributed playback systems.

Overview

@axsnull/audio-sync-engine is a production-grade audio synchronization library designed for distributed playback systems. It provides server-authoritative audio playback with precise time synchronization, drift detection and correction, and multi-device coordination.

Key Features

  • Server-Authoritative: Client is a renderer only, never the source of truth
  • Precise Clock Sync: WebSocket ping/pong with latency compensation
  • Web Audio API: High-precision audio clock
  • Drift Detection: Automatic detection of audio/sync drift
  • 3-Level Drift Correction: Ignore (50ms) → Soft (50-300ms) → Hard (>300ms)
  • Periodic Sync Loop: Automatic correction every 1-2 seconds
  • Synchronized Start: Delayed start support for multi-device coordination
  • Buffer Management: 3-10s buffer with rebuffer avoidance
  • Deterministic: Server State → Sync Engine → Audio Output

Installation

npm install @axsnull/audio-sync-engine

Quick Start

import { AudioSyncEngine } from '@axsnull/audio-sync-engine';

// Initialize the engine
const syncEngine = new AudioSyncEngine(
	async (timestamp) => {
		// Send ping to server and get pong with server timestamp
		const response = await fetch('/api/ping', {
			method: 'POST',
			body: JSON.stringify({ clientTimestamp: timestamp })
		});
		const data = await response.json();
		return data.serverTimestamp;
	},
	{
		syncIntervalMs: 1500,
		bufferMinSeconds: 3,
		bufferMaxSeconds: 10,
		bufferTargetSeconds: 5
	}
);

// Initialize with audio element
const audio = new Audio();
await syncEngine.initialize(audio, async (trackId) => {
	const response = await fetch(`/api/tracks/${trackId}`);
	return await response.json();
});

// Handle server player updates
socket.on('player:update', (state) => {
	syncEngine.handlePlayerUpdate(state);
});

// Schedule synchronized start
await syncEngine.scheduleSynchronizedStart(serverStartAt);

Architecture

Core Components

ClockSync

WebSocket ping/pong clock synchronization with latency compensation:

  • sync() - Perform clock sync
  • syncedNow() - Get synchronized time (Date.now() + offset)
  • Formula: latency = (t4 - t1) / 2, offset = t3 - (t1 + latency)

AudioClock

Web Audio API high-precision clock:

  • start() - Start AudioContext
  • getCurrentTime() - audioStartTime + audioContext.currentTime

DriftDetector

Calculate audio/sync drift:

  • calculateDrift() - actualPosition - expectedPosition
  • expectedPosition = server.positionMs + (syncedNow - server.updatedAt)
  • Thresholds: 50ms (ignore), 300ms (soft correction)

DriftCorrector

3-level drift correction:

  • Ignore: drift < 50ms
  • Soft: 50-300ms - adjust playbackRate (0.98/1.02)
  • Hard: > 300ms - seek to expectedPosition

PlayerStateSync

Handle server player updates:

  • handlePlayerUpdate() - Sync with server state
  • Load new tracks on trackId change
  • Apply play/pause + position sync

PeriodicSync

Automatic periodic synchronization:

  • Configurable interval (default 1.5s)
  • Automatic drift correction every 1-2s

SynchronizedStart

Delayed start for multi-device coordination:

  • scheduleStart() - Calculate delay and setTimeout
  • Support for server-provided startAt timestamp

BufferManager

Audio buffer management:

  • Min buffer: 3s
  • Max buffer: 10s
  • Target buffer: 5s
  • Avoid rebuffer during sync

API Reference

AudioSyncEngine

Main class that integrates all components.

constructor(
	sendPing: (timestamp: number) => Promise<number>,
	config?: AudioSyncEngineConfig
)

Methods

  • initialize(audio: HTMLAudioElement, loadTrack: (trackId: string) => Promise<TrackMetadata>) - Initialize engine
  • handlePlayerUpdate(state: PlayerState) - Handle server player update
  • performPeriodicSync() - Perform periodic drift correction
  • scheduleSynchronizedStart(serverStartAt: number) - Schedule delayed start
  • syncTime() - Synchronize time with server
  • getSyncedNow() - Get synchronized time
  • getClockOffset() - Get clock offset
  • getClockLatency() - Get clock latency
  • stop() - Stop all processes

AudioSyncEngineConfig

{
	syncIntervalMs?: number;        // Default: 1500
	bufferMinSeconds?: number;     // Default: 3
	bufferMaxSeconds?: number;     // Default: 10
	bufferTargetSeconds?: number;  // Default: 5
}

PlayerState

{
	userId: string;
	activeDeviceId: string | null;
	trackId: string | null;
	isPlaying: boolean;
	positionMs: number;
	updatedAt: number;
	lastServerSyncAt: number;
	queue?: string[];
	currentIndex?: number;
}

TrackMetadata

{
	id: string;
	streamUrl: string;
	duration: number;
	source: 's3' | 'cdn' | 'proxy';
}

Usage Examples

Basic Setup

import { AudioSyncEngine } from '@axsnull/audio-sync-engine';

const syncEngine = new AudioSyncEngine(
	async (timestamp) => {
		const response = await fetch('/api/ping', {
			method: 'POST',
			body: JSON.stringify({ clientTimestamp: timestamp })
		});
		const data = await response.json();
		return data.serverTimestamp;
	}
);

const audio = new Audio();
await syncEngine.initialize(audio, async (trackId) => {
	const response = await fetch(`/api/tracks/${trackId}`);
	return await response.json();
});

Handling Player Updates

socket.on('player:update', (state) => {
	syncEngine.handlePlayerUpdate(state);
});

Manual Time Sync

await syncEngine.syncTime();
const syncedNow = syncEngine.getSyncedNow();
console.log('Synced time:', syncedNow);
console.log('Clock offset:', syncEngine.getClockOffset());
console.log('Clock latency:', syncEngine.getClockLatency());

Synchronized Start

const schedule = await syncEngine.scheduleSynchronizedStart(serverStartAt);
console.log(`Starting in ${schedule.delay}ms`);

Cleanup

syncEngine.stop();

Best Practices

  1. Never Initiate Playback Locally: Always sync with server state
  2. Use Synced Time: Always use syncedNow() instead of Date.now() for calculations
  3. Handle Network Latency: Clock sync accounts for latency automatically
  4. Buffer Management: The engine manages buffers automatically
  5. Graceful Degradation: System continues to work even with occasional sync failures

Requirements

  • Node.js >= 16.0.0
  • Modern browser with Web Audio API support
  • WebSocket connection to server

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Support

For issues and questions, please open an issue on GitHub. #� �-�a�x�s�n�u�l�l�-�a�u�d�i�o�-�s�y�n�c�-�e�n�g�i�n�e� � �