Your first program¶
If you followed Command-line tools, you already ran a wake word with snsr-eval. This page shows the same Session API flow on each platform.
The C tab is a full from-scratch walk-through: a new directory, a short program, CMake, and a run command. The Java tab does the same with Gradle in a new directory. Android and iOS show the same API steps, then how to try them using the shipping sample projects. Android uses the Java API; iOS calls the C API from Swift via a bridging header (there is no separate Swift API).
Prerequisites¶
You need the same SDK setup as on the Command-line tools page:
- Install the TrulyNatural SDK using the provided installer.
- Open a terminal.
- Add ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin to your
PATH(optional for this page, but useful for tools).
- A C compiler and CMake 3.10 or later (Linux, macOS, or Windows).
- A microphone for live audio.
- A phrase-spot model file, for example the voice genie model at $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr.
- JDK 17 or later and Gradle 8.0 or later (or use a Gradle wrapper).
- A microphone (Java Audio capture via fromAudioDevice).
- A phrase-spot
.snsrfile (same voice genie model path as the C tab).
- Android Studio or a command-line Android SDK install; device or emulator with microphone support.
- To try the sample on this page you do not need to change sample source — only build and run snsr-debug.
- Xcode on macOS and a device or simulator with microphone access.
- To try the sample on this page you do not need to change sample source — only open and run PhraseSpot.
The program¶
The program below mirrors the pull-mode recipe in API overview: create a Session, load a spotter model, attach live audio, register a ^result handler, call run, then release.
This is a teaching sketch (minimal error handling). The shipped sample live-spot.c adds timing in the callback, full RC checks, and more.
Create first-spot.c with:
#include <snsr.h>
#include <stdio.h>
#include <stdlib.h>
static SnsrRC
resultEvent(SnsrSession s, const char *key, void *privateData)
{
const char *phrase;
SnsrRC r;
r = snsrGetString(s, SNSR_RES_TEXT, &phrase);
if (r != SNSR_RC_OK)
return r;
printf("Spotted \"%s\".\n", phrase);
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]);
return 1;
}
snsrNew(&s); // (1)!
snsrLoad(s, snsrStreamFromFileName(argv[1], "r")); // (2)!
snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM,
snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT)); // (3)!
snsrSetHandler(s, SNSR_RESULT_EVENT,
snsrCallback(resultEvent, NULL, NULL)); // (4)!
r = snsrRun(s); // (5)!
if (r != SNSR_RC_STOP)
fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); // (6)!
snsrRelease(s); // (7)!
return 0;
}
- new — allocate an empty Session handle.
- load the
.snsrmodel from disk (pass a phrase-spot.snsrfile, as on the Command-line tools page). - setStream attaches live PCM from the default capture device (fromAudioDevice).
- setHandler registers
resultEventon the ^result event (callback). - run blocks until the handler returns STOP or an error RC.
- On any code other than STOP, print errorDetail to
stderr(same pattern as live-spot.c). The handler propagates RC errors from getString. - release frees the session and attached streams.
Create FirstSpot.java with:
import com.sensory.speech.snsr.Snsr;
import com.sensory.speech.snsr.SnsrRC;
import com.sensory.speech.snsr.SnsrSession;
import com.sensory.speech.snsr.SnsrStream;
public class FirstSpot {
public static void main(String[] argv) throws Exception {
if (argv.length != 1) {
System.err.println("usage: FirstSpot spotter-model");
System.exit(1);
}
SnsrSession s = new SnsrSession(); // (1)!
s.load(argv[0]) // (2)!
.setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromAudioDevice()) // (3)!
.setHandler(Snsr.RESULT_EVENT, (ses, key) -> { // (4)!
System.out.println("Spotted \"" + ses.getString(Snsr.RES_TEXT) + "\".");
return SnsrRC.STOP;
});
s.run(); // (5)!
s.release(); // (6)!
}
}
new SnsrSession()— empty Session (new).- load the
.snsrmodel from the path inargv[0]. - setStream with fromAudioDevice on the method chain.
- setHandler on ^result; return STOP to end run.
- run — pull-mode loop until the handler stops.
- release the session.
Look up signatures under the Java tabs on Inference and I/O. The Java binding throws on failure instead of latched RC codes (see API overview § Language bindings).
Uses the Java Session API — see Java tabs on Inference for method details. The excerpt is the core wake-word-only flow in snsr-debug; the shipping app also uses a worker thread, UI, and optional debug logging.
SnsrStream audio = SnsrStream.fromAudioDevice();
SnsrSession session = new SnsrSession();
session.load(assetToString(BuildConfig.TRIGGER_MODEL))
.setStream(Snsr.SOURCE_AUDIO_PCM, audio)
.setHandler(Snsr.RESULT_EVENT, this);
session.run();
When you integrate into your own app, add RECORD_AUDIO to AndroidManifest.xml, use SnsrStream.fromAudioDevice(int device, int sampleRate) if you need a specific MediaRecorder.AudioSource, and follow Integrate with your build § Android.
Calls the C API from Swift — look up snsrLoad, snsrSetStream, and related functions under the C tabs on Inference and I/O. There is no Swift Session wrapper; PhraseSpot uses a bridging header and runs run on a background queue.
// Excerpt — see PhraseSpot.swift for load(), UI, and AVAudioSession setup.
snsrLoad(session, snsrStreamFromFileName(modelPath(modelName), "r"))
snsrSetStream(session, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromDefaultAudioDevice())
snsrSetHandler(session, SNSR_RESULT_EVENT, resultCallback)
// snsrRun(session) — invoked on a background thread in the sample app.
Build and run¶
Create a new directory anywhere (not under the SDK sample tree). The steps below assume ~/first-spot/.
-
Save the program above as first-spot.c in that directory.
-
Create CMakeLists.txt in the same directory:
cmake_minimum_required(VERSION 3.10) project(first-spot C) list(APPEND CMAKE_MODULE_PATH "$ENV{HOME}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9") include(SnsrLibrary) add_executable(first-spot first-spot.c) target_link_libraries(first-spot SnsrLibrary)This follows Integrate with your build (CMake is the recommended approach on Linux, macOS, and Windows). Using GNU Make only? See Integrate with your build § Make and C examples § Build with GNU Make.
-
Configure and build:
On Windows with Visual Studio generators, the executable may be under
build\Release\. See Integrate with your build for toolchain notes. -
Run the spotter. Say “voice genie” a few times:
./build/first-spot $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr Spotted "voicegenie".Press
^Cif the process does not exit after a spot (your handler should stop run with STOP).
Create a new directory anywhere (not under the SDK sample tree). The steps below assume ~/first-spot-java/.
-
Create the standard Gradle source layout and save FirstSpot.java from the Program tab at src/main/java/FirstSpot.java (default package).
-
Create settings.gradle in the project root:
-
Create build.gradle in the project root:
plugins { id 'java' id 'application' } // SDK root is the parent of m2repository (same layout as install.m2repo). def snsrMavenRepo = file("${System.getProperty('user.home')}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/m2repository") def snsrRoot = snsrMavenRepo.parentFile repositories { maven { url = snsrMavenRepo.toURI() } } dependencies { implementation "com.sensory.speech.snsr:tnl:7.8.0-pre.0" } application { mainClass = 'FirstSpot' } def snsrNativeLib = { def os = System.getProperty('os.name').toLowerCase(java.util.Locale.ROOT) if (os.contains('mac')) { return new File(snsrRoot, 'lib/macos') } if (os.contains('linux')) { def machine = ['gcc', '-dumpmachine'].execute().text.trim() return new File(snsrRoot, "lib/${machine}") } if (os.contains('windows')) { return new File(snsrRoot, 'lib/x86_64-windows-msvc') } throw new GradleException( 'Set -Djava.library.path on the run task for your platform (see build-java).') }() tasks.named('run') { jvmArgs "-Djava.library.path=${snsrNativeLib.absolutePath}" }Coordinates and JNI layout are described in Integrate with your build § Java.
-
From the project root, configure and run:
cd ~/first-spot-java gradle run --args="$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr"Gradle compiles everything under src/main/java/. If you see
ClassNotFoundException: FirstSpot, check that FirstSpot.java is in that folder, not the project root. If you seeUnsatisfiedLinkError: no SnsrJNI, confirm the Maven URL ends in m2repository sosnsrRootresolves to the SDK install (native libraries live in lib/macos on macOS). -
Say “voice genie”. Expect output similar to the C tab.
Without Gradle (javac / java)
On Linux or macOS you can compile and run without a Gradle project. Set SNSR_ROOT to $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9, pick the Sensory JAR under m2repository, and point java.library.path at the native library directory for your OS (see build-java). These commands expect FirstSpot.java in the current directory:
export SNSR_ROOT=$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
SNSR_JAR=$(find "$SNSR_ROOT/m2repository" -name 'tnl-*.jar' \
! -name '*-sources.jar' -print -quit)
javac -cp "$SNSR_JAR" FirstSpot.java
# macOS example:
java -Djava.library.path="$SNSR_ROOT/lib/macos" \
-cp ".:$SNSR_JAR" FirstSpot \
"$SNSR_ROOT/model/spot-voicegenie-enUS-6.5.1-m.snsr"
On Linux, replace lib/macos with lib/$(gcc -dumpmachine).
Try the sample (no code changes)
-
Open ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/snsr-debug/ in Android Studio or use the command line (see snsr-debug § Build).
-
Connect a device or start an emulator with microphone support.
-
Build and install (no edits to sample sources):
cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/snsr-debug ./gradlew installDebugIn Android Studio, press Run instead of the command above.
-
Launch SnsrDebug, choose Wakeword, press TALK, and say the trigger phrase (see snsr-debug § Run).
Integrate in your own app
Use the Program excerpt as a guide, then follow Integrate with your build § Android and the Android examples. A from-scratch Android walk-through is not duplicated here (manifest, AAR, assets, and UI threading are app-specific).
Try the sample (no code changes)
-
Open ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/ios/PhraseSpot/PhraseSpot.xcodeproj in Xcode.
-
Choose Product → Run on a device or simulator. Grant microphone access when prompted. Say the trigger phrase from PhraseSpot § Instructions.
The project is already configured with
SNSR_ROOT, bridging header, frameworks, andNSMicrophoneUsageDescription(see build-ios).
Integrate in your own app
Use the Program excerpt and C API reference tabs, then follow Integrate with your build § iOS and iOS examples. Creating a new Xcode target from scratch is integration work, not covered step-by-step on this page.
What you just did¶
Next steps¶
| Platform | Full sample | Look up API under |
|---|---|---|
| C | live-spot.c | C tabs on Inference and I/O, … |
| Java | evalUDT.java | Java tabs on Inference and I/O |
| Android | snsr-debug | Java tabs + Android examples |
| iOS | PhraseSpot | C tabs + Integrate with your build § iOS |
- C examples, Java examples, Android examples, iOS examples — full samples, tests, and platform-specific build files.
- Inference quick reference — common Session operations.
- FAQ § Recipes — push audio, capture speech after the wake word, and UI-thread callbacks (one screen each).
Same program, composed models¶
You do not need to change first-spot.c to run a multi-stage pipeline—only the model path on the command line. On Command-line tools § Speech To Text ( stt), use snsr-edit with a template such as tpl-opt-spot-vad-lvcsr to build a wake-word-gated STT .snsr file, then run ./build/first-spot my-pipeline.snsr. The same Session code loads any valid task file. live-spot.c Instructions step 3 shows this with the full sample (VAD + STT after the wake word).