> ## Documentation Index
> Fetch the complete documentation index at: https://developer.suki.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Audio Capture Best Practices

> Capture guidance for Ambient and Dictation streaming: mono PCM, sample rate, chunking, network readiness, and what to avoid before you open the WebSocket

Audio capture best practices define how to prepare audio before streaming it to Suki over WebSocket. Capture mono **LINEAR16 PCM** audio at **16 kHz**, split it into small chunks, Base64 encode each chunk, and send it as JSON text frames over the WebSocket.

Ambient, Form filling, and Dictation all use the same audio capture requirements. However, each product uses different WebSocket endpoints, message formats, and end-of-stream markers.

<Info>
  **This guide applies to:** Direct WebSocket integrations that stream raw PCM audio to Ambient, Form filling, or Dictation. Form filling uses the same ambient socket (`GET /ws/stream`) with an ambient session ID.

  For the exact WebSocket message formats, see [WebSocket streaming wire format](/documentation/how-to/audio-streaming/websocket-streaming-wire-format).
</Info>

Read the following related guides:

<Accordion title="Related Guides" defaultOpen={true}>
  <div className="doc-guide-btn-row">
    <a href="/documentation/how-to/audio-streaming/websocket-streaming-wire-format" className="doc-guide-btn">
      Wire Format
    </a>

    <a href="/documentation/how-to/audio-streaming/streaming-architecture" className="doc-guide-btn">
      Streaming Architecture
    </a>

    <a href="/api-reference/faqs/audio-capture-streaming" className="doc-guide-btn">
      Capture And Streaming FAQs
    </a>
  </div>
</Accordion>

## What this guide covers

Use this guide before implementing audio capture or opening a WebSocket connection.

You will learn:

* The audio format required by Ambient, Form filling, and Dictation
* How to prepare and stream audio over the WebSocket
* Recommended network requirements for reliable real-time streaming
* Product-specific streaming differences you must handle

## What audio format should you capture

Ambient, Form filling, and Dictation all use the same recommended audio format.

<CardGroup cols={2}>
  <Card title="16 kHz Sample Rate" icon="waveform">
    Capture audio at **16 kHz** to preserve the full range of clinical speech.
  </Card>

  <Card title="Mono Audio" icon="microphone">
    Capture a **single mono channel**. Do not stream stereo or multi-channel audio.
  </Card>

  <Card title="LINEAR16 PCM" icon="file-audio">
    Encode audio as **LINEAR16** (PCM signed 16-bit little-endian). Dictation refers to the same format as **PCM\_S16LE**. Strip WAV headers before streaming.
  </Card>

  <Card title="100 ms Chunks" icon="clock">
    Stream audio in approximately **100 ms** chunks. At 16 kHz mono 16-bit, each chunk is about **3200 bytes** of raw PCM.
  </Card>
</CardGroup>

| Setting       | Ambient and Form filling (`/ws/stream`)        | Dictation (`/ws/transcribe`)              |
| :------------ | :--------------------------------------------- | :---------------------------------------- |
| Encoding      | **LINEAR16** (PCM signed 16-bit little-endian) | **PCM\_S16LE** (same format)              |
| Channels      | Mono                                           | Mono                                      |
| Sample rate   | **16 kHz**                                     | **16 kHz**                                |
| Chunk size    | About **100 ms** (about **3200 bytes**)        | About **100 ms** (about **3200 bytes**)   |
| Audio payload | Base64-encoded raw PCM in **`data`**           | Base64-encoded raw PCM in **`audioData`** |

<Tip>
  If your audio source is a **`.wav`** file, remove the WAV header (typically **44 bytes** for a standard RIFF WAV file) or decode the file into raw PCM before Base64 encoding. Streaming WAV headers as audio data can reduce recognition quality and make troubleshooting more difficult.
</Tip>

## What should you avoid

Avoid the following common mistakes:

* Sending binary WebSocket frames instead of JSON text frames
* Sending multiple JSON objects in a single WebSocket message
* Encoding audio with hexadecimal, URL-safe Base64, or other non-standard Base64 variants
* Streaming audio over HTTP using **`Content-Type: application/json`**

Always encode the raw PCM bytes using standard Base64 defined by [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648).

## How do you prepare audio for streaming

Once audio has been captured:

1. Split the PCM stream into approximately **100 ms** chunks.
2. Encode each chunk using standard Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648)).
3. Wrap each chunk in a single JSON message.
4. Send one JSON text frame per audio chunk.
5. Stream chunks at approximately real-time speed so transmission stays synchronized with the captured audio.

For the required message fields, streaming sequence, and end-of-stream messages, see [WebSocket streaming wire format](/documentation/how-to/audio-streaming/websocket-streaming-wire-format).

## What network requirements are recommended

All streaming uses secure WebSockets (**`wss://`**).

For reliable real-time streaming, Suki recommends the following minimum network conditions:

| Requirement      | Recommended    |
| :--------------- | :------------- |
| Upload speed     | 1 Mbps         |
| Bitrate          | 768 kbps       |
| Ping             | 150 ms or less |
| Unloaded latency | Under 50 ms    |
| Loaded latency   | Under 150 ms   |

For the source of these recommendations, see [Audio capture and streaming FAQs](/api-reference/faqs/audio-capture-streaming).

For keep-alives, reconnection behavior, and pause handling, see [Streaming architecture](/documentation/how-to/audio-streaming/streaming-architecture#network-and-connection-management).

## What differs by product

Although all products use the same audio format, each streaming API has different protocol requirements.

### Ambient and Form filling

* Send a **`START_TIME`** message before streaming audio.
* Send Base64 PCM in the **`data`** field.
* End the stream by sending a final **`AUDIO`** message whose **`data`** value is **`RU9G`** (Base64 of ASCII **`EOF`**).
* While the stream is active, send audio at least once every **25 seconds**, or Suki disconnects the stream.
* While the stream is paused, send an **`EVENT`** message with **`event`**: **`KEEP_ALIVE`** at least every **5 seconds**. An ambient session can remain paused for up to **30 minutes**.
* You can reconnect to **`/ws/stream`** using the same **`ambient_session_id`** only while the session remains in the **`CREATED`** state. Otherwise the handshake returns **`FailedPrecondition`**.
* Sessions shorter than **1 minute** may not contain enough audio for note generation and can be marked as **`skipped`**.

### Dictation

* Open **`/ws/transcribe`** only when the session state is **`READY`** or **`IDLE`**. If the session is not ready, the handshake returns **`FailedPrecondition`**.
* Send Base64 PCM in **`audioData`**, not **`data`**.
* End streaming by sending **`{"type":"EVENT","event":"AUDIO_END"}`** after the last **`AUDIO`** chunk.
* Use interim transcripts (**`is_final: false`**) for live display, and treat **`is_final: true`** as the finalized transcript. See [Dictation transcript frames](/documentation/how-to/audio-streaming/dictation-streaming-transcripts).

## Next steps

<Icon icon="file-lines" iconType="solid" /> Review [WebSocket streaming wire format](/documentation/how-to/audio-streaming/websocket-streaming-wire-format) for the exact outbound message formats.

<Icon icon="file-lines" iconType="solid" /> Read [Audio capture and streaming FAQs](/api-reference/faqs/audio-capture-streaming) for additional guidance on audio formats and network requirements.

<Icon icon="file-lines" iconType="solid" /> Follow [Complete the session after streaming](/documentation/how-to/audio-streaming/websocket-streaming-complete-session) to properly finalize streaming sessions.
