SHiNE-server/Логика_установки_соединения_через_сервер_СТАРЫЙ_УДАЛИТЬ.md

114 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Логика установки соединения через сервер
Ниже описан фактический flow звонка в текущей реализации SHiNE с опорой на сообщения, которые проходят через сервер.
## 1) Основные операции и типы сообщений
Клиентские WS-операции:
- `CallInviteBroadcast` — широковещательный входящий вызов пользователю.
- `CallSignalToSession` — точечный сигнал в конкретную сессию.
Серверные события клиенту:
- `IncomingCallInvite` — уведомление о входящем вызове.
- `IncomingCallSignal` — сигнал по активному `callId`.
Коды `type` в `IncomingCallSignal`:
- `100``INVITE`
- `110``RINGING`
- `120``ACCEPT`
- `130``DECLINE_BUSY`
- `140``TIMEOUT`
- `150``HANGUP`
- `200``OFFER`
- `210``ANSWER`
- `220``ICE`
---
## 2) Старт исходящего звонка
1. Инициатор создаёт `callId` и отправляет:
- `CallInviteBroadcast(toLogin, callId, type=100)`.
2. Сервер находит все активные WS-сессии целевого логина и шлёт им `IncomingCallInvite`.
3. На устройствах callee появляется экран входящего вызова.
---
## 3) Ранние статусы до поднятия трубки
Каждое устройство callee может отправить инициатору:
- `RINGING (110)` — «звонок идёт».
Для исходящего звонка инициатор фиксирует выбранную `remoteSessionId`:
- первый валидный `RINGING`/`ACCEPT` выбирает сессию,
- сигналы с тем же `callId`, но от других сессий этого же пользователя, игнорируются.
Это защищает от гонок мультидевайса.
---
## 4) Принятие звонка на одном устройстве callee
1. На выбранном устройстве callee пользователь нажимает «Поднять»:
- отправляется `ACCEPT (120)` в выбранную сессию инициатора.
2. Сервер дополнительно рассылает на **другие** сессии этого же callee:
- `HANGUP (150)` с `data=accepted_on_other_device`.
3. Остальные устройства callee закрывают экран входящего вызова.
Итог: активным остаётся один путь «инициатор ↔ выбранная сессия callee».
---
## 5) Обмен SDP (OFFER/ANSWER)
После `ACCEPT`:
1. Инициатор формирует `RTCPeerConnection`, `createOffer()`, отправляет:
- `OFFER (200)`.
2. Calee применяет `setRemoteDescription(offer)`, делает `createAnswer()`, отправляет:
- `ANSWER (210)`.
3. Инициатор применяет `setRemoteDescription(answer)`.
Защиты:
- повторный `ACCEPT`/повторный старт `offer` игнорируется;
- `ANSWER` обрабатывается только для исходящего звонка;
- `ANSWER` без локального `offer` или дубликат в `stable` игнорируется.
---
## 6) Обмен ICE-кандидатами
`ICE (220)` может приходить раньше SDP. Поэтому:
- если `pc` ещё не создан — ICE кладётся в очередь;
- если `pc` есть, но `remoteDescription` ещё нет — ICE тоже в очередь;
- после установки `remoteDescription` очередь применяется (`addIceCandidate`).
Это устраняет race «remote description was null».
---
## 7) Завершение и ошибки
Нормальное завершение:
- `HANGUP (150)` от одной стороны → вторая завершает звонок.
Неуспех установки:
- сторона, у которой setup не удался, шлёт `HANGUP (150)` с `data=setup_failed:...`,
- вторая сторона сразу закрывает экран ожидания.
Также пишутся `CallDeliveryReport`:
- `call_connected`, `incoming_failed`, `outgoing_failed`, `unknown_error` и расширенная диагностика ICE/SDP.
---
## 8) Почему схема устойчива сейчас
Текущая устойчивость обеспечивается тремя правилами:
1. **Одна выбранная сессия callee** для исходящего звонка.
2. **Принятие на одном устройстве закрывает входящий на остальных** через сервер.
3. **ICE буферизуется до готовности SDP/PC**, а не ломает handshake.
Именно комбинация этих трёх пунктов закрывает основные причины «иногда дозванивается, иногда нет» при мультидевайсе.