Controlling and monitoring a Janus instance can be done using the Admin/Monitor API which includes ways to query information related to the state of ongoing PeerConnections (ICE/DTLS state, stats, etc.). That said, while powerful and useful the Admin API is a poll-based protocol: this means that you have to query for information yourself, and if you want to keep up-to-date with what is happening, you have to do that on a regular basis. As such, things can get problematic when dealing with many sessions and handles running in your application, as you may not be immediately aware of which session/handle corresponds to what, or which of them belong to the same scenario (e.g., all PeerConnections established in the context of the same VideoRoom).
This is where Event Handlers can help. Just like media and transport plugins, Event Handlers plugins in Janus themselves, meaning their modular nature allows for extensibility. When enabling Event handlers, Janus and other plugins generate real-time events related to several different aspects that may be happening during its lifetime: these events are then passed to all the available event handler plugins, plugins that can then decide to do with these events whatever they want. They might choose to store these events somehow, aggregate, dump or process them, format and send them to an external application, and so on. This really depends on what these events should be used for.
Janus will generate events related to:
All events generated by Janus are JSON object, which have a shared header and a custom body that will depend on the type (and in some cases subtype) of the event itself.
The header of the event will contain some information that is usually common to all events: this includes type
and (when needed) subtype
of the event, a timestamp in microseconds (so that you can know exactly when the event was generated in the first place from the server's perspective, no matter it was received), and various IDs. These IDs include the session identifier (Janus session the event refers to), the handle identifier (Janus handle the event refers to) and an opaque ID (set by whoever controls the Janus API): as we'll see, all these IDs are optional, as there are events that are not related to a session in particular (e.g., a server shutdown event), but can be very important for correlation purposes when they're used.
The generic format of events is the following:
{ "emitter" : "<string identifying the source of the event, if configured (optional)>", "type" : <numeric event type identifier>, "subtype" : <numeric event subtype identifier (specific to the event type; optional)>, "timestamp" : <time of when the event was generated>, "session_id" : <unique session identifier, if provided/available (optional)>, "handle_id" : <unique handle identifier, if provided/available (optional)>, "opaque_id" : "<user-provided opaque identifier, if provided/available (optional)>", "event" : { <event body, custom depending on event type> } }
For instance, this is what an event related to a new session being created would look like:
{ "emitter": "MyJanusInstance", "type": 1, "timestamp": 1582211094846980, "session_id": 3439056127855429, "event": { "name": "created", "transport": { "transport": "janus.transport.http", "id": "0x60400002c2d0" } } }
Since type
1
is related to session events, this event basically tells us that a new session with ID 3439056127855429
was created (we know this from the name
property in the event body) on the Janus instance called MyJanusInstance
at the timestamp 1582211094846980
. There are no subtype
, handle_id
or opaque_id
properties as they were unneeded or not applicable here.
As we've seen from the previous example, event types are numeric. In order to figure out what you're receiving, you can refer to the following table as a reference:
Type | Category of event |
---|---|
1 | Session related event |
2 | Handle related event |
4 | External event (injected via Admin API) |
8 | JSEP event (SDP offer/answer) |
16 | WebRTC state event (ICE/DTLS states, candidates, etc.) |
32 | Media event (media state, reports, etc.) |
64 | Plugin-originated event (e.g., event coming from VideoRoom) |
128 | Transport-originated event (e.g., WebSocket connection state) |
256 | Core event (server startup/shutdown) |
The types of events are not monotonically increasing as, internally, they're represented as a mask: this allows event handler plugins to only subscribe to a subset of them, rather than them all, when needed.
The event type
property dictates the syntax of the event
body , meaning that the body for a JSEP event (type 8
) will for instance be very different from a media event (type 32
). That said, the format of some events can change even within the same type: for instance, a WebRTC state event includes a lot of different notifications, including ICE states, DTLS states, local and remote candidates, selected pair, etc. In order to allow event handler recipients written in strongly typed languages to be able to use different classes for the different events, a different property called subtype
can help further discriminate an event of a specified type
. At the time of writing, a subtype
attribute will only be present if the event is of type 256
(core), 16
(WebRTC) and 32
(media): all other event types have a consistent format, and so don't need this differentiation (e.g., type 8
includes both SDP offers and answers, but the nature of the SDP is indicated in an attribute that has the same name in both cases).
The available subtypes are the following:
Core subtype | |
---|---|
1 | Server startup |
2 | Server shutdown |
WebRTC subtype | |
1 | ICE state |
2 | Local candidate |
3 | Remote candidate |
4 | Selected pair |
5 | DTLS state |
6 | PeerConnection state |
Media subtype | |
1 | Medium state |
2 | Slow link |
3 | Report/stats |