Document incoming call policies, busy confirmation and radio status replies

This commit is contained in:
evgeny committed 2026-10-19 15:20:04 +02:00
1 parent 558b2a2ac0
commit 97b537c005
1 file changed
+28 -2
+28 -2
View File
@@ -13,6 +13,31 @@ DM-группа, маршрутизация через `etcp_router` идент
Полный цикл: проверка онлайна (BGP) → INVITE → звонок → ACCEPT/DECLINE →
аудиопоток через роутер → HANGUP. CM инициируется вызывающим при старте, вызываемым при принятии вызова.
### Входящие вызовы и телефонная занятость
Android хранит пять независимых настроек: показывать статус звонка, предупреждать вызывающего,
отклонять при телефонной занятости, отклонять все обычные звонки, отклонять все приглашения в рацию.
Они передаются маской `CALL_POLICY_*` через `[chat] incoming_call_policy` при старте,
а при изменениях — вместе с живым состоянием телефона через JNI в uasync.
Первые три настройки используют `READ_PHONE_STATE`; запреты всех входящих разрешения не требуют.
Наблюдатель учитывает все активные SIM, набор номера, удержание и входящий телефонный вызов.
Без разрешения или без телефонной службы состояние неизвестно, а не свободно.
Приоритет: запрет типа вызова → автоматический отказ при телефонной занятости → предупреждение с выбором.
Отказ при занятости возвращает `CALL_REASON_PHONE_BUSY`/`RADIO_CALL_PHONE_BUSY`.
Предупреждение переводит попытку в `WAIT_DECISION`: у вызываемого нет события INCOMING, рингтона и регистрации в Telecom.
Вызывающий видит «Абонент разговаривает по телефону», «Всё равно позвонить» и «Завершить».
Продолжение подтверждается повторяемой командой внутри той же попытки; освобождение телефона само не запускает звонок.
Повторные пакеты не создают повторных входящих событий. При изменении политики перед продолжением запрет проверяется снова.
Предел всей попытки — 60с от начала, включая выбор; продолжение deadline не меняет.
У рации первый ответ и подтверждение продолжения ограничены 2с; сообщение о занятости является ответом, но не RINGING.
Рация, уже включённая у адресата в указанном канале, возвращает `RADIO_CALL_ALREADY_ACTIVE`:
вызывающий получает уведомление, входящий вызов не показывается, его собственная рация не включается.
Этот ответ описывает существующую подписку и не создаёт нового входящего вызова даже при включённом запрете приглашений.
Принятие обычного приглашения в рацию по-прежнему сначала включает местную подписку, затем отправляет ACCEPT.
Android обычного звонка показывает своё уведомление после `onShowIncomingCallUi` и обрабатывает отказ Telecom.
## 2. Разбиение файлов (отдельный каталог `src/call/`)
| Файл | Язык | Сборки | Назначение |
@@ -34,7 +59,7 @@ Autotools-сборка демона остаётся C-only (`.cpp` не ком
`ROUTER_SVC_PAYLOAD_OFF=26`, затем subcmd и тело команды.
```
CALL_INVITE 0x01 {call_id:8, group_id:8, tracks:[{type:AUDIO, codec:OPUS, sr:4, ch:1, bitrate:4}]}
CALL_INVITE 0x01 {call_id:8, group_id:8, num_tracks:1, force:1, expires_us:8, tracks:[{type:AUDIO, codec:OPUS, sr:4, ch:1, bitrate:4}]}
CALL_RINGING 0x02 {call_id:8}
CALL_ACCEPT 0x03 {call_id:8}
CALL_DECLINE 0x04 {call_id:8, reason:1}
@@ -42,6 +67,7 @@ CALL_BUSY 0x05 {call_id:8}
CALL_CANCEL 0x06 {call_id:8}
CALL_HANGUP 0x07 {call_id:8, reason:1}
CALL_END_ACK 0x08 {call_id:8}
CALL_PHONE_BUSY 0x09 {call_id:8}
CALL_MEDIA 0x10 {call_id:8, track_id:1, seq:2, ts_ms:4, capture_pts_us:8, capture_epoch:8, codec_delay_samples:4, payload}
```
@@ -72,7 +98,7 @@ NO_TRAFFIC / RING_TIMEOUT / CONNECT_FAIL`.
держит маршрут живым;
- **watchdog 2с у вызываемого** — нет кодограммы 2с → вызов считается сорванным
(отмена потерялась), сессия закрывается локально (`CALL_REASON_CANCEL`);
- ring-timeout 45с (вызывающий, нет ответа → CANCEL);
- ring-timeout 60с от начала, включая ожидание решения вызывающего (нет ответа → CANCEL);
- `CONN_EVENT_DOWN/TIMEOUT` CM не завершают звонок: роутер использует доступные пути;
- **NO_TRAFFIC 20с** — нет входящих медиа-кадров → авто HANGUP.