Files
callpipe/docs/control-protocol.md
T
2026-07-25 18:41:15 +05:00

2.0 KiB

callpipe control protocol (Pi ⇄ phone)

The phone app hosts a WebSocket server on the LAN (default port 8090). The Pi (or any client, e.g. wscat) connects in and drives the cellular call. No audio crosses this channel — audio is Bluetooth HFP between the phone and the Pi. This is purely call control + state.

Endpoint: ws://<phone-ip>:8090/ (any path is accepted)

Commands (client → phone)

JSON Action
{"cmd":"dial","number":"+9607…","sim":0} Place outgoing call. sim optional (0-based index from the sims event); omit for default SIM.
{"cmd":"answer"} Answer the ringing call.
{"cmd":"hangup"} End the active call (or reject if still ringing).
{"cmd":"reject"} Reject the ringing call.
{"cmd":"state"} Ask for the current call snapshot.
{"cmd":"sims"} Ask for the SIM list.
{"cmd":"ping"} Liveness check → pong.

Events (phone → client)

JSON Meaning
{"event":"hello","app":"callpipe","proto":1} Sent on connect.
{"event":"sims","sims":[{"index":0,"label":"Ooredoo"},{"index":1,"label":"Dhiraagu"}]} SIM list (sent on connect + on request).
{"event":"state","state":"ACTIVE","number":"+9607…","direction":"OUT"} Call state. Pushed on every change + on connect.
{"event":"ack","cmd":"dial"} Command accepted.
{"event":"error","cmd":"dial","msg":"…"} Command failed.
{"event":"pong"} Reply to ping.

state values: IDLE, CONNECTING, DIALING, RINGING, ACTIVE, HOLDING, DISCONNECTING, DISCONNECTED. direction: IN, OUT, or null.

Quick test (before the Pi is ready)

# phone IP is 10.0.1.239 (adb wireless). Install app, open it once so the
# foreground service + default-dialer role are granted.
npm i -g wscat        # or: nix-shell -p nodePackages.wscat
wscat -c ws://10.0.1.239:8090/
> {"cmd":"sims"}
> {"cmd":"dial","number":"+9607xxxxxx"}
> {"cmd":"hangup"}

You should see hello, sims, and live state events stream back.