---
source_path: "api/sample/c/data-stream.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream/"
---

# data-stream.c

This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation
for memory data, similar to [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory). It's used in the [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc)
example.

For a Python [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) example using a memory-backed audio source, see
[custom_stream.py](https://doc.sensory.com/tnl/7.8/api/sample/python/custom_stream.md#custom_streampy).

## Instructions

See [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc).

## Code

Available in this TrulyNatural SDK installation
at _~/Sensory/TrulyNaturalSDK/7.9.0-pre.0/sample/c/src/data-stream.{c,h}_

**data-stream.h:**

```c
/* Sensory Confidential
 * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/
 *
 * TrulyHandsfree SDK example of a custom stream, see data-stream.c.
 *------------------------------------------------------------------------------
 */

SnsrStream
streamFromData(void *data, size_t dataSize, SnsrStreamMode mode);

```

{ data-search-exclude }

**data-stream.c:**

```c
/* Sensory Confidential
 * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/
 *
 * TrulyHandsfree SDK example of a custom stream, such as an audio stream
 * to get input from a custom audio driver (in a RTOS for example).
 * Similar streams are in samples wmme-stream.c and alsa-stream.c.
 *
 * NOTE: Normally it's best to use snsrStreamFromMemory(..) for a
 * stream of data, although this example would also work.
 *-----------------------------------------------------------------------------
 */

#include <stdlib.h>
#include <string.h>

#include <snsr.h>

typedef struct {
  char *data;
  size_t dataSize;
  size_t index;
} ProviderData;

static SnsrRC
streamOpen(SnsrStream stream)
{
  ProviderData *instanceData = snsrStream_getData(stream);
  if (!instanceData->data) return SNSR_RC_ERROR;
  instanceData->index = 0;
  return SNSR_RC_OK;
}

static SnsrRC
streamClose(SnsrStream stream)
{
  ProviderData *instanceData = snsrStream_getData(stream);
  instanceData->index = 0;
  return SNSR_RC_OK;
}

static void
streamRelease(SnsrStream stream)
{
  ProviderData *instanceData = snsrStream_getData(stream);
  free(instanceData);
}

static size_t
streamRead(SnsrStream stream, void *buffer, size_t readSize)
{
  /* NOTE: For a live audio stream, if there is no data available,
   * this call should block until there is more data available.
   */
  ProviderData *d = snsrStream_getData(stream);
  size_t available, read;

  read = readSize;
  available = d->dataSize - d->index;
  if (read > available) {
    read = available;
    /* Session will end with SNSR_RC_STREAM_END */
    snsrStream_setRC(stream, SNSR_RC_EOF);
  }
  if (read) memcpy(buffer, d->data + d->index, read);
  d->index += read;
  return read;
}

static size_t
streamWrite(SnsrStream stream, const void *buffer, size_t writeSize)
{
  /* NOTE: For a live audio stream, implementing a streamWrite
   * would make no sense and this function should be removed.
   */
  ProviderData *d = snsrStream_getData(stream);
  size_t available, written;

  written = writeSize;
  available = d->dataSize - d->index;
  if (written > available) {
    written = available;
    /* Session will end with SNSR_RC_STREAM_END */
    snsrStream_setRC(stream, SNSR_RC_EOF);
  }
  if (written) memcpy(d->data + d->index, buffer, written);
  d->index += written;
  return written;
}

/* This is the interface any SnsrStream has to provide
 * (Virtual Method Table)
 */
static SnsrStream_Vmt methods = {
  "data", &streamOpen, &streamClose, &streamRelease, &streamRead, &streamWrite
};

/* This is the 'constructor' for this kind of stream */
SnsrStream
streamFromData(void *data, size_t dataSize, SnsrStreamMode mode)
{
  SnsrStream dataStream;
  int readable = (mode == SNSR_ST_MODE_READ);
  int writeable = (mode == SNSR_ST_MODE_WRITE);
  /* The stream object has instance data (particular to this instance)
   * and virtual method pointers (particular to this type)
   * just like it would in C++
   */
  ProviderData *instanceData = malloc(sizeof(*instanceData));
  memset(instanceData, 0, sizeof(*instanceData));
  instanceData->data = data;
  instanceData->dataSize = dataSize;

  dataStream = snsrStream_alloc(&methods, instanceData, readable, writeable);
  if (data == NULL) snsrStream_setRC(dataStream, SNSR_RC_INVALID_ARG);
  return dataStream;
}

```

<!-- Abbreviation definitions from includes/abbreviations.md -->
*[API]: Application Programming Interface
*[SDK]: Software Development Kit
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
