Frequently Asked Questions
Common questions from developers building voice AI bots, IVR systems, and live transcription pipelines on SFVoPI's audio streaming.
Does SFVoPI support bidirectional, full-duplex audio streaming?
Yes. A single WebSocket connection carries audio in both directions at once — Superfone streams caller audio to you via media events while independently accepting your playAudio commands on the same socket. Neither direction blocks the other.
If you only need one direction, set direction: "INBOUND" or "OUTBOUND" in your Stream JSON to cut bandwidth — see Stream Directions.
When the caller starts speaking, do I keep receiving live inbound audio while my outbound audio is still playing?
Yes. Inbound media events keep streaming to you continuously and are never paused or blocked by your own outbound playAudio traffic — there's no server-side gate that stalls inbound delivery while a queued response is playing out. This is what makes barge-in possible: your audio processor can detect the caller speaking mid-playback and react immediately (typically by calling clearAudio) instead of waiting for your current audio to finish.
See the media event and clearAudio command.
What command clears audio that's already buffered for playback?
Send a clearAudio command. It immediately stops playback and discards every queued playAudio message — it does not wait for the current chunk to finish.
{ "event": "clearAudio", "sequenceNumber": 42 }
Full spec: clearAudio command.
Is there an acknowledgement that the buffer was actually cleared?
Yes. clearAudio requires a sequenceNumber. Once the buffer is cleared, Superfone sends back a clearedAudio event carrying that same sequenceNumber — treat this as your confirmation, analogous to a "mark" event, and don't assume the clear happened until you receive it.
{ "event": "clearedAudio", "streamId": "SFV_STRM_IN_...", "sequenceNumber": 42 }
Don't confuse this with the separate checkpoint / playedStream pair, which confirms that previously-queued audio finished playing (e.g. "the greeting is done, start listening") rather than that a buffer was cleared. See clearedAudio event and checkpoint command.
What codecs, sample rate, frame size, and buffer limits does SFVoPI use?
| Detail | |
|---|---|
| Codecs | PCMA (recommended — native, zero transcoding), PCMU, L16 |
| Sample rate | 8000 Hz (matches the telephony trunk — use this); L16 also accepts 16000–48000 Hz, but SFVoPI is still upsampling/downsampling from an 8 kHz source, so higher rates add CPU cost with no real quality gain |
| Frame size | ~20 ms chunks — 160 bytes/frame for PCMA/PCMU @ 8 kHz, 320 bytes/frame for L16 @ 8 kHz |
Max playAudio payload | ~1.5 MB (1,500,000 base64 chars) per message — frames over this are silently dropped; stream small chunks (20–200 ms), don't buffer large blocks |
| Max pending checkpoints | 100 per stream — queue more without draining via playedStream acks and the newest ones are silently dropped |
Full detail: Supported Codecs and Sample Rates.
Can I transfer a call to the Superfone app, to hand it to a human agent?
Yes. Send a transfer command on the stream WebSocket with the phone number of a Superfone user in your organisation, and an optional reason that is shown to the agent in the Superfone app:
{ "event": "transfer", "to": "+91XXXXXXXXXX", "reason": "Caller wants a refund", "hold": true }
The agent's app rings for about 20 seconds. You get transferAccepted, transferRinging, and then either transferAnswered or transferFailed. By default the caller hears hold music while it rings. Set "hold": false to keep your bot talking instead.
It is a cold transfer. When the agent answers, your stream closes with a normal close (code 1000) and the caller talks to the agent. If the transfer fails, the call stays with your bot. You can try another number, keep talking, or send { "event": "hangup" }. Only one transfer can be pending at a time, and streams opened with direction INBOUND cannot send commands.
This call transfer to Superfone app reaches only users in the same Superfone organisation as your SFVoPI app. Transfers to other numbers, such as an external phone number, are rejected with NOT_ORG_USER. The agent's Superfone number must also be in the same number series as the number the call came in on. If it is in a different series, the transfer is rejected with TARGET_DIFFERENT_SERIES, the agent's app does not ring, and the call stays with your bot. To reach another number, place a second call with the Initiate Call API and relay audio between the two streams in your own application. See Transferring to any other number.
Full details: transfer command, transfer status events and transfer codes. Superfone does not pass your conversation context to the agent, so put what the agent needs to know in reason.
What reconnect, timeout, and call-ended events does the WebSocket provide?
- Reconnect: if your WebSocket server drops the connection, Superfone retries 3 times with exponential backoff (1s, 2s, 4s). On success it re-sends the
startevent with the samestreamId— your handler must treat this as a resume, not a new stream. See Reconnection Handling. - Timeout: set via
stream_timeoutin your Stream JSON response (max 24 hours). When it fires, the stream is torn down — there's no dedicated "timeout" event sent first, so don't rely on one; track your own elapsed time if you need a warning before cutoff. See Stream Object Fields. - Call-ended: there's no in-band
callEnded/stopmessage on the media WebSocket itself — the socket simply closes. The authoritative "the call is over" signal is the separate Hangup Webhook (hangup_url), which carriescall_statusand hangup cause. Don't try to infer final call status from the WebSocket closing alone — wait for the hangup webhook.
Next Steps
- Audio Streaming Overview — Architecture, codecs, sample rates
- WebSocket Protocol — All 8 event types and commands
- Audio Processing — Build your first audio processor
- Hangup Webhook — Handle call-end