Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
The Android app holds the call itself instead of opening the page in a
Custom Tab: hold the headset's voice button (HFP AT+BVRA=1 starts
VOICE_COMMAND), talk, short press to hang up, all with the phone locked
and without looking at it.
- VoiceCall: the page's Call in Java over WebRTC (webrtc-sdk/android):
delegation to Hermes, voice approvals, end_call, idle hang-up.
- CallService: a self-managed Telecom call in the foreground, so the
audio goes to the headset and its hang-up (AT+CHUP) ends the call; a
tone says it listens.
- Screens: the current conversation with Call / Hang up, the list of
conversations, and the settings (app token, permissions).
- hermes-voice accepts the app's own token (--app-token-file, clan var
hermes-voice-app on coaxmetal); assist.lassul.us/app/ passes it
through without the web login.
- The page keeps Talk / Hang up in view: only the transcript scrolls.
assetlinks.json, the TWA and the page's ?listen go away with the
Custom Tab.
The app holds each call of the page as a self-managed Telecom call
(transactional API, foreground service), so a headset's AT+CHUP reaches
it. Page and app talk over the Custom Tabs postMessage channel: the page
reports started/ended, the app sends hangup. assetlinks.json grants the
app use_as_origin for that.
/?listen, which the Android app opens, matched no static file and got 404.
The Android app now handles VOICE_COMMAND (HFP AT+BVRA from headsets),
shows over the lock screen and asks to unlock before opening the page.
It opens /?listen, which starts the call without pressing Talk.