Skip to main content
Rime does not detect when someone stops speaking. Your voice activity detector, turn detector, or push-to-talk control ends each utterance. The final transcript arrives after that. The code on this page connects your audio to the same stream call that the quickstart used on a file. The code is not a complete program. Your application supplies the audio capture, any decoding to PCM16, and the turn detection that ends each utterance.

Hear it working first

The SDK’s terminal voice loop records from your microphone and prints partial and final transcripts. It speaks each final transcript back through Rime text-to-speech. It needs a Rime API key and SoX.

How a stream works

Your code must meet two deadlines on each stream:
  • A stream fails after 15 seconds without audio. Send audio through pauses, and include silence.
  • A stream must finish within 120 seconds of connecting.
The SDK meets a third deadline for you, because it sends the stream settings as soon as it connects. A direct WebSocket or gRPC client must send them within 5 seconds. The limits table lists every limit.

Where audio flows

Browsers and phone systems send their audio to your backend. Your backend holds the Rime API key and opens every stream. A browser cannot call Rime directly, because the browser WebSocket API cannot set the Authorization header that carries the key. Decode the audio to headerless PCM16 before you pass it to the SDK. PCM16 is signed 16-bit little-endian samples, with stereo channels interleaved. The SDK does not decode other formats.

Send audio as you capture it

Give each utterance its own queue. Your capture code puts audio frames in the queue as they arrive, and the SDK takes the frames out at the other end. Capture never waits for the network, because audio that you capture while the stream connects stays in the queue until Rime accepts the stream. If your capture path drops silent frames, put frames of zeros in the queue in their place. This function transcribes one utterance from a queue. It returns the final transcript and the request ID. In each tab, the comments in the second code block show where to connect your capture and turn detection.
stream_utterance.py
Give each utterance a new queue, and connect the queue to your capture code and turn detector. Audio callbacks often run on another thread. The call_soon_threadsafe method safely passes their frames to the event loop from any thread:
Keep these points in mind when you adapt the example:
  • Input format: declare the format that your capture produces. The example uses 48 kHz mono, a common rate for browser and WebRTC audio. For telephone audio, use 8000. The SDK converts 8, 16, 24, or 48 kHz audio, mono or stereo, to the 16 kHz mono that the service reads. Because the SDK converts from the rate that you declare, a wrong rate distorts the audio, and the SDK does not raise an error.
  • Timeout: a timeout of 120 stops the call on the client side at the service limit. Python and Node.js both take the value in seconds. The timeout clock includes the time that the SDK waits for your audio source.
  • Update loop: do not do slow work in the update loop, such as waiting for your language model. A slow loop also slows the stream, through backpressure.

Open each stream when speech starts

Start the stream for each utterance when your voice activity detector reports speech. Do not start it earlier. A stream that opens early costs more than it saves:
  • It holds service capacity from the time Rime accepts it until it ends, even when nobody speaks.
  • Its 120-second clock starts when it connects.
  • Silence before speech counts toward the stream’s limits. For each partial transcript, the model recognizes all of the stream’s audio again. Leading silence uses model context that the speech needs.
You do not lose the first words when you wait for speech. Each SDK client keeps one gRPC connection and uses it again for every stream. A new stream on that connection takes one round trip, for Rime to accept the configuration. During that round trip, the queue for the utterance holds the audio that you capture. These two steps keep the first words:
  • Create one client per process. Pass it to every utterance, as the examples do. A new client for each utterance must open its own connection first.
  • Keep a short pre-roll. A voice activity detector reports speech a short time after the speech starts. By then, the first syllable is past. Keep the most recent audio in a short rolling buffer. Put its contents in the new queue before any other frame.

Show partials and act on the final

Each partial transcript is the full transcript so far, so replace the text on screen with each partial. If you append partials, words repeat. The service also does not send an update for each audio chunk. For example, the quickstart’s run got three partials in a 9-second call, then the final transcript. Send only the final transcript to your language model. Partials can still change, and only the final transcript covers all of the audio. Even an empty final transcript is a successful result. It means that the audio had no recognizable speech, and your agent decides whether to respond.

End the utterance

End the audio source when your turn detector decides that the speaker has finished: Ending the source does not cancel the stream. The SDK sends the remaining audio, and Rime recognizes that audio and sends the final transcript. Read updates until the final transcript arrives, and then start a new stream for the next utterance.

Split long turns at pauses

For each partial transcript, the model reads all of the stream’s audio again. So a long turn runs out of model context before the stream’s 120 seconds end. The turn then fails with a resource-limit error and no final transcript. When one speaker talks for a long time, split the turn into several utterances:
  1. Find the first pause after about a minute of speech. Split the turn at that pause. Do this even when the pause is too short to end the turn for your turn detector.
  2. To split, start the next stream on a new queue. Switch your capture code to the new queue, and then end the old utterance. This order keeps every frame of audio in one of the two streams.
  3. While a later part streams, show the earlier final transcripts, followed by the current partial. When the turn ends, join the final transcripts in order, with a space between them. Send the joined text to your language model.
A split at a pause keeps each word whole. A split after about a minute leaves time to wait for a pause before the context runs out.

Cancel when the caller hangs up

Cancel the stream when the caller hangs up during a sentence, or when your agent no longer needs the utterance. Also stop capturing audio for it. A cancelled stream never produces a final transcript.
Closing the client cancels every stream that it owns. Cancelling one stream does not stop the others. Each SDK documents its rules for releasing your audio source: Python, Node.js, Go, and Rust.

Common mistakes

Most of these mistakes do not raise an error. Each row links to the section that covers it:

Call the API directly

To call the WebSocket or gRPC API without the SDK, start at Choose how to connect, which compares the transports and the output contracts. The WebSocket and gRPC references give each message and audio rule, and the WebSocket reference shows how to transcribe a long recording.

Next

Recognition settings

Switch to word-for-word text, or add the names that your callers say.

Speak the reply

Choose a starter that streams your agent’s reply through Rime text-to-speech.