/*! * \mainpage Janus - General purpose WebRTC server * * \par Developer Documentation for the Janus WebRTC server * This is the main developer documentation for the Janus WebRTC * Server, generated with the help of * Doxygen. Make sure you * check the \ref DEPS before attempting a compilation. If you are * interested in how to compile, install and use Janus, * checkout the \ref README information. A \ref FAQ page is also available, * as well as an overview on \ref CHANGELOG. * * \par A general purpose WebRTC server * The Janus WebRTC Server has been conceived as a general purpose * server. As such, it doesn't provide any functionality per se * other than implementing the means to set up a WebRTC media communication * with a browser, exchanging JSON messages with it, and relaying RTP/RTCP * and messages between browsers and the server-side application logic they're attached to. Any specific * feature/application needs to be implemented in server side plugins, * that browsers can then contact via the Janus core to take advantage of * the functionality they provide. Example of such plugins can be * implementations of applications like echo tests, conference bridges, * media recorders, SIP gateways and the like. * * The reason for this is simple: we wanted something that would have a * small footprint (hence a C implementation) and that we could only * equip with what was really needed (hence pluggable modules). That is, * something that would allow us to deploy either a full-fledged WebRTC * server on the cloud, or a small nettop/box to handle a specific use case. * * \par Architecture and APIs * The core of the server is specified in the \ref core section. The protocols * implemented in the Janus core are listed in the \ref protocols group * instead. A list of plugins provided out of the box by Meetecho are * documented in the \ref pluginslist page: these plugins can be changed * or extended to match your requirements, or just used as a simple * reference should you be interested in writing a new plugin from * scratch (and you're definitely welcome to!). A \ref pluginapi to * create new plugins, or understand how they're conceived, is documented * as well. A documentation on the available API tranports and the * HTTP/WebSocket JavaScript API to use Janus and the plugins it * makes available in your web application can be found in the \ref JS * and \ref rest pages. New API transports can be created referring to * the \ref transportapi page. If you're interested in monitoring Janus * resources, you can refer to the \ref admin page. Event handler * plugins can also be used for the purpose: refer to the \ref eventhandlers * and, for more developer oriented info, to the \ref eventhandlerapi * page if you're interested in creating your own. For what concerns logging, * out of the box Janus supports printing the output to \c stdout and saving * to a local file, but logging can also be extended via additional plugins: * refer to the \ref loggerapi for more details, and to learn how to write * your own. * * Janus also supports \ref recordings out of the box, so check the * related documentation to know more about how that works. * * Finally, some information on how to deploy Janus and your web * applications that want to make use of it are provided in the \ref deploy * page. If you're interested in starting Janus as a service/daemon rather * than launching it normally, check the information provided in the * \ref service page. Some additional \ref resources are also listed in * case you're interested in talking to Janus from different languages * and platforms. * * To conclude, the \ref debug page contains info on how you can help us * fixing issues you might encounter along the road. * * \section copyright Copyright and author * * Janus WebRTC Server © 2014-2020 Meetecho (http://www.meetecho.com/) * * \author Lorenzo Miniero ( \ref CREDITS ) * * \section license License * This program is free software, distributed under the terms of * the GNU General Public License Version 3. For more details and licensing * options, including a commercial license, see the \ref COPYING page. * */ /*! \page DEPS Dependencies * * The application and the plugins depend on the following open source * software and libraries, so make sure you install the related development * versions before attempting a compilation: * * - \b GLib: http://library.gnome.org/devel/glib/ * - \b pkg-config: http://www.freedesktop.org/wiki/Software/pkg-config/ * - \b gengetopt: http://www.gnu.org/software/gengetopt/ (command line) * - \b Jansson: http://www.digip.org/jansson/ (JSON) * - \b libconfig: https://hyperrealm.github.io/libconfig/ (configuration files) * - \b libnice: http://nice.freedesktop.org/wiki/ (ICE/STUN/TURN, at least v0.1.16 suggested, master recommended) * - \b OpenSSL: http://www.openssl.org/ (DTLS, at least v1.0.1e) * - \b libsrtp: https://github.com/cisco/libsrtp (SRTP, at least v1.5 suggested) * - \b usrsctp: http://code.google.com/p/sctp-refimpl/ (\c optional, Data Channels) * - \b libmicrohttpd: http://www.gnu.org/software/libmicrohttpd/ (\c optional, v0.9.59, Web server) * - \b libwebsockets: https://libwebsockets.org/ (\c optional, WebSockets) * - \b rabbitmq-c: https://github.com/alanxz/rabbitmq-c (\c optional, v1.0.4, RabbitMQ) * - \b paho.mqtt.c: https://eclipse.org/paho/clients/c (\c optional, v1.1.0 for MQTT v3.1 & v3.1.1 or v1.3.0 for MQTT v5) * - \b nanomsg: https://nanomsg.org/ (\c optional, Nanomsg) * - \b Sofia-SIP: http://sofia-sip.sourceforge.net/ (\c optional, only needed for the SIP plugin) * - \b libopus: http://opus-codec.org/ (\c optional, only needed for the bridge plugin) * - \b libogg: http://xiph.org/ogg/ (\c optional, only needed for the voicemail plugin) * - \b libcurl: https://curl.haxx.se/libcurl/ (\c optional, only needed for the TURN REST API, * RTSP support in the Streaming plugin and the sample Event Handler plugin) * - \b zlib: https://zlib.net/ (gzip compression utility) * - \b Lua: https://www.lua.org/download.html (\c optional, only needed for the Lua plugin) * - \b npm: https://docs.npmjs.com/ (\c optional, used during build for generating JavaScript modules) * */ /*! \page JS JavaScript API * Janus exposes, assuming the HTTP transport has been compiled, a * pseudo-RESTful interface, and optionally also WebSocket/RabbitMQ/MQTT/Nanomsg/UnixSockets * interfaces as well, all of which based on JSON messages. These * interfaces are described in more detail in the \ref plainhttp \ref WS * \ref rabbit \ref apimqtt \ref apinanomsg and \ref unix documentation respectively, and all allow clients to * take advantage of the features provided by Janus and the functionality * made available by its plugins. Considering most clients will be web browsers, * a common choice will be to rely on either the REST or the WebSockets * interface for the purpose. To make things easier for web * developers, a JavaScript library (\c janus.js) is available that can * make use of both interfaces using exactly the same API. This library * eases the task of creating sessions with the Janus core, attaching WebRTC * users to plugins, send and receive requests and events to the plugins * themselves and so on. For real examples of how this library can be * used, check the demos in the \b html folder of this package. Notice * that the \c janus.js library makes use of the features made available * by the webrtc-adapter * shim, which means that your web application should always include it * as a dependency. For instance, all the demos link to it externally via * cdnjs.com. * * \note The current \c janus.js library allows you to provide custom implementations of * certain dependencies, in order to make it easier to integrate with other JavaScript * libraries and frameworks. Using this feature you can ensure \c janus.js does not (implicitly) * depend on certain global variables. Two implementations are included in \c janus.js itself: * * -# \ref js-default-deps which relies on native browser APIs, * which in turn require somewhat more modern browsers * -# \ref js-old-deps which uses jQuery (http://jquery.com/) instead, * and should provide equivalent behaviour to previous versions of \c janus.js * * By default \ref js-default-deps will be used, but you can override this * when initialising the Janus library and pass a custom dependencies object instead. * For details, refer to: \ref js-dependencies * * In general, when using the Janus features, you would normally do the following: * * -# include the Janus JavaScript library in your web page; * -# initialize the Janus JavaScript library and (optionally) passing its dependencies; * -# connect to the server and create a session; * -# create one or more handles to attach to a plugin (e.g., echo test and/or streaming); * -# interact with the plugin (sending/receiving messages, negotiating a PeerConnection); * -# eventually, close all the handles and shutdown the related PeerConnections; * -# destroy the session. * * The above steps will be presented in order, describing how you can use * the low level API to accomplish them. Consider that in the future we might * provide higher level wrappers to this API to address specific needs, e.g., * a higher level API for each plugin: this would make it even easier to use * the server features, as a high level API for the streaming plugin, for * instance, may just ask you to provide the server address and the ID of * the \c <video> element to display the stream in, and would take care of all the * above mentioned steps on your behalf. Needless to say, you're very welcome * to provide wrapper APIs yourself, if you feel a sudden urge to do so! :-) * * \section janusjs Using janus.js * * As a first step, you should include the Janus library in your project. * Depending on your needs you can either use \c janus.js or one of the generated * JavaScript module variants of it. For available module syntaxes and how to build the * corresponding variants, see: \ref js-modules * \verbatim \endverbatim * * The core of the JavaScript API is the \c Janus object. This object needs * to be initialized the first time it is used in a page. This can be done * using the static \c init method of the object, which accepts the * following options: * * - \c debug: whether debug should be enabled on the JavaScript console, and what levels * - \c true or \c "all": all debuggers enabled (Janus.trace, Janus.debug, Janus.log, Janus.warn, Janus.error) * - array (e.g., ["trace", "warn"]): only enable selected debuggers (allowed tokens: trace, debug, log, warn, error) * - \c false: disable all debuggers * - \c callback: a user provided function that is invoked when the initialization is complete * - \c dependencies: a user provided implementation of Janus library dependencies * * Here's an example: * * \verbatim Janus.init({ debug: true, dependencies: Janus.useDefaultDependencies(), // or: Janus.useOldDependencies() to get the behaviour of previous Janus versions callback: function() { // Done! }); \endverbatim * * \note When using one of the JavaScript module variants of \c janus.js, you * will need to import the \c Janus symbol from the module first. See also: \ref js-modules * For example, using the ECMAScript module variant, the above example should be altered to: * * \verbatim import * as Janus from './janus.es.js' Janus.init({ debug: true, dependencies: Janus.useDefaultDependencies(), // or: Janus.useOldDependencies() to get the behaviour of previous Janus versions callback: function() { // Done! }); }); \endverbatim * * Once the library has been initialized, you can start creating sessions. * Normally, each browser tab will need a single session with the server: in * fact, each Janus session can contain several different plugin handles * at the same time, meaning you can start several different WebRTC sessions * with the same or different plugins for the same user using the same * Janus session. That said, you're free to set up different Janus * sessions in the same page, should you prefer so. * * Creating a session is quite easy. You just need to use the \c new constructor * to create a new \c Janus object that will handle your interaction with the * server. Considering the dynamic and asynchronous nature of Janus sessions * (events may occur at any time), there are several properties and callbacks you * can configure when creating a session: * * - \c server: the address of the server as a specific address (e.g., * http://yourserver:8088/janus to use the plain HTTP API or ws://yourserver:8188/ * for WebSockets) or as an array of addresses to try sequentially to allow * automatic for fallback/failover during setup; * - \c iceServers: a list of STUN/TURN servers to use (a default STUN server * will be used if you skip this property); * - \c ipv6: whether IPv6 candidates should be gathered or not; * - \c withCredentials: whether the \c withCredentials property of XHR requests * should be enabled or not (false by default, and only valid when using HTTP * as a transport, ignored for WebSockets); * - \c max_poll_events: the number of events that should be returned when polling; * the default is 1 (polling returns an object), passing a higher number will * have the backend return an array of objects instead (again, only valid for HTTP usage as this is strictly related to long polling, ignored for WebSockets); * - \c destroyOnUnload: whether we should destroy automatically try and * destroy this session via Janus API when \c onbeforeunload is called (true by default); * - \c token , \c apisecret: optional parameters only needed in case you're \ref auth ; * - a set of callbacks to be notified about events, namely: * - \c success: the session was successfully created and is ready to be used; * - \c error: the session was NOT successfully created; * - \c destroyed: the session was destroyed and can't be used any more. * * These properties and callbacks are passed to the method as properties * of a single parameter object: that is, the \c Janus constructor takes a * single parameter, which although acts as a container for all the available * options. The \c success callback is where you tipically start your application * logic, e.g., attaching the peer to a plugin and start a media session. * * Here's an example: * \verbatim var janus = new Janus( { server: 'http://yourserver:8088/janus', success: function() { // Done! attach to plugin XYZ }, error: function(cause) { // Error, can't go on... }, destroyed: function() { // I should get rid of this } }); \endverbatim * * As anticipated, the server may be a specific address, e.g.: * \verbatim var janus = new Janus( { server: 'http://yourserver:8088/janus', // or server: 'ws://yourserver:8188/', [..] \endverbatim * * or an array of addresses. Such an array can be especially useful if * you want the library to first check if the WebSockets server is * reachable and, if not, fallback to plain HTTP, or just to provide * a link multiple instances to try for failover. This is an example of * how to pass a 'try websockets and fallback to HTTP' array: * \verbatim var janus = new Janus( { server: ['ws://yourserver:8188/','http://yourserver:8088/janus'], [..] \endverbatim * * Once created, this object represents your session with the server. * you can interact with a \c Janus object in several different ways. * In particular, the following properties and methods are defined: * * - \c getServer(): returns the address of the server; * - \c isConnected(): returns \c true if the Janus instance is connected * to the server, \c false otherwise; * - \c getSessionId(): returns the unique Janus session identifier; * - \c attach(parameters): attaches the session to a plugin, creating an handle; * more handles to the same or different plugins can be created at the same time; * - \c destroy(parameters): destroys the session with the server, and closes * all the handles (and related PeerConnections) the session may have with any plugin as well. * * The most important property is obviously the \c attach() method, as * it's what will allow you to exploit the features of a plugin to manipulate * the media sent and/or received by a PeerConnection in your web page. * This method will create a plugin handle you can use for the purpose, * for which you can configure properties and callbacks when calling the * \c attach() method itself. As for the \c Janus constructor, the \c attach() * method takes a single parameter that can contain any of the following * properties and callbacks: * * - \c plugin: the unique package name of the plugin (e.g., \c janus.plugin.echotest ); * - \c opaqueId: an optional opaque string meaningful to your application (e.g., to map all the handles of the same user); * - a set of callbacks to be notified about events, namely: * - \c success: the handle was successfully created and is ready to be used; * - \c error: the handle was NOT successfully created; * - \c consentDialog: this callback is triggered just before \c getUserMedia is called * (parameter=true) and after it is completed (parameter=false); this means it can * be used to modify the UI accordingly, e.g., to prompt the user about the need to accept the device access consent requests; * - \c webrtcState: this callback is triggered with a true value * when the PeerConnection associated to a handle becomes active (so ICE, DTLS and * everything else succeeded) from the Janus perspective, while false is * triggered when the PeerConnection goes down instead; useful to figure out * when WebRTC is actually up and running between you and Janus (e.g., to notify * a user they're actually now active in a conference); notice that in case * of false a reason string may be present as an optional parameter; * - \c iceState: this callback is triggered when the ICE state for the * PeerConnection associated to the handle changes: the argument of the callback * is the new state as a string (e.g., "connected" or "failed"); * - \c mediaState: this callback is triggered when Janus starts or stops * receiving your media: for instance, a \c mediaState with type=audio and * on=true means Janus started receiving your audio stream (or started * getting them again after a pause of more than a second); a \c mediaState with * type=video and on=false means Janus hasn't received any video * from you in the last second, after a start was detected before; useful to * figure out when Janus actually started handling your media, or to detect * problems on the media path (e.g., media never started, or stopped at some time); * - \c slowLink: this callback is triggered when Janus reports trouble * either sending or receiving media on the specified PeerConnection, typically * as a consequence of too many NACKs received from/sent to the user in the * last second: for instance, a \c slowLink with uplink=true means * you notified several missing packets from Janus, while uplink=false * means Janus is not receiving all your packets; useful to figure out when * there are problems on the media path (e.g., excessive loss), in order to * possibly react accordingly (e.g., decrease the bitrate if most of our * packets are getting lost); * - \c onmessage: a message/event has been received from the plugin; * - \c onlocalstream: a local \c MediaStream is available and ready to be displayed; * - \c onremotestream: a remote \c MediaStream is available and ready to be displayed; * - \c ondataopen: a Data Channel is available and ready to be used; * - \c ondata: data has been received through the Data Channel; * - \c oncleanup: the WebRTC PeerConnection with the plugin was closed; * - \c detached: the plugin handle has been detached by the plugin itself, * and so should not be used anymore. * * Here's an example: * \verbatim // Attach to echo test plugin, using the previously created janus instance janus.attach( { plugin: "janus.plugin.echotest", success: function(pluginHandle) { // Plugin attached! 'pluginHandle' is our handle }, error: function(cause) { // Couldn't attach to the plugin }, consentDialog: function(on) { // e.g., Darken the screen if on=true (getUserMedia incoming), restore it otherwise }, onmessage: function(msg, jsep) { // We got a message/event (msg) from the plugin // If jsep is not null, this involves a WebRTC negotiation }, onlocalstream: function(stream) { // We have a local stream (getUserMedia worked!) to display }, onremotestream: function(stream) { // We have a remote stream (working PeerConnection!) to display }, oncleanup: function() { // PeerConnection with the plugin closed, clean the UI // The plugin handle is still valid so we can create a new one }, detached: function() { // Connection with the plugin closed, get rid of its features // The plugin handle is not valid anymore } }); \endverbatim * * So the \c attach() method allows you to attach to a plugin, and specify * the callbacks to invoke when anything relevant happens in this interaction. * To actively interact with the plugin, you can use the \c Handle object * that is returned by the \c success callback (pluginHandle in the example). * * This \c Handle object has several methods you can use to interact with * the plugin or check the state of the session handle: * * - \c getId(): returns the unique handle identifier; * - \c getPlugin(): returns the unique package name of the attached plugin; * - \c send(parameters): sends a message (with or without a jsep to * negotiate a PeerConnection) to the plugin; * - \c createOffer(callbacks): asks the library to create a WebRTC compliant OFFER; * - \c createAnswer(callbacks): asks the library to create a WebRTC compliant ANSWER; * - \c handleRemoteJsep(callbacks): asks the library to handle an incoming WebRTC compliant session description; * - \c dtmf(parameters): sends a DTMF tone on the PeerConnection; * - \c data(parameters): sends data through the Data Channel, if available; * - \c getBitrate(): gets a verbose description of the currently received stream bitrate; * - \c hangup(sendRequest): tells the library to close the PeerConnection; if the optional \c sendRequest argument is * set to \c true, then a \c hangup Janus API request is sent to Janus as well (disabled by default, Janus can usually * figure this out via DTLS alerts and the like but it may be useful to enable it sometimes); * - \c detach(parameters): detaches from the plugin and destroys the handle, tearing * down the related PeerConnection if it exists. * * While the \c Handle API may look complex, it's actually quite straightforward * once you get the concept. The only step that may require a little more * effort to understand is the PeerConnection negotiation, but again, if * you're familiar with the WebRTC API, the \c Handle actually makes it * a lot easier. * * The idea behind it's usage is the following: * * -# you use \c attach() to create a \c Handle object; * -# in the \c success callback, your application logic can kick in: you may * want to send a message to the plugin (send({msg})), negotiate * a PeerConnection with the plugin right away ( \c createOffer followed * by a send({msg, jsep})) or wait for something to happen to do anything; * -# the \c onmessage callback tells you when you've got messages from the plugin; * if the \c jsep parameter is not null, just pass it to the library, which will take * care of it for you; if it's an \b OFFER use \c createAnswer (followed by a * send({msg, jsep}) to close the loop with the plugin), otherwise use * \c handleRemoteJsep ; * -# whether you took the initiative to set up a PeerConnection or the plugin did, * the \c onlocalstream and/or the \c onremotestream callbacks will provide * you with a stream you can display in your page; * -# each plugin may allow you to manipulate what should flow through the * PeerConnection channel: the \c send method and \c onmessage callback * will allow you to handle this interaction (e.g., to tell the plugin * to mute your stream, or to be notified about someone joining a virtual room), * while the \c ondata callback is triggered whenever data is received * on the Data Channel, if available (and the \c ondataopen callback * will tell you when a Data Channel is actually available). * * The following paragraphs will delve a bit deeper in the negotiation * mechanism provided by the \c Handle API, in particular describing * the properties and callbacks that may be involved. To follow the approach * outlined by the W3C WebRTC API, this negotiation mechanism is heavily * based on asynchronous methods as well. Notice that the following paragraphs * address the first negotiation step, that is the one to create a new * PeerConnection from scratch: to know how to originate or handle a * renegotiation instead (e.g., to add/remove/replace a media source, or * force an ICE restart) check the \ref renegotiation section instead. * * - \c createOffer takes a single parameter, that can contain any of the * following properties and callbacks: * - \c media: you can use this property to tell the library which media (audio/video/data) * you're interested in, and whether you're going to send and/or receive any of them; by default * audio and video are enabled in both directions, while the Data Channels are disabled; * this option is an object that can take any of the following properties: * - \c audioSend: \c true/false (do or do not send audio); * - \c audioRecv: \c true/false (do or do not receive audio); * - \c audio: \c true/false (do or do not send \b and receive audio, takes precedence on the above); * - \c audio: object with \c deviceId property (specify ID of audio device to capture, takes precedence on the above; * devices list can be accessed with \c Janus.listDevices(callback) ); * - \c videoSend: \c true/false (do or do not send video); * - \c videoRecv: \c true/false (do or do not receive video); * - \c video: \c true/false (do or do not send \b and receive video, takes precedence on the above); * - \c video: \c "lowres"/"lowres-16:9"/"stdres"/"stdres-16:9"/"hires"/"hires-16:9" * (send a 320x240/320x180/640x480/640x360/1280x720 video, takes precedence on the above; default is \c "stdres" ) * this property will affect the resulting getUserMedia that the library will issue; please * notice that Firefox doesn't support the \c "16:9" variants, which will fallback * to the ones; besides, \c "hires" and \c "hires-16:9" are currently synonymous, as * there's no 4:3 high resolution constraint as of now; * - \c video: \c "screen" (use screensharing for video, disables audio, takes precedence on both audio and video); * - \c video: object with \c deviceId , \c width and/or \c height properties (specify ID of video device to capture * and optionally resolution to use, takes precedence on the above; devices list can be accessed with \c Janus.listDevices(callback) ); * - \c data: \c true/false (do or do not use Data Channels, default is false) * - \c failIfNoAudio: \c true/false (whether a getUserMedia should fail if audio send is asked, but no audio device is available, default is false) * - \c failIfNoVideo: \c true/false (whether a getUserMedia should fail if video send is asked, but no video device is available, default is false) * - \c screenshareFrameRate: in case you're sharing a screen/application, allows you to specify the framerate (default=3); * - \c trickle: \c true/false, to tell the library whether you want * Trickle ICE to be used (true, the default) or not (false); * - \c stream: optional, only to be passed in case you obtained a MediaStream object yourself with a \c getUserMedia * request, and that you want the library to use instead of having it get one by itself (makes * the \c media property useless, as it won't be read for accessing any device); * - a set of callbacks to be notified about the result, namely: * - \c success: the session description was created (attached as a parameter) and is ready to be sent to the plugin; * - \c error: the session description was NOT successfully created; * - \c customizeSdp: you can modify the sdp generated by the webrtc engine if you need; * - \c createAnswer takes the same options as createOffer, but requires * an additional one as part of the single parameter argument: * - \c jsep: the session description sent by the plugin (e.g., as received * in an \c onmessage callback) as its OFFER. * * Whether you use \c createOffer or \c createAnswer depending on the scenario, * you should end up with a valid \c jsep object returned in the \c success * callback. You can attach this \c jsep object to a message in a \c send request * to pass it to the plugin, and have Janus negotiate a PeerConnection * with your application. * * Here's an example of how to use \c createOffer, taken from the Echo Test demo page: * \verbatim // Attach to echo test plugin janus.attach( { plugin: "janus.plugin.echotest", success: function(pluginHandle) { // Negotiate WebRTC echotest = pluginHandle; var body = { "audio": true, "video": true }; echotest.send({"message": body}); echotest.createOffer( { // No media property provided: by default, // it's sendrecv for audio and video success: function(jsep) { // Got our SDP! Send our OFFER to the plugin echotest.send({"message": body, "jsep": jsep}); }, error: function(error) { // An error occurred... }, customizeSdp: function(jsep) { // if you want to modify the original sdp, do as the following // oldSdp = jsep.sdp; // jsep.sdp = yourNewSdp; } }); }, [..] onmessage: function(msg, jsep) { // Handle msg, if needed, and check jsep if(jsep !== undefined && jsep !== null) { // We have the ANSWER from the plugin echotest.handleRemoteJsep({jsep: jsep}); } }, [..] onlocalstream: function(stream) { // Invoked after createOffer // This is our video }, onremotestream: function(stream) { // Invoked after handleRemoteJsep has got us a PeerConnection // This is the remote video }, [..] \endverbatim * * This, instead, is an example of how to use \c createAnswer, taken from the Streaming demo page: * \verbatim // Attach to echo test plugin janus.attach( { plugin: "janus.plugin.streaming", success: function(pluginHandle) { // Handle created streaming = pluginHandle; [..] }, [..] onmessage: function(msg, jsep) { // Handle msg, if needed, and check jsep if(jsep !== undefined && jsep !== null) { // We have an OFFER from the plugin streaming.createAnswer( { // We attach the remote OFFER jsep: jsep, // We want recvonly audio/video media: { audioSend: false, videoSend: false }, success: function(ourjsep) { // Got our SDP! Send our ANSWER to the plugin var body = { "request": "start" }; streaming.send({"message": body, "jsep": ourjsep}); }, error: function(error) { // An error occurred... } }); } }, [..] onlocalstream: function(stream) { // This will NOT be invoked, we chose recvonly }, onremotestream: function(stream) { // Invoked after send has got us a PeerConnection // This is the remote video }, [..] \endverbatim * * Of course, these are just a couple of examples where the scenarios * assumed that one plugin would only receive (Echo Test) or generate * (Streaming) offers. A more complex example (e.g., a Video Call plugin) * would involve both, allowing you to either send offers to a plugin, * or receive some from them. Handling this is just a matter of checking * the \c type of the \c jsep object and reacting accordingly. * * \section renegotiation Updating an existing PeerConnection (renegotiations) * While the JavaScript APIs described above will suffice for most of the * common scenarios, there are cases when updates on a PeerConnection may * be needed. This can happen whenever, for instance, you want to add a * new media source (e.g., add video to an audio only call), replace an * existing one (e.g., switch from capturing the camera to sharing your * screen), or trigger an ICE restart because of a network change. All * these actions require a renegotiation to occur, which means a new SDP * offer/answer round to update the existing PeerConnection. * * Since version \c 0.2.6, renegotiations are indeed supported by Janus, * and the \c janus.js library exposes ways to easily handle the process * of updating a media session. More specifically, there are additional * properties you can pass to \c createOffer and \c createAnswer for the * purpose: most of the properties introduced in the previous section will * still be usable, as it will be clearer in the next paragraphs. * * The new properties you can pass to \c media in \c createOffer and * \c createAnswer are the following: * * - \c addAudio: if set, start capturing audio if you weren't (will fail * if you're sending audio already); * - \c addVideo: if set, start capturing video if you weren't (will fail * if you're sending video already); * - \c addData: if set, negotiate a datachannel if it didn't exist (is * actually just a synonym for \c data:true ); * - \c removeAudio: if set, stop capturing audio and remove the local audio track; * - \c removeVideo: if set, stop capturing video and remove the local video track; * - \c replaceAudio: if set, stop capturing the current audio (remove the * local audio track), and capture a new audio source; * - \c replaceVideo: if set, stop capturing the current video (remove the * local video track), and capture a new video source. * * Notice that these properties are only processed when you're trying a * renegotiation, and will be ignored when creating a new PeerConnection. * * These properties don't replace the existing \c media properties, but go * along with them. For instance, when adding a new video stream, or * replacing an existing one, you can still use the video related properties * as before, e.g., to pass a specific device ID or asking for a screenshare * instead of a camera. Besides, notice that you'll currently have to pass * info on the streams you want to keep as well, or they might be removed: * this means that, if for instance you want to replace the video source, * but want to keep the audio as it is, passing \c audio:false to the new * createOffer will potentially disable audio. * * It's important to point out that, as for negotiations that result in * the creation of a new PeerConnection in the first place, how to perform * a renegotiation in practice will typically vary depending on the plugin * that you're trying to do it for. Some plugins may allow you to offer * a renegotiation, others may require you to send a different request * instead in order to trigger a renegotiation from the plugin. As it * will be clearer later, this is especially true for ICE restarts. As * such, apart from the generic and core-related definitions introduced * in this section, please refer to the documentation for each individual * plugin for more information about how to perform renegotiations in * specific use cases. * * Here's a simple example of how you can use \c removeVideo to remove * the local video capture in a session, e.g., in the EchoTest demo: * \verbatim // Remove local video echotest.createOffer( { media: { removeVideo: true }, success: function(jsep) { Janus.debug(jsep); echotest.send({message: {audio: true, video: true}, "jsep": jsep}); }, error: function(error) { bootbox.alert("WebRTC error... " + JSON.stringify(error)); } }); \endverbatim * * This other example shows how you can add a new video stream to an-audio * only PeerConnection instead: * \verbatim // Add local video echotest.createOffer( { media: { addVideo: true }, success: function(jsep) { Janus.debug(jsep); echotest.send({message: {audio: true, video: true}, "jsep": jsep}); }, error: function(error) { bootbox.alert("WebRTC error... " + JSON.stringify(error)); } }); \endverbatim * * Finally, this example shows how you can replace the video track, by * also showing how you can combine this with one of the properties we * already met in the previous section: * \verbatim // Replace local video echotest.createOffer( { media: { video: { deviceId: "44f4740bee234ce6ddcfea8e59e8ed7505054f75edf27e3a12294686b37ff6a7" }, replaceVideo: true }, success: function(jsep) { Janus.debug(jsep); echotest.send({message: {audio: true, video: true}, "jsep": jsep}); }, error: function(error) { bootbox.alert("WebRTC error... " + JSON.stringify(error)); } }); \endverbatim * * Notice that renegotiations involving media changes (both local and remote) * will likely result in new calls to the \c onlocalstream and \c onremotestream * application callbacks: as such, be prepared to see those callbacks called * for the same PeerConnection more than once during the course of a media session. * * \section restarts ICE restarts * While ICE restarts can be achieved with a renegotiation, they're complex * enough to deserve a specific subsection. In fact, ICE restarts don't * address changes in the media, but in the underlying transport itself. * They're used, for instance, when there's a network change (e.g., the * IP address changed, or the user switched from WiFi to 4G). In order for * this to work, new candidates must be exchanged, and connectivity checks * must be restarted in order to find the new optimal path. * * With \c janus.js, you can only force an ICE restart when sending a new * offer. In order to do so, all you need to do is add `iceRestart:true` * to your `createOffer` call, and an ICE restart will be requested. The * following example shows how this can be done with the EchoTest: * \verbatim echotest.createOffer({ iceRestart: true, media: { data: true }, success: function(jsep) { echotest.send({message: {audio: true, video: true}, jsep: jsep}); } }); \endverbatim * * In this particular example, we're not asking for any change on the * media streams, but just an ICE restart. If successful, as soon as the * answer is received, the client and Janus will restart the ICE process * and find a new path for the media packets. * * Notice that, with Janus and its plugins, you won't always be able to * force an ICE restart by sending a new SDP offer yourself: some plugins, * like the Streaming plugin for instance, will want to always send an * offer themselves, which means they'll be the ones actually forcing the * ICE restart from a negotiation perspective. In order to still allow * users to actually originate the process, all the stock Janus plugins * that assume they'll be sending offers for some or all of their media * streams also expose APIs to force an ICE restart from the server side. * You can learn more about this on a plugin level basis * here and * here. * Besides, make sure you read the documentation for each of the plugins * you're interested in using ICE restarts for, as the details for how * to perform it properly are typically provided there. * *
* * This is it! For more information about the API, have a look at the * demo pages that are available in the \b html folder in this package. * */ /*!\page js-modules Using janus.js as JavaScript module * * To facilitate integration of \c janus.js within modular JavaScript code bases, * you can instruct the build system(s) to generate a modular variants of \c janus.js. * Generated modules may then be copied to your own JavaScript projects and seamlessly integrated with your own project's build system. * * Building the modules can be done in two ways: * * -# As part of a regular build of the Janus WebRTC Server, using \c make, by enabling the integrated support via \c configure * -# By running NPM commands manually. This may be useful if you are looking to build just the JavaScript modules without * incurring the overhead of a full build of Janus. * * As an alternative to generating the module and copying it to your project, you can also tweak * your module bundler to use \c janus.js directly from the official Janus repository. See more * details (including concrete instructions for Webpack): \ref js-webpack * * \section auto-build-js-modules Building modules using make * Each supported variant may be enabled by passing a corresponding \c --enable-javascript-*-module flag * (with or without a \c =yes directive) to \c configure before invoking \c make to build Janus. * Please note: if you do not pass any such flag, by default no modules will be built. * * The following table provides a summary of available module formats and their corresponding \c configure options: * * * * * * * *
Module format (syntax)File nameconfigure flag to pass
ECMAScriptjanus.es.js\c --enable-javascript-es-module
Universal Module Definition (UMD)janus.umd.js\c --enable-javascript-umd-module
CommonJSjanus.cjs.js\c --enable-javascript-common-js-module
Immediately Invoked Function Expression (IIFE)janus.iife.js\c --enable-javascript-iffe-module
* * The \c --enable-all-js-modules shortcut is available, in case you want to enable and build them all. * * When built and installed, these module variants may be found in the \c $PREFIX/share/janus/javascript * folder, alongside the \c janus.js file itself (assuming \c $PREFIX the installation directory passed to \c configure). * * \note Building the JavaScript modules still requires NPM and may involve an \c install which means \c npm must be able * to download dependencies. By default \c configure will attempt to auto-detect available \c npm on your PATH, but * if you have installed NPM outside the PATH you can override this by passing the (full) path to your \c npm executable, e.g.: * \verbatim ./configure NPM=/path/to/my/custom/npm --enable-javascript-es-module=yes \endverbatim * * \section manual-build-modules Building modules manually with NPM * You can also opt to build modules by invoking \c npm manually. The \c npm subdirectory contains the necessary * configuration files to get you started: * \verbatim cd ./npm npm install npm run rollup -- --o /path/to/desired/output/file-name.js --f cjs # or es, iffe, umd, amd, ... \endverbatim * * Using \c npm directly is useful if you want to build the JavaScript modules only, without building Janus itself * or if you are looking for advanced customisation options or alternative formats which are not integrated in \c configure yet. * As you may have surmised from the example command, the actual build consists mostly of invoking \c rollup with the * correct parameters. For more information on available parameters, please refer to the \c rollup documentation: * * -# https://rollupjs.org/#command-line-flags * -# https://rollupjs.org/#configuration-files * * \section js-webpack Using janus.js directly with Webpack and other bundlers * * Generating a converted version of \c janus.js and copying it to your project is not always the best * solution. In many situations it may be prefered to let your JavaScript module bundler (e.g. * Webpack) grab the file directly from the official Janus repository. * Doing that you can manage \c janus.js just like any other dependency coming from Github or the npm Registry, * getting rid of the manual copy step and letting the bundler take care of version management, updates * and downloads. * * Of course, the first step is to include the official Janus repository as a dependency in your * project by adding it to your \c packages.json file. * \verbatim { "dependencies": { "janus-gateway": "git://github.com/meetecho/janus-gateway.git" } } \endverbatim * * That will automatically drag in the dependency on the appropriate version of the * WebRTC Adapter from the npm Registry. * But \c janus.js expects such adapter to be available as a global variable. * So we have to make that happen for it to work properly. In the case of Webpack, is as easy as * adding this to your \c webpack.config.js file. \verbatim const webpack = require('webpack'); module.exports = { plugins: [ // janus.js does not use 'import' to access to the functionality of webrtc-adapter, // instead it expects a global object called 'adapter' for that. // Let's make that object available. new webpack.ProvidePlugin({ adapter: 'webrtc-adapter' }) ] } \endverbatim * * On the other hand, \c janus.js defines the \c Janus object globally. So a small tweak is also * needed to serve such object via \c export. That can be done using * exports-loader and adding this to * \c webpack.config.js \verbatim module.exports = { module: { rules: [ // janus.js does not use 'export' to provide its functionality to others, instead // it creates a global variable called 'Janus' and expects consumers to use it. // Let's use 'exports-loader' to simulate it uses 'export'. { test: require.resolve('janus-gateway'), use: 'exports-loader?Janus=Janus' } ] } } \endverbatim * * With that extra configuration, the official \c janus.js can be used directly in any modular * JavaScript code base without any previous transformation of the file. That means you can simply * do this to access to the Janus API from your modular code. \verbatim import { Janus } from 'janus-gateway'; \endverbatim * For more detailed or updated documentation check the * Webpack shimming guide or the equivalent * documentation for your bundler of choice. */ /*!\page js-dependencies Working with custom janus.js dependencies * * Certain dependencies of \c janus.js may be passed during library initialization as * a property list containing the following keys: * * -# \c newWebSocket: a function which given WebSockets server and protocol arguments * should return a new WebSocket (or something that acts like it) * -# \c webRTCAdapter: an \c adapter object such as provided by the * webrtc-adapter library * -# \c isArray: a function which tests if a given argument is a JavaScript array * -# \c checkJanusExtension: a function which tests if the Janus Screensharing extension * for Chrome is installed/available. This can be done by testing whether or not an element * with an \c id attribute value of \c janus-extension-installed is present. * -# \c httpAPICall: a function which given an url and options argument performs an * HTTP API request to Janus. This function is not as straightforward to implement, * see the section on \ref js-http-apicall below for details. * * Depending on your needs you do not have to provide all these dependencies, e.g. * you do not need to implement the \c httpAPICall function if your application relies * exclusively on WebSockets to access the Janus API. * * Two implementations of the dependencies object are provided by \c janus.js: * * -# \c Janus.useDefaultDependencies * -# \c Janus.useOldDependencies * * In turn, each of these implementations accept their dependencies as arguments or fallback on * certain global variables. Below follows an overview: * * \section js-default-deps Janus.useDefaultDependencies * The \c Janus.useDefaultDependencies method relies on the following native browser APIs: * * -# \c Promise: support for \c Promises as standardised in ES 6 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) * -# \c fetch: support for the \c fetch API (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) * -# \c WebSocket: support for the \c WebSocket API (https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) * -# \c document.querySelector: support for the \c document.querySelector API (https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) * * Additionally the \c adapter object from the webrtc-adapter library is also required. * These dependencies may either be passed explicitly to the function as a property list with keys of the same name, or * if omitted the function will fallback to relying on global variables of that name instead. * * Example: \verbatim var customDependencies = Janus.useDefaultDependencies({ fetch: myCustomFetchImplementation // myCustomFetchImplementation should provide a compatible fetch() API }); var relyingOnGlobalsEntirely = Janus.useDefaultDependencies(); \endverbatim * * Being able to passe dependencies like this is especially useful in the context of modern ES modules: * \verbatim import adapter from 'webrtc-adapter'; // other imports elided const setupDeps = () => Janus.useDefaultDependencies({ adapter, // other dependencies elided }); export const initialiseJanusLibrary = () => Janus.init({dependencies: setupDeps()}); \endverbatim * * \section js-old-deps Janus.useOldDependencies * The \c Janus.useOldDependencies method relies on: * * -# \c jQuery: the JQuery library (http://jquery.com/) * -# \c WebSocket: support for the \c WebSocket API (https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) * -# \c adapter: the \c adapter object from the webrtc-adapter library * * This function provides a simple upgrade path for existing applications which are heavily * tied to jQuery (especially since previous versions of \c janus.js depended on it). * * \section js-http-apicall httpAPICall * The \c httpAPICall function is used to issue API calls to the Janus HTTP(S) interfaces. * It will be passed two arguments: * * -# \c url: a string which refers to the (server) URL of the API endpoint to contact * -# \c options a property list (see below) * * Any return values from the \c httpAPICall function will be ignored. * * When working with HTTP request or response bodies, the \c httpAPICall is responsible for * serialisation to, and deserialisation from the 'wire format' (JSON). * That is: the \c httpAPICall must transform objects to JSON or parse JSON as and when required. * Similarly, the \c httpAPICall is also responsible for setting appropriate HTTP * \c Content-Type (application/json) and/or \c Accept headers. * * The \c options argument may contain the following keys: * * -# \c timeout: a timeout in miliseconds which should be imposed on the request. * The \c httpAPICall implementation is required to implement support for imposing timeouts * on HTTP API requests. * -# \c body: payload to include as body of the outgoing HTTP request. The \c httpAPICall must encode it in the 'wire format' (JSON). * -# \c withCredentials: a boolean indicating whether or not HTTP credentials should be sent * -# \c success: a callback which should be dispatched when an API request was successful. * -# \c error: a callback which should be dispatched when an API request was unsuccessful, or timed out * -# \c async: a boolean hint which indicates whether or not asynchronous requests are desirable. * This hint is a primarily a remnant for backwards compatible behaviour when working with jQuery. * * The \c success callback should be passed the deserialised API response body. * The \c error callback accepts two arguments: a descriptive status text string and the raw error object * which caused the \c error callback to be invoked. * * \note The \c httpAPICall represents the primary way to intercept HTTP(S) API calls issued from within the * \c janus.js library. You can use this mechanism to augment outgoing requests with additional headers * or to intercept responses. For example: * * -# You can support authentication schemes based on the HTTP \c Authorization header by * injecting it into outgoing API requests and routing them through a proxy. * -# You can intercept incoming responses and extract data from custom header values generated by a proxy. * -# You can combine both to implement a robust defence against CSRF * -# You can reroute the control flow entirely, and e.g. use \c httpAPICall as an action creator in your * Redux application. * * \section js-extension Custom Screensharing Extension for Chrome * To use a different extension for screensharing permissions in Chrome you can pass a \c extension object * to \c Janus.useDefaultDependencies and \c Janus.useOldDependencies. * The object should provide the following methods: * * -# \c init(): Do any setup work here. Will be called once when the dependencies are loaded. * -# \c isInstalled(): should return a boolean indicating whether the Extension was detected and is ready to use. * -# \c getScreen(callback): make a call to the extension to get a \c streamId here. The streamId can be obtained * from chrome using chrome.desktopCapture.chooseDesktopMedia(). * When the request is successful pass the \c streamId back using callback(null, streamId), * otherwise pass an \c Error object like \c callback(error) */ /*! \page rest RESTful, WebSockets, RabbitMQ, MQTT, Nanomsg and UnixSockets API * * Since version \c 0.0.6, there are different ways to interact with a * Janus instance: a \ref plainhttp (the default), a \ref WS, a \ref rabbit, \ref apimqtt, \ref apinanomsg * and a \ref unix (both optional, need an external library to be available). All of * the interfaces use the same messages (in terms of requests, responses * and notifications), so almost all the concepts described in the * \ref plainhttp section apply to the WebSocket/RabbitMQ/MQTT/Nanomsg/UnixSockets interfaces as well. * Besides, since version \c 0.1.0 the transport mechanism for the Janus API * has been made modular, which means other protocols for transporting * Janus API messages might become available in the future: considering the * Janus protocol is supposed to be mostly agnostic to the protocol it is * transported on, the concepts explained in the following sections should * apply to those as well. * * As it will be explained later in the \ref WS, \ref rabbit, \ref apimqtt, \ref apinanomsg and \ref unix sections * below, the only differences come when addressing specific sessions/handles * and in part in how you handle notifications using something different than * the REST interface: in fact, since with WebSockets, RabbitMQ, MQTT, Nanomsg and UnixSockets * (and, as anticipated, with other protocols that may be added in the future too) * there's no REST-based path involved, you'll need a couple of additional * identifiers to bridge the gap. * Some details are also provided in case you're interested in \ref auth. * * \section plainhttp Plain HTTP REST Interface * As anticipated in the \ref JS documentation, the server deploys a * RESTful interface that clients can exploit. The \c janus.js library * makes use of it in a transparent way, but if you're interested in * more details about it (e.g., because you want to talk to the server * your own way), this page described the interface and the protocol * the API exposes and uses. * * There are basically three types/levels of endpoints you can meet: * * -# \ref root (\c /janus by default, but configurable), which * you only \b POST to in order to create a Janus session; * -# \ref sessions (e.g., \c /janus/12345678, using the * identifier retrieved with a previous create), which you either send * a \b GET to (long poll for events and messages from plugins) or a \b POST * (to create plugin handles or manipulate the session); * -# \ref handles (e.g., \c /janus/12345678/98765432, appending * the handle identifier to the session one) which you only send \b POST * messages to (messages/negotiations for a plugin, handle manipulation), * as all events related to this handle would be received in the session * endpoint \b GET (the \c janus.js library would redirect the incoming * messages to the right handle internally). * * Messages and requests you can send to and receive from any of the * above mentioned endpoints are described in the following chapters. * In general, all messages share at least two fields: * * - \c janus: the request/event (e.g., "create", "attach", "message", etc.); * - \c transaction: a random string that the client can use to match incoming * messages from the server (since, as explained in the \ref plugins * documentation, all messages are asynchronous). * * Different messages will of course add different information to this * base syntax. Error message, instead, usually have these fields: * * - \c janus: this would be "error"; * - \c transaction: this would be the transaction identifier of the request * that failed; * - \c error: a JSON object containing two fields: * - \c code: a numeric error code, as defined in apierror.h; * - \c reason: a verbose string describing the cause of the failure. * * An example of an error is presented here: * \verbatim { "janus" : "error", "transaction" : "a1b2c3d4" "error" : { "code" : 458 "reason" : "Could not find session 12345678" } } \endverbatim * * * \section info Getting info about the Janus instance * The API exposes an \c info endpoint you can query to get information * about the Janus instance you're talking to. Specifically, it returns * information about the version of the Janus server, whether some of the * optional features (e.g., Data Channels or IPv6) are supported or not, * and which transports and plugins are available. * * To get this information, just send an HTTP \b GET message to the \c info * endpoint (e.g., http://yourserver:8088/janus/info), which will return * something like this: * \verbatim { "janus": "server_info", "transaction": "i1bzIL341Kl2", "name": "Janus WebRTC Server", "version": 73, "version_string": "0.7.3", "author": "Meetecho s.r.l.", "data_channels": "true", // Data channels are supported "ipv6": "false", // IPv6 is not configured "ice-tcp": "false", // ICE-TCP support is disabled, [..] "transports": { "janus.transport.http": { "name": "JANUS REST (HTTP/HTTPS) transport plugin", "author": "Meetecho s.r.l.", "description": "This transport plugin adds REST (HTTP/HTTPS) support to the Janus API via libmicrohttpd.", "version_string": "0.0.2", "version": 2 }, [..] // Other transport plugins }, "plugins": { "janus.plugin.sip": { // The SIP plugin is available "version_string": "0.0.7", "description": "This is a simple SIP plugin for Janus, allowing WebRTC peers to register at a SIP server and call SIP user agents through Janus.", "author": "Meetecho s.r.l.", "name": "JANUS SIP plugin", "version": 7 }, "janus.plugin.videoroom": { // The Video SFU plugin is available "version_string": "0.0.3", "description": "This is a plugin implementing a videoconferencing SFU (Selective Forwarding Unit) for Janus, that is an audio/video router.", "author": "Meetecho s.r.l.", "name": "JANUS VideoRoom plugin", "version": 3 }, [..] // Other plugins } \endverbatim * * You can use this information to selectively enable or disable features * in your application according to what's available in the Janus instance * you're trying to contact. * * * \section root The server root * The server root is \c /janus by default but, as anticipated, it is * configurable, either via command line or in the \c janus.jcfg configuration. * * You can only contact the server root when you want to create a new * session with the server. To do so, you need to \b POST the a \c janus "create" * JSON message to the server: * \verbatim { "janus" : "create", "transaction" : "" } \endverbatim * * If the request is successful, you'll receive the unique session identifier * in a response formatted like this: * \verbatim { "janus" : "success", "transaction" : "", "data" : { "id" : } } \endverbatim * * In case of an error, you'll receive an error message as the one introduced * before. This request, if issued with a POST to the server root, can only * fail if you miss any of the required fields in the request. * * * \section sessions The session endpoint * Once you've created a session, a new endpoint you can use is created * in the server. Specifically, the new endpoint is constructed by * concatenating the server root and the session identifier you've been * returned (\c e.g., \c /janus/12345678). * * This endpoint can be used in two different ways: * * -# using a parameter-less \b GET request to the endpoint, you'll * issue a long-poll request to be notified about events and incoming * messages from this session; * -# using a \b POST request to send JSON messages, you'll interact * with the session itself. * *
* * \par Long-poll requests * The long-poll will only trigger events related to messages you're * being sent from plugins, and as such will be clearer to understand * once you read the \ref handles section. That said, the events are formatted * this way: * * - \c janus: this would be "event"; * - \c sender: this would be the unique numeric plugin handle identifier; * - \c transaction: this is optional: it is either related to a request * you sent to a plugin before, or it may be missing in case this is an * event the plugin sent on its own account; * - \c plugindata: a JSON object containing the info coming from the plugin itself: * - \c plugin: the plugin's unique package name (e.g., \c janus.plugin.echotest); * - \c data: an opaque JSON object that is plugin specific. * - \c jsep: an optional JSON object containing the JSEP SDP (offer or * answer) the plugin may send to negotiate a WebRTC PeerConnection with * the client (check the \ref handles section for more details). * * An example of such an event (in this case, sent by the janus_echotest.c * plugin in response to a request) is presented here: * \verbatim { "janus" : "event", "sender" : 1815153248, "transaction" : "sBJNyUhH6Vc6", "plugindata" : { "plugin": "janus.plugin.echotest", "data" : { "echotest" : "event", "result" : "ok" } }, } \endverbatim * * The long-poll request has a 30 seconds timeout. If it has no event to * report, a simple \em keep-alive message will be triggered: * \verbatim { "janus" : "keepalive", } \endverbatim * * As with all long-poll based approaches, it's up to your application * to send a new polling request as soon as an event or a keep-alive * has been received. * * Notice that, by default, the long poll returns a single event: that is, * as soon as a message becomes available in the session queue, that event * is returned and the long poll closes. If you want to receive more events * within the context of the same long poll, you can pass the \c maxev * query string parameter to the GET, e.g.: * \verbatim GET http://host:port/janus/?maxev=5 \endverbatim * \verbatim [ { // Event #1 "janus" : "event", [..] }, { // Event #2 "janus" : "event", [..] }, [..] ] \endverbatim * * This request will instruct the server to return at maximum 5 events * within the context of the same long poll, formatted as a JSON array * of events. Please beware that this does \b NOT mean that you'll * always get 5 events this way: it only means that, if a message becomes * available in the queue and more events are present as well, Janus will * return more than one without needing you to send multiple long polls * immediately thereafter to get them. For this reason, don't be surprised * if even with a \c maxev parameter set, you'll still get a single * event being notified as the sole object in the returned array. * *
* * \par Interacting with the session * To interact with the session, e.g., to create a new handle to attach * to a plugin or destroy the current session, you need to send a \b POST * JSON message to the session endpoint. * * To attach to a plugin in order to exploit its features, you need to * \b POST a \c janus "attach" JSON message to the server; you'll need * of course to provide information on the plugin you want to attach to, * which can be done using the \c plugin field: * \verbatim { "janus" : "attach", "plugin" : "", "transaction" : "" } \endverbatim * * Notice that you can also provide an optional \c opaque_id string * identifier (for more details on why this might be useful, read more * here). * If the request is successful, you'll receive the unique plugin handle * identifier in a response formatted the same way as the session create * one, that is like this: * \verbatim { "janus" : "success", "transaction" : "", "data" : { "id" : } } \endverbatim * * In case of an error, you'll receive an error message as the one introduced * before. This request, if issued with a POST to a valid session endpoint, can only * fail if you miss any of the required fields in the request or if the * plugin you requested is not available in the server. * * To destroy the current session, instead, just send a "destroy" \c janus * request: * \verbatim { "janus" : "destroy", "transaction" : "" } \endverbatim * * This will also destroy the endpoint created for this session. * If your session is currently managing one or more plugin handles, * make sure you destroy them first (as explained in the next section). * The server tries to do this automatically when receiving a session * destroy request, but a cleaner approach on the client side would help * nonetheless avoid potential issues. * * \section handles The plugin handle endpoint * Once you've created a plugin handle, a new endpoint you can use is created * in the server. Specifically, the new endpoint is constructed by * concatenating the server root, the session identifier and the new * plugin handle identifier you've been returned (\c e.g., * \c /janus/12345678/98765432). * * You can use this plugin handle for everything that is related to the * communication with a plugin, that is, send the plugin a message, * negotiate a WebRTC connection to attach to the plugin, and so on. * * To send a plugin a message/request, you need to \b POST the handle * endpoint a \c janus "message" JSON payload. The \c body field will * have to contain a plugin-specific JSON payload. In case the message * also needs to convey WebRTC-related negotiation information, a \c jsep * field containing the JSON-ified version of the JSEP object can be * attached as well. * * \note If you attach a \c jsep object, whether it's an offer or an answer, * you're stating your will to negotiate a PeerConnection. This means that * an empty or invalid \c jsep object will trigger a validation and will * cause the whole request to fail, so make sure you exclude the field * completely from your request if all you're interested into is sending * a message to a plugin. * * Here's an example of a message you may send the janus_echotest.c plugin * to mute your audio: * \verbatim { "janus" : "message", "transaction" : "sBJNyUhH6Vc6", "body" : { "audio" : false } } \endverbatim * * The same message containing negotiation information as well, instead, * (an OFFER, in this example), is presented here: * \verbatim { "janus" : "message", "transaction" : "sBJNyUhH6Vc6", "body" : { "audio" : false }, "jsep" : { "type" : "offer", "sdp" : "v=0\r\no=[..more sdp stuff..]" } } \endverbatim * * Please notice that, if for any reason you don't want to use the * trickling of ICE candidates from your application (which means you'll * include them all in the SDP OFFER or ANSWER, which is usually not * recommended), you'll have to add an additional "trickle" : false * attribute to the "jsep" object, to explicitly tell Janus you won't * send any \c trickle candidate (by default Janus will always assume * support for trickle). * * If you're going to \c trickle candidates, instead, there is an ad-hoc * message you can use to do so which is called, unsurprisingly, \c trickle * and which you can use to send one or more trickle candidates to Janus. * Since such a message is related to a specific PeerConnection, it will * need to be addressed to the right Handle just as the \c message introduced * previously. A \c trickle message can contain three different kind of * information: * * - a single trickle candidate; * - an array of trickle candidates; * - a null candidate or a \c completed JSON object to notify the end of the * candidates. * * This is an example of a single candidate being trickled: * \verbatim { "janus" : "trickle", "transaction" : "hehe83hd8dw12e", "candidate" : { "sdpMid" : "video", "sdpMLineIndex" : 1, "candidate" : "..." } } \endverbatim * * This, instead, is an example of how to group more trickle candidates * in a single request (particularly useful if you're wrapping Janus in * your server and want to reduce the number of transactions): * \verbatim { "janus" : "trickle", "transaction" : "hehe83hd8dw12e", "candidates" : [ { "sdpMid" : "video", "sdpMLineIndex" : 1, "candidate" : "..." }, { "sdpMid" : "video", "sdpMLineIndex" : 1, "candidate" : "..." }, [..] ] } \endverbatim * * Finally, this is how you can tell Janus that you sent all the trickle * candidates that were gathered: * \verbatim { "janus" : "trickle", "transaction" : "hehe83hd8dw12e", "candidate" : { "completed" : true } } \endverbatim * * Plugins may handle this requests synchronously or asynchronously. In * the former, plugins would return a response to the request itself * immediately; in the latter, instead, the plugin would only notify a * successful reception of the request, which it would process later. * Considering the asynchronous nature of the Janus API, a successful * management of such messages within Janus would in such case result in * a \c janus "ack" messages being sent back to the client. A logical response * to those messages, if needed, would be provided as an event in the * long-poll interface described previously, and clients would be able * to match it to the original request by means of the transaction * identifiers. It is worth noting, though, that should a WebRTC negotiation * be involved you don't have to expect an ANSWER to your OFFER to be * sent back in the same transaction. A plugin may decide, in its * application logic, to not provide you with an ANSWER right away, but * only after some internal state changes occur. It's up to your application * to handle the negotiation state accordingly. * * An example of an "ack" being sent back to the client, using the previous * sample request as a reference, is presented here: * \verbatim { "janus" : "ack", "transaction" : "sBJNyUhH6Vc6" } \endverbatim * * If you receive this ack instead of a "success" response, you can be * sure the plugin has received the message, and is going to process it soon. * * In case of an error, instead, you'll receive an error message as the one * introduced before. This request, if issued with a POST to a valid plugin * handle endpoint, can only fail if you miss any of the required fields * in the request, if the plugin you tried to contact is not available in * the server anymore, if an error occurred in the plugin when trying to * receive the message or if the \c jsep SDP you may have provided is * invalid. * * To destroy the plugin handle, instead, just send a "detach" \c janus * request: * \verbatim { "janus" : "detach", "transaction" : "" } \endverbatim * * This will also destroy the endpoint created for this plugin handle. * If your plugin handle is also managing an ongoing WebRTC connection * with the plugin, make sure it is torn down as part of this process. * The plugin implementation and the Janus core should do this * automatically, but implementing the right behaviour in clients would * help avoid potential issues nonetheless. * * If you're interested in keeping the handle alive but want to hang up * the associated PeerConnection, if available, just send a "hangup" \c janus * request: * \verbatim { "janus" : "hangup", "transaction" : "" } \endverbatim * * This is usually not required, as you can typically just hangup your * WebRTC PeerConnection normally and Janus will figure out it's gone * by itself. Anyway, there are cases where this might be useful (e.g., * the connection was stuck in some weird ICE/DTLS state) as it can be * used to reset the connection state for the handle. * * \section events WebRTC-related events * * As anticipated in the previous sections, Janus can send events and * notifications at any time through the long poll channel (or, as it * will be explained later, through the related push mechanisms made * available by other transport protocols ). While this channel is * mostly used to convey asynchronous notifications originated by * plugins as part of the messaging they may have with the application * using it, the same channel is actually used by Janus to trigger * events related to different aspects pertaining a specific handle. * * In particular, for each handle involving a PeerConnection Janus * provides notifications about its current state. To do so, the * following events may be received as well: * * - \c webrtcup: ICE and DTLS succeeded, and so Janus correctly * established a PeerConnection with the user/application; * - \c media: whether Janus is receiving (\c receiving: \c true/false) * audio/video (\c type: \c "audio/video") on this PeerConnection; * - \c slowlink: whether Janus is reporting trouble sending/receiving * (\c uplink: \c true/false) media on this PeerConnection; * - \c hangup: the PeerConnection was closed, either by Janus or by * the user/application, and as such cannot be used anymore. * * As such, to monitor the status of a PeerConnection as seen from * Janus you can make use of these events to track what's going on. A * correct flow for an active PeerConnection would be one that, after a * WebRTC negotiation and setup, results in a \c webrtcup event followed * by two \c media events (in case both audio and video have been * negotiated) specifying that the first audio/video packets have been * received. A \c hangup event would inform the user/application that * no media is being exchanged with Janus anymore. * * Here are a few examples of how these events may look like. * * A PeerConnection becoming ready: * \verbatim { "janus" : "webrtcup", session_id: , sender: } \endverbatim * * First audio bytes being received by Janus: * \verbatim { "janus" : "media", session_id: , sender: , "type" : "audio", "receiving" : true } \endverbatim * * Audio not getting to Janus anymore for some reason: * \verbatim { "janus" : "media", "session_id" : , "sender" : "type" : "audio", "receiving" : false } \endverbatim * * Audio getting to Janus again (same message as first audio): * \verbatim { "janus" : "media", "session_id" : , "sender" : "type" : "audio", "receiving" : true } \endverbatim * * Janus reporting problems sending media to a user (user sent many NACKs * in the last second; uplink=true is from Janus' perspective): * \verbatim { "janus" : "slowlink", "session_id" : , "sender" : "uplink" : true, "nacks" : } \endverbatim * * PeerConnection closed for a DTLS alert (normal shutdown): * \verbatim { "janus" : "hangup", "session_id" : , "sender" : , "reason" : "DTLS alert" } \endverbatim * * It is important to point out that the \c media event notifications * only apply if your PeerConnection is going to actually send media to * Janus. A \c recvonly PeerConnection, for instance (e.g., as the * Streaming plugin would create) would never trigger any \c media * event, as Janus would never be receiving media, but only send it. * * \section WS WebSockets Interface * WebSockets provide a more efficient means for implementing a bidirectional communication. * This is especially useful if you're wrapping the Janus API on your * servers, as it allows you to avoid all the noise and overhead introduced * by several concurrent HTTP transactions and long polls by relying on * what may be seen as a single "control channel". * * To interact with Janus using WebSockets you MUST specify a specific * subprotocol, named \c janus-protocol, e.g., * \verbatim var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol'); \endverbatim * * The \c janus.js library does this automatically. * * As anticipated at the beginning of this section, the actual messages * being exchanged are exactly the same. This means that all the concepts * introduced before still apply: you still create a session, attach to * a plugin and interact with it exactly the same way. What is different * is, of course, the REST path approach that becomes unavailable when * using a WebSocket as a control channel. To address the idenfitiers * that become missing using WebSockets, you'll need to add additional * fields to the requests when necessary. * * So, when you want to create a session using the REST API, you send a * POST to the server base path: * \verbatim { "janus" : "create", "transaction" : "" } \endverbatim * * The same applies if you're interested in getting generic info from the * Janus instance. Since there's no \b GET you can use, a specific \c janus * request type called \c info is available: * \verbatim { "janus" : "info", "transaction" : "" } \endverbatim * * Since you'd contact the base path for both requests, you don't need to add any identifier * for this scenario. But if instead you want to attach to a plugin within * the context of a specific session, using the REST API you'd send a * post to the \c /janus/ endpoint: * \verbatim { "janus" : "attach", "plugin" : "", "transaction" : "" } \endverbatim * * To make this work with WebSockets as well, you need to add a further * field called \c session_id in the request: * \verbatim { "janus" : "attach", "session_id" : , // NEW! "plugin" : "", "transaction" : "" } \endverbatim * * which will allow the WebSocket server to understand which session this * request pertains to. At the same time, when you need to address a * specific handle (e.g., to send a message to a plugin, or negotiate a * WebRTC PeerConnection) you'll need to add a \c handle_id field to the * request as well, or the request will be rejected: * \verbatim { "janus" : "message", "session_id" : , // NEW! "handle_id" : , // NEW! "transaction" : "sBJNyUhH6Vc6", "body" : { "audio" : false } } \endverbatim * * Considering the bidirectional nature of WebSockets and the fact that * the channel will be shared for different requests, you'll need to pay * extra attention to the \c transaction identifier, which will allow you * to map incoming responses and events to the request you sent that * originated them. * * An \b important aspect to point out is related to keep-alive messages * for WebSockets Janus channels. A Janus session is kept alive as long * as there's no inactivity for 60 seconds: if no messages have been * received in that time frame, the session is torn down by the server. * A normal activity on a session is usually enough to prevent that; * for a more prolonged inactivity with respect to messaging, on plain * HTTP the session is usually kept alive through the regular long poll * requests, which act as activity as long as the session is concerned. * This aid is obviously not possible when using WebSockets, where a single channel is * used both for sending requests and receiving events and responses. For * this reason, an ad-hoc message for keeping alive a Janus session should * to be triggered on a regular basis: * \verbatim { "janus" : "keepalive", "session_id" : , "transaction" : "sBJNyUhH6Vc6" } \endverbatim * * This will make sure that the server detects activity on the session * even when no actual messages are being exchanged with handles. * * As a last point, another slight difference with WebSockets comes from * how push notifications are implemented. In the \ref plainhttp this is * done via long polls: that is, you explicitly subscribe to notifications, * and have to do that again as soon as an event has been received. With * WebSockets, this is not needed: as soon as you create a session on a * WebSocket, that channel becomes automatically subscribed for events * related to that sessions, and you'll receive them on the same WebSocket. * For the same reason, as soon as the WebSocket is closed, all the sessions * created within its context are considered closed as well, and so their * resources (including all the handles and PeerConnections) will be * released as well. * * \note The same \c janus.js JavaScript library can be used both with the * REST and the WebSockets API: all you need to do is provide the right * Janus server address during the initialization and the library will * use one or the other according to the protocol prefix. * * \section rabbit RabbitMQ interface * The semantics of how the requests have to be built, when compared to * the usage of plain HTTP, is exactly the same as for WebSockets, so * refer to the \ref WS documentation for details about that. * * Of course, there are other aspects that differ when making use of * RabbitMQ messaging to talk to Janus, rather than using HTTP messages * or WebSockets. Specifically, RabbitMQ just basically forwards messages * on queues, and as such implementing a pseudo-bidirectional channel * as the Janus API requires some precaution. * * In particular, when configuring Janus to use RabbitMQ you'll have to * specify \b two \b queues: * * - a queue for \b incoming messages (application -> Janus); * - a queue for \b outgoing messages (Janus -> application). * * The proper usage of these queues will allow you to implement the kind * of bidirectional channel Janus needs. * * Another aspect to point out is that Janus requires all requests to * have a random \c correlation_id identifier. In fact, as pointed out * in the previous sections, the Janus API is conceived as a request/response * protocol that can involve asynchronous notifications as well. In order * to make sure that an application can match a received response to one * of the requests made earlier, Janus copies the \c correlation_id * identifier from the original request in the response to it: this is * compliant with the * RPC pattern * as specified in the RabbitMQ documentation. Notifications originated by * Janus, instead, will not include a \c correlation_id identifier, and as * such applications shouldn't expect any: applications will still be able * to match a notification to a request, if the involved plugin was * implemented to do so, by looking at the Janus-level \c transaction * identifier. * * \section apimqtt MQTT interface * The semantics of how the requests have to be built, when compared to * the usage of plain HTTP, is exactly the same as for WebSockets, so * refer to the \ref WS documentation for details about that. * * Of course, there are other aspects that differ when making use of * MQTT messaging to talk to Janus, rather than using HTTP messages * or WebSockets. Similar to RabbitMQ, MQTT just basically forwards messages * on queues, and as such implementing a pseudo-bidirectional channel * as the Janus API requires some precaution. * * In particular, when configuring Janus to use MQTT you'll have to * specify \b two \b queues: * * - a queue for \b incoming messages (application -> Janus); * - a queue for \b outgoing messages (Janus -> application). * * The proper usage of these queues will allow you to implement the kind * of bidirectional channel Janus needs. * * \section apinanomsg Nanomsg interface * The semantics of how the requests have to be built, when compared to * the usage of plain HTTP, is exactly the same as for WebSockets, RabbitMQ * and MQTT, so refer to the \ref WS documentation for details about that. * * Apart from that, the only configuration needed is related to the Nanomsg * address to use, and whether it should be used to bind locally or to * connect to a remote endpoint. Notice that only the \c NN_PAIR pattern * is supported by the plugin, so no Pub/Sub or other variations. * * \section unix UnixSockets interface * The semantics of how the requests have to be built, when compared to * the usage of plain HTTP, is exactly the same as for WebSockets, RabbitMQ * MQTT and Nanomsg, so refer to the \ref WS documentation for details about that. * * Apart from that, the only configuration needed is related to the path * the client and server will be sharing, and the socket type. Notice that only the * \c SOCK_SEQPACKET and \c SOCK_DGRAM types are supported in the plugin. * */ /*! \page auth Authenticating the Janus API * By default no authentication is involved when using the Janus API. * This means that the API is completely open, and that everybody can * talk to Janus and its plugins and set up media connections. There are * times, though, where limiting access to Janus may be desirable, e.g., * when you want to prevent unauthorized users to join a service you * created, or when you wrap the Janus API in your server and you want * your application to be the only one to be able to interact with * Janus from a messaging perspective. * * There are a couple of ways to authenticate requests in Janus: * * - using a \ref token (useful for web users); * - using a \ref signed (useful for web users); * - using a \ref secret (useful when wrapping the Janus API). * * \section token Stored token based authentication mechanism * The token based authentication mechanism expects all users to provide, * in each request, a \c token string attribute: if this token is * known to Janus, the request will be accepted, otherwise it will be * rejected as an \c unauthorized response. Configuring the token based * authentication mechanism is easy enough: you can do that either via * the command line (\c -A or \c --token-auth ) or in the \c janus.jcfg * configuration (\c token_auth value in the \c general section). * * These tokens are completely opaque to Janus, meaning they can be * pretty much anything that you want. Janus does not do any form of * authorization/authentication itself: it's up to you to provide it * with valid tokens users can use, e.g., as part of your server-side * application handling users. You can add and remove tokens * dynamically using the \ref admin, which means you will need to enable * it if you want to use tokens, or otherwise all requests will fail * (Janus will never have a valid token, so all requests will be rejected). * * You add tokens using the \c add_token admin request, while you * remove them using \c remove_token. You can also limit the scope of tokens * to specific plugins, by passing a list of plugins to \c add_token or * modifying the token properties via \c allow_token and \c disallow_token. * By default (\c add_token without any plugin specified) Janus assumes * a new token is allowed to access all plugins. A list of all the * existing tokens can be retrieved with a \c list_tokens request. * * Here are a couple of examples of how you can use the requests: * \verbatim { "janus" : "add_token", "token": "a1b2c3d4", "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * This adds a new token (a1b2c3d4) that is allowed to access all the * plugins in Janus (no limitation provided in \c add_token ). To create * a new token and limit the scope to a few selected plugins, you can * use this other syntax instead (notice the extra \c plugins array): * \verbatim { "janus" : "add_token", "token": "a1b2c3d4", "plugins": [ "janus.plugin.streaming", "janus.plugin.videoroom" ], "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * In this other example, we're creating a new token, and also telling * Janus that the only plugins a user with this token can access are * the Streaming and Videoroom plugins. An attempt to attach to a * different plugin (e.g., EchoTest) will result in an error. * * You can change the permissions a token has with respect to plugin * access at any time. In the following example, we add a new plugin * to the permissions for an existing token: * \verbatim { "janus" : "allow_token", "token": "a1b2c3d4", "plugins": [ "janus.plugin.echotest" ], "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * This way, the provided token is now also allowed to access the EchoTest * plugin. To remove a permission, the syntax is this one instead: * \verbatim { "janus" : "disallow_token", "token": "a1b2c3d4", "plugins": [ "janus.plugin.videoroom" ], "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * To retrieve a list of all the valid tokens Janus is aware of, together * with the plugins each of them is allowed to access, a \c list_tokens * request can be used: * \verbatim { "janus" : "list_tokens", "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * Finally, you can get rid of a token using a \c remove_token request: * \verbatim { "janus" : "remove_token", "token": "a1b2c3d4", "transaction" : "sBJNyUhH6Vc6", "admin_secret": "adminpassword" } \endverbatim * * As anticipated, with the token based mechanism enabled, all users * will need to provide a valid token as part of their requests. This is * done by adding a \c token attribute to the request root, e.g.: * \verbatim { "janus" : "create", "transaction" : "sBJNyUhH6Vc6", "token": "usertoken" } \endverbatim * * The same applies for the long poll GET messages as well, which will * need to contain the \c token as a query string parameter. * * A valid token will mean the request will be accepted and processed * normally. A missing or invalid token, instead, will result in an * error being returned: * \verbatim { "janus" : "error", "transaction" : "sBJNyUhH6Vc6", "error" : { "code" : 403, "reason" : "Unauthorized request (wrong or missing secret/token)" } } \endverbatim * * An attempt to use a valid token to attach to a plugin it is not * allowed to access, instead, will result in a different error: * \verbatim { "janus" : "error", "transaction" : "sBJNyUhH6Vc6", "error" : { "code" : 405, "reason" : "Provided token can't access plugin 'janus.plugin.echotest'" } } \endverbatim * * \section signed HMAC-Signed token authentication * *
NOTE WELL: At the time of writing, HMAC-Signed * tokens are ONLY available for the VideoRoom plugin. If you need authentication * for other plugins, you should use the \ref token instead.
* * Simple token based authentication requires the application host to * continuously update the Janus instance on permission changes. * Since Janus stores the tokens in memory, it can be problematic to guarantee * the permissions of a dynamic application stay in sync with Janus. * * This problem can be solved by using a type of nonce / lease system to * let the application server generate automatically expiring tokens without * requiring direct communication with or any data storage in Janus. * * You can use the HMAC signed token mechanism by enabling token authentication * in general, as above (\c -A or \c --token-auth) and specifying an encryption * secret using \c --token-auth-secret. The same can be accomplished using * \c token_auth and \c token_auth_secret in the \c general section of * \c janus.jcfg. * * With Signed token support enabled, dynamic token creation via the \ref admin * is not supported. Instead, Janus will look for tokens with a format like: * \verbatim ,janus,[,plugin2...]: \endverbatim * * Where \c timestamp is a UNIX timestamp (seconds since 0:00 UTC, 1.1.1970) * that marks the point in time at which the token expires; * \c plugin1 etc. are the \c bundle names of plugins (such as \c janus.plugin.videoroom); * and \c signature is the base64-encoded HMAC-SHA1 signature of the expiry * timestamp in ASCII format, hashed using the \c --token-auth-secret as a key. * * The following function can be used to sign tokens using the node.js crypto library: * \verbatim const crypto = require('crypto'); function getJanusToken(realm, data = [], timeout = 24 * 60 * 60) => { const expiry = Math.floor(Date.now() / 1000) + timeout; const strdata = [expiry.toString(), realm, ...data].join(','); const hmac = crypto.createHmac('sha1', secret); hmac.setEncoding('base64'); hmac.write(strdata); hmac.end(); return [strdata, hmac.read()].join(':'); }; const token = getJanusToken('janus', ['janus.plugin.videoroom']), \endverbatim * * The \c janus parameter here is the \c realm of the token. For authenticating the * Janus API it should always be set to \c janus. * * When Janus encounters a token, it will: * * - verify that the timestamp has not passed * - verify that the signature matches the timestamp * - if the request requires access to a plugin, verify that the signature allows access * * Since the auth secret should never leave the application side, a signature * like this can only be generated by the application server, which needs to * be configured using the same secret. * * Please note that tokens of this sort cannot be revoked after being signed * and passed to the client. Instead of signing tokens with late expirys, * it is recommended to use tokens with shorter durations and generate and * transition to a new token within the expiry time of every last token when * the lease time is unknown and security is critical. * * \section secret Shared static secret * Several deployers showed an interest in wrapping the Janus API on * their server side: this allows them to keep the interaction with their * users the way it was before, while still benefiting from the features * Janus provides. This is an easy enough step, as it just needs developers * to relay the involved SDP, and implementing the Janus API messages to * handle the logic. * * That said, since in this case Janus would be contacted, through the API, * just by a limited number of applications (e.g., application servers * made in node.js, Ruby, Java Servlets or whatever) and not random * browsers, it is reasonable to involve a mechanism to control who is * allowed to contact and control it. The previous section described * how you can exploit a token based mechanism for authenticating * requests, but since in this case you only need a single application, * or a limited set of them, * to be able to talk to Janus, it's worthwhile to resort to something * simpler and more static. To allow for that, Janus also exposes a * shared API secret mechanism: that is, you configure Janus with a string * applications need to present when sending requests, and if they don't, * Janus rejects them with an \c unauthorized message. * * Configuring the API secret mechanism is easy enough: you can do that * either via the command line (\c -a or \c --apisecret ) or in the * \c janus.jcfg configuration (\c api_secret value in the \c general section). * When enabled, all requests addressed to that Janus instance \b MUST * also contain an \c apisecret field in the Janus message headers. For * instance, this message presented above would fail: * \verbatim { "janus" : "create", "transaction" : "" } \endverbatim * \verbatim { "janus" : "error", "transaction" : "" "error" : { "code" : 403, "reason" : "Unauthorized request (wrong or missing secret/token)" } } \endverbatim * * For a successful transaction, the message would have to look like this: * \verbatim { "janus" : "create", "apisecret" : "", "transaction" : "" } \endverbatim * * The same applies for the long poll GET messages as well, which will * need to contain the \c apisecret as a query string parameter. * */ /*! \page admin Admin/Monitor API * Recent versions of Janus introduced a new feature: an Admin/Monitor * API that can be used to ask Janus for more specific information * related to sessions and handles. This is especially useful when you * want to debug issues at the media level. * * \note Right now, this new API mostly allows you to retrieve information, * but only act on part of it: for more interaction (e.g., to force a * session removal), you can rely on the existing \ref rest for the purpose. * Besides, notice that this is a pull-based API. If you're interested in * asynchronous notifications about the internal state of core and plugins, * check the recently added janus_eventhandler mechanism instead. * * The API, for security reasons, is typically not enabled by default in any of the * transport plugins: that's definitely the case for the stock transport * plugins, for instance, while additional, third party plugins may choose * to expose the functionality without requiring any tweaking. As to the * existing transport, you can enable the admin API by editing the \c [ \c admin \c ] * section in the related transport configuration file (e.g., \c janus.transport.http.jcfg * for the REST interface, to use the admin API over HTTP). The configuration * is pretty much the same as the one for the Janus API. In addition, you * can configure restrictions in the form of a password/secret that clients * need to provide or other transport-specific ones. * * For what concerns the syntax, it's very similar to the \ref rest and * so this page will briefly discuss the differences. Notice that, when * using WebSockets, you'll have to use janus-admin-protocol * as the subprotocol, instead of the janus-protocol of the * regular Janus API. * * \section adminreq Admin API requests * There are several different requests that this API implementents, so, * to make this documentation easier to read and the functionality easier * to identify, we can group requests depending on what they provide. * * \subsection adminreqg Generic requests * - \c info: get the generic on the Janus instance; this returns exactly * the same information that a Janus API \c info request would return, * and doesn't require any secret; * - \c ping: a simple ping/pong mechanism for the Admin API, that returns * a \c pong back that the client can use as a healthcheck or to measure * the protocol round-trip time; together with the \c info request introduced * above, it's the only one that doesn't require a secret. * * \subsection adminreqc Configuration-related requests * - \c get_status: returns the current value for the settings that can be * modified at runtime via the Admin API (see below); * - \c set_session_timeout: change the session timeout value in Janus; * - \c set_log_level: change the log level in Janus; * - \c set_log_timestamps: selectively enable/disable adding a timestamp * to all log lines Janus writes on the console and/or to file; * - \c set_log_colors: selectively enable/disable using colors in all * log lines Janus writes on the console and/or to file; * - \c set_locking_debug: selectively enable/disable a live debugging of * the locks in Janus on the fly (useful if you're experiencing deadlocks * and want to investigate them); * - \c set_refcount_debug: selectively enable/disable a live debugging of * the reference counters in Janus on the fly (useful if you're experiencing * memory leaks in the Janus structures and want to investigate them); * - \c set_libnice_debug: selectively enable/disable libnice debugging; * - \c set_min_nack_queue: change the value of the min NACK queue window; * - \c set_no_media_timer: change the value of the no-media timer property; * - \c set_slowlink_threshold: change the value of the slowlink-threshold property. * * \subsection adminreqt Token-related requests * - \c add_token: add a valid token (only available if you enabled the \ref token); * - \c allow_token: give a token access to a plugin (only available if you enabled the \ref token); * - \c disallow_token: remove a token access from a plugin (only available if you enabled the \ref token); * - \c list_tokens: list the existing tokens (only available if you enabled the \ref token); * - \c remove_token: remove a token (only available if you enabled the \ref token). * * \subsection adminreqs Session-related requests * - \c accept_new_sessions: configure whether Janus should accept new * incoming sessions or not; this can be particularly useful whenever, e.g., * you want to stop accepting new sessions because you're draining this instance; * - \c list_sessions: list all the sessions currently active in Janus * (returns an array of session identifiers); * - \c destroy_session: destroy a specific session; this behaves exactly * as the \c destroy request does in the Janus API. * * \subsection adminreqh Handle- and WebRTC-related requests * - \c list_handles: list all the ICE handles currently active in a Janus * session (returns an array of handle identifiers); * - \c handle_info: list all the available info on a specific ICE handle; * if a \c plugin_only property is set to \c true then only the plugin-specific * information is returned, excluding the more verbose WebRTC info and stats; * - \c start_pcap: start dumping incoming and outgoing RTP/RTCP packets * of a handle to a pcap file (e.g., for ex-post analysis via Wireshark); * - \c stop_pcap: stop the pcap dump; * - \c start_text2pcap: same as above, but saves to a text file instead, * to be fed to \c text2pcap in order to generate a \c .pcap or \c .pcapng file; * - \c stop_text2pcap: stop the text2pcap dump; * - \c message_plugin: send a synchronous request to a plugin and return a * response; implemented by most plugins to facilitate and streamline the * management of plugin resources (e.g., creating rooms in a conference plugin); * - \c hangup_webrtc: hangups the PeerConnection associated with a specific * handle; this behaves exactly as the \c hangup request does in the Janus API. * - \c detach_handle: detached a specific handle; this behaves exactly * as the \c detach request does in the Janus API. * * \subsection adminreqe Event handlers-related requests * - \c query_eventhandler: send a synchronous request to an event handler and * return a response; implemented by most event handlers to dynamically * configure some of their properties; * - \c custom_event: push a custom "external" event to notify via event handlers; * this can be useful whenever info from a third-party application needs to be * easily correlated to events originated by Janus, or to push information * Janus doesn't have available (e.g., a script polling CPU usage regularly). * * \subsection adminreql Custom logging-related requests * - \c custom_logline: push a custom "external" string to print on the logs; * this can be useful whenever info from a third-party application needs to be * injected in the Janus logs for whatever reason. The log level can be chosen. * * \subsection adminreqz Helper requests * - \c resolve_address: helper request to evaluate whether this Janus instance * can resolve an address via DNS, and how long it takes; * - \c test_stun: helper request to evaluate whether this Janus instance * can contact a STUN server, what is returned, and how long it takes. * * \section adminsyntax Admin API syntax * Following the same spirit of the \ref rest these methods need to be * invoked on the right path and/or providing the right \c session_id and * \c handle_id identifiers. Specifically, the following requests must be invoked * without any session/handle information, as they're global requests: * * - \c info , \c ping , \c get_status , all the configuration setters, all * the token requests, all the event-handler related requests, all the * helper requests, \c accept_new_sessions and \c list_sessions * * Here's an example of how such a request and its related response might look like: * \verbatim POST /admin { "janus" : "list_sessions", "transaction" : "", "admin_secret" : "" } \endverbatim * * \verbatim { "janus" : "success", "transaction" : "", "sessions" : [ , , [..] ] } \endverbatim * * On the other hand, some requests may be targeting a specific session, * in which case a \c session_id property must be provided. Specifically, * these are the requests that do need a valid session identifier: * * - \c destroy_session , \c list_handles * * Using the REST API, this can be done by appending the session identifier (e.g., one of the ID returned by a \c list_sessions call) to the API root, * but a more generic approach that works for all transports is to just * specify a \c session_id property in the request, e.g.: * \verbatim POST /admin/12345678 { "janus" : "list_handles", "session_id" : 12345678, "transaction" : "", "admin_secret" : "" } \endverbatim * * \verbatim { "janus" : "success", "transaction" : "", "session_id" : 12345678, "handles" : [ , , [..] ] } \endverbatim * * Finally, some requests need not only a valid session identifier, but * a handle identifier as well, as they may address a specific handle * that the Janus instance is serving. It is the case for all requests * that address a specific handle and/or the related PeerConnection, * namely: * * - \c handle_info , all the pcap-related requests, \c message_plugin , * \c hangup_webrtc and \c detach_handle * * The following is an example of how a \c handle_info call addressing * a specific handle might look like. Since this is a handle-specific * request, the correct handle identifier must be * referenced, e.g., by appending the ID to the session it belongs to * or adding a \c handle_id attribute besides the \c session_id parent: * \verbatim POST /admin/12345678/98765432 { "janus" : "handle_info", "session_id" : 12345678, "handle_id" : 98765432, "transaction" : "", "admin_secret" : "" } \endverbatim * * \verbatim { "janus" : "success", "transaction" : "", "session_id" : 12345678, "handle_id" : 98765432, "info" : { "session_id" : 12345678, "session_last_activity": 7927759122, "session_transport": "janus.transport.websockets", "handle_id" : 98765432, "opaque_id": "echotest-YZcsLRCI4uSV", "loop-running": true, "created": 18695669309, "current_time": 18706199704, "plugin": "janus.plugin.echotest", "plugin_specific": { // plugin specific (e.g., EchoTest internals) }, "flags": { // flags }, "agent-created": 18696092523, "ice-mode": "full", "ice-role": "controlled", "sdps": { "profile": "UDP/TLS/RTP/SAVPF", "local": "v=0[..]", "remote": "v=0[..]" }, "queued-packets": 0, "streams": [ // WebRTC info, including SSRCs, codecs, ICE and DTLS states, RTCP stats, etc. ] } } \endverbatim * * With respect to the \c handle_info request we used as an example, here, * the actual content of the last response is omitted for brevity, but * you're welcome to experiment with it in order to check whether more * information (of a different nature, maybe) may be useful to have. In * particular, you may want to play with the plugin-specific details, as * different plugins will return different information according to what * they provide: for instance, the VideoRoom plugin might clarify whether * a handle is being used for publishing media or for receiving it, and * what are the involved IDs, the current status of the delivery, and so on. * At the same time, the \c streams object will contain invaluable details * related to the WebRTC PeerConnection associated with the handle, as * in input/output statistics statistics (bytes, bytes per seconds, NACKs, * etc.) or the SDP/ICE/DTLS states. Notice that the information as * returned by the Admin API here is just a snapshot: if you're more * interested in how this information evolves in a more dynamic way, you * may want to start using the Event Handlers instead, which return pretty * much the same information, but conveying it as dynamic events pushed * to an application you control. * * \section adminpcap Capturing unencrypted WebRTC traffic * As anticipated, you can also enable/disable the dumping of the RTP/RTCP * packets a handle is sending and receiving to a pcap or text2pcap file. This is * especially useful for debugging reasons, e.g., to check whether or not * there are issues in a specific packet Janus is sending or receiving * with tools like Wireshark. Notice that this is not supposed to be used * for recording Janus streams: while it can be used for that, the * janus_recorder utility is much more suited for the task, and is what * all plugins make use of when they're interested in \ref recordings . * * The syntax for the \c start_pcap and \c start_text2pcap commands is * trivial, and apart from the command name pretty much the same: all you * need to specify are information on the handle to dump, information * on the target file (target folder and filename), and whether to truncate * packets or not before dumping them: * \verbatim POST /admin/12345678/98765432 { "janus" : "start_pcap", // Use start_text2pcap for a text file instead "folder" : "", "filename" : "", "truncate" : "", "transaction" : "", "admin_secret" : "" } \endverbatim * * If successful, the full path of the dump file can be obtained by doing * a \c handle_info request. A \c stop_pcap or \c start_text2pcap command * is even easier to generate, as it doesn't need any parameter: * \verbatim POST /admin/12345678/98765432 { "janus" : "stop_pcap", // Use stop_text2pcap if you started a text-based capture "transaction" : "", "admin_secret" : "" } \endverbatim * */ /*! \page deploy Deploying Janus * * When you're going to deploy Janus (e.g., to try the demos we made * available out-of-the-box), there's one thing that is important to point * out: while Janus does indeed provide an HTTP RESTful interface (documented * in \ref rest), it does \b NOT also act as a webserver for static files. * This means you'll need a different webserver to host static files, including * HTML/PHP/JSP/etc. pages, JavaScript files, images and whatever is part * of your web application. * * That said, deploying Janus is, in principle, quite simple: just start Janus on a * machine, put the HTML and JavaScript that will make use of it on a webserver * somewhere, make sure the JavaScript code is configured with the right * address for the server and you're done! * * Let's assume, for the sake of simplicity, that your webserver is serving * files on port \c 80. By default, Janus binds on the \c 8088 port for HTTP. * So, if Janus and the webserver hosting the are co-located, all you need to get your * application working is configure the web application to point to the right * address for the server. In the demos provided with these packages, this * is done by means of the \c server variable: * \verbatim var server = "http://" + window.location.hostname + ":8088/janus"; \endverbatim * * which basically tells the JavaScript application that the Janus API can be * contacted at the same host as the website but at a different port (8088) and path (/janus). * In case you configured the server differently, e.g., 7000 as the port * for HTTP and /my/custom/path as the API endpoint, the \c server variable * could be built this way: * \verbatim var server = "http://" + window.location.hostname + ":7000/my/custom/path"; \endverbatim * * In case the webserver and Janus are NOT colocated, instead, just * replace the \c window.location.hostname part with the right address of * the server, e.g.: * \verbatim var server = "http://www.example.com:8088/janus"; \endverbatim * * It's important to point out, though, that this more "static" approach * only works if the webserver is serving files via HTTP. As soon as you * start involving \b HTTPS, things start to get more complicated: in fact, * for security reasons you cannot contact an HTTP backend if the page is * made available via HTTPS. This means that if you're interested in serving * your web application via HTTPS, you'll need to enable the HTTPS embedded * webserver in Janus as well, and configure the JavaScript code to refer to * that itself, e.g.: * \verbatim var server = "https://" + window.location.hostname + ":8089/janus"; \endverbatim * * assuming \c 8089 is the port you configured Janus to use for HTTPS. * To make this more "dynamic", e.g., allow both HTTP and HTTPS instead of * just sticking to one, you might make use of something like this: * \verbatim var server = null; if(window.location.protocol === 'http:') server = "http://" + window.location.hostname + ":8088/janus"; else server = "https://" + window.location.hostname + ":8089/janus"; \endverbatim * * that is evaulate the right address to use at runtime. * * Anyway, there's a much easier way to address these scenarios, which * is explained in the next section. * * \section apache Deploying Janus behind a web frontend * * To avoid most of the issues explained above, an easy approach can be * deploying Janus behind a frontend (e.g., Apache HTTPD, nginx, lighttpd * or others) that would act as a reverse proxy for incoming requests. * This would allow you to make the Janus API available as a relative path * of your web application, rather than a service reachable at a different * port and/or domain. * * Configuring the web application, as a consequence, would be even easier, * as all you'd need to do would be to provide a relative path for the API, * e.g.: * \verbatim var server = "/janus"; \endverbatim * * which would automatically work whether the page is served via HTTP or * HTTPS. In fact, all the HTTPS requests would be terminated at the webserver, * which would then always send simple HTTP messages to the server itself. * * An easy way to do so in Apache HTTPD is by means of the following directives: * \verbatim ProxyRequests Off ProxyVia Off ProxyPass /janus http://127.0.0.1:8088/janus retry=0 ProxyPassReverse /janus http://127.0.0.1:8088/janus \endverbatim * * Different versions of HTTPD or different webservers may require a * different syntax, but the principle is usually always the same: you instruct * the webserver to act as a proxy for a local endpoint, in this case a * Janus instance colocated at the webserver and configured with the * default settings. * * A way to do the same with nginx, as explained by some Janus users * here, * is the following directive: * \verbatim location /janus { proxy_pass http://127.0.0.1:8088/janus; } \endverbatim * * \section webserver A quick and easy web server * While opening WebRTC-powered web applications by just opening the * application HTML files from file system works with some browsers, it * doesn't in others. Specifically, this works in Firefox but not in Chrome * (see issue #291). * Anyway, considering that you will eventually want other people besides * you to use your Janus services, this means that to test and use Janus * you'll want/need to host your applications on a webserver. * * If you're not interested in configuring a full-fledged webserver, but * are only interested in a quick and easy way to test the demos, you can * make use of the embedded webservers some frameworks like PHP and Python * provide. To start a webserver for the demos, for instance, just open a * terminal in the \c html folder of the project, and type: * *\verbatim php -S 0.0.0.0:8000 \endverbatim * * or: * *\verbatim python -m SimpleHTTPServer 8000 \endverbatim * * This will setup a webserver on port \c 8000 for you to use, meaning you'll * just need to have your browser open a local connection to that port to * try the demos: * *\verbatim http://yourlocaliphere:8000 \endverbatim * * You can do the same on a different port to also access the HTML version of the Doxygen generated * documentation, starting the embedded webservers from the \c docs/html * folder instead: * *\verbatim php -S 0.0.0.0:9000 \endverbatim * * or: * *\verbatim python -m SimpleHTTPServer 9000 \endverbatim * * \section deplyws Using Janus with WebSockets * * Configuring the usae of WebSockets rather than the REST API in the JavaScript * library is quite trivial, as it's a matter of passing a \c ws:// address * instead of an \c http:// one to the constructor. That said, most of the same * considerations provided for the REST API apply here as well, e.g., * to just use \c window.location.hostname if the webserver and Janus are * colocated: * \verbatim var server = "ws://" + window.location.hostname + ":8188/"; \endverbatim * * to specify the port if you change it: * \verbatim var server = "ws://" + window.location.hostname + ":7000/"; \endverbatim * * and/or the right address of the server in case the webserver and Janus * are NOT colocated: * \verbatim var server = "ws://www.example.com:8188/"; \endverbatim * * Notice how the path (\c /janus by default for HTTP) is not provided * for WebSockets, as it is ignored by the server. * * The considerations for deploying Janus behind a proxy/webserver, though, * differ if you use WebSockets, as most webservers don't provide an easy * way to proxy WebSocket requests, and usually require custom modifications * for the purpose. Recent versions of HTTPD (>= 2.4.5), with the right * module (proxy_wstunnel), do allow you to also proxy WebSockets requests the * same way you do with HTTP, which can be useful to do the same * WSS-to-WS proxying in a frontend. Here's a sample configuration: * \verbatim ProxyPass /janus-ws ws://127.0.0.1:8188 retry=0 ProxyPassReverse /janus-ws ws://127.0.0.1:8188 \endverbatim * * that will allow you to expose a wss://myserver/janus-ws * or ws://myserver/janus-ws address, and have all communication * forwarded to and from Janus at ws://127.0.0.1:8188. * * Similar configurations are probably available for other systems as well, * so in case this is something you're interested in, we recommend you * follow the best practices related to that made available by the web server developers. * * \section both Using fallback addresses * As anticipated in the \ref JS section, you can also pass an array of servers * to the Janus library initialization. This allows you, for instance, to * pass a link to both the WebSockets and REST interfaces, and have the * library try them both to see which one is reachable, e.g.: * \verbatim var ws_server = "ws://" + window.location.hostname + ":8188/"; var http_server = "http://" + window.location.hostname + ":8088/janus"; var servers = [ws_server, http_server]; \endverbatim * * which is especially useful if you're not sure whether or not WebSockets * will work in some specific networks. Please notice that, for the individual * servers listed in the array, the same considerations given above (e.g., * in terms of relative vs. absolute linking) still apply. * * Such an approach can also be used when you've deployed several different * instances of Janus, and you want the library to try some and fallback * to others if any of them is not reachable for any reason. * */ /*! \page service Janus as a daemon/service * * By default, Janus starts in foreground, and as such works as a server * application that you start normally and displays output on the console. * That said, there are several reasons why you may not want to keep * Janus in the foreground, while still being interested in checking * the console to see what's happening. * * There are different ways to "daemonize" it and have it run as a service, * though. This page tries to summarize a few ways to do so, starting * from "dumb" approaches like sending to background and/or using screen/tmux, * to more sophisticated approaches involving \c systemd, \c upstart * and others. * * \section daemon Running Janus as a daemon * Since version \c 0.1.0, you can run Janus as a daemon application. To * do so, just pass either \c -b or \c --daemon as a command line * argument, and Janus will be daemonized. Just beware, though, that * since this results in stdout/stdin/stderr being closed, you MUST * specify a log file for Janus to use, either via command line (\c -L * or \c --log-file ) or in \c janus.jcfg. * * \section bg Running in background * Another simple way to run Janus in the background is to just append the * \c & character to the command line. Anyway, this will still "flood" the console * with output from Janus. While there are ways to handle it (e.g., as * explained here), * a nice and easy way to handle this is redirecting the output to a * separate file, e.g., a dedicated log: * \verbatim /opt/janus/bin/janus -d 5 -6 >/path/to/mylogfile 2>&1 & \endverbatim * * This is especially useful in case you want to keep a log of what * happened when Janus was running, and can also be used as a simple and * effective way to watch the console "live" using \c tail: \verbatim tail -f /path/to/mylogfile \endverbatim * * \section screen Terminal multiplexers * Another easy way to run Janus in the background is using terminal * multiplexers like \c screen or \c tmux. If you're not familiar with * such applications, you can find a quick overview * here. * * The following is a simple example with \c screen: * \verbatim screen -S janus -d -m screen -r janus -X stuff $'/opt/janus/bin/janus -d 5 -6\n' \endverbatim * * This will create a session called "janus" and launch Janus in it with * a few command line options (in this case, just the option to enable * IPv6 support and set the debug to verbose). Janus will then be running * in the background: accessing the console is just a matter of attaching * to the "janus" screen: * \verbatim screen -r janus [CTRL+A+D to detach again] \endverbatim * * Terminal multiplexers usually allow for logging the output to file * as well, if you want to keep an history of what happened during the * Janus lifetime. * * \section systemd systemd * This section shows how you can add Janus as a service to * systemd. * \verbatim [Unit] Description=Janus WebRTC Server After=network.target [Service] Type=simple ExecStart=/opt/janus/bin/janus -o Restart=on-abnormal LimitNOFILE=65536 [Install] WantedBy=multi-user.target \endverbatim * * \note Remember to adjust the path in ExecStart to match the Janus binary path. * * \warning Please beware that, per the default \c RateLimitInterval and * and \c RateLimitBurst values in the default sytemd configuration, logger * messages are dropped if they arrive faster than ~33 per second. You * may want to configure them accordingly, or otherwise Janus log messages * may be missing. To fix this, setting RateLimitInterval=1s * and RateLimitBurst=2000 in * /etc/systemd/journald.conf is usually enough. * * \note systemd example provided by * \@saghul * * \section upstart upstart * This section shows how you can add Janus as a daemon to * upstart, which is * typically available on Ubuntu systems. * \verbatim description "janus" start on filesystem or runlevel [2345] stop on runlevel [!2345] limit nofile 50000 50000 limit core unlimited unlimited respawn respawn limit 10 5 exec /opt/janus/bin/janus \endverbatim * * \note upstart example provided by * \@ploxiln * * \warning In case starting Janus depends on some external conditions, you * may need to modify the \c start and \c stop lines accordingly. Here you can * find an example, * provided by \@stormbkk87, * showing how you can wait, for instance, for RabbitMQ to start before starting Janus too. * * \section sysvinit sysvinit * This section shows how you can add Janus as a daemon to * SysVinit based systems. * \verbatim #!/bin/sh ### BEGIN INIT INFO # Provides: Janus # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Janus WebRTC Server # Description: Janus WebRTC Server ### END INIT INFO DAEMON=/usr/bin/janus DAEMON_NAME=janus # Add any command line options for your daemon here DAEMON_OPTS="-D -o" # This next line determines what user the script runs as. # Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python. DAEMON_USER=root # The process ID of the script when it runs is stored here: PIDFILE=/var/run/$DAEMON_NAME.pid . /lib/lsb/init-functions do_start () { log_daemon_msg "Starting system $DAEMON_NAME daemon" start-stop-daemon --start --background --no-close --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS >> /var/log/$DAEMON_NAME.log 2>&1 log_end_msg $? } do_stop () { log_daemon_msg "Stopping system $DAEMON_NAME daemon" start-stop-daemon --stop --pidfile $PIDFILE --retry 10 log_end_msg $? } case "$1" in start|stop) do_${1} ;; restart|reload|force-reload) do_stop do_start ;; status) status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $? ;; *) echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}" exit 1 ;; esac exit 0 \endverbatim * * \note sysvinit example provided by * \@saghul * * \section supervisor supervisor * This section shows how you can add Janus to * supervisor, which is * typically available on Ubuntu systems. * \verbatim [program:janus] command=/opt/janus/bin/janus user=root autostart=true autorestart=true stderr_logfile=/var/log/janus.err.log stdout_logfile=/var/log/janus.out.log \endverbatim * * \note The above configuration file should be added to * /etc/supervisor/conf.d/janus.conf. Then the following commands * should be run: * \verbatim sudo supervisorctl reread sudo supervisorctl update \endverbatim * * \section Others * TODO. * */ /*! \page debug Debugging Janus * * In the magical world of fairies and unicorns, the sun always shines * and everything always works smoothly and without issues. Unfortunately, * this is not the world we live in, and so you might still encounter * issues using Janus, e.g., unexpected crashes and the like. We always * try and tackle bugs as soon as we spot them, but some issues may be * always lingering in the background. * * Should you encounter a bug or a crash, open a new * issue * on GitHub. Make sure you carefully read the * guidelines * for contributing, or otherwise we may decide to close the issue and * not even look at it. * * What's important for us to look into issues and bugs definitely is * having enough information to do so. As such, whenever possible try to * provide as many details and data as possible. Quite useful to us are * GDB stacktraces and/or AddressSanitizer output. The following sections * give a quick overview on how you can collect this information after * a crash, but for a more detailed description of the tools you should * refer to the related documentation pages and tutorials. * * \section gdb GDB * GDB is the GNU Project Debugger * and is an effective tool for looking at what has happened (or is * happening) inside an application. As such, it's quite useful to spot * bugs and the like, as it can provide information about the values of * variables when they were used and the application crashed. * * When Janus crashes, you should get a core dump file somewhere. This is * a recorded state of the application memory at the time of crashing, and * so a backtrace of what lead to an issue can help. You can open such * a core dump file via gdb this way: * \verbatim gdb /path/to/bin/janus /path/to/coredump gdb bt \endverbatim * * The \c bt command retrieves the backtrace, and is what you should provide * as part of your new issue. * * \note Please \c DON'T paste this backtrace in the issue text. Use a * service like Gist or * Pastebin and pass the generated * link instead. * * \section sanitizer Address Sanitizer * An even better tool for spotting issues is * Address Sanitizer, * a fast memory error detector. Since it can spot memory errors, it's * very useful to find out about hidden race conditions and the like. * * Unlike GDB which can be used as is, though, to use Address Sanitizer * you'll first need to recompile Janus with some new settings, as it * requires a specific dependency on a library, libasan, which you'll need * to install through your repository manager if needed. Besides, you'll * need at least gcc 4.8 for this to work: older versions of gcc won't * work. * * Once you've installed libasan, reconfigure Janus like this: * \verbatim CFLAGS="-O1 -g3 -ggdb3 -fno-omit-frame-pointer -fsanitize=address -fno-sanitize-recover=all -fsanitize-address-use-after-scope" LDFLAGS="-fsanitize=address" ./configure --prefix=/opt/janus \endverbatim * * Of course you're free to add whatever additional configuration parameter * you were using before: the important parts are the environment variables * before that. Once done configuring, do a \c make \c clean (to make sure * everything is recompiled from scratch) and then a \c make and \c make \c install * as usual. * * At this point, your Janus version should be Address Sanitizer compliant. * To make sure, try using \c ldd to check whether libasan is indeed a * dependency or not: * \verbatim ldd janus | grep asan \endverbatim * * If it is, you're done: whenever Janus crashes for any reason, you'll * get additional output from Address Sanitizer automatically with details * on what went wrong, and that's what you should provide as part of the * issue content. Just as a side note, please beware that using Address * Sanitizer Janus will run just a bit slower, even though not to the * point of being unusable (as when using, e.g., valgrind). * * \note Please \c DON'T paste Address Sanitizer output in the issue text. * Use a service like Gist or * Pastebin and pass the generated * link instead. * */ /*! \page pluginslist Plugins documentation * Out of the box, Janus comes with a set of different and heterogeneous * media manipulation plugins. These can be used individually or composed * together at an application level for building complex WebRTC-based * media applications. * * The list of plugins currently available is the following. Since new * plugins may become available available in the future, make sure you * come back to this page for more information. * * - \ref echotest * - \ref streaming * - \ref videocall * - \ref sip * - \ref nosip * - \ref audiobridge * - \ref videoroom * - \ref textroom * - \ref recordplay * - \ref voicemail * - \ref lua * - \ref duktape */ /*! \page eventhandlers Event handlers documentation * Controlling and monitoring a Janus instance can be done using the * \ref admin 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: * - session related events (e.g., session created/destroyed, etc.); * - handle related events (e.g., handle attached/detached, etc.); * - JSEP related events (e.g., got/sent offer/answer); * - WebRTC related events (e.g., PeerConnection up/down, ICE updates, DTLS updates, etc.); * - media related events (e.g., media started/stopped flowing, stats on packets/bytes, etc.); * - generic events originated by the Janus core (e.g., Janus started/stopped); * - events originated by plugins (content specific plugins themselves); * - events originated by transports (see above); * - events originated by external applications via the Admin API (content specific to source). * * \section evhsyntax Events format * 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 \c type and (when needed) \c 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: \verbatim { "emitter" : "", "type" : , "subtype" : , "timestamp" :