Android M1: meeting recording via foreground service
- core/recording: MeetingRecorder (AudioRecord at the device's native rate, WAV on disk + 60 s rolling window resampled to 16 kHz), streaming WavWriter, thread-safe RollingWindow, linear resampler; WavReader moved here from the app - app: RecorderService (foreground, type microphone) with ongoing notification and StateFlow state; Record/Stop UI with timer and level meter; runtime permission flow; finished recordings auto-load for transcription - launcher icon (mic + waveform, matching the desktop brand) and notification glyph - fix real M0 bug caught by the new unit tests: WavReader parsed 16-bit fmt fields (audioFormat/channels/bitsPerSample) with 32-bit reads - JVM tests: WAV round trip, native-rate header, resampler, rolling window — 5/5 green; assembleDebug and aapt2 APK checks pass - validated on-device on a Fairphone 6 (Android 16): model download, engine load, recording and transcription all working
This commit is contained in:
+17
-10
@@ -4,10 +4,10 @@ Native Android app with the same functionality as the desktop meetrec:
|
||||
record meetings and transcribe them on-device with Whisper. Nothing leaves
|
||||
the phone — no cloud, no telemetry.
|
||||
|
||||
Status: **M0 (engine proof)** — the app can download a GGML model, load it
|
||||
via JNI (whisper.cpp, CPU/NEON) and transcribe a picked WAV file. Recording,
|
||||
live transcript, and output files arrive in later milestones (see the
|
||||
milestone plan in the project docs).
|
||||
Status: **M1 (recording)** — record a meeting with a foreground service
|
||||
(native sample rate, timer, level meter), then transcribe it on device.
|
||||
Model download + engine load are from M0; the live rolling transcript
|
||||
arrives with M2 (see the milestone plan in the project docs).
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -28,15 +28,15 @@ adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
`third_party/whisper.cpp` is gitignored — the fetch script pins the exact
|
||||
release tag so the JNI layer never breaks on upstream churn.
|
||||
|
||||
## Test on device (M0)
|
||||
## Test on device
|
||||
|
||||
1. Launch **MeetRec**, pick a model (`tiny` is fine for a first test) and tap
|
||||
**Download** (model comes from Hugging Face; tiny is ~75 MB).
|
||||
2. Tap **Load engine**.
|
||||
3. Tap **Pick WAV file** and choose a 16 kHz mono WAV for best results
|
||||
(other PCM WAVs are resampled automatically).
|
||||
4. Tap **Transcribe** — segments with timestamps appear; share via the
|
||||
share sheet.
|
||||
3. Tap **Record**, speak, then tap **Stop** — the recording is saved as WAV
|
||||
(native device rate) and auto-loaded for transcription.
|
||||
4. Tap **Transcribe** — segments with timestamps appear; share via the share
|
||||
sheet. You can also pick any PCM WAV file instead of recording.
|
||||
|
||||
Expect roughly realtime transcription with `tiny`/`base` on the
|
||||
Fairphone 6's CPU; `small` is noticeably slower — use it for final passes
|
||||
@@ -51,12 +51,19 @@ only (the live/final split comes with the recorder milestones).
|
||||
## Module layout
|
||||
|
||||
```
|
||||
app/ Compose UI (model download, WAV picker, transcript view)
|
||||
app/ Compose UI + RecorderService (foreground mic recording)
|
||||
core/recording/ MeetingRecorder, WavWriter/WavReader, RollingWindow,
|
||||
linear resampler — pure Kotlin, unit tested on the JVM
|
||||
core/whisper/ whisper.cpp JNI wrapper: CMake build + LibWhisper.kt +
|
||||
WhisperEngine.kt (the on-device transcription API)
|
||||
tools/ fetch-whisper.sh — vendor the pinned whisper.cpp release
|
||||
```
|
||||
|
||||
Recording mirrors the desktop app: audio is captured at the input's native
|
||||
rate (WAV on disk keeps it), while the 60 s rolling window is resampled to
|
||||
Whisper's 16 kHz for the upcoming live pass. Recording continues while the
|
||||
app is backgrounded via the microphone foreground service.
|
||||
|
||||
Models live in the app's private storage (`filesDir/models`), shared files
|
||||
with the desktop app's `~/.cache/meetrec/whisper-cpp` naming
|
||||
(ggml-tiny.bin … ggml-large-v3.bin).
|
||||
Reference in New Issue
Block a user