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

# live-spot-stream.c

This example shows how to run a recognizer on live
audio captured using a custom audio stream.

**Also see these related items:** [alsa-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream.md#alsa-streamc), [aqs-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream.md#aqs-streamc), [wmme-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/wmme-stream.md#wmme-streamc), [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)

## Instructions

1.  [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code.
    In the same terminal window type the command after the `%`,
    then say "hello blue genie":

    ```console
    % ./bin/live-spot-stream ../../model/spot-hbg-enUS-1.4.0-m.snsr
    Spotted "hello blue genie" at 5.34 seconds.
    ```

2.  This example works with any [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) recognizer type, so let's
    create a concurrent combination of two wake words:

    ```console
    % ./bin/snsr-edit -vt ../../model/tpl-spot-concurrent-1.5.0.snsr \
        -f 0 ../../model/spot-voicegenie-enUS-6.5.1-m.snsr \
        -f 1 ../../model/spot-hbg-enUS-1.4.0-m.snsr \
        -o spot-vg-or-hbg.snsr
    Output written to "spot-vg-or-hbg.snsr".
    ```

    _spot-vg-or-hbg.snsr_ listens for both "voice genie" and "hello blue genie".
    Run the `live-spot-stream` example again and say one of these phrases:

    ```console
    % ./bin/live-spot-stream spot-vg-or-hbg.snsr
    Spotted "voicegenie" at 6.75 seconds.

    % ./bin/live-spot-stream spot-vg-or-hbg.snsr
    Spotted "hello blue genie" at 8.28 seconds.
    ```

3.  _(TrulyNatural only)_ A VAD combined with either an LVCSR or STT model also works:

    ```console
    %  ./bin/snsr-edit -vt ../../model/tpl-vad-lvcsr-3.17.0.snsr \
        -f 0 ../../model/lvcsr-build-enUS-14.0.2-5MB.snsr \
        -g phrases-stream "hello world; this is a test sentence; stop everything" \
        -o vad-lvcsr.snsr
    Output written to "vad-lvcsr.snsr".

    % ./bin/live-spot-stream vad-lvcsr.snsr
    Spotted "this is a test sentence" at 4.46 seconds.

    % ./bin/live-spot-stream vad-lvcsr.snsr
    Spotted "<no-match/>" at 2.15 seconds.

    % ./bin/live-spot-stream vad-lvcsr.snsr
    Spotted "stop everything" at 1.88 seconds.
    ```

## Code

Available in this TrulyNatural SDK installation
at _~/Sensory/TrulyNaturalSDK/7.9.0-pre.0/sample/c/src/live-spot-stream.c_

**live-spot-stream.c:**

```c
/* Sensory Confidential
 * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/
 *
 * Keyword spotting minimal example using a custom audio stream.
 *------------------------------------------------------------------------------
 */

#include <snsr.h>

#include <stdlib.h>

/* Use the custom audio stream for this operating system */

#ifdef __linux__
#  include "alsa-stream.h"
#  define streamFromCustom(r, m, l) streamFromALSA("default", r, m, l)

#elif defined(__APPLE__)
#  include "aqs-stream.h"
#  define streamFromCustom(r, m, l) streamFromAQS(r, m, l)

#elif defined(_WIN32)
#  include "wmme-stream.h"
#  define streamFromCustom(r, m, l) streamFromWMME(-1, r, m, l)

#else
#  error Not supported on this platform.

#endif

/* Result callback function, see snsrSetHandler() in main() below.
 * Print the result text and the start time of the first spotted phrase.
 */
static SnsrRC
resultEvent(SnsrSession s, const char *key, void *privateData)
{
  SnsrRC r;
  const char *phrase;
  double begin;

  /* Retrieve the phrase text and start time from the session handle. */
  snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin);
  r = snsrGetString(s, SNSR_RES_TEXT, &phrase);

  /* Quit early if an error occurred. */
  if (r != SNSR_RC_OK) return r;
  printf("Spotted \"%s\" at %.2f seconds.\n", phrase, begin/1000.0);

  /* Returning a code other than SNSR_RC_OK instructs snsrRun() to return it. */
  return SNSR_RC_STOP;
}

int
main(int argc, char *argv[])
{
  SnsrRC r;
  SnsrSession s;

  if (argc != 2) {
    fprintf(stderr, "usage: %s spotter-model\n", argv[0]);
    exit(1);
  }

  /* Create a new session handle. */
  snsrNew(&s);

  /* Load and validate the spotter model task file. */
  snsrLoad(s, snsrStreamFromFileName(argv[1], "r"));
  snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT);

  /* Create a live audio stream instance using a custom stream type,
   * then attach it to the session.
   */
  snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM,
                streamFromCustom(16000, SNSR_ST_MODE_READ, STREAM_LATENCY_LOW));

  /* Register a result callback. Private data handle is not used */
  snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL));

  /* Main recognition loop. The result handler will cause snsrRun() to
   * return SNSR_RC_STOP. Other return codes indicate an unexpected error.
   * Session errors remain until explicitly cleared: Any errors that occured
   * earlier will also be reported here.
   */
  r = snsrRun(s);
  if (r != SNSR_RC_STOP)
    fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s));

  /* Release the session. This will also release the model and audio streams,
   * and the callback handler. No other references to these handles are held,
   * so their memory will be reclaimed.
   */
  snsrRelease(s);
  return r;
}

```

<!-- Abbreviation definitions from includes/abbreviations.md -->
*[ALSA]: Advanced Linux Sound Architecture
*[API]: Application Programming Interface
*[AQS]: Audio Queue Services, Apple's audio capture API on Darwin / macOS
*[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder
*[SDK]: Software Development Kit
*[STT]: Speech To Text: transformers with language model and CTC decoding
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
*[VAD]: Voice Activity Detector
*[WMME]: Windows Multimedia Extensions, the audio capture API on Windows
