Skip to main content
Plivo can stream linear PCM at 16 kHz, which reduces audio conversion in a PyAI Live Translation bridge. Give each human a separate controlled call and Audio Stream, paired to one PyAI interpretation session.
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.
  1. Create a test room and send the customer and English-speaking agent their separate invitations.
  2. 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.
  3. Watch original and translated captions in the operator’s room. The bridge retains source and translation records with the call identifiers.
  4. Select Invite replacement agent and share that invitation. The internal transfer completes when the replacement agent joins; the customer stays in the same room.
  5. Select End call and wait for carrier cleanup confirmation. Leaving a participant page disconnects that browser’s call.
Each invitation is short-lived and single-use. The Console page shows the current preview’s room cap and expiry. No production concurrency guarantee is made by this internal preview. Keep participant links private. Punjabi captions apply a narrow spelling correction for the weekday “Friday.” When a caption changes, View original recognition shows the unmodified source. The durable transcript preserves raw text, source offsets and correction metadata. This display correction does not alter translation input or claim improved recognition accuracy.

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’s app 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:
Create the agent’s separate call with the same stream configuration and 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 actual start.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:
Associate that checkpoint with the PyAI utterance, participant epoch, output generation and original sample count. Require a matching 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:
Serialize clear requests per stream. Send a fresh, unique checkpoint immediately after 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 using leg.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.