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

@cloudfort/callum-voice-web

v0.0.3

Published

Real-time voice chat SDK for web browsers — AudioWorklet-based mic capture and peer playback mixing

Readme

Callum Voice Web

Real-time voice chat SDK for web browsers. Connects to the Callum voice service over WebSocket, captures microphone audio via AudioWorklet, and plays back remote peer audio with proper device routing.

Features

  • AudioWorklet mic capture and playback mixing (no separate worker files needed)
  • Automatic reconnection with room/mic state restoration
  • Peer speaking detection via RMS analysis
  • Resampling support for mismatched sample rates
  • TypeScript with full type definitions
  • Zero dependencies — uses only browser Web APIs

Install

npm install callum-voice-web

Quick Start

import { VoiceClient, createVoiceConfig } from 'callum-voice-web';

const client = new VoiceClient(createVoiceConfig({
  server: 'callem.cloudfort.ir',
  apiKey: 'vc_live_YOUR_API_KEY',
  peerId: 'user_123',
}));

client.setListener({
  onConnected: () => {
    console.log('Connected!');
    client.joinRoom('general');
  },
  onPeerJoined: (peerId) => console.log(`${peerId} joined`),
  onPeerSpeaking: (peerId) => console.log(`${peerId} is speaking`),
  onPeerStopped: (peerId) => console.log(`${peerId} stopped speaking`),
  onPeerLeft: (peerId) => console.log(`${peerId} left`),
  onError: (err) => console.error('Error:', err),
});

await client.connect();

API

createVoiceConfig(overrides)

Create a config with sensible defaults:

| Option | Type | Default | Description | |--------|------|---------|-------------| | server | string | '' | Server address (e.g. callem.cloudfort.ir) | | apiKey | string | '' | API key from account registration | | peerId | string | '' | Unique peer identifier | | useTls | boolean | undefined | Force WSS/WS. Auto-detected when undefined | | sampleRate | number | 48000 | Audio sample rate in Hz | | autoReconnect | boolean | true | Auto reconnect on disconnect | | maxReconnectAttempts | number | 5 | Max reconnection attempts | | reconnectDelayMs | number | 2000 | Delay between reconnect attempts | | echoCancellation | boolean | true | Browser echo cancellation | | noiseSuppression | boolean | true | Browser noise suppression | | autoGainControl | boolean | true | Browser auto gain control |

VoiceClient

Properties

| Property | Type | Description | |----------|------|-------------| | state | VoiceClientState | Current connection state | | isConnected | boolean | Whether connected to server | | isInRoom | boolean | Whether joined a room | | isMicEnabled | boolean | Whether microphone is active | | currentRoomId | string \| null | Current room ID | | peerIds | string[] | List of peer IDs in the room | | audio | AudioContext \| null | AudioContext (available after joinRoom) |

Methods

| Method | Returns | Description | |--------|---------|-------------| | connect() | Promise<void> | Connect to the voice server | | disconnect() | void | Disconnect from the server | | joinRoom(roomId) | Promise<void> | Join a voice room | | leaveRoom() | Promise<void> | Leave the current room | | enableMic() | Promise<void> | Enable microphone | | disableMic() | void | Disable microphone | | toggleMic() | Promise<boolean> | Toggle microphone, returns new state | | isPeerSpeaking(peerId) | boolean | Check if a peer is speaking | | getPeerSpeakingInfo(peerId) | { speaking, rms } | Get peer speaking state with RMS level | | setListener(listener) | void | Set the event listener | | dispose() | void | Dispose and release all resources |

Events (VoiceEventListener)

| Event | Parameters | Description | |-------|------------|-------------| | onConnected | — | Connection established | | onDisconnected | — | Connection lost | | onReconnecting | attempt: number | Reconnection attempt in progress | | onAuthFailed | reason: string | Authentication failed | | onRoomJoined | roomId: string | Joined a room | | onRoomLeft | roomId: string | Left a room | | onPeerJoined | peerId: string | New peer joined | | onPeerLeft | peerId: string | Peer left | | onPeerSpeaking | peerId: string | Peer started speaking | | onPeerStopped | peerId: string | Peer stopped speaking | | onMicEnabled | — | Microphone enabled | | onMicDisabled | — | Microphone disabled | | onError | error: Error | Error occurred | | onStateChanged | state: VoiceClientState | Connection state changed |

VoiceClientState Enum

enum VoiceClientState {
  Disconnected = 0,
  Connecting = 1,
  Connected = 2,
  InRoom = 3,
  Reconnecting = 4,
}

Speaker Routing

Use the audio property to route output to a specific device:

await client.joinRoom('general');

// Route to a specific speaker
const devices = await navigator.mediaDevices.enumerateDevices();
const speaker = devices.find(d => d.kind === 'audiooutput');
if (speaker) {
  await client.audio.setSinkId(speaker.deviceId);
}

Protocol

  • WebSocket: Binary PCM audio at 16-bit signed integer, mono, 48000 Hz
  • Packet format: [1B RoomLen][RoomID][1B PeerLen][PeerID][PCM Audio]
  • Speaking detection: RMS threshold 0.012, checked every 80ms
  • Auth failure: WebSocket close codes 1008 / 4001

Build

npm install
npm run build

License

MIT