Kotlin library for on-device wake word detection on Android using ONNX Runtime.
🔊 Multi-Wake-Word - Register unlimited ONNX classifier models at runtime
🧩 Straightforward API - Simple Flow-based API with minimal boilerplate
🚀 Kotlin Coroutines - Background audio + inference without blocking UI
- Android SDK 23+ (Android 6.0 Marshmallow)
- RECORD_AUDIO permission
./gradlew :wakeword:publishToMavenLocaldependencies {
implementation("xyz.rementia:openwakeword:0.1.3")
}Import the engines:
import com.rementia.openwakeword.lib.WakeWordEngine
import com.rementia.openwakeword.lib.ParallelWakeWordEngine// 1. Define wake word models
val models = listOf(
WakeWordModel("Hello World", "hello_world.onnx", threshold = 0.5f),
WakeWordModel("Hey Assistant", "hey_assistant.onnx", threshold = 0.08f)
)
// 2. Create engine (choose based on your needs)
// Option A: Standard engine - good for 1-2 models
val engine = WakeWordEngine(
context = context,
models = models,
detectionMode = DetectionMode.SINGLE_BEST
)
// Option B: Parallel engine - optimal for 3+ models or low-latency requirements
val parallelEngine = ParallelWakeWordEngine(
context = context,
models = models,
detectionMode = DetectionMode.ALL,
maxWorkers = 8 // Adjust based on device capabilities
)
// 3. Start detection
engine.start()
// 4. Collect detections
lifecycleScope.launch {
engine.detections.collect { detection ->
Log.d("WakeWord", "${detection.model.name} detected!")
}
}
// 5. Cleanup
override fun onDestroy() {
super.onDestroy()
engine.release()
}// Configure multiple wake words with different thresholds
val models = listOf(
WakeWordModel("Computer", "computer.onnx", 0.1f),
WakeWordModel("Assistant", "assistant.onnx", 0.08f),
WakeWordModel("Robot", "robot.onnx", 0.15f),
WakeWordModel("Jarvis", "jarvis.onnx", 0.12f),
WakeWordModel("Alexa", "alexa.onnx", 0.09f)
)
// For 3+ models, use ParallelWakeWordEngine for optimal performance
val parallelEngine = ParallelWakeWordEngine(
context = context,
models = models,
detectionMode = DetectionMode.ALL,
maxWorkers = models.size * 2 // Allow parallel processing
)
// Handle detections with proper SharedFlow collection
lifecycleScope.launch {
parallelEngine.detections
.onEach { detection ->
Log.d("WakeWord", "${detection.model.name}: ${detection.score}")
}
.catch { e ->
Log.e("WakeWord", "Error collecting detections", e)
}
.collect()
}// For memory-constrained devices
<application
android:largeHeap="true"
...>
// Optimize for many models
val engine = ParallelWakeWordEngine(
context = context,
models = models,
maxWorkers = 12, // Increase for more parallelism
detectionCooldownMs = 1000L // Reduce for faster re-detection
)Place ONNX models in your app's assets directory:
app/src/main/assets/
├── your_wake_word.onnx
├── melspectrogram.onnx
└── embedding_model.onnx
| Engine | Best For | Characteristics |
|---|---|---|
| WakeWordEngine | • 1-2 models • Simple use cases • Lower memory devices |
• Sequential processing • Lower CPU usage • Stable latency |
| ParallelWakeWordEngine | • 3+ models • Low-latency requirements • High-performance devices |
• Parallel processing • Non-blocking architecture • Optimal multi-model performance |
The standard wake word detection engine with sequential processing.
class WakeWordEngine(
context: Context,
models: List<WakeWordModel>,
detectionMode: DetectionMode = DetectionMode.SINGLE_BEST,
detectionCooldownMs: Long = 2000L,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
)High-performance engine with fully parallel, non-blocking processing.
class ParallelWakeWordEngine(
context: Context,
models: List<WakeWordModel>,
detectionMode: DetectionMode = DetectionMode.SINGLE_BEST,
detectionCooldownMs: Long = 2000L,
maxWorkers: Int = 8, // Maximum concurrent workers
scope: CoroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
)Key Features:
- Non-blocking: Audio processing never blocks inference
- True parallelism: Each model runs independently
- Worker pool: Prevents resource exhaustion with
maxWorkers - Ring buffer: Efficient audio data management
- Fine-grained sliding: 50ms windows for better temporal resolution
Properties:
detections: Flow<WakeWordDetection>- Flow of detection events
Methods:
start()- Start wake word detectionstop()- Stop wake word detectionrelease()- Release all resources
Configuration for a wake word model.
data class WakeWordModel(
val name: String,
val modelPath: String,
val threshold: Float = 0.5f
)Detection event data.
data class WakeWordDetection(
val model: WakeWordModel,
val score: Float,
val timestamp: Long = System.currentTimeMillis()
)# Clone the repository
git clone https://github.com/rementia/openwakeword-android-kt.git
cd openwakeword-android-kt
# Build the project
./gradlew build
# Run tests
./gradlew test
# Build and install sample app
./gradlew :app:installDebugThis project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright 2025 Re-mentia
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This project includes code derived from OpenWakeWord for Android by hasanatlodhi, also licensed under Apache License 2.0.
This library is based on and inspired by OpenWakeWord for Android by hasanatlodhi, licensed under Apache License 2.0. We've ported the Java implementation to Kotlin and restructured it as a reusable library with a modern Flow-based API.
This project uses models from the OpenWakeWord project by David Scripka:
melspectrogram.onnx- Audio preprocessing model (Apache 2.0 License)embedding_model.onnx- Speech embedding model (Apache 2.0 License, originally from Google)
The embedding model is based on Google's speech embedding model released under Apache 2.0 License.
To train your own wake word models:
- Use the official OpenWakeWord training repository: openWakeWord
- Follow the training notebook: Google Colab Training Guide
- Export your trained model as ONNX format
- Place the
.onnxfile in your app'sassetsdirectory
Contributions are welcome! Please feel free to submit a Pull Request.

