Android voice client for the AI crew at sea. Offline STT/TTS, E2EE Matrix, no cloud speech processing.
DeckChat is your voice line to the crew. Press the headset button, hail the bridge, and your words are transcribed on-device by Sherpa-ONNX, carried below decks over E2EE Matrix, and the crew's reply spoken back in their own voice — your voice never leaves the ship.
flowchart TD
A[Bluetooth headset] --> B[RecordingService\n16kHz mono PCM]
B --> C[Sherpa-ONNX STT\nWhisper Tiny EN, int8 ONNX]
C --> D[Matrix E2EE\nmatrix-rust-sdk, Simplified Sliding Sync]
D --> E[Crew bridge bot\nMatrix, external]
E --> F[Sherpa-ONNX TTS\nPiper VITS crew voices]
F --> G[Bluetooth headset / speaker]
click E href "https://github.com/Klazomenai/bridge" "Bridge repository" _blank
| Component | Implementation | License |
|---|---|---|
| STT | Sherpa-ONNX + Whisper Tiny EN int8 ONNX | Apache 2.0 |
| TTS | Sherpa-ONNX + Piper VITS voice models | Apache 2.0 / MIT |
| Matrix | matrix-rust-sdk (UniFFI Kotlin bindings) | Apache 2.0 |
| Credentials | Android Keystore (EncryptedSharedPreferences) | — |
| Audio | Android AudioRecord/AudioTrack, Bluetooth SCO | — |
| Crew | Voice model | Accent |
|---|---|---|
| Maren | vits-piper-en_GB-cori-high |
British English |
| Crest | vits-piper-en_US-lessac-high |
US English |
| Target | Version |
|---|---|
| minSdk | 28 |
| targetSdk | 36 |
| compileSdk | 36 |
| Java | 17 |
devenv shell # recommended — includes convenience scripts
nix develop # alternative — Gradle + SDK only, no convenience scriptsdevenv shell provides JDK 17, Gradle, Android SDK (build-tools 36, platforms 35 and 36),
adb, emulator, and convenience scripts. On entry it prints all available commands.
nix develop provides the same toolchain but without the devenv scripts —
use ./gradlew and adb commands directly.
Note: Commands like
install-debug,device-test,logcat,devices, anddownload-modelsare devenv convenience scripts.nix developusers can use the underlying./gradlewandadbequivalents shown in their descriptions.
The dev shell includes an Android emulator (API 35, x86_64). On Linux, enable KVM for hardware acceleration (the emulator can run without it but will be slower):
sudo usermod -aG kvm $USER # one-time setup on Linux (requires logout/login)
emulator # devenv shell — creates AVD on first run, then launchesThe emulator command is a devenv convenience script. nix develop users can
create and launch the AVD manually with avdmanager and $ANDROID_HOME/emulator/emulator.
SettingsActivity, HeadsetButtonReceiver, and permission-denial tests run on emulator. Bluetooth and microphone-dependent tests skip (no mic/BT hardware).
./gradlew assembleDebug # debug APK
install-debug # build + install to connected device./gradlew lint test # lint + unit tests (no device needed)
device-test # instrumented tests on device or emulatorUnit tests use mock engines (MockSttEngine, MockTtsEngine) — no JNI or
model files required. Instrumented tests require a connected device or emulator.
STT and TTS models are not committed to the repo (~200 MB total). Download them before building for real device use:
download-models # devenv shell
scripts/download-stt-models.sh && scripts/download-tts-models.sh # nix developThis fetches:
- STT: Whisper Tiny EN int8 ONNX (~37 MB) from HuggingFace
- TTS: Piper VITS voices (~80 MB each) from k2-fsa/sherpa-onnx releases
Models are placed in app/src/main/assets/stt/ and app/src/main/assets/tts/
(both gitignored).
Connect a device via USB with USB debugging enabled:
devices # list connected devices
install-debug # build + install
logcat # filtered log output for DeckChatlogcat detects no-device, unauthorized, and multi-device states with
actionable messages. Set ANDROID_SERIAL to target a specific device when
multiple are connected.
wrapper # regenerate Gradle wrapper (9.4.0)
check-gms # audit for Google Play Services deps (F-Droid)./
├── app/
│ └── src/main/java/dev/klazomenai/deckchat/
│ ├── MainActivity.kt # launch activity
│ ├── SettingsActivity.kt # Matrix credentials + preferences
│ ├── SecureStorage.kt # Android Keystore wrapper
│ ├── CrewRegistry.kt # crew member definitions + voice mapping
│ ├── MatrixClient.kt # Matrix client interface + crew message parsing
│ ├── RustMatrixClient.kt # matrix-rust-sdk implementation
│ ├── SttEngine.kt # STT interface
│ ├── SherpaOnnxSttEngine.kt # Sherpa-ONNX Whisper wrapper (JNI)
│ ├── TtsEngine.kt # TTS interface
│ ├── SherpaOnnxTtsEngine.kt # Sherpa-ONNX Piper wrapper (JNI)
│ ├── RecordingService.kt # foreground service, 16kHz PCM capture
│ ├── HeadsetButtonReceiver.kt # media button broadcast receiver
│ └── DeckChatAudioManager.kt # Bluetooth SCO + audio routing
└── scripts/
├── download-stt-models.sh # fetch Whisper models from HuggingFace
└── download-tts-models.sh # fetch Piper voices from k2-fsa releases
What's said aboard stays aboard. Voice is transcribed and spoken entirely on-device — no whisper reaches open water. Matrix messages are end-to-end encrypted. Session tokens are encrypted with Android Keystore (StrongBox when available). No telemetry. No analytics. No Google Play Services. No exceptions.
Apache-2.0