---
source_path: "api/io.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/api/io/"
---

# Input and output

The [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) uses [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instances for all input and output. This includes
model loading, audio input and output, binary data, and large sections of text.

Most-used [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) APIs:

| API | Summary |
|-----|---------|
| [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) | Open a file path for read, write, or append. |
| [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) | Read or write a fixed memory buffer. |
| [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) | Capture live audio from the platform microphone. |
| [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream) | Convert audio format on an existing source stream. |
| [fromBuffer](https://doc.sensory.com/tnl/7.8/api/io.md#frombuffer) | Ring buffer for streaming audio with bounded history. |
| [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) | Custom source or sink implemented with callbacks. |
| [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) | Open a stream before [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write). |
| [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) | Read bytes from an open stream (blocks until data or EOF). |
| [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) | Write bytes to an open stream. |
| [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy) | Copy all data from one stream to another. |

Stream error state clears on the next operation; use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect.
Checked `IOException`s on Java stream I/O are summarized in [API overview](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview).
See [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) and [operations](https://doc.sensory.com/tnl/7.8/api/io.md#operations) for the full lists.

## Stream

<!-- tab: c -->

**C/C++**

```c
typedef struct SnsrStream_  *SnsrStream;
```
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public class SnsrStream {}
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
class Stream: ...
```
<!-- /tab -->

`SnsrStream` is the TrulyNatural SDK API input and output type.

This `SnsrStream` abstraction decouples the inference type from the actual data sources
and sinks. This, for example, allows models to load and run even when a file system isn't available.

The [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) section describes all of the stream implementations (adapters, wrappers)
included in this SDK.

Stream instances support the same set of [operations](https://doc.sensory.com/tnl/7.8/api/io.md#operations).

<!-- tab: c -->

**C/C++**

`SnsrStream` handles are [reference-counted](https://doc.sensory.com/tnl/7.8/api/heap.md#reference-counting), with lifetimes
managed by [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release).
<!-- /tab -->

<!-- tab: java -->

**Java**

Best practice is to [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release) a stream object before allowing garbage collection
to reclaim the object memory. This will free all encapsulated resources immediately.
<!-- /tab -->

<!-- tab: py -->

**Python**

`Stream` is a context manager. `with Stream.from_*(...) as s:` opens the stream
on entry and releases it on exit. Call [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release) explicitly when
the stream lifetime does not fit a `with` block.
<!-- /tab -->

**Note:**

The current implementation does not do any thread-level locking.
Threaded access to stream handles must be protected by explicit
synchronization calls.

### Constructors

This section describes the predefined stream constructors.

Built-in stream implementations cover [files](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename), [file handles](https://doc.sensory.com/tnl/7.8/api/io.md#fromfile),
[live audio sources](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice), [circular buffers](https://doc.sensory.com/tnl/7.8/api/io.md#frombuffer),
[models compiled to code](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode), [memory segments](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory), [strings](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring),
and [user-defined data](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) sources or sinks.

This library also includes stream transformations for [audio format conversion](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream),
stream [concatenation](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams), and [limiting the extent](https://doc.sensory.com/tnl/7.8/api/io.md#fromopenstream) of [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read)
or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) operations.

<!-- tab: c -->

**C/C++**

**Note:**

Functions in this group that take `SnsrStream` arguments [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) these
handles and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) them when they are no longer used. A `SnsrStream`
handle with a zero reference count used as an argument will therefore
be deallocated when it is no longer needed. Be sure to call
[retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) on handles that need to survive these function invocations.

<!-- /tab -->

<!-- tab: py -->

**Python**

Python omits `from_code` and `from_FILE`. Use [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) for packaged model
bytes, [fromFilename](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) for file paths, or [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) for custom sources
and sinks.
<!-- /tab -->

#### fromAsset
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromAsset(AAssetManager *mgr, const char *filename);
```

**Parameters and return value:**

**Input parameter:** `mgr`

* Android [AAssetManager][] object.

**Input parameter:** `filename`

* Path to the asset, relative to the `assets/` directory.

Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a compressed Android asset.

`filename` is relative to `assets/` and must not include this as part of the name.

**Note:**

This function is available in C TrulyNatural SDK on Android only.
Contact [Sensory][] if you need access to these libraries for Android.

**Also see these related items:** [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename)

<!-- /tab -->

<!-- tab: java -->

**Java**

On Android, [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) includes support for reading files from `assets/`.
<!-- /tab -->

<!-- tab: py -->

**Python**

_This constructor is not available in the Python language binding._
<!-- /tab -->

#### fromAudioDevice
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromAudioDevice(SnsrStreamAudioFormat format, ...);
```

**Parameters and return value:**

**Input parameter:** `format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) format specifier, determines additional arguments.

**Input parameter:** `...`

* The specific additional arguments required depend on the value of `format`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Streams live audio from an audio capture device.

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) attached to the specified audio device.
This supports audio capture with [ALSA][] on Linux,
with [Audio Queue Services][] on macOS and iOS, and with the
[Windows Multimedia Extensions][] Wave API on Windows.

[DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) sets the default capture device with the format
(16-bit little-endian LPCM) and sample rate (16 kHz) required by most
TrulyNatural SDK recognizers. This is the recommended format specifier.

**Example:**

```c
// Use a specific ALSA device, rather than the default.
// The "plughw" device typically includes sample rate conversion,
// use this if the hardware does not support sampling at 16 kHz.
SnsrStream a = snsrStreamFromAudioDevice(SNSR_ST_AF_DEVICE, "plughw:1,0");
```

**Also see these related items:** [ALSA][], [Audio Queue Services][], [Windows Multimedia Extensions][]

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromAudioDevice();

static SnsrStream fromAudioDevice(int device, int sampleRate); // (1)!

static SnsrStream fromAudioDevice(int sampleRate);
```

1. Available on Android only.

**Parameters and return value:**

**Input parameter:** `device`

* Android audio [source specifier][MediaRecorder.AudioSource].

**Input parameter:** `sampleRate`

* Audio capture sample rate.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Streams live audio from an audio capture device.

`#!java static SnsrStream fromAudioDevice()` creates a new stream attached to the
default audio recording device, with the [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) encoding and sample rate.

`#!java static SnsrStream fromAudioDevice(int device, int sampleRate)` creates a new stream
attached to the specified [MediaRecorder.AudioSource][] and sample rate.
_This method is available on Android devices only._

`#!java static SnsrStream fromAudioDevice(int sampleRate)` creates a new stream attached to
the default audio recording device at the sample rate specified.

**Also see these related items:** [AudioRecord][], [Java Audio][]

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_audio_device(
    cls,
    audio_format: snsr.StreamAudioFormat = snsr.StreamAudioFormat.DEFAULT,
    *args,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `audio_format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) format specifier, determines additional arguments.

**Input parameter:** `args`

* Additional arguments required by `audio_format`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

#### fromAudioFile
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromAudioFile(const char *filename, const char *mode,
                        SnsrStreamAudioFormat format, ...);
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r` to open for reading, or `w` for writing.

**Input parameter:** `format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromAudioFile(String filename, String mode);
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r` to open for reading, or `w` for writing.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_audio_file(
    cls,
    filename: str,
    mode: str = "r",
    audio_format: snsr.StreamAudioFormat = snsr.StreamAudioFormat.DEFAULT,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r` to open for reading, or `w` for writing.

**Input parameter:** `audio_format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a [RIFF WAV] audio file.

This is equivalent to the code snippet below, with the difference
that the RIFF header is updated after each write to the stream.

<!-- tab: c -->

**C/C++**

```c
SnsrStream s;
s = snsrStreamFromAudioStream(snsrStreamFromFileName(filename, mode),
                              format);
```
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
SnsrStream s;
s = SnsrStream.fromAudioStream(SnsrStream.fromFileName(filename, mode),
                               SnsrStreamAudioFormat.DEFAULT);
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
s = snsr.Stream.from_audio_stream(
    snsr.Stream.from_filename(filename, mode),
    snsr.StreamAudioFormat.DEFAULT,
)
```
<!-- /tab -->

Only a subset of the [fopen()][] modes are supported:

- `r` for read-only access.
- `w` for write-only access, truncating the file to zero on open.

This stream type supports re-opening. The behavior follows that of
[fopen()][] with the given access mode.

**Also see these related items:** [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream), [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename)

#### fromAudioStream
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromAudioStream(SnsrStream a, SnsrStreamAudioFormat format, ...);
```

**Parameters and return value:**

**Input parameter:** `a`

* Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromAudioStream(SnsrStream a, SnsrStreamAudioFormat format);
```

**Parameters and return value:**

**Input parameter:** `a`

* Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_audio_stream(
    cls,
    stream: snsr.Stream,
    audio_format: snsr.StreamAudioFormat = snsr.StreamAudioFormat.DEFAULT,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `stream`

* Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `audio_format`

* [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Converts stream audio format.

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on an existing one. The new stream produces audio
in `format`, converting as needed.

This implementation reads the audio format header in the source stream upon
opening. If this is a known, but unsupported format, `fromAudioStream` will
report an error. If the format isn't known, it assumes that the data
are headerless little-endian 16-bit LPCM audio samples.

_The current implementation supports the 16-bit LPCM RIFF WAVE format,
sampled at 16 kHz, for a single channel only. The `format` parameter
must be set to [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default)._

**Note:**

When this stream type is used for output, all stream data will
be buffered in memory until the stream is closed. The audio header and
the data will then be written to the encapsulated stream.

If the final destination is a file on disk, use [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile) instead.

**Also see these related items:** [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile)

#### fromBuffer
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromBuffer(size_t initialSizeInBytes, size_t maxSizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `initialSizeInBytes`

* The minimum size of the allocated ring buffer.

**Input parameter:** `maxSizeInBytes`

* The limit the ring buffer is allowed to expand to.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromBuffer(long initialSizeInBytes, long maxSizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `initialSizeInBytes`

* The minimum size of the allocated ring buffer.

**Input parameter:** `maxSizeInBytes`

* The limit the ring buffer is allowed to expand to.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_buffer(
    cls,
    initial_size: int = 2**10,
    max_size: int = 2**20,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `initial_size`

* The minimum size of the allocated ring buffer.

**Input parameter:** `max_size`

* The limit the ring buffer is allowed to expand to.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on a ring buffer with FIFO semantics.

The initial buffer will be large enough to hold `initialSizeInBytes`
bytes, and will dynamically grow up to `maxSizeInBytes`.

If this ring buffer cannot be expanded when needed, [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) will
set the [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) condition on the stream.

This stream type does not support re-opening.

**Note:**

Calls to [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) on streams of this type never block.
`read` returns [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) if the buffer runs empty.

#### fromCode
<!-- tab: c -->

**C/C++**

```c
// Opaque type used for task models converted to C code.
typedef const struct SnsrCodeModel_ *SnsrCodeModel;

SNSR_API SnsrStream
snsrStreamFromCode(SnsrCodeModel identifier);
```

**Parameters and return value:**

**Input parameter:** `identifier`

* `SnsrCodeModel` handle.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on a model compiled to code.

The `SnsrCodeModel` handle is an identifier loaded from an object file,
compiled from C code generated by a call to [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) with the
[SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source) or [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram) format types.

These data are typically loaded into the read-only `TEXT` (code) segment.

Use this on platforms where the `TEXT` segment is read from ROM to reduce
the amount of RAM a model needs to run.

**Warning:**

You must compile the generated model code with the same alignment
and `struct` packing requirements that the TrulyNatural SDK library was built with.
Most platforms use the toolchain defaults.

 If you compile the model code with an incompatible alignment
[load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) will fail and report a [STREAM](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error with [detail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail):
`"SnsrCodeModel compiled with incompatible -fpack-struct alignment"`.

**Example:**

```c
extern SnsrCodeModel snsrmodel;
SnsrSession s;
snsrNew(&s);
snsrLoad(s, snsrStreamFromCode(snsrmodel));
```

**Also see these related items:** [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source), [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram), [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit)

<!-- /tab -->

<!-- tab: java -->

**Java**

_The Java language binding does support models converted to code._
<!-- /tab -->

<!-- tab: py -->

**Python**

_This constructor is not available in the Python language binding. Use
[fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) over packaged `.snsr` bytes instead._
<!-- /tab -->

#### fromFILE
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromFILE(FILE *handle, SnsrStreamMode mode);
```

**Parameters and return value:**

**Input parameter:** `handle`

* A standard library `FILE *`, typically `stdout` or `stderr`.

**Input parameter:** `mode`

* [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), open for reading or writing, but not both.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new `SnsrStream` from on a `<stdio.h>` `FILE *` handle.

Calls to [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) on this handle will not close the
encapsulated `FILE *`.

This stream type does not support re-opening.

**Example:**

```c
SnsrStream out = snsrStreamFromFILE(stderr, SNSR_ST_MODE_WRITE);
snsrStreamOpen(out);
snsrStreamPrint(out, "hello world\n");
snsrRelease(out);
```

**Also see these related items:** [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename)

<!-- /tab -->

<!-- tab: java -->

**Java**

_The Java language binding does support `FILE *` handles._
<!-- /tab -->

<!-- tab: py -->

**Python**

_This constructor is not available in the Python language binding. Use
[fromFilename](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) or [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) instead._
<!-- /tab -->

#### fromFileName
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromFileName(const char *filename, const char *mode);
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r`, `w`, or `a` followed by an optional `b` or `t`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromFileName(String filename, String mode);
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r`, `w`, or `a` followed by an optional `b` or `t`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_filename(cls, filename: str, mode: str = "r") -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `filename`

* The name of a file to open.

**Input parameter:** `mode`

* `r`, `w`, or `a` followed by an optional `b` or `t`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a file on disk.

Only a subset of the [fopen()][] modes are supported:

 - `r` for read-only access.
 - `w` for write-only access, truncating the file to zero on open.
 - `a` for write-only append access.

 `mode` supports an optional second character:

 - `b` for binary mode. This is the default if `mode` contains
    just one character.
 - `t` for text mode. On Windows this translates line-endings
   between `\n` and `\r\n`.

This stream type supports re-opening. The behavior follows that of
[fopen()][] with the given access mode.

<!-- tab: java -->

**Java**

**Note:**

On Android, `SnsrStream.fromFileName()` includes support for reading from the
the compressed application `assets/` directory.

<!-- /tab -->

#### fromMemory
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromMemory(void *buffer, size_t bufferSize, SnsrStreamMode mode);
```

**Parameters and return value:**

**Input-output parameter:** `buffer`

* Pointer to a memory segment.

**Input parameter:** `bufferSize`

* The size of `buffer` in bytes.

**Input parameter:** `mode`

* [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), to open for reading or writing, but not both.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a segment of memory.

[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) operations are limited to the first `bufferSize` bytes
of the segment starting at `buffer`.

This stream type does not support re-opening.

**Example:**

```c
char *data = malloc(1000);
SnsrStream b = snsrStreamFromMemory(data, 1000, SNSR_ST_MODE_WRITE);
snsrStreamOpen(b);
snsrStreamPrint(b, "hello world, data=%p\n", data);
snsrRelease(b);
printf("wrote: %s\n", data);
free(data);
```

**Also see these related items:** [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromMemory(byte[] store, SnsrStreamMode mode);
```

**Parameters and return value:**

**Input-output parameter:** `store`

* Data made available to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `mode`

* [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), to open for reading or writing, but not both.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a segment of memory.

This stream type does not support re-opening.

**Note:**

Changes written through the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) API will only be visible in `store`
_after_ the stream instance is [released](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release).

Read behavior is undefined if `store` is modified after the `stream` is created.

**Also see these related items:** [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_memory(
    cls,
    buffer: bytes | bytearray | memoryview,
    mode: snsr.StreamMode,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input-output parameter:** `buffer`

* Data made available to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `mode`

* [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), to open for reading or writing, but not both.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

For [READ](https://doc.sensory.com/tnl/7.8/api/io.md#st_mode_read), `buffer` may be `bytes`, `bytearray`, or
`memoryview`. For [WRITE](https://doc.sensory.com/tnl/7.8/api/io.md#st_mode_write), pass `bytearray` or a writable
`memoryview`; immutable `bytes` raises `TypeError`.

<!-- /tab -->

#### fromOpenStream
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromOpenStream(SnsrStream source, size_t sizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `source`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

**Input parameter:** `sizeInBytes`

* New stream read or write limit.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromOpenStream(SnsrStream source, long sizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `source`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

**Input parameter:** `sizeInBytes`

* New stream read or write limit.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_open_stream(cls, source: snsr.Stream, size: int) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `source`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

**Input parameter:** `size`

* New stream read or write limit.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from an existing, open stream.

The new stream mode (read or write) matches that of the `source` stream.
Read and write operations are passed through to the `source` stream, but
the number of bytes read or written is limited to `sizeInBytes`.

Input and output operations will set the stream status to [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof)
when this limit is reached.

Closing this stream will not close `source`.

#### fromProvider
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStream_alloc(SnsrStream_Vmt *def, void *data, int readable, int writable);

#define snsrStreamFromProvider(p, d, r, w) snsrStream_alloc(p, d, r, w)
```

**Parameters and return value:**

**Input parameter:** `def`

* Table of [function pointers](https://doc.sensory.com/tnl/7.8/api/io.md#provider) that define the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) type.

**Input parameter:** `data`

* User pointer for stream context.

**Input parameter:** `readable`

* `1` if the stream supports reading, `0` if not.

**Input parameter:** `writable`

* `1` if the stream supports writing, `0` if not.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

The `def` [virtual method table](https://doc.sensory.com/tnl/7.8/api/io.md#provider) defines the behavior of the new stream.

`data` is an arbitrary pointer that can be retrieved from the
[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle with [getData](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getData).
Use this to hold data specific to the instance.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromProvider(SnsrStream.Provider custom);

static SnsrStream fromProvider(SnsrStream.Provider custom, SnsrStreamMode mode);
```

**Parameters and return value:**

**Input parameter:** `custom`

* An object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface.

**Input parameter:** `mode`

* [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), open for reading or writing, but not both.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

`#!java static SnsrStream fromProvider(SnsrStream.Provider custom)` creates a new
stream that supports both reading and writing.

`#!java static SnsrStream fromProvider(SnsrStream.Provider custom, SnsrStreamMode mode)` creates
a new stream that supports either reading or writing, but not both.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_provider(
    cls,
    open: Callable[[], None] = lambda: None,
    close: Callable[[], None] = lambda: None,
    release: Callable[[], None] = lambda: None,
    read: Callable[[memoryview], int | None] | None = None,
    write: Callable[[memoryview], int | None] | None = None,
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `open`

* Function invoked when the stream opens.

**Input parameter:** `close`

* Function invoked when the stream closes.

**Input parameter:** `release`

* Function invoked when the native handle is released.

**Input parameter:** `read`

* Callback that fills a writable `memoryview`, or `None`.

**Input parameter:** `write`

* Callback that consumes a read-only `memoryview`, or `None`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

`read` and `write` callbacks receive zero-copy `memoryview` objects. Do not keep
references to those views after the callback returns.

<!-- /tab -->

#### fromStreams
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromStreams(SnsrStream a, SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `a`

* First source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `b`

* Second source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromStreams(SnsrStream a, SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `a`

* First source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `b`

* Second source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_streams(cls, a: snsr.Stream, b: snsr.Stream) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `a`

* First source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `b`

* Second source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

<!-- /tab -->

Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) by concatenating two streams.

Streams `a` and `b` will be each be opened exactly once. These should
be unopened ([getMeta](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta) for [OPEN_COUNT](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta)
must be `0`) when `fromStreams` is called.

The new stream will read from (or write to) stream `a` until end-of-stream
is reached, then switch to stream `b` until that is exhausted,
at which point [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) returns [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof).

Streams `a` and `b` must have identical modes. If one stream was created
for reading, and the other for writing, this function will set the
error code to [WRONG_MODE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc).

Closing this stream will close the current source stream. The next
open call will open the next source stream. When no further source
streams remain [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) returns [CANNOT_REOPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc).

#### fromString
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream
snsrStreamFromString(const char *store);
```

**Parameters and return value:**

**Input parameter:** `store`

* Data made available to the new stream. Terminated with `\0`.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from string data.

Equivalent to: `#!c snsrStreamFromMemory(store, strlen(store), SNSR_ST_MODE_READ);`

This stream type does not support re-opening.

**Also see these related items:** [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
static SnsrStream fromString(String store);
```

**Parameters and return value:**

**Input parameter:** `store`

* Data made available to the new stream.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from `String` data.

**Note:**

[Read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) behavior is undefined if `store` is modified
after calling `SnsrStream.fromString(store)`.

**Also see these related items:** [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_string(cls, text: str) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `text`

* Text made available to the new stream.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

The string is encoded as UTF-8 and retained for the lifetime of the returned
`Stream`.

<!-- /tab -->

#### raise
<!-- tab: c -->

**C/C++**

```c
typedef SnsrRC (*SnsrStreamEvent)(SnsrStream s, void *data);

typedef void (*SnsrDataRelease)(const void *data);

SNSR_API SnsrStream
snsrStreamRaise(SnsrStreamEvent e, SnsrDataRelease r, void *data);
```

**Parameters and return value:**

**Input parameter:** `e`

* Function to call when this stream is opened. Must not be `NULL`.

**Input parameter:** `r`

* A function that releases `data` when this stream is deallocated. Use `NULL` if no clean-up is required.

**Input parameter:** `data`

* User data pointer, for context.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Inserts an event marker into a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Use this stream type with [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) to embed events in a stream.

Creates a new stream that is readable, but provides no data.
Any [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) operation will immediately
return [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof).

Calls `#!c e(b, data)` when this stream is opened. This function should return
[OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) unless it encounters an error.

Calls `#!c r(data)` when this stream is released, unless `r == NULL`.
This function should release the `data` handle.

**Also see these related items:** [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public interface Raise {
  public static final long OK = 0;
  public static final long EOF = -1;
  public static final long INTERRUPTED = -2;
  public static final long INVALID_ARG = -3;
  public static final long NOT_IMPLEMENTED = -4;
  public static final long ERROR = -5;
  public static final long NOT_OPEN = -6;
  public long onOpen();
}

public static SnsrStream raise(SnsrStream.Raise jevent);
```

**Parameters and return value:**

**Input parameter:** `jevent`

* An object that implements the `SnsrStream.Raise` interface.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Inserts an event marker into a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Use this stream type with [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) to embed events in a stream.

Creates a new stream that is readable, but provides no data.
Any [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) operation will immediately
return [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof).

Calls the `#!java long onOpen()` interface method when this stream is opened.
This method should return `Raise.OK` unless it encounters an error.

**Also see these related items:** [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@classmethod
def from_event(
    cls,
    callback: Callable[[snsr.Stream], snsr.RC | None],
) -> snsr.Stream: ...
```

**Parameters and return value:**

**Input parameter:** `callback`

* Function invoked when this stream is opened.

**Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance.

The callback receives the wrapper stream and should return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) or
`None` on success. Exceptions are surfaced through the normal Python error path.

<!-- /tab -->

### Operations

These functions or methods implement basic [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) operations, such as
[opening](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open), [reading](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), [writing](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write), and
[closing](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close). Utility functions [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print) formatted data to a stream,
and [inspect stream state](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta).

The [error state](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) of a [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle persists only until the next operation on the stream.

These functions do not change the stream handle reference counts. They are therefore safe
to use on handles where the reference count is zero.

#### atEnd
<!-- tab: c -->

**C/C++**

```c
SNSR_API int
snsrStreamAtEnd(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * A boolean value, `1` if at the end of the stream, `0` if not.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public int atEnd();
```

**Parameters and return value:**

**Return value:** * A boolean value, `1` if at the end of the stream, `0` if not.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def at_end(self) -> bool: ...
```

**Parameters and return value:**

**Return value:** * `True` if at the end of the stream, `False` if not.

<!-- /tab -->

Reports stream end status.

Returns `1` if the stream has reached its end,
equivalent to [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) `==` [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof).

Follows Unix semantics:

- The end-of-stream indicator is only valid after a read attempt.
- A read on stream `b` could very well return `0`, even if
 `atEnd` returned `0` just before attempting the read.

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC)

#### close
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrRC
snsrStreamClose(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
SnsrRC close();
```

**Parameters and return value:**

**Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def close(self) -> None: ...
```
<!-- /tab -->

Closes an open stream.

Flushes any remaining buffered output and discards any remaining buffered input.
This does not destroy the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) data structure, use [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release) to do so.

Closing a stream that is not open is _not_ an error.

Streams that are still open when they're released are explicitly closed before
the data structure is torn down.

#### copy
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamCopy(SnsrStream dst, SnsrStream src, size_t sizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `dst`

* Destination [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `src`

* Source `Stream`.

**Input parameter:** `sizeInBytes`

* The number of bytes to copy from `src` to `dst`.

**Return value:** * The number of bytes written to `dst`.

Copies from [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Ensures that both streams are open, copies `sizeInBytes`
bytes from `src` to `dst`, then returns the number of bytes
successfully written to `dst`.

If an error occurred (including an end-of-stream condition on either
`dst` or `src`) the return value will be less than `sizeInBytes`.

This function duplicates errors that occur in `src` to `dst`.
Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect these.

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long copy(SnsrStream src) throws java.io.IOException;

long copy(SnsrStream src, long sizeInBytes) throws java.io.IOException;
```

**Parameters and return value:**

**Input parameter:** `src`

* Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `sizeInBytes`

* The number of bytes to copy from `src` into this stream.

**Return value:** * The number of bytes copied to this `Stream` instance.

Copies from [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Ensures that both streams are open, copies either `sizeInBytes`
bytes, or all available data if `sizeInBytes` isn't specified,
from `src` to this stream, then returns the number of bytes
successfully written.

If an error occurred (including an end-of-stream condition on either
`dst` or `src`) the return value will be less than `sizeInBytes`.

These methods duplicate errors that occur in `src` to `dst`;
use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect these.

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def copy(self, source: snsr.Stream, size: int) -> int: ...
```

**Parameters and return value:**

**Input parameter:** `source`

* Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `size`

* The number of bytes to copy from `source` into this stream.

**Return value:** * The number of bytes copied to this `Stream` instance.

<!-- /tab -->

#### errorDetail
<!-- tab: c -->

**C/C++**

```c
SNSR_API const char *
snsrStreamErrorDetail(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * A detailed message describing the most recent reason for failure in `b`. The memory pointed to is owned by this library and must not be released. It is not reference-counted. This pointer remains valid only until the next API call on `b`.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
String errorDetail();
```

**Parameters and return value:**

**Return value:** * A detailed message describing the most recent reason for failure on this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@property
def error_detail(self) -> str: ...
```

**Parameters and return value:**

**Return value:** * A detailed message describing the most recent reason for failure on this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

<!-- /tab -->

Retrieves a detailed stream error message.

This human-readable error message containing the reason for failure.
Use for display or logging only, as the content of the message is
unspecified and system-specific.

Do not parse this to determine program flow,
use the [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) return code instead.

#### getDelim
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamGetDelim(SnsrStream b, void *buffer, size_t bufferSize, int delim);
```

**Parameters and return value:**

**Input parameter:** `b`

* Input stream.

**Output parameter:** `buffer`

* Destination buffer.

**Input parameter:** `bufferSize`

* Size of `buffer` in bytes.

**Input parameter:** `delim`

* delimiter character to search for.

**Return value:** * The number of characters read and placed into `buffer`.

Reads one line from a stream.

Reads a line from stream `b`, delimited by the character `delim`, into
`buffer`. This is similar to [`getdelim()`][getdelim], except that it operates on
[stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and does not allocate memory for the destination buffer.

`getDelim` ensures that `b` is open, reads up to `bufferSize - 1` bytes from
`b` into `buffer`, stops when `delim` has been read (`buffer` will include `delim`).
It terminates the string in `buffer` with `\0` and returns the number of characters
read (not including the terminating `\0`).

If the delimiter is not found after reading `bufferSize - 1` bytes, the
error code in `b` is set to [DELIM_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc).

`buffer` must not be `NULL` and `bufferSize` must be `>= 2`.

`buffer` will contain all characters read and will be terminated with `\0`,
 even if an error occurs.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long getDelim(byte[] buffer, int delim) throws java.io.IOException;
```

**Parameters and return value:**

**Output parameter:** `buffer`

* Destination buffer, must be at least two bytes long.

**Input parameter:** `delim`

* delimiter character to search for.

**Return value:** * The number of characters read and placed into `buffer`.

Reads one line from a stream.

Reads a line from stream `b`, delimited by the character `delim`, into
`buffer`. This is similar to [`getdelim()`][getdelim], except that it operates on
[stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and does not allocate memory for the destination buffer.

`getDelim` ensures that `b` is open, reads up to `buffer.length - 1` bytes from
`b` into `buffer`, stops when `delim` has been read (`buffer` will include `delim`).
It terminates the string in `buffer` with `\0` and returns the number of characters
read (not including the terminating `\0`).

If the delimiter is not found after reading `buffer.length - 1` bytes, the
error code in `b` is set to [DELIM_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc).

`buffer` must not be `null` and `buffer.length` must be `>= 2`.

`buffer` will contain all characters read and will be terminated with `\0`,
even if an error occurs.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def get_delim(self, max_size: int = 4096, delimiter: str = "\n") -> bytes: ...
def readline(self, size: int | None = None) -> bytes: ...
def readlines(self, hint: int | None = None) -> list[bytes]: ...
```

**Parameters and return value:**

**Input parameter:** `max_size`

* Maximum number of bytes to scan.

**Input parameter:** `delimiter`

* Single-character delimiter to search for.

**Return value:** * Bytes read, with the delimiter stripped.

Python strips the delimiter from the returned bytes. A blank line yields `b""`,
not `b"\n"`. `readline()` raises `snsr.Error(snsr.RC.DELIM_NOT_FOUND)` if no
newline is found within the size limit.

<!-- /tab -->

#### getMeta
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamGetMeta(SnsrStream b, SnsrStreamMeta key);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to query.

**Input parameter:** `key`

* [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) query type.

**Return value:** * The value for `key`.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long getMeta(SnsrStreamMeta key);
```

**Parameters and return value:**

**Input parameter:** `key`

* [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) query type.

**Return value:** * The value for `key`.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def get_meta(self, key: snsr.StreamMeta) -> int: ...
@property
def closed(self) -> bool: ...
def readable(self) -> bool: ...
def seekable(self) -> bool: ...
def writable(self) -> bool: ...
```

**Parameters and return value:**

**Input parameter:** `key`

* [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) query type.

**Return value:** * The value for `key`.

<!-- /tab -->

Queries stream metadata.

Returns [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) metadata, selected by `key`.
If an error occurs this function returns `0` and sets the error state in
the stream. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to check the error state.

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta)

#### open
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrRC
snsrStreamOpen(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to open.

**Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
SnsrRC open() throws java.io.IOException;
```

**Parameters and return value:**

**Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def open(self) -> None: ...
```
<!-- /tab -->

Opens a stream.

Read and write operations are valid only on open streams, and
newly created streams are not open.

Some stream types can be closed and re-opened. See the [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) section for details.
If re-opening is not supported `open` will return [CANNOT_REOPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc)
when an attempt is made to open it a second time.

#### print
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamPrint(SnsrStream b, const char *format, ...);
```

**Parameters and return value:**

**Input parameter:** `b`

* Output [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Input parameter:** `format`

* [printf()][] style format string.

**Input parameter:** `...`

* Arguments specified by `format`.

**Return value:** * The number of bytes written to `b`, or `0` if an error occurred.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long print(String format, Object... args) throws java.io.IOException;
```

**Parameters and return value:**

**Input parameter:** `format`

* [printf()][] style format string.

**Input parameter:** `args`

* Arguments specified by `format`.

**Return value:** * The number of bytes written to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), or `0` if an error occurred.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def print(self, text: str) -> int: ...
```

**Parameters and return value:**

**Input parameter:** `text`

* Text to write to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * The number of bytes written.

<!-- /tab -->

Prints a formatted string to a stream.

This function is similar to [printf()][], but operates on a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream)
instead of a `FILE *`.

`print` will open the output stream if it's not already open.

If an error occurs this function returns `0` and sets the error state in
`b`. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to check the error state.

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [printf()][]

#### rC
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrRC
snsrStreamRC(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for `b`.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
SnsrRC rC();
```

**Parameters and return value:**

**Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
@property
def rc(self) -> snsr.RC: ...
```

**Parameters and return value:**

**Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

<!-- /tab -->

Retrieves the most recent return code for a stream.

**Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd)

#### read
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamRead(SnsrStream a, void *buffer, size_t size, size_t nitems);
```

**Parameters and return value:**

**Input parameter:** `a`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to read from.

**Output parameter:** `buffer`

* Memory to write to.

**Input parameter:** `size`

* The size of an item, in bytes.

**Input parameter:** `nitems`

* The number of items to read.

**Return value:** * The number of items read.

Reads binary data from a stream.

Opens the stream if it is not already open, reads `nitems` items, each `size` bytes long,
into `buffer` and returns the number of items read.

If either `size` or `nitems` is zero this function returns `0` without
reading anything.

A short read (fewer than `nitems`) will occur only if the end of the stream
was reached before `nitems` were read, or if an error occurred.
The stream return code will be set appropriately.
Use [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd) or [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to distinguish between these conditions.

If the end of the stream is encountered in the middle of an object, it
returns the number of complete items read. The partial object is
discarded and the stream remains in the end-of-stream condition.

Read operations block until all the requested data have been read, or
an error or end-of-stream occurs.

**Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
int read() throws java.io.IOException;

long read(byte[] buffer) throws java.io.IOException;

long read(byte[] buffer, long offset, long count) throws java.io.IOException;
```

**Parameters and return value:**

**Return value:** * `int` value of the single byte read, or `Integer.MIN_VALUE` if an error occurred.

**Output parameter:** `buffer`

* Destination buffer where read data are copied to.

**Input parameter:** `offset`

* Number of bytes from the beginning of `buffer` where writing will start.

**Input parameter:** `count`

* Number of bytes to read from the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * `long` the number of bytes read.

Reads binary data from a stream.

These methods open the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) if it's not already open.

`#!java int read()` reads a single byte from the stream.

`#!java long read(byte[] buffer)` attempts to fill the entire `buffer` with data from the stream
and returns the number of bytes read.

`#!java long read(byte[] buffer, long offset, long count)` reads up to `count` bytes for the stream into
`buffer` starting at `offset` bytes from the start. It returns the number of bytes read.
A short read (fewer than `count` bytes) will occur if `buffer` fills up first, the stream ends, or an
error occurs. Use [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd) or [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to distinguish between these conditions.

Read operations block until all the requested data have been read, or an error or end-of-stream occurs.

**Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def read(self, size: int) -> bytes: ...
def readinto(self, buffer: bytearray | memoryview) -> int: ...
```

**Parameters and return value:**

**Input parameter:** `size`

* Maximum number of bytes to read.

**Output parameter:** `buffer`

* Writable destination buffer.

**Return value:** * Bytes read, or the number of bytes copied into `buffer`.

`read(size)` allocates and returns a fresh `bytes`. Use `readinto(buffer)` in
hot loops to reuse caller-owned storage; `bytes` is rejected because it is
immutable.

<!-- /tab -->

#### release
<!-- tab: c -->

**C/C++**

_The C language binding uses reference counting to manage object lifetimes, see [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) in the [memory management](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management) section._
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public void release();
```

Releases the native library handle encapsulated by the [SnsrStream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) class.

This method releases native handles immediately. Use this to free
up resources without having to depend on garbage collection cycle eventually running.

*No instance methods must be invoked after calling this method.*

**Example:**

```java
SnsrStream s = SnsrStream.fromAudioDevice();
// ...
s.release();
s = null;
```

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def release(self) -> None: ...
```

Releases the native stream handle immediately. Prefer
`with Stream.from_*(...) as s:` when a scope naturally owns the stream.
No instance methods that touch the handle may be invoked after `release()`.

<!-- /tab -->

#### skip
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamSkip(SnsrStream a, size_t size, size_t nitems);
```

**Parameters and return value:**

**Input parameter:** `a`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to read from.

**Input parameter:** `size`

* The size of an item, in bytes.

**Input parameter:** `nitems`

* The number of items to read and discard.

**Return value:** * The number of items read and discarded.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long skip(long count) throws java.io.IOException;

long skip(long size, long nitems) throws java.io.IOException;
```

**Parameters and return value:**

**Input parameter:** `size`

* The size of an item, in bytes. `size == 1` if not specified.

**Input parameter:** `nitems`

* The number of items to read and discard.

**Return value:** * The number of items read and discarded.

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def skip(self, size: int) -> int: ...
```

**Parameters and return value:**

**Input parameter:** `size`

* Number of bytes to read and discard.

**Return value:** * The number of bytes read and discarded.

<!-- /tab -->

Reads from a stream and discards the results.

This function is similar to [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), but discards the read data
instead of writing it to a memory buffer.

**Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read)

#### write
<!-- tab: c -->

**C/C++**

```c
SNSR_API size_t
snsrStreamWrite(SnsrStream a, const void *buffer, size_t size, size_t nitems);
```

**Parameters and return value:**

**Input parameter:** `a`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to write to.

**Output parameter:** `buffer`

* Memory to read from.

**Input parameter:** `size`

* The size of an item, in bytes.

**Input parameter:** `nitems`

* The number of items to write.

**Return value:** * The number of items written.

Writes from a buffer to a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Opens the stream if it is not already open, then writes `nitems` from `buffer`,
each `size` bytes long, to the stream. Returns the number of items written.

Returns less than `nitems` only if an error occurred. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC)
to obtain the error code.

Write operations block until the requested data have been transferred
to the underlying implementation, but may return well before the
data have reached their final destination (written to disk, played from
a speaker, etc.)

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long write(int oneByte) throws java.io.IOException;

long write(byte[] buffer) throws java.io.IOException;

long write(byte[] buffer, long offset, long count) throws java.io.IOException;
```

**Parameters and return value:**

**Input parameter:** `oneByte`

* A single source byte to write.

**Input parameter:** `buffer`

* Source buffer data are read from.

**Input parameter:** `offset`

* Number of bytes from the beginning of `buffer` where reading will start.

**Input parameter:** `count`

* Number of bytes to write to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

**Return value:** * The number of bytes written.

Writes data to a stream.

`#!java long write(int oneByte)` writes a single byte to this [SnsrStream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and
returns `1`, or `0` in case of an error.

`#!java long write(byte[] buffer)` writes `buffer.length` bytes from `buffer` to the stream and
returns the number of bytes written.

`#!java long write(byte[] buffer, long offset, long count)` writes `count` bytes from `buffer`
starting at `offset` bytes from the beginning to the stream. It returns the number of bytes
written.

These methods open the stream if it's not already open. The number of bytes written will be
fewer than the requested amount only if an error occurs. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to identify such errors.

Write operations block until the requested data have been transferred to the underlying
implementation, but may return well before the data have reached their final destination
(written to disk, played from a speaker, etc.)

**Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def write(self, data: bytes) -> int: ...
```

**Parameters and return value:**

**Input parameter:** `data`

* Bytes to write.

**Return value:** * The number of bytes written.

<!-- /tab -->

### User-defined

This section describes the [provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) data structure used with [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) to
create custom [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) types. Each stream must implement at least a subset of the
[open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open), [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close), [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release),
[read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read), and [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) methods.

<!-- tab: c -->

**C/C++**

The `data` argument to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) should point to a `struct` that holds the
entire context needed for each instance of a custom stream. Retrieve this pointer
in the implementation functions with a call to [getData](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getData).

Use [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) and [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail) to report any errors encountered.
<!-- /tab -->

<!-- tab: java -->

**Java**

The `custom` argument to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) is an object that implements the
[SnsrStream.Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface. This object should hold the entire context
needed for each instance of a custom stream.
<!-- /tab -->

<!-- tab: py -->

**Python**

Python custom streams pass callables directly to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider). Those callables
can close over the context needed by the stream instance; no separate provider
object or user-data pointer is exposed.
<!-- /tab -->

#### Provider

<!-- tab: c -->

**C/C++**

```c
typedef struct {
  const char *name; // Stream identifier
  SnsrRC (*open)(SnsrStream b); // (1)!
  SnsrRC (*close)(SnsrStream b); // (2)!
  void   (*release)(SnsrStream b); // (3)!
  size_t (*read)(SnsrStream b, void *data, size_t sizeInBytes); // (4)!
  size_t (*write)(SnsrStream b, const void *data, size_t sizeInBytes); // (5)!
} SnsrStream_Vmt;
```

1. _(optional)_ **Also see these related items:** [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) Opens the stream
2. _(optional)_ **Also see these related items:** [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) Closes the stream
3. _(optional)_ **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release) Releases stream data
4. _(optional)_ **Also see these related items:** [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read) Reads from the encapsulated data source
5. _(optional)_ **Also see these related items:** [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) Writes to the encapsulated data sink

[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) virtual method table.

This method table defines stream behavior when used as an argument to
[fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider). This struct must remain valid for the entire life of
all the streams of this type. Static allocation is recommended.

When one of these functions return ([open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open), [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close))
or [set](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) ([read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read), [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write))
an [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), and additional
error detail is available, it should also set a detailed human-readable
error message using [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail).

Set the fields for optional members without implementations to `NULL`.

**Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public interface Provider {
  public static final long OK = 0; // (6)!
  public static final long EOF = -1; // (7)!
  public static final long INTERRUPTED = -2; // (8)!
  public static final long INVALID_ARG = -3; // (9)!
  public static final long NOT_IMPLEMENTED = -4; // (10)!
  public static final long ERROR = -5; // (11)!
  public static final long NOT_OPEN = -6; // (12)!

  public long onOpen() throws IOException; // (1)!
  public long onClose() throws IOException; // (2)!
  public void onRelease(); // (3)!
  public long onRead(byte[] buffer) throws IOException; // (4)!
  public long onWrite(byte[] buffer) throws IOException; // (5)!
}
```

1. **Also see these related items:** [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) Opens the stream
2. **Also see these related items:** [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) Closes the stream
3. **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release) Releases stream data
4. **Also see these related items:** [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read) Reads from the encapsulated data source
5. **Also see these related items:** [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) Writes to the encapsulated data sink
6. Operation successful
7. End-of-stream reached
8. The read or write operation was interrupted
9. Argument validation failed
10. This operation is not implemented, e.g. write operation on a read-only stream
11. All errors that are not `EOF`, `INTERRUPTED`, `INVALID_ARG`, `NOT_IMPLEMENTED`, or `NOT_OPEN`
12. Attempt was made to use a stream that is not open

Custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) interface specification.

Use this interface to add new stream types.

Each [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) type exposes a single [constructor](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) used to create a new instances of this type. The constructor function sets up the required data structures and copies arguments into these structures for use by the [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) method.

The constructor must not open the underlying data stream. The [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) method
will do this instead. Delaying the open operation allows for function compositions, such as a stream that is a concatenation of other streams.

Use [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) to create an instance from an object that implements this
`SnsrStream.Provider` interface.

**Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
open: Callable[[], None]  # (1)!
close: Callable[[], None]  # (2)!
release: Callable[[], None]  # (3)!
read: Callable[[memoryview], int | None] | None  # (4)!
write: Callable[[memoryview], int | None] | None  # (5)!
```

1. **Also see these related items:** [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) Opens the stream
2. **Also see these related items:** [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) Closes the stream
3. **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release) Releases stream data
4. **Also see these related items:** [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read) Reads from the encapsulated data source
5. **Also see these related items:** [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) Writes to the encapsulated data sink

Pass these callables to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider). The `read` and `write` callbacks are
optional; pass at most one direction depending on the custom stream. `read`
receives a writable zero-copy `memoryview` over the SDK destination buffer, and
`write` receives a read-only zero-copy `memoryview` over SDK source bytes.

Do not keep either `memoryview` after the callback returns.

<!-- /tab -->

##### open
<!-- tab: c -->

**C/C++**

```c
SnsrRC (*open)(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Opens the underlying data stream.

Called in response to an [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) API call, and only on
[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are not already open.

Must open the underlying stream in binary mode, unless documented otherwise.

Must return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the operation succeeded, and an
error code if the resource could not be opened.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public long onOpen() throws IOException;
```

**Parameters and return value:**

**Return value:** * `Provider.OK` on success, `Provider.NOT_OPEN` on failure.

Opens the underlying data stream.

Called in response to an [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) API call, and only on
[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are not already open.

Must open the underlying stream in binary mode, unless documented otherwise.

Must return `Provider.OK` if the operation succeeded, or
`Provider.NOT_OPEN` if the resource could not be opened.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def open() -> None: ...
```

Called in response to an [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream)
handles that are not already open. Raise an exception to report failure; the
wrapper sets the stream [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) to [ERROR](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) and attaches the exception text as
detail.

<!-- /tab -->

##### close
<!-- tab: c -->

**C/C++**

```c
SnsrRC (*close)(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Closes the underlying data stream.

Called in response to a [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) API call, and only
on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are currently open.

This function must flush buffered output and discard any remaining
buffered input.

Must return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the operation succeeded, and an error code
if the underlying resource could not be closed.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long onClose() throws IOException;
```

**Parameters and return value:**

**Return value:** * `Provider.OK` on success or `Provider` error code on failure.

Closes the underlying data stream.

Called in response to a [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) API call, and only
on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are currently open.

This function must flush buffered output and discard any remaining
buffered input.

Must return `Provider.OK` if the operation succeeded, and an error code
if the underlying resource could not be closed.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def close() -> None: ...
```

Called in response to a [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream)
handles that are currently open. Flush buffered output and discard any remaining
buffered input. Raise an exception to report failure.

<!-- /tab -->

##### release
<!-- tab: c -->

**C/C++**

```c
void (*release)(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
void onRelease();
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def release() -> None: ...
```
<!-- /tab -->

Releases private [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) data.

Called just before the stream handle is de-allocated.
The stream will have been [closed](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) when this function is called.

Must release all the resources allocated by the [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) function.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

##### read
<!-- tab: c -->

**C/C++**

```c
size_t (*read)(SnsrStream b, void *data, size_t sizeInBytes);
```

**Parameters and return value:**

**Output parameter:** `data`

* Memory location to write to.

**Input parameter:** `sizeInBytes`

* Number of bytes to read from the encapsulated data source.

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

Reads data from the encapsulated source.

Called in response to a [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) API call.

The handle will be open when this function is called, and
`sizeInBytes` will be larger than `0`.

Must read `sizeInBytes` bytes into the buffer pointed to by `data`.

The read must block (i.e. not return) until all the requested data
have been read, or an error occurs.

Must return the number of actual bytes read.
This number of bytes read must be `sizeInBytes`, unless:

* An error occurred, in which case it must call
  [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with an appropriate error code.
* The end of the stream was reached, in which case it must call
  [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof).

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long onRead(byte[] buffer) throws IOException;
```

**Parameters and return value:**

**Output parameter:** `buffer`

* Destination buffer.

**Return value:** * Number of bytes read from the stream.

Reads data from the encapsulated source.

Called in response to a [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) API call.

The handle will be open when this function is called.

Must read `buffer.length` bytes into buffer.

The read must block (i.e. not return) until all the requested data
have been read, or an error occurs.

Must return the number of actual bytes read, unless an error occurred.
Returning fewer than `buffer.length` bytes indicates that the end of the stream was reached.

Must return `Provider.INTERRUPTED` if the read was interrupted.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def read(buffer: memoryview) -> int | None: ...
```

**Parameters and return value:**

**Output parameter:** `buffer`

* Writable zero-copy destination buffer.

**Return value:** * Number of bytes read, or `None` if the entire buffer was filled.

Called in response to a [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) API call. Fill `buffer` with data.
Returning fewer than `len(buffer)` bytes signals end-of-stream; returning `None`
means the buffer was filled completely. Raise an exception to report failure.

<!-- /tab -->

##### write
<!-- tab: c -->

**C/C++**

```c
size_t (*write)(SnsrStream b, const void *data, size_t sizeInBytes);
```

**Parameters and return value:**

**Input parameter:** `data`

* Memory location to read from.

**Input parameter:** `sizeInBytes`

* Number of bytes to write to the encapsulated data source.

**Input parameter:** `b`

* [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * The number of bytes written.

Writes data to the encapsulated data stream.

Called in response to a [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) API call.

The stream handle will be open when this function is called,
and `sizeInBytes` will be larger than `0`.

Must write `sizeInBytes` bytes, reading them from the buffer
pointed to by `data`.

The write must block (i.e. not return) until all of the
requested data have been written to the encapsulated sink,
or an error occurs.

Must return the number of bytes actually written.
This number of bytes must be `sizeInBytes`, unless an error occurred,
in which case it must call [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with an
appropriate error code.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

```java
long onWrite(byte[] buffer) throws IOException;
```

**Parameters and return value:**

**Input parameter:** `buffer`

* Source buffer to read from.

**Return value:** * The number of bytes written to the stream.

Writes data to the encapsulated data stream.

Called in response to a [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) API call.

The stream handle will be open when this function is called.

Must read `buffer.length` bytes from `buffer` and write them to the
encapsulated [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

The write must block (i.e. not return) until all of the requested data have been
written to the encapsulated sink, or an error occurs.

Must return the number of bytes actually written.

Return `Provider.INTERRUPTED` if the write operation was interrupted.

**Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: py -->

**Python**

```python
def write(buffer: memoryview) -> int | None: ...
```

**Parameters and return value:**

**Input parameter:** `buffer`

* Read-only zero-copy source buffer.

**Return value:** * Number of bytes written, or `None` if the entire buffer was consumed.

Called in response to a [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) API call. Consume bytes from the
read-only `buffer`. Returning fewer than `len(buffer)` bytes signals
end-of-stream; returning `None` means the entire buffer was consumed. Raise an
exception to report failure.

<!-- /tab -->

#### getData
<!-- tab: c -->

**C/C++**

```c
SNSR_API void *
snsrStream_getData(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * A pointer to user data.

Gets the user data pointer from a custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Returns the `data` argument passed to the [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)
call that created stream `b`.

**Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

Use the `custom` object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface instead.
<!-- /tab -->

<!-- tab: py -->

**Python**

_Not available in the Python language binding._

Python custom streams pass state through closures captured by the callables
given to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider). There is no exposed user-data pointer to retrieve.
<!-- /tab -->

#### getVmt
<!-- tab: c -->

**C/C++**

```c
SNSR_API SnsrStream_Vmt *
snsrStream_getVmt(SnsrStream b);
```

**Parameters and return value:**

**Input parameter:** `b`

* A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Return value:** * A pointer to the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) `struct` for `b`.

Gets the [virtual method table](https://doc.sensory.com/tnl/7.8/api/io.md#provider) from a custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

Returns the `def` argument passed to the [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)
call that created stream `b`.

**Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

Use the `custom` object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface instead.
<!-- /tab -->

<!-- tab: py -->

**Python**

_Not available in the Python language binding._

The Python wrapper builds the provider table internally from the callables
passed to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), so there is no public virtual-method table handle.
<!-- /tab -->

#### setDetail
<!-- tab: c -->

**C/C++**

```c
SNSR_API void
snsrStream_setDetail(SnsrStream b, const char *format, ...);
```

**Parameters and return value:**

**Input parameter:** `b`

* A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Input parameter:** `format`

* [printf()][] style format string.

**Input parameter:** `...`

* Arguments specified by `format`.

Sets a detailed [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) error message.

Sets the detailed human-readable error message in stream `b` to `format`,
which is a standard C library [printf()][] format string.

This detailed error message is made available through the
[errorDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-errorDetail) API function.

**Also see these related items:** [errorDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-errorDetail), [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

Use `#!java throw new IOException(message);` instead.
<!-- /tab -->

<!-- tab: py -->

**Python**

_Not available in the Python language binding._

Raise an exception from a provider callback instead. The wrapper records the
exception text as stream error detail and surfaces the exception at the next
Python call boundary.
<!-- /tab -->

#### setRC
<!-- tab: c -->

**C/C++**

```c
SNSR_API void
snsrStream_setDetail(SnsrStream b, const char *format, ...);
```

**Parameters and return value:**

**Input parameter:** `b`

* A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle.

**Input parameter:** `code`

* [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) return code, [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success.

This sets the return code for custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) `b` to `code`.

**Note:**

Only a subset of the [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) codes are valid for streams: `code` must be in
the range from [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) to [FORMAT_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc).

**Also see these related items:** [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider)

<!-- /tab -->

<!-- tab: java -->

**Java**

Return one of the `SnsrStream.Provider` error
codes (e.g. `#!java return Provider.NOT_OPEN;`) instead.
<!-- /tab -->

<!-- tab: py -->

**Python**

_Not available in the Python language binding._

For end-of-stream, return fewer bytes than requested (or `0`) from `read` or
`write`. For failures, raise an exception from the provider callback; the
wrapper sets the stream [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) and error detail.
<!-- /tab -->

## Enumerations

[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) functions and methods use the enumerations below to select from a small
set of alternate behaviors.

### StreamAudioFormat
<!-- tab: c -->

**C/C++**

```c
typedef enum {
    SNSR_ST_AF_{name},
    ...
} SnsrStreamAudioFormat;

// Where {name} is from the table below, e.g.: SNSR_ST_AF_DEFAULT
```
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public enum SnsrStreamAudioFormat {
  {name},
  ...
}

// Where {name} is from the table below, e.g.: SnsrStreamAudioFormat.DEFAULT
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
import snsr

snsr.StreamAudioFormat.{name}

# Where {name} is from the table below, e.g.: snsr.StreamAudioFormat.DEFAULT
```
<!-- /tab -->

Audio format specifier for [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream).

The default format is 16-bit little-endian LPCM sampled at 16 kHz.
Most Sensory models expect this format, making the
[DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) and [DEFAULT_LOW_LATENCY](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) the
most salient.

**Also see these related items:** [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice), [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream)

**`DEFAULT`**

_(recommended)_ Default audio stream format.

**`DEFAULT_LOW_LATENCY`**

Low latency, at the expense of higher CPU overhead.

**`LPCM_S16_16K`**

16-bit little-endian LPCM at 16 kHz (default).

**`LPCM_S16_16K_SAMPLES`**

WAV file sample count.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_LPCM_S16_16K_SAMPLES,
    size_t *samples
  );
  ```
  - **Output parameter:** `samples`: Number of audio samples read from the RIFF header.

**`LPCM_S16_16K_LOW_LATENCY`**

Low latency, at the expense of higher CPU overhead.

**Also see these related items:** [DEFAULT_LOW_LATENCY](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat)

**`DEVICE`**

Default format with a user-specified device.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVICE,
    const char *device
  );
  ```
  - **Input parameter:** `device`: Platform-specific device selector.

**`DEVICE_LOW_LATENCY`**

Low-latency default format with a user-specified device.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVICE_LOW_LATENCY,
    const char *device
  );
  ```
  - **Input parameter:** `device`: Platform-specific device selector.

**`DEVICE_RATE_MODE`**

16-bit LE LPCM with user-specified device, sample rate, and mode.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVICE_RATE_MODE,
    const char *device,
    unsigned rate,
    SnsrStreamMode mode
  );
  ```
  - **Input parameter:** `device`: Platform-specific device selector.
- **Input parameter:** `rate`: Sample rate in Hz.
- **Input parameter:** `mode`: Read or write.

**Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode)

**`DEVICE_RATE_MODE_LOW_LATENCY`**

Low-latency 16-bit LE LPCM with user-specified device, sample rate, and mode.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVICE_RATE_MODE_LOW_LATENCY,
    const char *device,
    unsigned it rate,
    SnsrStreamMode mode
  );
  ```
  - **Input parameter:** `device`: Platform-specific device selector.
- **Input parameter:** `rate`: Sample rate in Hz.
- **Input parameter:** `mode`: Read or write.

**Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode)

**`DEVID`**

Default audio format with a user-specified device.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVID,
    int devid
  );
  ```
  - **Input parameter:** `devid`: Platform-specific device selector.

On Windows, `devid` is the device ID used with the Multimedia Extensions, such as
[waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx).

**`DEVID_LOW_LATENCY`**

Low-latency default audio format with a user-specified device.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVID,
    int devid
  );
  ```
  - **Input parameter:** `devid`: Platform-specific device selector.

On Windows, `devid` is the device ID used with the Multimedia Extensions, such as
[waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx).

**`DEVID_RATE_MODE`**

16-bit LE LPCM with user-specified device, sample rate, and mode.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVID,
    int devid,
    unsigned int rate,
    SnsrStreamMode mode
  );
  ```
  - **Input parameter:** `devid`: Platform-specific device selector.
- **Input parameter:** `rate`: Sample rate in Hz.
- **Input parameter:** `mode`: Read or write.

On Windows, `devid` is the device ID used with the Multimedia Extensions, such as
[waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx).

**Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode)

**`DEVID_RATE_MODE_LOW_LATENCY`**

Low-latency 16-bit LE LPCM with user-specified device, sample rate, and mode.

**snsrStreamFromAudioDevice() parameters**

  ```c
  SNSR_API SnsrStream
  snsrStreamFromAudioDevice(
    SNSR_ST_AF_DEVID,
    int devid,
    unsigned int rate,
    SnsrStreamMode mode
  );
  ```
  - **Input parameter:** `devid`: Platform-specific device selector.
- **Input parameter:** `rate`: Sample rate in Hz.
- **Input parameter:** `mode`: Read or write.

On Windows, `devid` is the device ID used with the Multimedia Extensions, such as
[waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx).

**Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode)

### StreamMeta
<!-- tab: c -->

**C/C++**

```c
typedef enum {
    SNSR_ST_META_{name},
    ...
} SnsrStreamMeta;

// Where {name} is from the table below, e.g.: SNSR_ST_META_BYTES_READ
```
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public enum SnsrStreamMeta {
  {name},
  ...
}

// Where {name} is from the table below, e.g.: SnsrStreamMeta.BYTES_READ
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
import snsr

snsr.StreamMeta.{name}

# Where {name} is from the table below, e.g.: snsr.StreamMeta.BYTES_READ
```
<!-- /tab -->

[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) metadata introspection key.

**Also see these related items:** [getMeta](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta)

**`BYTES_READ`**

Number of bytes read from the stream.

**`BYTES_WRITTEN`**

Number of bytes written to the stream.

**`IS_OPEN`**

Boolean, `1` if the stream is open, `0` if not.

**`IS_READABLE`**

Boolean, `1` if the stream is readable, `0` if not.

**`IS_WRITABLE`**

Boolean, `1` if the stream is writable, `0` if not.

**`OPEN_COUNT`**

Number of times the stream has been opened.

### StreamMode
<!-- tab: c -->

**C/C++**

```c
typedef enum {
    SNSR_ST_MODE_{name},
    ...
} SnsrStreamMode;

// Where {name} is from the table below, e.g.: SNSR_ST_MODE_READ
```
<!-- /tab -->

<!-- tab: java -->

**Java**

```java
public enum SnsrStreamMode {
  {name},
  ...
}

// Where {name} is from the table below, e.g.: SnsrStreamMode.READ
```
<!-- /tab -->

<!-- tab: py -->

**Python**

```python
import snsr

snsr.StreamMode.{name}

# Where {name} is from the table below, e.g.: snsr.StreamMode.READ
```
<!-- /tab -->

[Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) input or output mode.

**`READ`**

Read from this input stream.

**`WRITE`**

Write to this output stream.

<!-- Reference definitions from includes/links.md -->
[AAssetManager]: https://developer.android.com/ndk/reference/group___asset.html "Android Asset access"
[ALSA]: http://www.alsa-project.org/main/index.php/ALSA_Library_API "Advanced Linux Sound Architecture"
[Audio Queue Services]: https://developer.apple.com/documentation/audiotoolbox/audio-queue-services "Audio Toolbox, Core Audio"
[AudioRecord]: https://developer.android.com/reference/android/media/AudioRecord "Android AudioRecord class"
[fopen()]: https://en.cppreference.com/w/c/io/fopen "fopen() standard C library function"
[getdelim]: https://www.man7.org/linux/man-pages/man3/getdelim.3p.html "Linux manual page for getdelim()"
[Java Audio]: https://docs.oracle.com/javase/tutorial/sound/capturing.html "Audio capturing in Java"
[MediaRecorder.AudioSource]: https://developer.android.com/reference/android/media/MediaRecorder.AudioSource "Android MediaRecorder.AudioSource"
[printf()]: https://en.cppreference.com/w/c/io/fprintf "printf() standard C library function"
[Sensory]: https://sensory.com/ "Sensory, Inc. AI on the Edge & Beyond"
[Windows Multimedia Extensions]: https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-waveinopen "waveInOpen"

<!-- Abbreviation definitions from includes/abbreviations.md -->
*[ALSA]: Advanced Linux Sound Architecture
*[API]: Application Programming Interface
*[FIFO]: First in, first out
*[LPCM]: Linear pulse-code modulation
*[RAM]: Random Access Memory
*[ROM]: Read-Only Memory, typically nonvolatile flash memory
*[SDK]: Software Development Kit
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
