The SDK includes
PlivoInterpretationTransport and signed stream admission,
reusing the two-human room described in the
shared integration guide.
The plivo-live-translation example supplies a bounded browser-call host.Recordings and transcripts in Console
Open Live Translation in Console, select your team’s live project, and start a new conversation or call. Confirm that everyone agrees to recording before starting. For a carrier call, the Console explicitly shows whether the connected host supports recording. Choose End conversation or End call and wait for saving to finish. In Call history, select the call to play its recording, download the audio, or read and download the original and translated transcripts. Other signed-in members of the same project can open the same history. Invitation links and upload tokens do not grant access to stored recordings. Original audio is on the left channel and translated audio is on the right. Browser recordings contain the microphone and the translation rendered by the browser. Carrier recordings contain source audio accepted by the bridge and translated audio sent to the call; a cancelled or interrupted translation can sound different at the listener. A recording is not proof that someone heard all sent audio. Agent replacement retains the same call record and transcript. Earlier tests have no recoverable recording. An incomplete upload is labelled Incomplete, and any successfully saved transcript remains available. Recordings stay private; playback and download require current project access.Try two-person calling in Console
Open the Plivo calling test and sign in with a verified saaslabs.co account. Console identifies the carrier currently available for an internal rehearsal, together with its room cap and expiry. The permanent Plivo tester is still undergoing end-to-end qualification. When Plivo is available, select an active live project to create a Hindi ↔ English or Punjabi ↔ English room. The selected project controls operator access. Preview calls use a shared internal test allowance and do not debit that project’s balance. This internal preview is not a customer production test.- Create a test room and send the customer and English-speaking agent their separate invitations.
- Each participant signs in and selects Join call to grant microphone access. Participants do not need access to the operator’s project. Use separate devices and headphones.
- Watch original and translated captions in the operator’s room. The bridge retains source and translation records with the call identifiers.
- Select Invite replacement agent and share that invitation. The internal transfer completes when the replacement agent joins; the customer stays in the same room.
- Select End call and wait for carrier cleanup confirmation. Leaving a participant page disconnects that browser’s call.
Route browser calls through a dedicated application
Create a dedicated Plivo Voice application and separate customer, agent and replacement-agent endpoints. Configure the application’s answer and status webhooks on your bridge. Issue short-lived browser access tokens on your server using Plivo’s token API; keep account credentials on the server. The browser token’sapp claim selects the dedicated outgoing application.
Pass the server-returned bare application ID to client.call() as an opaque
destination marker. The example requires a 16–32 digit ID, outside the E.164
phone-number limit. The SDK sends this marker through its registered
phone.plivo.com route; direct app.plivo.com SIP admission is a separate flow.
Include the single-use X-PH-JoinGrant header from the join response. Validate
the signed webhook, expected source endpoint and exact marker, accepting only
its bare or normalized phone.plivo.com SIP forms before admitting the call.
The answer XML returns only a Stream, so it creates no PSTN or second SIP leg.
See Plivo’s browser call flow.
Connect each person’s call
Return this XML from the customer’s authenticated answer webhook. This address is an endpoint you implement on your bridge:leg=agent. Validate Plivo’s V3 signatures and nonce using the official SDK on
answer/status requests and the WebSocket handshake. Bind the account,
start.callId, stream and expected participant to server-owned room state.
Treat extraHeaders as metadata, not permission to join a conversation.
The example uses SDK 0.4.5’s explicit signatureProtocol: "http" setting for
the canonical upgrade URI validated by the official helper. The media transport
remains encrypted WSS. Answer/status signatures still use HTTPS. Fix the signing
URI to your configured host and exact one-time path; do not derive it from
forwarded headers or accept alternate signatures on failure. Existing SDK
callers retain the HTTPS signing default unless they select HTTP explicitly.
Plivo also serves an older stream protocol: its start sequence is zero and the
account field can contain an internal numeric identifier. The example establishes
account ownership through the official account-token signature over the exact
WSS URL and a single-use permit bound to the signed call, participant and room.
Attachment consumes that saved admission proof once before constructing the
transport. Missing, expired, replayed or mismatched proofs close the socket.
The transport still validates the expected call, stream and audio format, and
drops audio until verification completes. Do not treat the numeric start field
as proof of account ownership.
Bidirectional streams use the inbound track. Do not select outbound or both
tracks, which can reintroduce generated speech. See
Stream XML and
WebSocket authentication.
Forward 16 kHz audio
Inspect the actualstart.mediaFormat before accepting media. Validate mono
16 kHz linear PCM and signed little-endian sample framing; do not assume that
an unexpected format is compatible.
Wrap each participant’s incoming PCM in PyAI audio.append with the
acknowledged epoch and contiguous per-leg sequence. Use 20 ms frames where
practical: 640 bytes of PCM16 before base64 encoding. Send generated PCM only
to its current target_leg:
Confirm playback and clearing
After an utterance’s final audio, send a unique checkpoint on the listener’s stream:playedStream or
legacy played receipt on that stream before reporting the complete utterance
as played. Each checkpoint can be consumed only once.
Correlate these receipts by exact stream and checkpoint name independently of the
media sequence; a receipt never advances the strictly ordered media cursor.
When PyAI cancels output, invalidate older checkpoints, stop local output and
send:
clearAudio. A sequenced clearedAudio receipt or that exact checkpoint
can complete the current clear barrier. Ignore uncorrelated legacy zero-sequence
clear receipts, old checkpoints and duplicate events. Only then acknowledge
PyAI playback.cleared for the current identity. A received PCM chunk, successful
send or generation EOF does not establish playback. See the
Audio Streams protocol
and legacy audio-stream reference
for these message types.
Keep the call record and transfers together
Store Plivo call/stream IDs with PyAI’s session ID, source and translated caption ledgers, and the stable conversation ID. Your application performs the actual Plivo transfer. Replace the interpreter participant usingleg.replace,
then adopt both updated epochs/generations and clear both output queues before
acknowledging them.
Drop microphone frames while input.gated is active and resume only after
input.resumed. Do not buffer gated audio for later replay.
On hangup or terminal error, end the PyAI session and close the room’s streams.
Before launch, test both directions, actual playback, clear/late-checkpoint
races, strict echo injection, participant replacement and normal cleanup.
For a strict echo check, inject translated output into the listener browser’s
microphone during playback and its tail. Confirm those frames are dropped before
recognition and do not create reverse transcripts or translations. Keep original
captions and translated captions attributable to their current participants
through the transfer. Provider playback acknowledgments and browser audio capture
do not establish physical speaker audibility, room acoustics, human speech
quality, PSTN routing or concurrent-call capacity.