androidPorcupine - Android API

  • Wake Word Engine
  • Offline Voice Commands
  • Local Speech Recognition
  • Always Listening
  • Android
  • Java

This document outlines how to integrate Porcupine wake word engine within an Android application.

Installation

Porcupine can be found on Maven Central. To include the package in your Android project, ensure you have included mavenCentral() in your top-level build.gradle file and then add the following to your app's build.gradle:

dependencies {
// ...
implementation 'ai.picovoice:porcupine-android:1.9.0'
}

Permissions

To enable recording with your Android device's microphone you must add the following line to your AndroidManifest.xml file:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Usage

The module provides you with two levels of API to choose from depending on your needs.

High-Level API

PorcupineManager provides a high-level API that takes care of audio recording and wake word detection. This class is the quickest way to get started.

To create an instance of PorcupineManager, use the PorcupineManager Builder:

import ai.picovoice.porcupine.*;
try {
Porcupine.BuiltInKeyword[] keywords = new Porcupine.BuiltInKeyword[]{
Porcupine.BuiltInKeyword.PICOVOICE,
Porcupine.BuiltInKeyword.PORCUPINE
}
PorcupineManager porcupineManager = new PorcupineManager.Builder()
.setKeywords(keywords)
.build(context, wakeWordCallback);
} catch (PorcupineException e) { }

The context parameter is the Android application context - this is used to extract Porcupine resources from the APK. The wakeWordCallback parameter is PorcupineManagerCallback that will be invoked when Porcupine has detected one of the keywords. The callback should accept a single integer, keywordIndex, which specifies which wake word has been detected.

PorcupineManagerCallback wakeWordCallback = new PorcupineManagerCallback() {
@Override
public void invoke(int keywordIndex) {
if(keywordIndex == 0){
// picovoice detected!
}
else if(keywordIndex == 1){
// porcupine detected!
}
}
}

Available built-in keywords are accessible via the Porcupine.BuiltInKeyword enum.

To create an instance of PorcupineManager that detects custom keywords, you can use the setKeywordPaths() builder argument instead:

try {
String[] keywordPaths = new String[]{
"absolute/path/to/keyword/one.ppn",
"absolute/path/to/keyword/two.ppn"
}
PorcupineManager porcupineManager = new PorcupineManager.Builder()
.setKeywordPaths(keywordPaths)
.build(context, wakeWordCallback);
} catch (PorcupineException e) { }

In addition to custom keywords, you can override the default Porcupine english model file and/or keyword sensitivities.

Sensitivity is the parameter that enables trading miss rate for the false alarm rate. It is a floating-point number within [0, 1]. A higher sensitivity reduces the miss rate at the cost of increased false alarm rate.

The model file contains the parameters for the wake word engine. To change the language that Porcupine understands, you'll pass in a different model file.

These optional parameters can be set like so:

try {
PorcupineManager porcupineManager = new PorcupineManager.Builder()
.setKeywordPaths(keywordPaths)
.setModelPath("absolute/path/to/porcupine_model.pv")
.setSensitivities(new float[] { 0.6f, 0.35f })
.build(context, wakeWordCallback);
} catch (PorcupineException e) { }

Once you have instantiated a PorcupineManager, you can start audio capture and wake word detection by calling:

porcupineManager.start();

And then stop it by calling:

try{
porcupineManager.stop();
} catch (PorcupineException e) { }

Once the app is done with using an instance of PorcupineManager, be sure you explicitly release the resources allocated to Porcupine:

porcupineManager.delete();

Low-Level API

Porcupine provides low-level access to the wake word engine for those who want to incorporate wake word detection into a already existing audio processing pipeline.

Porcupine uses the a Builder pattern to construct instances. Creating an instance of Porcupine

import ai.picovoice.porcupine.*;
try {
Porcupine porcupine = new Porcupine.Builder()
.setKeyword(Porcupine.BuiltInKeyword.PICOVOICE)
.build(context);
} catch (PorcupineException e) { }

To search for a keyword in audio, you must pass frames of audio to Porcupine using the process function. The keywordIndex returned will either be -1 if no detection was made or an integer specifying which keyword was detected.

short[] getNextAudioFrame(){
// .. get audioFrame
return audioFrame;
}
while(true) {
try {
int keywordIndex = porcupine.process(getNextAudioFrame());
if(keywordIndex >= 0) {
// .. detection made!
}
} catch (PorcupineException e) { }
}

For process to work correctly, the audio data must be in the audio format required by Picovoice. The required audio format is found by calling .getSampleRate() to get the required sample rate and .getFrameLength() to get the required number of samples per input frame. Audio must be single-channel and 16-bit linearly-encoded.

Once you're done with Porcupine, ensure you release its resources explicitly:

porcupine.delete();

Creating Custom Wake Word

You can create custom Porcupine wake word models using Picovoice Console.

Custom Wake Word Integration

To add a custom wake word to your Android application a couple of extra steps must be taken. First, add your .ppn file to the /res/raw folder. All resources are compressed when the build system creates an APK, so you will have to extract your ppn file first before using it:

// in this example our file located at '/res/raw/keyword.ppn'
try (
InputStream is = new BufferedInputStream(
getResources().openRawResource(R.raw.keyword), 256);
OutputStream os = new BufferedOutputStream(
openFileOutput("keyword.ppn", Context.MODE_PRIVATE), 256)
) {
int r;
while ((r = is.read()) != -1) {
os.write(r);
}
os.flush();
}

Non-English Wake Words

In order to detect non-English wake words you need to use the corresponding model file. The model files for all supported languages are available here.


Issue with this doc? Please let us know.