Skip to content

spot-data-stream.c

This example runs a wake word from code space with a custom audio stream, using pull mode processing with run. It is a reasonable starting point for running on a small device with an RTOS.

fromProvider, data-stream.c

Instructions

Build the sample code. In the same terminal window type the command after the %:

% ./bin/spot-data-stream

Spotted "hello blue genie" from sample 6720 to sample 18000
Done, found phrase.

Code

Available in this TrulyNatural SDK installation at ~/Sensory/TrulyNaturalSDK/7.6.1/sample/c/src/spot-data-stream.c

spot-data-stream.c

/* Sensory Confidential
 * Copyright (C)2018-2025 Sensory, Inc. https://sensory.com/
 *
 * TrulyHandsfree SDK example illustrating the use of the
 * sample custom data-stream (see data-stream.c)  This should
 * be easily adaptable to a custom live-audio stream
 * (in case of a custom audio driver for RTOS for example.)
 *
 * The spotter model is loaded from code space. On platforms where code is
 * read directly from ROM, this will reduce heap requirements.
 *-----------------------------------------------------------------------------
 */

#include <stdio.h>
#include <stdlib.h>

#include <snsr.h>

#include "data-stream.h"


/* See spot-hbg-enUS-1.4.0-m.c */
extern SnsrCodeModel spot_hbg_enUS;

/* NOTE: extern char * foo is NOT always the same as extern char foo[] */
extern unsigned char audioData[];
extern unsigned int audioDataLen;


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

  /* Retrieve the phrase text and alignments from the session handle */
  snsrGetDouble(s, SNSR_RES_BEGIN_SAMPLE, &begin);
  snsrGetDouble(s, SNSR_RES_END_SAMPLE, &end);
  rc = snsrGetString(s, SNSR_RES_TEXT, &phrase);
  /* Quit early if an error occurred. */
  if (rc != SNSR_RC_OK) return rc;
  printf("\nSpotted \"%s\" from sample %d to sample %d\n",
         phrase, (int)begin, (int)end);
  /* This return code from the event handler sets the
   * return code in the SnsrSession and causes the session
   * to stop
   */
  return SNSR_RC_STOP;
}


int
main(int argc, char **argv)
{
  SnsrRC rc;
  SnsrSession s = NULL;
  SnsrStream audioStream = NULL;

  rc = snsrNew(&s);
  if (rc != SNSR_RC_OK) {
    const char *err = s ? snsrErrorDetail(s) : snsrRCMessage(rc);
    fprintf(stderr, "Error on init: %d - %s\n", rc, err);
    return rc;
  }

  /* Load and validate the spotter model task from code space */
  snsrLoad(s, snsrStreamFromCode(spot_hbg_enUS));
  if (snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT) != SNSR_RC_OK) {
    fprintf(stderr, "Error loading spotter: %s\n", snsrErrorDetail(s));
    return rc;
  }

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

  /* NOTE: Audio stream should be 16 KHz, 16 bits/sample, mono */

  /* NOTE: Directly casting char to short works on little-endian only */
  /* ARM and x86 are little-endian, MIPS may not be */
  audioStream = streamFromData(audioData, audioDataLen, SNSR_ST_MODE_READ);
  snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, audioStream);

  /* snsrRun won't return until stopped or interrupted or end of data */
  rc = snsrRun(s);

  switch (rc) {
    case SNSR_RC_OK:
      printf("Done, no error but no phrase.\n");
      break;
    case SNSR_RC_STOP:
      printf("Done, found phrase.\n");
      break;
    case SNSR_RC_STREAM_END:
      printf("Reached end of stream.\n");
      break;
    default:
      printf("Unexpected return: %d\n", rc);
      return rc;
  }
  printf("\n");
  if (s) snsrRelease(s);
  /* audioStream has already been released because session had
   * the only reference to it - so don't snsrRelease it again.
   */

  return 0;
}