@panaudia/client
v1.0.5
Published
Panaudia client for spatial audio streaming — MOQ and WebRTC transports
Maintainers
Readme
@panaudia/client
Unified TypeScript client for Panaudia spatial audio. Supports MOQ (Media over QUIC) and WebRTC transports behind a common API.
Installation
npm install @panaudia/clientQuick Start
Production (with gateway)
import {PanaudiaClient, resolveServer} from '@panaudia/client';
// Resolve server URL via gateway
const serverUrl = await resolveServer(ticket);
// Create and connect (audio starts automatically)
const client = new PanaudiaClient({serverUrl, ticket});
await client.connect();
// Set spatial pose (Panaudia coordinates: position 0-1, rotation in degrees)
client.setPose({
position: {x: 0.5, y: 0.5, z: 0.5},
rotation: {yaw: 90, pitch: 0, roll: 0}
});
// Listen for other entities
client.on('entityState', (state) => {
console.log(`${state.uuid} at (${state.position.x}, ${state.position.y}, ${state.position.z})`);
});
// Disconnect
await client.disconnect();With coordinate conversion (Three.js example)
import { PanaudiaClient } from '@panaudia/client';
import { threejsToPanaudia, panaudiaToThreejs } from '@panaudia/client';
const client = new PanaudiaClient({ serverUrl, ticket });
await client.connect();
// Convert Three.js pose to Panaudia and send
const pose = threejsToPanaudia(
{ x: 0, y: 1.6, z: -5 },
{ x: 0, y: Math.PI / 2, z: 0 },
);
client.setPose(pose);
// Convert incoming entity state back to Three.js
client.on('entityState', (state) => {
const threejs = panaudiaToThreejs(state.position, state.rotation);
mesh.position.set(threejs.position.x, threejs.position.y, threejs.position.z);
});With world bounds normalization
// Positions are automatically normalized from [-100, 100] to [0, 1] for the server,
// and denormalized back to [-100, 100] in entityState events.
const client = new PanaudiaClient({
serverUrl,
ticket,
worldBounds: { min: -100, max: 100 },
});Microphone Selection
Bluetooth microphones force stereo audio to collapse to mono (the HFP/SCO profile replaces A2DP). The client detects this and refuses to connect with a Bluetooth default mic — instead throwing a BluetoothMicDefaultError that includes the full device list so you can show a mic picker.
import { PanaudiaClient, BluetoothMicDefaultError } from '@panaudia/client';
const client = new PanaudiaClient({ serverUrl, ticket });
try {
await client.connect();
} catch (err) {
if (err instanceof BluetoothMicDefaultError) {
// Default mic is Bluetooth — show a picker with the available devices
console.log('Please select a microphone:', err.availableDevices);
// err.availableDevices → [{ deviceId, label, type: 'bluetooth'|'usb'|'builtin'|'unknown' }, ...]
// After the user picks one, reconnect with their choice:
const client2 = new PanaudiaClient({ serverUrl, ticket, microphoneId: chosenDeviceId });
await client2.connect();
}
}
// If the user explicitly chooses a Bluetooth mic, it connects but emits a warning
client.on('warning', (w) => {
if (w.code === 'BLUETOOTH_MIC') {
showWarningBanner(w.message);
}
});You can also proactively show a mic picker before connecting:
// List all mics with type classification
const mics = await PanaudiaClient.listMicrophones();
// Or get the recommended non-Bluetooth mic for pre-selection
const recommended = await PanaudiaClient.getRecommendedMicrophone();Microphone Capture Options
By default the client captures raw mic audio — no echo cancellation, no
noise suppression, no auto gain control. This preserves the signal for
spatial mixing. You can opt in to the browser's processing by passing
an audio config:
const client = new PanaudiaClient({
serverUrl,
ticket,
audio: {
echoCancellation: true, // Default: false
noiseSuppression: true, // Default: false
autoGainControl: true, // Default: false
},
});These flags apply to both MOQ and WebRTC transports. Sample rate is fixed at 48 kHz.
Local Development (no gateway)
const client = new PanaudiaClient({
serverUrl: 'quic://dev.panaudia.com:4433/moq',
ticket: devJwt,
});
await client.connect();Coordinate Conversion
The library includes conversion functions for 7 web 3D frameworks. Each pair converts between that framework's native coordinate system and Panaudia's internal coordinates.
| Framework | To Panaudia | From Panaudia | Position Convention | Rotation Convention |
|-----------|-------------|---------------|--------------------|--------------------|
| Three.js | threejsToPanaudia() | panaudiaToThreejs() | RH, Y-up, -Z fwd | XYZ Euler, radians |
| Babylon.js | babylonToPanaudia() | panaudiaToBabylon() | LH, Y-up, +Z fwd | YXZ Euler, radians |
| A-Frame | aframeToPanaudia() | panaudiaToAframe() | RH, Y-up, -Z fwd | YXZ Euler, degrees |
| PlayCanvas | playcanvasToPanaudia() | panaudiaToPlaycanvas() | RH, Y-up, -Z fwd | XYZ Euler, degrees |
| Unity | unityToPanaudia() | panaudiaToUnity() | LH, Y-up, +Z fwd | ZXY Euler, degrees |
| Unreal | unrealToPanaudia() | panaudiaToUnreal() | LH, Z-up, +X fwd | FRotator (P/Y/R), degrees |
| PixiJS | pixiToPanaudia() | panaudiaToPixi() | 2D, Y-down | Scalar rotation, radians |
All rotations use quaternion intermediary math to correctly handle handedness and axis permutation differences between frameworks.
Transport Selection
The client supports two transports:
| Transport | Protocol | Browser Support | |-----------|----------|-----------------------| | MOQ (default) | WebTransport + QUIC | Chrome, Edge, Firefox | | WebRTC (fallback) | WebSocket signaling + RTCPeerConnection | All browsers |
// Auto-detect (default): MOQ if WebTransport supported, else WebRTC
const client = new PanaudiaClient({ serverUrl, ticket });
// Force MOQ
const client = new PanaudiaClient({ serverUrl, ticket, transport: 'moq' });
// Force WebRTC
const client = new PanaudiaClient({ serverUrl, ticket, transport: 'webrtc' });API Reference
See docs/api-reference.md for the full API reference, types, sub-path exports, direct MOQ access, and migration guide.
Browser Support
| Browser | Transport | Notes | |---------|-----------|-------| | Chrome 114+ | MOQ (WebTransport) | Default | | Edge 114+ | MOQ (WebTransport) | Default | | Firefox 114+ | MOQ (WebTransport) | Default | | Safari 18+ | WebRTC | Auto-fallback (no WebTransport yet) |
Development
npm install
npm run build # TypeScript + Vite build
npm test # Unit tests (vitest)
npm run typecheck # Type checking only
npm run test:integration # Playwright integration tests