> ## 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 & Streaming

> Questions about audio capture, streaming, and WebSocket implementation

<AccordionGroup>
  <Accordion title="What is the precise audio streaming format?">
    LINEAR16 (16KHz sampling rate) over the mono channel. Audio should be chunked into 100ms packets for optimal performance. We only support 100ms audio chunks to achieve the right balance between quality, latency, and efficiency.
  </Accordion>

  <Accordion title="What are the bandwidth and latency requirements?">
    Network connection speed and consistency are important for Suki to perform well.

    **Suki requires:**

    * **Upload speed**: 1Mbps
    * **Bitrate**: 768kbps
    * **Ping time**: 150ms
    * **Unloaded latency**: \<50ms
    * **Loaded latency**: \<150ms
  </Accordion>

  <Accordion title="What is the streaming protocol?">
    Client should set up a WebSocket Secure (wss\://) request with the Suki endpoint. Refer to the [Audio stream API](/api-reference/ambient-sessions/audio-stream) for implementation details.
  </Accordion>

  <Accordion title="What is the audio streaming message format?">
    For **Ambient** WebSocket **`/ws/stream`** message format, send **LINEAR16**, **16 kHz**, **mono** audio, in about **100 ms** chunks (see the [Audio streaming](/api-reference/ambient-sessions/audio-stream) reference and [Ambient audio streaming](/documentation/ambient-audio-streaming) guide).

    ### How messages are sent

    Each outbound message from the client must be:

    * **One WebSocket text frame** (UTF-8) with **one JSON object** inside
    * **One logical send** per frame (do not pack multiple JSON objects in one frame)

    <Warning>
      On **`/ws/stream`**, do **not** send PCM as **binary** WebSocket frames. Do **not** stream raw audio over HTTP with `Content-Type: application/json`.
    </Warning>

    **Field names (proto-style JSON)**

    * **`START_TIME`** and **`AUDIO`**: use **`type`** and **`data`**
    * **`data`**: standard Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648)) of the **raw bytes** you mean to send (same idea as Go `encoding/json` for `[]byte`). Do not use hex, URL-safe Base64, or raw binary inside the JSON string.
    * **`EVENT`**: use **`type`**: `"EVENT"` and the **`event`** field. Do **not** put the action name in **`data`**.

    ### Message order (each stream segment)

    1. Send **`START_TIME`** once: **`data`** is Base64 of a UTF-8 **RFC 3339** timestamp (for example `2026-04-25T12:34:56Z`).
    2. Send one or more **`AUDIO`** messages: **`data`** is Base64 of each **raw PCM** chunk.
    3. Send a final **`AUDIO`** to end audio: **`data`** is **`RU9G`** (Base64 of ASCII **`EOF`**, bytes `0x45`, `0x4F`, `0x46`). Do not use a separate `end_of_stream` type unless your integration team tells you otherwise.

    `EVENT` messages can go **anywhere** in the stream when you need control (pause, resume, keep-alive, cancel, abort).

    <span id="supported-events" />

    ### EVENT values you can send

    Use **`{"type":"EVENT","event":"<VALUE>"}`** with one of:

    | Value           | What it does                                                                                                                                          |
    | :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **PAUSE**       | Pause the stream                                                                                                                                      |
    | **RESUME**      | Resume the stream                                                                                                                                     |
    | **CANCEL**      | User cancels the stream                                                                                                                               |
    | **ABORT**       | Stream is aborted (interruption)                                                                                                                      |
    | **KEEP\_ALIVE** | Keep the connection alive during inactivity. While **paused**, send at least once every **five seconds** so the server does not close the connection. |

    ### Message examples

    <CodeGroup>
      ```json START_TIME theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "START_TIME",
        "data": "<base64(UTF-8 RFC 3339 timestamp, e.g. 2026-04-25T12:34:56Z)>"
      }
      ```

      ```json AUDIO (PCM chunk) theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "AUDIO",
        "data": "Base64EncodedPcmBytes"
      }
      ```

      ```json AUDIO (stream end marker) theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "AUDIO",
        "data": "RU9G"
      }
      ```

      ```json PAUSE Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "EVENT",
        "event": "PAUSE"
      }
      ```

      ```json RESUME Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "EVENT",
        "event": "RESUME"
      }
      ```

      ```json CANCEL Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "EVENT",
        "event": "CANCEL"
      }
      ```

      ```json KEEP_ALIVE Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "EVENT",
        "event": "KEEP_ALIVE"
      }
      ```

      ```json ABORT Event theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      {
        "type": "EVENT",
        "event": "ABORT"
      }
      ```
    </CodeGroup>

    <Note>
      The stream end marker is an **`AUDIO`** message whose **`data`** is Base64 of the raw bytes **`EOF`**, not a bare JSON string `"EOF"` and not an **`EVENT`** named EOF, unless your stack documentation says otherwise.
    </Note>
  </Accordion>
</AccordionGroup>
