There are two kinds of connectors. The front and the back connectors. The only front connector is the BrowserConnector. It has access to all WebSocket connections and is responsible for delivering RCT:engine protocol messages to the WebSocket clients, and for forwarding messages from the WebSocket clients to the router.
Currently there are four back connectors (SipConnector, XmppConnector, WebrtcConnector, ConferenceConnector). Every back connector implements a certain communication use case.
The router is very simple stateless message broker, that is responsible for delivering the messages to the right connector. To decide where to send the message, the router takes a look at the recipient address (to) and forwards the message to the specified connector.
An app is a scope for a certain RTC:engine integration. Every user can have multiple apps. And an app contains sessions.
A network is a user wide configuration, that maps a custom network name (tag) to a certain back connector. Additionally it can also store network specific configurations. And any account that is related to a certain network, will merge its custom configs with the network configs, and send its messages to the specified connector.
An account represents the credentials for a specific network. Usually it consists of an identifier like a SIP uri (sip:user@domain.tld) and an access token or rather a password.
A typical message created by the browser sdk contains the following fields:
{ "method": "module.action", "from": "connector:id", "to": "connector:id", "session": "session", "body": { ... } }
It is separated in two parts. The first part is the module. It is a delegation key to separate concerns in the code. The second part is the action, which represents a specific method in a module.
It represents the current sender of a message. For example the user creates a new call via the browser sdk, the message would look like this:
{ "method": "call.start", "from": "", "to": "webrtc:b2bua1", "session": "session1", "body": { ... } }
The content of the field is completely irrelevant, because the BrowserConnector will overwrite this field. The reason is to avoid user manipulation.
{ "method": "call.start", "from": "browser:ws1", "to": "webrtc:b2bua1", "session": "session1", "body": { ... } }
In general this field represents the recipient of a message. The recipients address consists of two parts. First part is the prefix that targets the connector. Second part is the identifier of the recipient.
If you provisioned with the RTCEngine, you get a session and its token property. The browser SDK adds this token to every message.
Mainly an account consists of credentials (identifier, accessToken), that are needed to authenticate against the related network. Its lifecycle is bound to the lifecycle of the related session.
After RTC:engine received session.open, it responds a session.validated message. This message contains all provisioned accounts in its property "body.accounts".
RTC:engine needs one message per account. The message should contain the id of the account. The id is the object key in the accounts object from the [session.validated](../session/index.md) message.
{ "from": "", "to": "...:...", "method": "account.connect", "session": "...", "body": { "id": "..." } }
This message gives state information about the authentication and registration process of the related network and the corresponding connector. For example, if the related connector is the SipConnector, it creates a new SIP B2BUA in background, and notify the browser if any state change happens.
{ "from": "...:...", "to": "browser:...", "method": "account.state", "session": "...", "body": { "id": "...", "reason": "...", "state": "..." } }
The caller sends this message to the RTC:engine to initiate a new call dialog.
{ "from": "local", "to": ["...:..."], "method": "call.start", "session": "...", "body": { "id": "...", "gcid": "...", "account": "..." "replace": true|false, "trickle": true|false, "target": "...", "sdp": "..." } }
The id is a UUID version 4 that identifies the call dialog in the system. But caller and callee never have the same.
Whereas the gcid is a system wide and end-to-end consistent call identifier. It is necessary to track the entire call dialog.
If is set to true, the callee expects ice candidates, before the full sdp delivered by the caller, to accelerate the negotiation process.
The sdp property contains a very early state of the browsers media machine. It contains no ice candidates so far.
After the callee received the "call.start" message, it responds with a "call.alive" to the RTC:engine, immediately.
{ "from": "...", "to": "...", "method": "call.alive", "session": "...", "body": { "id": "...", "gcid": "..." } }
After the callee received the "call.start" message, it responds with a "call.ringing" to the RTC:engine, immediately.
{ "from": "...", "to": "...", "method": "call.ringing", "session": "...", "body": { "id": "...", "gcid": "...", "account": null } }
The callee sends this message after accepting the call explicitly.
{ "from": "...", "to": "...", "method": "call.accept", "session": "...", "body": { "id": "...", "gcid": "...", "account": null, "trickle": true|false, "sdp": "..." } }
Caller sends this message after it received the "call.accept" message from the callee.
{ "from": "...", "to": "...", "method": "call.ack.accept", "session": "...", "body": { "id": "...", "gcid": "..." } }
Both, caller and callee send ice candidates immediately after initiating respectively accepting the call.
{ "from": "...", "to": "...", "method": "call.candidate", "session": "...", "body": { "id": "...", "gcid": "...", "candidate": { "payload": "...", "type": "WEBRTC_LEGACY" } } }
Both, caller and callee send this message after the ice gathering finished and all candidates are available.
{ "from": "...", "to": "...", "method": "call.fullsdp", "session": "...", "body": { "id": "...", "gcid": "...", "sdp": "..." } }
All messages, that begin with "call.change", are important for renegotiation and glare handling.
Only works if the connector of the related account supports DTMF messages.
{ "from": "...", "to": "...", "method": "call.dtmf", "session": "...", "body": { "id": "...", "gcid": "...", "dtmf": "...", "account": null } }
Both, caller and callee can send this message. It forces the counter part to end and destroy the call.
{ "from": "...", "to": "...", "method": "call.end", "session": "...", "body": { "id": "...", "gcid": "...", "reason": "..." } }
{ "method": "session.open", "from": "", "to": "", "session": "session1", "body": { "credentials": { "userSession": "session1" } } }
This message is the response to session.open. If the session property is a valid session, you get a response where the result property is true. In addition you get the account information to connect to the networks.
{ "method": "session.validated", "from": "core", "to": "browser:ws1", "session": "session1" "body": { "result": true, "accounts": { "account1": { "identifier": "sip:account1@foo.bar" "target": "sip-connector:b2bua-account1", "network": { "tag": "sip-network" } } } }, }
If something went wrong, result is set to false and an error reason appears.
{ "method": "session.validated", "from": "core", "to": "browser:ws1", "session": "session1" "body": { "result": false, "reason": { "type": "invalidToken", "message": "Your token is not a valid user session token!" } } }, }