Skip to content

VideoRoom plugin documentation

James edited this page Nov 20, 2021 · 15 revisions

This is a plugin implementing a videoconferencing SFU (Selective Forwarding Unit) cluster of the Janus server. It tries to keep almost the same API with the videoroom plugin of Janus-gateway server, and scale it out by distributing different publishers to different backend Janus server, to make Janus-proxy can support more publishers in one videoconferencing room than the single Janus server.

Principle & Topology

The following diagram shows how the Videoroom plugin works.

      +-----------------------------------------------------+
      |                                                     |
      |                +----------------------------------------------------+
      |                |                                    |               |
      |                |                                    |               |
      |       +--------+-------+                   +--------+-------+       |
      |       |                |  WS           WS  |                |       |
      |       |     JanusA     +<----+        +--->+    JanusB      |       |
      |       |                |     |        |    |                |       |
      |       +--------+-------+     |        |    +--------+-------+       |
 Bob  |                ^             |        |             ^               | Alice
Media |                |             |        |             |               | Media
      |                |             |        |             |               |
      |                |        +----+--------+---+         |               |
      |                |        |                 |         |               |
      |                |        |   Janus-proxy   |         |               |
      |                |        |                 |         |               |
      |          Alice |        +----+--------+---+         |  Bob          |
      |          Media |             ^        ^             | Media         |
      |                |             |        |             |               |
      |                |           WS|        |WS           |               |
      |        +-------+-------+     |        |    +--------+------+        |
      +------->+    Alice      +-----+        +----+       Bob     +<-------+
               +---------------+                   +---------------+


Alice(from browser) make the WS connction with janus-proxy, attaches a videoroom handle and join the room as a publisher, Janus-proxy select one of the backend Janus server (e.g. JanusA) to make the connection, according to its selection algorithm, then attach a new videoroom handle, create an exclusive room and join to this room as the only publisher on behave of Alice.So Alice makes the peerconnection with JanusA and send his media to it. Bob joins later, so does for him by Janus-proxy except select JanusB as his backend server. So Bob makes the peerconnection with JanusB and send his media to it. When Alice is aware of Bob's attendance, he attaches a new handle with Janus-proxy and join as a subscriber to Bob, then Janux-proxy attaches a new handle with the JanusB(Bob's backend server), join to the Bob's room as a subscriber on behave of Alice, so that Alice makes the peerconnection with JanusB and receive Bob's media on it. So does for Bob.

Finally, Janus-proxy distribute all the publishers among the backend Janus server and balance the media traffic load, so that the Janus server can be scale out.

API compliance

this APIs is compatible with the videoroom plugin of Janus-gateway util v0.10.7(2020-10-30), except for:

  • Switch
  • String ID

Features

In this chaper, some special features of this Videoroom plugin which are different from Janus-gateway would be described below, about What, Why, How.

Room DB

As for Janus-gateway videoroom plugin, the room configuration is stored by a config file which is suitables for the case of tens of rooms. But Janus-cloud is designed for the cluster application, which need to deal with thousands of the video-conferencing rooms, including rapidly creation and deletion. So the database approach is chosen as the room persistence solution by Janus-cloud. As so far, VideoRoom plugin of Janus-cloud supports memory DB to store the room config info, and is going to support redis DB in the near future.

DB url format which is set in the plugin's configuration file:

For memory db:

memory

For Redis,

redis://{user}:{secret}@{hostname}:{port}/{db_id}

Room auto-destroy

For the original Janus-gateway videroom plugin, the room can only be destroyed dynamically by API so that the client must call the room-destroy API by manual to free the room's resources . But for the Internet environment, clients may disappear at anytime, which may result into the leak of the room resources. To solve this problem, Janus-cloud's videoroom plugins supports the room auto-destroy feature. When a room is idle for a specific time, this room would be destroyed automatically and the related resources would be reclaimed by system. This feature can ease the room management for client system effectly, and prevent from long-running resource leak.

Backend sweeper

Because of the original Janus-gateway cannot destroy the idle rooms automatically, Janus-proxy provide the Backend sweeper to avoid the risk of room resource leak. The backend sweeper would check every active backend server at a interval, and destroy the found idle room.

Recording & forwarding

Janus-proxy videroom plugin can support media recording and forwarding just like Janus-gateway, but it does not implement them by it self. Instead, it relays the relevant request to the backend Janus servers, so that these functions are delegated to them. So the related parameters, like the recording path, is for the backend server running Janus-gateway, not for the server running Janus-proxy.

Limitation

In this chaper, some shortages about the Janus-proxy scheme would be listed.

Switch

In original Janus-gateway, videoroom provides a interesting feature called "switch", which means a subscriber can change the feed without re-join the room. This feature can be implemented in Janus-gateway because all the feed streams are processed by the same server. But in case of Janux-proxy, different publishers pushes their stream to different backend server, if a subscriber want to "switch", he must make the peerconnection with the new backend server, so that "switch" make no sense for Janus-proxy.

String ids

In original Janus-gateway, videoroom plugin supports the string ids feature which means the user can specify a string, as well as integer as the room id or paticipant id. But this is feature is not supported by Janus-proxy because it does not make much sense for the common case, in which the integer id is sufficient. And it complicates and obscure the procesing logic to suport both data-types of id.

Note: The string_ids feature should be set to false in videoroom plugin configuration file of the backend Janus-gateway

Admin API

Besides the business API which is kept the same with janus-gateway (by WebSockets), the videoroom plugin also provides a set of RESTful APIs for efficient administration, by HTTP. The user's backend service can make use of them to convinently manage the videoroom plugin of janus-proxy, as well as the user's frontend client(like browser) make use of the business API for the normal funciton.

The host address and port of URL of these REST APIs are indicated by the janus-proxy's configuration file, so that only the path would be provided for each API.

Plugin info

Get the plugin info

  • Http Method: GET
  • URL Path: /plugins/videoroom
  • Params:
No
  • Response Content
{
    'package': <the plugin's unique package name, i.e. janus.plugin.videoroom>,
    'version': <version number>,
    'version_str': <version string>,
    'name': <the plugin's text name, i.e. JANUS VideoRoom plugin>,
    'author': <the plugin's author>,
    'description': <the plugin's description>,
    'handles': <number of the current handles>,
    'rooms': <number of the current rooms>
}

Room management

Get room list

  • Http Method: GET
  • URL Path: /plugins/videoroom/rooms
  • Params:
"admin_key": <string, if admin_key is provided, the private rooms would be list too, default is empty>
"offset": <integer, the index of the first room returned in the list, default is 0>
"limit":  <integer, max number of room returned in the list, default is 100>
  • Response Content
[
{   // Room #offset
    "room" : <unique numeric ID>,
    "description" : "<Name of the room>",
    "pin_required" : <true|false, whether a PIN is required to join this room>,
    "max_publishers" : <how many publishers can actually publish via WebRTC at the same time>,
    "bitrate" : <bitrate cap that should be forced (via REMB) on all publishers by default>,
    "bitrate_cap" : <true|false, whether the above cap should act as a limit to dynamic bitrate changes by publishers>,
    "fir_freq" : <how often a keyframe request is sent via PLI/FIR to active publishers>,
    "audiocodec" : "<comma separated list of allowed audio codecs>",
    "videocodec" : "<comma separated list of allowed video codecs>",
    "record" : <true|false, whether the room is being recorded>,
    "record_dir" : "<if recording, the path where the .mjr files are being saved>",
    "lock_record" : <true|false, whether the room recording state can only be changed providing the secret>,
    "num_participants" : <count of the participants (publishers, active or not; not subscribers)>
},
...  //other rooms
]

Get room info

  • Http Method: GET
  • URL Path: /plugins/videoroom/rooms/{room_id}
  • Params:
NO
  • Response Content
{   // Room #offset
    "room" : <unique numeric ID>,
    "description" : "<Name of the room>",
    "pin_required" : <true|false, whether a PIN is required to join this room>,
    "max_publishers" : <how many publishers can actually publish via WebRTC at the same time>,
    "bitrate" : <bitrate cap that should be forced (via REMB) on all publishers by default>,
    "bitrate_cap" : <true|false, whether the above cap should act as a limit to dynamic bitrate changes by publishers>,
    "fir_freq" : <how often a keyframe request is sent via PLI/FIR to active publishers>,
    "audiocodec" : "<comma separated list of allowed audio codecs>",
    "videocodec" : "<comma separated list of allowed video codecs>",
    "record" : <true|false, whether the room is being recorded>,
    "record_dir" : "<if recording, the path where the .mjr files are being saved>",
    "lock_record" : <true|false, whether the room recording state can only be changed providing the secret>,
    "num_participants" : <count of the participants (publishers, active or not; not subscribers)>
}

Remove room

  • Http Method: DELETE
  • URL Path: /plugins/videoroom/rooms/{room_id}
  • Params:
"secret": <string, this room's secret, default is empty.>
"permanent": <True/False, whether save this change. default is False.>
  • Response Content
NO

Create room

  • Http Method: POST
  • URL Path: /plugins/videoroom/rooms
  • Params:
"room" : <unique numeric ID, optional, chosen by plugin if missing>,
"permanent" : <true|false, whether the room should be saved in the config file, default=false>,
"description" : "<pretty name of the room, optional>",
"secret" : "<password required to edit/destroy the room, optional>",
"pin" : "<password required to join the room, optional>",
"is_private" : <true|false, whether the room should appear in a list request>,
"allowed" : [ array of string tokens users can use to join this room, optional],
...  //other room params

  • Response Content

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

Participant management

Get participant list

  • Http Method: GET
  • URL Path: /plugins/videoroom/rooms/{room_id}/participants
  • Params:
No
  • Response Content
[
{   // participant info
    "id" : <unique numeric ID of the participant>,
    "display" : "<display name of the participant, if any; optional>",
    "publisher" : "<true|false, whether user is an active publisher in the room>",
    "talking" : <true|false, whether user is talking or not (only if audio levels are used)>
    "backend_server" : <backend server name and url>
    "backend_room_id" : <backend room id>
},
...  //other participant
]

Remove Participant

  • Http Method: DELETE
  • URL Path: /plugins/videoroom/rooms/{room_id}/participants/{participant_id}
  • Params:
"secret": <string, this room's secret, default is empty.>
  • Response Content
NO

Token management

  • Http Method: POST
  • URL Path: /rooms/{room_id}/tokens
  • Params:

"secret" : "<room secret, mandatory if configured>",
"action" : "enable|disable|add|remove",
"room" : <unique numeric ID of the room to update>,
"allowed" : <Array of strings (tokens users might pass in "join", only for add|remove), seperated by comma>

  • Response Content

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

Rtp forwarder management

List rtp forwarder

  • Http Method: GET
  • URL Path: /rooms/{room_id}/rtp_forwarders
  • Params:
"secret" : "<room secret, mandatory if configured>",
  • Response Content
[  // Array of publishers with RTP forwarders
                {       // Publisher #1
                        "publisher_id" : <unique numeric ID of publisher #1>,
                        "rtp_forwarders" : [            // Array of RTP forwarders
                                {       // RTP forwarder #1
                                        "audio_stream_id" : <unique numeric ID assigned to this audio RTP forwarder, if any>,
                                        "video_stream_id" : <unique numeric ID assigned to this video RTP forwarder, if any>,
                                        "data_stream_id" : <unique numeric ID assigned to this datachannel messages forwarder, if any>
                                        "ip" : "<IP this forwarder is streaming to>",
                                        "port" : <port this forwarder is streaming to>,
                                        "rtcp_port" : <local port this forwarder is using to get RTCP feedback, if any>,
                                        "ssrc" : <SSRC this forwarder is using, if any>,
                                        "pt" : <payload type this forwarder is using, if any>,
                                        "substream" : <video substream this video forwarder is relaying, if any>,
                                        "srtp" : <true|false, whether the RTP stream is encrypted>
                                },
                                ...// Other forwarders for this publisher
                        ],
                },
                ...// Other publishers
]

Launch rtp forwarders

  • Http Method: POST
  • URL Path: /rooms/{room_id}/rtp_forwarders
  • Params:
"admin_key": <plugin's admin key if lock_rtp_forward is enabled>,
"secret" : "<room secret, mandatory if configured>",
"publisher_id" : <unique numeric ID of the publisher to relay externally>,
"host" : "<host address to forward the RTP and data packets to>",
"host_family" : "<ipv4|ipv6, if we need to resolve the host address to an IP; by default, whatever we get>",
"audio_port" : <port to forward the audio RTP packets to>,
"audio_ssrc" : <audio SSRC to use to use when streaming; optional>,
"audio_pt" : <audio payload type to use when streaming; optional>,
"audio_rtcp_port" : <port to contact to receive audio RTCP feedback from the recipient; optional, and currently unused for audio>,
"video_port" : <port to forward the video RTP packets to>,
"video_ssrc" : <video SSRC to use to use when streaming; optional>,
"video_pt" : <video payload type to use when streaming; optional>,
"video_rtcp_port" : <port to contact to receive video RTCP feedback from the recipient; optional>,
"simulcast" : <true|false, set to true if the source is simulcast and you want the forwarder to act as a regular viewer (single stream being forwarded) or false otherwise (substreams forwarded separately); optional, default=false>,
"video_port_2" : <if simulcasting and forwarding each substream, port to forward the video RTP packets from the second substream/layer to>,
"video_ssrc_2" : <if simulcasting and forwarding each substream, video SSRC to use to use the second substream/layer; optional>,
"video_pt_2" : <if simulcasting and forwarding each substream, video payload type to use the second substream/layer; optional>,
"video_port_3" : <if simulcasting and forwarding each substream, port to forward the video RTP packets from the third substream/layer to>,
"video_ssrc_3" : <if simulcasting and forwarding each substream, video SSRC to use to use the third substream/layer; optional>,
"video_pt_3" : <if simulcasting and forwarding each substream, video payload type to use the third substream/layer; optional>,
"data_port" : <port to forward the datachannel messages to>,
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>"

  • Response Content

{
		"host" : "<host this forwarder is streaming to, same as request if not resolved>",
		"audio" : <audio RTP port, same as request if configured>,
		"audio_rtcp" : <audio RTCP port, same as request if configured>,
		"audio_stream_id" : <unique numeric ID assigned to the audio RTP forwarder, if any>,
		"video" : <video RTP port, same as request if configured>,
		"video_rtcp" : <video RTCP port, same as request if configured>,
		"video_stream_id" : <unique numeric ID assigned to the main video RTP forwarder, if any>,
		"video_2" : <second video port, same as request if configured>,
		"video_stream_id_2" : <unique numeric ID assigned to the second video RTP forwarder, if any>,
		"video_3" : <third video port, same as request if configured>,
		"video_stream_id_3" : <unique numeric ID assigned to the third video RTP forwarder, if any>,
		"data" : <data port, same as request if configured>,
		"data_stream_id" : <unique numeric ID assigned to datachannel messages forwarder, if any>
}

Stop rtp forwarders

  • Http Method: DELETE
  • URL Path: /rooms/{room_id}/rtp_forwarders
  • Params:
"admin_key": <plugin's admin key if lock_rtp_forward is enabled>,
"secret" : "<room secret, mandatory if configured>",
"publisher_id" : <unique numeric ID of the publisher to relay externally>,
"stream_id" : <unique numeric ID, same as request>
  • Response Content
NO