Fork me on GitHub
Data Structures | Macros | Typedefs
plugin.h File Reference

Plugin-Core communication (implementation) More...

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <inttypes.h>
#include <glib.h>
#include "refcount.h"
Include dependency graph for plugin.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  janus_plugin_session
 Plugin-Gateway session mapping. More...
 
struct  janus_plugin
 The plugin session and callbacks interface. More...
 
struct  janus_callbacks
 Callbacks to contact the Janus core. More...
 
struct  janus_plugin_result
 Janus plugin result. More...
 
struct  janus_plugin_rtp_extensions
 Janus plugin RTP extensions. More...
 
struct  janus_plugin_rtp
 Janus plugin RTP packet. More...
 
struct  janus_plugin_rtcp
 Janus plugin RTCP packet. More...
 
struct  janus_plugin_data
 Janus plugin data message. More...
 

Macros

#define JANUS_PLUGIN_API_VERSION   15
 Version of the API, to match the one plugins were compiled against. More...
 
#define JANUS_PLUGIN_INIT(...)
 Initialization of all plugin properties to NULL. More...
 

Typedefs

typedef struct janus_callbacks janus_callbacks
 Callbacks to contact the Janus core. More...
 
typedef struct janus_plugin janus_plugin
 The plugin session and callbacks interface. More...
 
typedef struct janus_plugin_session janus_plugin_session
 Plugin-Gateway session mapping. More...
 
typedef struct janus_plugin_result janus_plugin_result
 Result of individual requests passed to plugins. More...
 
typedef struct janus_plugin_rtp janus_plugin_rtp
 RTP packet exchanged with the core. More...
 
typedef struct janus_plugin_rtp_extensions janus_plugin_rtp_extensions
 RTP extensions parsed in an RTP packet. More...
 
typedef struct janus_plugin_rtcp janus_plugin_rtcp
 RTCP message exchanged with the core. More...
 
typedef struct janus_plugin_data janus_plugin_data
 Data message exchanged with the core. More...
 
typedef struct json_t json_t
 
typedef janus_plugincreate_p(void)
 The hook that plugins need to implement to be created from the Janus core. More...
 

Functions

Janus plugin media packets

The Janus core and plugins exchange different kind of media packets, specifically RTP packets, RTCP messages and datachannel data. While previously these were exchanged between core and plugins using generic pointers and their length, Janus now uses a dedicated structure for each of them: this allows metadata and other info to be carried along the media data itself, making the exchange process extensible as a result (the signature remains the same, the data contained in the struct can change).

The janus_plugin_rtp structure represents an RTP packet. When creating a new packet, it should be initialized with janus_plugin_rtp_init. Besides the data and its length, it also contains info on whether the packet is audio or video, and a list of the parsed RTP extensions provided in an instance of the janus_plugin_rtp_extensions structure. Notice that, while this list of extensions is mostly a commodity when receiving a packet, making it easier to access their values (the RTP extensions will still be part of the incoming RTP packet, so plugins are still free to parse them manually), they're very important when it comes to outgoing packets instead: in fact, since the Janus core may needs to terminate its own extensions with the peer, all RTP extensions that are in an RTP packet sent by a plugin are stripped when relay_rtp is called. This means that any attempt to inject an RTP extension in an outgoing packet will fail if the RTP extension is added to the payload manually, and will need to be set in the janus_plugin_rtp_extensions structure instead. It's also important to initialize the extensions structure before passing the packet to the core, as for each extension there may be a different way of telling the core whether the extension needs to be added or not (e.f., -1 instead of 0 or NULL ) . If the RTP extension management you need is not supported, it must be added to the core to get it working.

The janus_plugin_rtcp, instead, represents an RTCP packet, which may contain one or more RTCP compound messages. The only info it contains are whether it's related to the audio or video stream, and a pointer to the data itself and its length. When creating a new packet, it should be initialized with janus_plugin_rtcp_init. To make the generation of some of the most common RTCP messages easier, a few helper core callbacks are provided: this means that, while you can craft RTCP messages yourself using the methods available in rtcp.h, it might be easier to send, e.g., a keyframe request using the dedicated method, which will leave the RTCP crafting process up tp the core.

Finally, the janus_plugin_data represents a datachannel message. The only info it contains are the label the message came from, a pointer to the data itself and its length. When creating a new packet, it MUST be initialized with janus_plugin_data_init.

void janus_plugin_rtp_extensions_reset (janus_plugin_rtp_extensions *extensions)
 Helper method to initialise/reset the RTP extensions field. More...
 
void janus_plugin_rtp_reset (janus_plugin_rtp *packet)
 Helper method to initialise/reset the RTP packet. More...
 
void janus_plugin_rtcp_reset (janus_plugin_rtcp *packet)
 Helper method to initialise/reset the RTCP packet. More...
 
void janus_plugin_data_reset (janus_plugin_data *packet)
 Helper method to initialise/reset the data message. More...
 

Janus plugin results

When a client sends a message to a plugin (e.g., a request or a command) this is notified to the plugin through a handle_message() callback. The plugin can then either handle the request immediately and provide a response (synchronous approach) or decide to queue it and process it later (asynchronous approach). In both cases the plugin must return a janus_plugin_result instance to the core, that will allow the client to: 1. know whether a response is immediately available or it will be later on through notifications, and 2. what the actual content of the result might be. Of course, notifications related to the transaction may occur later on even for synchronous requests, if the plugin was implemented with use cases that envisage this approach.

Note
An error may be returned as well, but this would cause a core-level error to be returned to the client. If you want to provide indications about a failed operation for application-level reason, the correct approach is to return a success with a plugin-specific payload describing the error.
enum  janus_plugin_result_type { JANUS_PLUGIN_ERROR = -1, JANUS_PLUGIN_OK, JANUS_PLUGIN_OK_WAIT }
 Result types. More...
 
typedef enum janus_plugin_result_type janus_plugin_result_type
 Result types. More...
 
janus_plugin_resultjanus_plugin_result_new (janus_plugin_result_type type, const char *text, json_t *content)
 Helper to quickly create a janus_plugin_result instance. More...
 
void janus_plugin_result_destroy (janus_plugin_result *result)
 Helper to quickly destroy a janus_plugin_result instance. More...
 

Detailed Description

Plugin-Core communication (implementation)

Plugin-Core communication.

Author
Lorenzo Miniero loren.nosp@m.zo@m.nosp@m.eetec.nosp@m.ho.c.nosp@m.om

Plugin API

Author
Lorenzo Miniero loren.nosp@m.zo@m.nosp@m.eetec.nosp@m.ho.c.nosp@m.om

In particular, the Janus core implements the janus_callbacks interface. This means that, as a plugin, you can use the methods it exposes to contact the core, e.g., in order to have it relay a message, event or RTP/RTCP packet to the peer you're handling. In particular, the methods the core exposes to plugins are:

On the other hand, a plugin that wants to register at the Janus core needs to implement the janus_plugin interface. Besides, as a plugin is a shared object, and as such external to the core itself, in order to be dynamically loaded at startup it needs to implement the create_p() hook as well, that should return a pointer to the plugin instance. This is an example of such a step:

static janus_plugin myplugin = {
        [..]
};

janus_plugin *create(void) {
        JANUS_LOG(LOG_VERB, , "%s created!\n", MY_PLUGIN_NAME);
        return &myplugin;
}

This will make sure that your plugin is loaded at startup by the Janus core, if it is deployed in the proper folder.

As anticipated and described in the above example, a plugin must basically be an instance of the janus_plugin type. As such, it must implement the following methods and callbacks for the core:

All the above methods and callbacks, except for incoming_rtp , incoming_rtcp , incoming_data and slow_link , are mandatory: the Janus core will reject a plugin that doesn't implement any of the mandatory callbacks. The previously mentioned ones, instead, are optional, so you're free to implement only those you care about. If your plugin will not handle any data channel, for instance, it makes sense to not implement the incoming_data callback at all. At the same time, if your plugin is ONLY going to use data channels and can't care less about RTP or RTCP, incoming_rtp and incoming_rtcp can be left out. Finally, slow_link is just there as a helper, some additional information you may be interested about, but you're not forced to receive it if you don't care.

The Janus core janus_callbacks interface is provided to a plugin, together with the path to the configurations files folder, in the init() method. This path can be used to read and parse a configuration file for the plugin: the plugins we made available out of the box use the package name as a name for the file (e.g., janus.plugin.echotest.cfg for the Echo Test plugin), but you're free to use a different one, as long as it doesn't collide with existing ones. Besides, the existing plugins use the same INI format for configuration files the core uses (relying on the janus_config helpers for the purpose) but again, if you prefer a different format (XML, JSON, etc.) that's up to you.

Both the the Janus core and a plugin can have several different sessions with the same and/or different peers: to match a specific session, a plugin can rely on a mapping called janus_plugin_session that is what all the communication between the plugins and the core (that is, both methods invoked by the core and callbacks invoked by the plugins) will make use of. See the janus_videoroom.c plugin for an example of multiple handles associated to the same peer.

All messages/requests/events sent to and received from a plugin are asynchronous, meaning there's no way to immediately reply to a message sent by a browser, for instance. Messages/requests coming from browsers in a handle_message() callback, though, have a transaction identifier, which you can use in a push_event() reply to allow the browser to match it to the original request, if needed.

As anticipated, both handle_message() and push_event() can attach a JSEP/SDP payload. This means that a browser, for instance, can attach a JSEP/SDP offer to negotiate a WebRTC PeerConnection with a plugin: the plugin would then need to provide, immediately or not, a JSEP/SDP answer to do so. At the same time, a plugin may want to originate the call instead: in that case, the plugin would attach a JSEP/SDP offer in a push_event() call, to which the browser would then need to reply with a JSEP/SDP answer, as described in JavaScript API. Renegotiating a session can be done using the same mechanism above: in case plugins want to force an ICE restart, though, they must add a boolean property called restart to the JSEP object before passing it to the core. Notice that the core adds a property called update whenever the remote user is requesting a renegotiation, whether it's for ICE restarts or just for some media related change.

Note
It's important to notice that, while the Janus core would indeed take care of the WebRTC PeerConnection setup itself in terms of ICE/DTLS/RT(C)P on your behalf, plugins are what will actually manipulate the media flowing around, and as such it's them who are responsible for what concerns the codec negotiation in a JSEP/SDP offer/answer. This normally is not something you need to worry about, especially if you're just moving SDP around (e.g., janus_echotest.c or janus_videocall.c). If your plugin is going to generate media frames (e.g., as janus_audiobridge.c), you only support some codecs (e.g., Opus in janus_audiobridge.c) or you want to use the same SDP offer for several different sessions (e.g., a webinar), you need to make sure that your offer/answer does not contain anything you don't support. Besides, you also need to make sure that you use SDP-provided information (e.g., payload types, increasing versions in case of renegotiations) coherently.

Plugin API

Macro Definition Documentation

◆ JANUS_PLUGIN_API_VERSION

#define JANUS_PLUGIN_API_VERSION   15

Version of the API, to match the one plugins were compiled against.

Note
This was added in version 0.0.7 of Janus, to address changes to the API that might break existing plugin or the core itself. All plugins MUST implement the get_api_compatibility() method to make this work. Do NOT try to launch a pre 0.0.7 plugin on a >= 0.0.7 Janus instance or it will crash.

◆ JANUS_PLUGIN_INIT

#define JANUS_PLUGIN_INIT (   ...)
Value:
{ \
.init = NULL, \
.destroy = NULL, \
.get_api_compatibility = NULL, \
.get_version = NULL, \
.get_version_string = NULL, \
.get_description = NULL, \
.get_name = NULL, \
.get_author = NULL, \
.get_package = NULL, \
.create_session = NULL, \
.handle_message = NULL, \
.handle_admin_message = NULL, \
.setup_media = NULL, \
.incoming_rtp = NULL, \
.incoming_rtcp = NULL, \
.incoming_data = NULL, \
.data_ready = NULL, \
.slow_link = NULL, \
.hangup_media = NULL, \
.destroy_session = NULL, \
.query_session = NULL, \
## __VA_ARGS__ }

Initialization of all plugin properties to NULL.

Note
This was added in version 0.0.8 of Janus, to address changes to the API that might break existing plugin or the core itself. All plugins MUST add this as the FIRST line when initializing their plugin structure, e.g.:
static janus_plugin janus_echotest_plugin =
        {
                JANUS_PLUGIN_INIT,

                .init = janus_echotest_init,
                [..]

Typedef Documentation

◆ create_p

typedef janus_plugin* create_p(void)

The hook that plugins need to implement to be created from the Janus core.

◆ janus_callbacks

Callbacks to contact the Janus core.

◆ janus_plugin

typedef struct janus_plugin janus_plugin

The plugin session and callbacks interface.

◆ janus_plugin_data

Data message exchanged with the core.

◆ janus_plugin_result

Result of individual requests passed to plugins.

◆ janus_plugin_result_type

Result types.

◆ janus_plugin_rtcp

RTCP message exchanged with the core.

◆ janus_plugin_rtp

RTP packet exchanged with the core.

◆ janus_plugin_rtp_extensions

RTP extensions parsed in an RTP packet.

◆ janus_plugin_session

Plugin-Gateway session mapping.

◆ json_t

typedef struct json_t json_t

Enumeration Type Documentation

◆ janus_plugin_result_type

Result types.

Enumerator
JANUS_PLUGIN_ERROR 

A severe error happened (not an application level error)

JANUS_PLUGIN_OK 

The request was correctly handled and a response is provided (synchronous)

JANUS_PLUGIN_OK_WAIT 

The request was correctly handled and notifications will follow with more info (asynchronous)

Function Documentation

◆ janus_plugin_data_reset()

void janus_plugin_data_reset ( janus_plugin_data packet)

Helper method to initialise/reset the data message.

Parameters
[in]packetPointer to the janus_plugin_data message to reset

◆ janus_plugin_result_destroy()

void janus_plugin_result_destroy ( janus_plugin_result result)

Helper to quickly destroy a janus_plugin_result instance.

Parameters
[in]resultThe janus_plugin_result instance to destroy
Returns
A valid janus_plugin_result instance, if successful, or NULL otherwise

◆ janus_plugin_result_new()

janus_plugin_result* janus_plugin_result_new ( janus_plugin_result_type  type,
const char *  text,
json_t content 
)

Helper to quickly create a janus_plugin_result instance.

Parameters
[in]typeThe type of result
[in]textString to add to the result (for JANUS_PLUGIN_OK_WAIT or JANUS_PLUGIN_ERROR), if any
[in]contentThe json_t object with the content of the result, if any
Returns
A valid janus_plugin_result instance, if successful, or NULL otherwise

◆ janus_plugin_rtcp_reset()

void janus_plugin_rtcp_reset ( janus_plugin_rtcp packet)

Helper method to initialise/reset the RTCP packet.

Parameters
[in]packetPointer to the janus_plugin_rtcp packet to reset

◆ janus_plugin_rtp_extensions_reset()

void janus_plugin_rtp_extensions_reset ( janus_plugin_rtp_extensions extensions)

Helper method to initialise/reset the RTP extensions field.

Note
This is important because each of the supported extensions may use a different value to specify an "extension missing" state, which may be different from a 0 or a NULL (e.g., a -1 instead)
Parameters
[in]extensionsPointer to the janus_plugin_rtp_extensions instance to reset

◆ janus_plugin_rtp_reset()

void janus_plugin_rtp_reset ( janus_plugin_rtp packet)

Helper method to initialise/reset the RTP packet.

Note
The main motivation for this method comes from the presence of the extensions as a janus_plugin_rtp_extensions instance.
Parameters
[in]packetPointer to the janus_plugin_rtp packet to reset