Fork me on GitHub
Janus TextRoom documentation

This is a plugin implementing a DataChannel only text room. As such, it does NOT support or negotiate audio or video, but only data channels, in order to provide text broadcasting features. The plugin allows users to join multiple text-only rooms via a single PeerConnection. Users can send messages either to a room in general (broadcasting), or to individual users (whispers). This plugin can be used within the context of any application that needs real-time text broadcasting (e.g., chatrooms, but not only).

The only message that is typically sent to the plugin through the Janus API is a "setup" message, by which the user initializes the PeerConnection itself. Apart from that, all other messages can be exchanged directly via Data Channels. For room management purposes, though, requests like "create", "edit", "destroy", "list" and "exists" are available through the Janus API as well: notice that in this case you'll have to use "request" and not "textroom" as the name of the request.

Each room can also be configured with an HTTP backend to contact for incoming messages. If configured, messages addressed to that room will also be forwarded, by means of an HTTP POST, to the specified address. Notice that this will only work if libcurl was available when configuring and installing Janus.

Note
This plugin is only meant to showcase what you can do with data channels involving multiple participants at the same time. While functional, it's not inherently better or faster than doing the same thing using the Janus API messaging itself (e.g., as part of the plugin API messaging) or using existing instant messaging protocols (e.g., Jabber). In fact, while data channels are being used, you're still going through a server, so it's not really peer-to-peer. That said, the plugin can be useful if you don't plan to use any other infrastructure than Janus, and yet you also want to have text-based communication (e.g., to add a chatroom to an audio or video conference).

Notice that, in general, all users can create rooms. If you want to limit this functionality, you can configure an admin admin_key in the plugin settings. When configured, only "create" requests that include the correct admin_key value in an "admin_key" property will succeed, and will be rejected otherwise.

Rooms to make available at startup are listed in the plugin configuration file. A pre-filled configuration file is provided in conf/janus.plugin.textroom.cfg and includes a demo room for testing.

To add more static rooms or modify the existing one, you can use the following syntax:

[<unique room ID>]
description = This is my awesome room
is_private = true|false (whether this room should be in the public list, default=true)
secret = <optional password needed for manipulating (e.g. destroying) the room>
pin = <optional password needed for joining the room>
post = <optional backend to contact via HTTP post for all incoming messages>

As explained in the next section, you can also create rooms programmatically.

Text Room API

All TextRoom API requests are addressed by a textroom named property, and must contain a transaction string property as well, which will be returned in the response. Notice that, for the sake of brevity, the transaction property will not be displayed in the documentation, although, as explained, it MUST be present, and WILL be included in all responses (but not in the unsolicited events, like join/leave or incoming messages).

To get a list of the available rooms (excluded those configured or created as private rooms) you can make use of the list request, which has to be formatted as follows:

{
        "textroom" : "list",
}

A successful request will produce a list of rooms in a success response:

{
        "textroom" : "success",
        "rooms" : [             // Array of room objects
                {       // Room #1
                        "room" : <unique numeric ID>,
                        "description" : "<Name of the room>",
                        "pin_required" : <true|false, depending on whether the room is PIN-protected>,
                        "num_participants" : <count of the participants>
                },
                // Other rooms
        ]
}

To create new TextRoom rooms you can use the create request. The API room creation supports the same fields as creation via configuration files, which means the request must be formatted as follows:

{
        "textroom" : "create",
        "room" : <unique numeric room ID to assign; optional, chosen by plugin if missing>,
        "admin_key" : "<plugin administrator key; mandatory if configured>",
        "description" : "<description of room; optional>",
        "secret" : "<secret to query/edit the room later; optional>",
        "pin" : "<PIN required for participants to join room; optional>",
        "is_private" : <true|false, whether the room should be listable; optional, true by default>,
        "post" : "<backend to contact via HTTP post for all incoming messages; optional>",
        "permanent" : <true|false, whether the mountpoint should be saved to configuration file or not; false by default>
}

A successful creation procedure will result in a success response:

{
        "textroom" : "success",
        "room" : <unique numeric ID>,
        "permanent" : <true if saved to config file, false if not>
}

If you requested a permanent room but a false value is returned instead, good chances are that there are permission problems.

An error instead (and the same applies to all other requests, so this won't be repeated) would provide both an error code and a more verbose description of the cause of the issue:

{
        "textroom" : "event",
        "error_code" : <numeric ID, check Macros below>,
        "error" : "<error description as a string>"
}

Once a room has been created, you can still edit some (but not all) of its properties using the edit request. This allows you to modify the room description, secret, pin, whether it's private or not and the backend to forward incoming messages to: you won't be able to modify other more static properties, though, like the room ID for instance. If you're interested in changing the ACL, instead, check the allowed message. An edit request has to be formatted as follows:

{
        "textroom" : "edit",
        "room" : <unique numeric ID of the room to edit; mandatory>,
        "secret" : "<room secret; mandatory if configured>",
        "new_description" : "<new pretty name of the room; optional>",
        "new_secret" : "<new password required to edit/destroy the room; optional>",
        "new_pin" : "<new password required to join the room; optional>",
        "new_is_private" : <true|false, whether the room should appear in a list request; optional>,
        "permanent" : <true|false, whether the room should be also removed from the config file; default=false>
}

A successful edit procedure will result in a success response:

{
        "textroom" : "edited",
        "room" : <unique numeric ID>,
        "permanent" : <true if changes were saved to config file, false if not>
}

On the other hand, destroy can be used to destroy an existing text room, whether created dynamically or statically, and has to be formatted as follows:

{
        "textroom" : "destroy",
        "room" : <unique numeric ID of the room to destroy; mandatory>,
        "secret" : "<room secret; mandatory if configured>",
        "permanent" : <true|false, whether the room should be also removed from the config file; default=false>
}

A successful destruction procedure will result in a destroyed response:

{
        "textroom" : "destroyed",
        "room" : <unique numeric ID>,
        "permanent" : <true if the room was removed from config file too, false if not>
}

This will also result in a destroyed event being sent to all the participants in the room, which will look like this:

{
        "textroom" : "destroyed",
        "room" : <unique numeric ID of the destroyed room>
}

You can check whether a room exists using the exists request, which has to be formatted as follows:

{
        "textroom" : "exists",
        "room" : <unique numeric ID of the room to check; mandatory>
}

A successful request will result in a success response:

{
        "textroom" : "success",
        "room" : <unique numeric ID>,
        "exists" : <true|false>
}

You can configure whether to check tokens or add/remove people who can join a room using the allowed request, which has to be formatted as follows:

{
        "textroom" : "allowed",
        "secret" : "<room secret; mandatory if configured>",
        "action" : "enable|disable|add|remove",
        "room" : <unique numeric ID of the room to update; mandatory>,
        "allowed" : [
                // Array of strings (tokens users might pass in "join", only for add|remove)
        ]
}

A successful request will result in a success response:

{
        "textroom" : "success",
        "room" : <unique numeric ID>,
        "allowed" : [
                // Updated, complete, list of allowed tokens (only for enable|add|remove)
        ]
}

If you're the administrator of a room (that is, you created it and have access to the secret) you can kick participants using the kick request. Notice that this only kicks the user out of the room, but does not prevent them from re-joining: to ban them, you need to first remove them from the list of authorized users (see allowed request) and then kick them. The kick request has to be formatted as follows:

{
        "textroom" : "kick",
        "secret" : "<room secret; mandatory if configured>",
        "room" : <unique numeric ID of the room; mandatory>,
        "username" : "<unique username of the participant to kick; mandatory>"
}

A successful request will result in a success response:

{
        "textroom" : "success",
}

This will also result in a kicked event being sent to all the other participants in the room, which will look like this:

{
        "textroom" : "kicked",
        "room" : <unique numeric ID of the room>,
        "username" : "<unique username of the kicked participant>"
}

For what concerns room participation, you can join a room using the join request, send messages (public and private) using the message request, and leave a room with leave instead.

A join request must be formatted as follows:

{
        "textroom" : "join",
        "room" : <unique numeric ID of the room to join>,
        "pin" : "<pin to join the room; mandatory if configured>",
        "username" : "<unique username to have in the room; mandatory>",
        "display" : "<display name to use in the room; optional>"
}

A successful join will result in a success response, which will include a list of all the other participants currently in the room:

{
        "textroom" : "success",
        "participants" : [
                {
                        "username" : "<username of participant #1>",
                        "display" : "<display name of participant #1, if any>"
                },
                // Other participants
        ]
}

As explained previously, there's no hardcoded limit in how many rooms you can join with the same participant and on the same PeerConnection.

Notice that a successful join request will also result in a join event being sent to all the other participants, so that they're notified about the new participant getting in the room:

{
        "textroom" : "join",
        "room" : <room ID>,
        "username" : "<username of new participant>",
        "display" : "<display name of new participant, if any>"
}

To leave a previously joined room, instead, the leave request can be used, which must be formatted like this:

{
        "textroom" : "leave",
        "room" : <unique numeric ID of the room to leave>
}

A successful leave will result in a success response:

{
        "textroom" : "success"
}

Notice that a successful leave request will also result in a leave event being sent to all the other participants, so that they're notified about the participant that just left the room:

{
        "textroom" : "leave",
        "room" : <room ID>,
        "username" : "<username of gone participant>"
}

Finally, the message request allows you to send public and private messages within the context of a room. It must be formatted like this:

{
        "textroom" : "message",
        "room" : <unique numeric ID of the room this message will refer to>,
        "to" : "<username to send the message to; optional, only needed in case of private messages>",
        "tos" : "<array of usernames to send the message to; optional, only needed in case of private messages>",
        "text" : "<content of the message to send, as a string>",
        "ack" : <true|false, whether the sender wants an ack for the sent message(s); optional, true by default>
}

A message with no to and no tos is considered a public message, and so will be sent to all the participants in the room. In case either to or tos is specified, instead, this is considered to be a whisper, that is a private message only meant for the specified recipients. Notice that to and tos are mutually exclusive, and you cannot specify both.

text must be a string, but apart from that there's no limit on what you can put in there. It could be, for instance, a serialized JSON string, or a stringified XML document, or whatever makes sense to the application.

A successful message delivery will result in a success response, but only if ack was true in the message request. This was done by design, to allow users to disable explicit acks for every outgoing message, especially in case of verbose communications. In case an ack is required, the response will look like this:

{
        "textroom" : "success"
}

Incoming messages can come either as message or whisper events. message will notify the user about an incoming public message, that is a message that was sent to the whole room:

{
        "textroom" : "message",
        "room" : <room ID the message was sent to>,
        "from" : "<username of participant who sent the public message>",
        "date" : "<date/time of when the message was sent>",
        "text" : "<content of the message>"
}

whisper messages, instead, will notify the user about an incoming private message from another participant in the room:

{
        "textroom" : "whisper",
        "room" : <room ID the message was sent to>,
        "from" : "<username of participant who sent the private message>",
        "date" : "<date/time of when the message was sent>",
        "text" : "<content of the message>"
}