Skip to main content
A web page that talks to your Pearl, in four small files. Your server creates the stream token and keeps the API key; the page connects with the token, streams the microphone and plays Pearl’s voice through a small jitter buffer. The audio is HD Opus, coded by the browser itself with WebCodecs, with no library to add.

The server

Node.js 18 or later: npm install express.
server.mjs
Use your own id for the visitor as endUserId, so Pearl remembers them and their calls are grouped in the call history. For an anonymous visitor, leave it out.

The page

public/index.html
public/app.js

The audio

An AudioWorklet runs in real time, which gives the pacing the protocol asks for without any timer: it sends one 20 ms frame of the microphone every 20 ms, silence included when the end user is muted, and plays Pearl’s frames once 80 ms are buffered.
public/pearl-audio.js

Run it

Open http://localhost:3000, click Talk to Pearl and allow the microphone. If the call does not start, the browser console shows why, such as a missing variable: add it to callData in server.mjs.
  • Browsers allow the microphone only on https:// pages and on localhost.
  • WebCodecs audio, which codes the Opus, is in Chrome and Edge, Firefox 130 and later on desktop, and Safari 26 and later.
  • AudioContext({ sampleRate: 24000 }) makes the browser resample the microphone to 24 kHz. Chrome, Edge and Safari do this; check your other target browsers.
  • On a laptop, test with headphones: browser echo cancellation does not always cover audio played through Web Audio, and Pearl would hear itself.

Going further

  • Phone quality: with audioFormat: "opus_8000", use 8000 instead of 24000 for the context, the encoder and the decoder, and divide the worklet’s FRAME, CUSHION and MAX_BEHIND by 3.
  • Hang-up button: hangup is answered by ended, then the socket closes and onclose releases the microphone.
  • Transfers: a transfer event carries the target set on your Pearl’s Transfer Call node. In a browser there is usually no phone line to pass on, so show the end user the next step instead, or let your server act on it.

Stream WebSocket

Every message, audio format, event and limit.