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

# Streams and State

> How SDK objects hold per-stream state, when to reset it, and which calls are real-time safe.

Every SDK object that takes audio is stateful over time. A processor's enhancement, a VAD's speech history, and an analyzer's rolling window all depend on the blocks you passed before. This page covers how that state is scoped, how to clear it, and which calls are safe on an audio thread.

## One object per stream

State belongs to the object, not to the model. Create one processor, VAD, or collector and analyzer pair per stream, pass that stream's blocks to it in order, and reuse the same [model handle](/reference/sdk/models#loading-and-reusing-models) across all of them.

Interleaving two streams through one object mixes their history and produces unstable output. This is also why the two sides of a call, or the channels of a multi-channel input that represent independent streams, each need their own object. See [Audio Format](/reference/concepts/audio-format#independent-streams-stored-as-channels).

## Resetting state

Reset clears the internal buffers and history of one object while keeping its audio configuration. The object stays initialized, so you can continue processing immediately afterwards without reinitializing.

| Object        | Call                                                                 | What it clears                                                                                                                                           |
| ------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Processor     | `processor.get_context().reset()`<br />`aic_processor_context_reset` | The processor's internal buffers and enhancement state. It does not touch a VAD.                                                                         |
| VAD           | `vad.get_context().reset()`<br />`aic_vad_context_reset`             | The VAD's state, plus the published speech decision and raw probability, which drop to `false` and `0.0` immediately rather than returning stale values. |
| Analyzer pair | `analyzer.reset()`<br />`aic_analyzer_reset`                         | The analyzer's state **and** the audio buffered by its paired collector. The collector stays initialized.                                                |

Call reset when the audio you are about to pass is not a continuation of the audio you passed before:

* The stream was interrupted, or a caller reconnected
* You are seeking in a file or a recording
* You are reusing the object for a new call or a new stream
* A long gap in the audio makes the previous content irrelevant

Skipping the reset leaves the object convolving new audio with unrelated history, which causes artifacts in enhanced output and mispredictions in the VAD and the analyzer.

<Note>
  Resetting is per object. If you run enhancement, VAD, and analysis side by side on one stream, reset all of them when that stream is interrupted.
</Note>

Reset is not a replacement for reinitialization. Changing the sample rate or the maximum block size requires initializing the object again, which allocates memory and must not happen on a real-time audio thread. See [Block size](/reference/concepts/audio-format#block-size).

## Real-time safety

The audio path is designed to run inside a real-time callback. Setup, analysis, and anything that talks to our backend is not.

| Call                                                     | Real-time safe                          |
| -------------------------------------------------------- | --------------------------------------- |
| `process` on a processor or VAD, `buffer` on a collector | Yes                                     |
| Reset, on any object                                     | Yes                                     |
| Reading or writing parameters through a context          | Yes                                     |
| Reading the audio delay or the prediction delay          | Yes                                     |
| Creating an object, or `initialize`                      | No, it allocates memory                 |
| `analyze_buffered` on an analyzer                        | No, it runs an expensive model          |
| `update_bearer_token`                                    | No, it locks a mutex and allocates      |
| `terminate_session`                                      | No, it may block until the session ends |

<Warning>
  The analyzer is the one that catches people out. Analysis models cost far more than a real-time audio block, which is exactly why the collector and the analyzer are separate objects. See [Real-Time Analysis](/models/audio-insight/real-time-analysis#two-objects-two-threads).
</Warning>

Each object is also single-threaded with respect to itself: do not call `process` on one processor from two threads at once. Parallelize across streams with one object per stream instead. See [Performance](/reference/concepts/performance#parallel-processing).

## Contexts

Control and query APIs live on a separate context handle rather than on the audio object itself, so they can be used from a different thread than the one running audio:

```python theme={null}
proc_ctx = processor.get_context()
vad_ctx = vad.get_context()

proc_ctx.set_parameter(aic.ProcessorParameter.EnhancementLevel, 0.8)
print(vad_ctx.is_speech_detected())
```

Create a context once during setup and keep it for as long as you need it. In C, contexts are independent handles: `aic_processor_context_destroy` does not destroy the processor, and a context may be destroyed before or after the object it controls, in any order.
