WSMServer
WSMServer — мост между WSMedia WebSocket session и внутренним UDP media translator. Он не знает про UI-устройства напрямую. Его единица маршрутизации — ssrc.
Основной алгоритм
flowchart TB
Frame[WS binary media frame]
Header[Parse WsBinaryMediaHeader]
SSRC[ssrc]
Find[Find socket by ssrc]
Create[Create UDP socket for ssrc]
SendUDP[Send payload to 127.0.0.1:port]
Translator[Media translator]
Frame --> Header --> SSRC --> Find
Find -->|exists| SendUDP
Find -->|missing| Create --> SendUDP
SendUDP --> Translator
Обратная доставка
sequenceDiagram
participant Translator
participant UDP as Per-SSRC UDP socket
participant WSM as WSMServer
participant WS as WSMedia session
participant Client
Translator->>UDP: RTP/RTCP packet
UDP->>WSM: callback(data, src address, local socket port)
WSM->>WSM: local port -> ssrc -> session
WSM->>WS: write WSM binary media frame
WS-->>Client: frame with ssrc
Client->>Client: demux by ssrc
Cleanup session
flowchart TB
Logout[WSMedia logout / socket closed]
End[WSMServer::EndSession(session)]
Iterate[Iterate sockets]
Match{socket.session == session}
Stop[Stop UDP socket]
Erase[Erase ssrc and local port mappings]
Logout --> End --> Iterate --> Match
Match -->|yes| Stop --> Erase
Match -->|no| Iterate
Подтверждённый инвариант
Одна WSMedia session может владеть несколькими ssrc. Это видно из текущей реализации:
socketsхранитssrc -> Socket{ session, udp_socket };portsхранитudp local port -> ssrc;Send(session, data)создаёт UDP socket поssrc, если его ещё нет;SendToWS(...)находитssrcпо local UDP port и пишет frame в сохранённуюsession;EndSession(session)удаляет все sockets, чейsocket.sessionсовпадает с закрываемой session.
Что нельзя ломать
- Нельзя делать
session -> single ssrc. - Нельзя удалять все
ssrcклиента при одномdevice_disconnect, если media session остаётся живой. - Нельзя считать количество
WSMediasessions количеством устройств. - Нельзя маршрутизировать WSMedia payload по
device_id; только поssrc.