This article is to introduce Janus based SFU media architecture for WebRTC systems. It also aims at evaluating the performance of the VP9 simulcast p2p model with Janus based SFU system.
- Janus
- Centralised media conferencing / mixing service using Janus
- Streaming Video via CDN
- Server Selection and Setup from source
- Issues with installation of janus
- Self Signed SSL certs
- Check Janus Running
- ECHO Test
- Run
- WebRTC Client for Janus System
- Security consideration before taking janus live
Janus
We know Janus is a popular small footprint gateway/media Server with support for WebRTC features like JSEP/SDP, ICE, DTLS-SRTP, DataChannels. Its plugins expose Janus API over different transports – HTTP, WS, rabbitMQ, Unix sockets, MQTT so on. Other plugins provide deeper modifications such as Video SFU, Audio MCU, SIP/RTSP gateways, broadcasting etc.
Centralised media conferencing / mixing service using Janus

Streaming Video via CDN

Tip : use mixing for Audio and Relay for video in large participant sessions.
Server Selection and Setup from source
Janus Setup on public ec2 isntance. Since the a media server can clog the server space make sure to choose alarge instance like c5.large. Sample log file size

Install prerequisite libraries
sudo apt-get install libmicrohttpd-dev libjansson-dev libnice-dev libssl-dev libsrtp-dev libsofia-sip-ua-dev libglib2.0-dev libopus-dev libogg-dev libini-config-dev libcollection-dev libwebsockets-dev pkg-config gengetopt automake libtool doxygen graphviz git libconfig-dev cmake
Make Sure libsrtp v2.x is installed instead of existing 1.4 in debain /ubuntu default such as
libsrtp0-dev is already the newest version (1.4.5~20130609~dfsg-2ubuntu1).
Manually installing libsrtp2 from https://github.com/cisco/libsrtp
wget https://github.com/cisco/libsrtp/archive/v2.2.0.tar.gz tar xfv v2.2.0.tar.gz cd libsrtp-2.2.0 ./configure --prefix=/usr --enable-openssl make shared_library && sudo make install
Since we are going to use websocket as signalling, ensure lws (libwebsocket) >= 2.0.0 is installed
git clone https://libwebsockets.org/repo/libwebsockets cd libwebsockets mkdir build cd build cmake -DLWS_MAX_SMP=1 -DLWS_WITHOUT_EXTENSIONS=0 -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_FLAGS="-fpic" make && sudo make install
Also libnice (at least v0.1.16) need to be installed
Get Janus source code and configure
git clone git://github.com/meetecho/janus-gateway.git cd janus-gateway sh autogen.sh ./configure --disable-data-channels --disable-docs --prefix=/opt/janus LDFLAGS="-L/usr/local/lib -Wl,-rpath=/usr/local/lib" CFLAGS="-I/usr/local/include"
At this point Janus prinst a config detail such as below and asks if its ok . Ensure Websocket is yes. One can start the make process if it is
Compiler: gcc libsrtp version: 2.x SSL/crypto library: OpenSSL DTLS set-timeout: not available Mutex implementation: GMutex (native futex on Linux) DataChannels support: no Recordings post-processor: no TURN REST API client: no Doxygen documentation: no Transports: REST (HTTP/HTTPS): yes WebSockets: yes RabbitMQ: no MQTT: no Unix Sockets: yes Nanomsg: no Plugins: Echo Test: yes Streaming: yes Video Call: yes SIP Gateway: yes NoSIP (RTP Bridge): yes Audio Bridge: yes Video Room: yes Voice Mail: yes Record&Play: yes Text Room: yes Lua Interpreter: no Duktape Interpreter: no Event handlers: Sample event handler: no WebSocket ev. handler: yes RabbitMQ event handler:no MQTT event handler: no Nanomsg event handler: no GELF event handler: yes External loggers: JSON file logger: no JavaScript modules: no
Make and install
make && sudo make install
Making configs
sudo make configs
For details refer to actual README on Janus git repo https://github.com/meetecho/janus-gateway
Start
By default, Janus starts in foreground, as a console application that stop with Ctrl + c command
./janus

Starting janus as backvroudn or daemon service
sudo ./janus -N -d 0 --daemon --log-file /var/log/janus
tailing the log file
> tail -f /var/log/janus
--------------------------------------------------- Starting Meetecho Janus (WebRTC Server) v0.11.1 --------------------------------------------------- Checking command line arguments... Debug/log level is 0 Debug/log timestamps are disabled Debug/log colors are enabled
references : https://janus.conf.meetecho.com/docs/service.html
Issues with installation of janus
Before resolving any issue, it is important to verify whether you are runing multiple versions of janus on your system
altanai@xx:~/janus-gateway$ janus --version Janus commit: bed081c03ad4854f3956898646198100a8ed82cf Compiled on: Fri Apr 2 07:28:14 UTC 2021 janus 0.11.1 altanai@xx:~/janus-gateway$ ./janus --version Janus commit: c970528037d46d52a4bc1fd7db2a44c900c2baf2 Compiled on: Thu Apr 8 18:01:36 UTC 2021 janus 0.10.8
If this is so, delete the one you dont require. I’d go with rmeoove the one installed globally.
Cmake version error
If you see an error in rabbitmq instalation , which is part of janus installation
CMake 3.12...3.18 or higher is required. You are running version 3.10.2
then proceed to remove existing version and install updates ne by first removing tghe existing cmake version
sudo apt remove cmake wget https://github.com/Kitware/CMake/releases/download/v3.20.1/cmake-3.20.1-linux-x86_64.sh sh cmake-3.20.1-linux-x86_64.sh
check version
>> cmake-3.20.1-linux-x86_64/bin/cmake --version cmake version 3.20.1
lib websocket error in libjanus_websockets.so
Couldn't load transport plugin 'libjanus_websockets.so': /opt/janus/lib/janus/transports/libjanus_websockets.so: undefined symbol: lws_hdr_custom_length
Libwebsockets (LWS) is a flexible, lightweight pure C library for implementing modern network protocols easily with a tiny footprint, using a nonblocking event loop.
Fisrt check the version of libwebsockets u have on ur machine . If it is lesse that 2.0.0 version
>> apt show libwebsockets-dev Package: libwebsockets-dev Version: 2.0.3-3build1 Priority: optional Section: universe/libdevel Source: libwebsockets Origin: Ubuntu Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> Original-Maintainer: Laszlo Boszormenyi (GCS) <gcs@debian.org> Bugs: https://bugs.launchpad.net/ubuntu/+filebug Installed-Size: 502 kB Depends: libwebsockets8 (= 2.0.3-3build1), libev-dev, libssl-dev, libuv1-dev, zlib1g-dev Homepage: https://libwebsockets.org/ Download-Size: 133 kB APT-Manual-Installed: yes APT-Sources: http://us-west-1.ec2.archive.ubuntu.com/ubuntu bionic/universe amd64 Packages Description: lightweight C websockets library - development files Libwebsockets is a lightweight pure C library for both websockets clients and servers built to use minimal CPU and memory resources and provide fast throughput in both directions. . This package contains the header files needed for developing programs using libwebsockets and a static library.
Follow the steps to install libwebsocket , libwebsockets >= 2.0.0, the current v3.2-stable is good http://libwebsockets.org/
Failures due to ICE
ICE failed for component 1 in stream 1… No WebRTC media anymore WebRTC resources freed;
Self Signed SSL certs
Make a new directory for SSL certs
mkdir /home/ubuntu/ssl generate certs openssl req -new -newkey rsa:4096 -nodes -keyout key.pem -out cert.csr openssl x509 -req -sha256 -days 365 -in cert.csr -signkey key.pem -out cert.pem chmod 600 cert.csr chmod 600 cert.pem chmod 600 key.pem
Remember to allow advanced access if the ssl are self signed and not from a varified CA
Update janus config
Path for Janus configuration is usually /opt/janus/etc/janus/janus.jcfg as given by the prefix during instalation. some of the types of config are
>> vi /opt/janus/etc/janus/janus.jcfg
general: { configs_folder = "/opt/janus/etc/janus" # Configuration files folder plugins_folder = "/opt/janus/lib/janus/plugins" # Plugins folder transports_folder = "/opt/janus/lib/janus/transports" # Transports folder events_folder = "/opt/janus/lib/janus/events" # Event handlers folder loggers_folder = "/opt/janus/lib/janus/loggers" # External loggers folder .... }
- SSL certs for DTLS can also be specified under certificates
- Restricting media ports between a range . Comes in handy when u have to selectively open ports ona cloud instance such as AWS instance
media: { ipv6 = false #min_nack_queue = 500 rtp_port_range = "20000-40000" #dtls_mtu = 1200 #no_media_timer = 1 #slowlink_threshold = 4 #twcc_period = 100 #dtls_timeout = 500 .... }
- changing NAT for STUN/TURN servers to gather ICE
using 1:1 NAT( suited to Amzon EC2) requires specifying public address
nat_1_1_mapping = "1.1.1.1"
- To change transport http , set http to true from false
goto installation location for janus config
cd /opt/janus/etc/janus/
> vi /opt/janus/etc/janus/janus.transport.http.jcfg general: { #events = true # Whether to notify event handlers about transport events (default=true) json = "indented" # Whether the JSON messages should be indented (default), # plain (no indentation) or compact (no indentation and no spaces) base_path = "/janus" # Base path to bind to in the web server (plain HTTP only) http = true # Whether to enable the plain HTTP interface port = 8088 # Web server HTTP port #interface = "eth0" # Whether we should bind this server to a specific interface onlya #ip = "x.x.x.x" # Whether we should bind this server to a specific IP address (v4 or v6) only https = true # Whether to enable HTTPS (default=false) secure_port = 8089 # Web server HTTPS port, if enabled #secure_interface = "eth0" # Whether we should bind this server to a specific interface only #secure_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address (v4 or v6) only #acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses }

Change path for certs and key pem files
> vi janus.jcfg certificates: { cert_pem = "/home/ubuntu/ssl/cert.pem" cert_key = "/home/ubutu/ssl/key.pem" #cert_pwd = "secretpassphrase" #dtls_accept_selfsigned = false #dtls_ciphers = "your-desired-openssl-ciphers" #rsa_private_key = false #ciphers = "PFS:-VERS-TLS1.0:-VERS-TLS1.1:-3DES-CBC:-ARCFOUR-128" }
There are options for other ciphers and passphrass , leave them for now.
- To change transport ws for websocket
general: { #events = true # Whether to notify event handlers about transport events (default=true) json = "indented" # Whether the JSON messages should be indented (default), # plain (no indentation) or compact (no indentation and no spaces) #pingpong_trigger = 30 # After how many seconds of idle, a PING should be sent #pingpong_timeout = 10 # After how many seconds of not getting a PONG, a timeout should be detected ws = true # Whether to enable the WebSockets API ws_port = 8188 # WebSockets server port #ws_interface = "eth0" # Whether we should bind this server to a specific interface only #ws_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address only wss = true # Whether to enable secure WebSockets wss_port = 8989 # WebSockets server secure port, if enabled #wss_interface = "eth0" # Whether we should bind this server to a specific interface only #wss_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address only #ws_logging = "err,warn" # libwebsockets debugging level as a comma separated list of things # to debug, supported values: err, warn, notice, info, debug, parser, # header, ext, client, latency, user, count (plus 'none' and 'all') #ws_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses }

Simillar to http transport conf above , also update the certs section with valid path for ssl certs
Check Janus Running
Running ports check ( http )
> sudo lsof -i | grep janus janus 26450 ubuntu 7u IPv6 418550 0t0 UDP *:rfe janus 26450 ubuntu 8u IPv6 418551 0t0 UDP *:5004 janus 26450 ubuntu 17u IPv6 418557 0t0 TCP *:omniorb (LISTEN) janus 26450 ubuntu 20u IPv6 672518 0t0 TCP *:8089 (LISTEN) janus 26450 ubuntu 24u IPv4 672519 0t0 TCP *:8188 (LISTEN) janus 26450 ubuntu 25u IPv4 672520 0t0 TCP *:8989 (LISTEN)
Janus INFO
Going to deployed janus URL like http://x.x.x.x:8088/janus/info
"janus": "server_info", "transaction": "rGuo8HNI4wu", "name": "Janus WebRTC Gateway", "version": 26, "version_string": "0.2.6", "author": "Meetecho s.r.l.", "commit-hash": "not-a-git-repo", "compile-time": "Wed Feb 28 07:02:15 UTC 2018", "log-to-stdout": true, "log-to-file": false, "data_channels": false, "session-timeout": 60, "server-name": "MyJanusInstance", "local-ip": "x.x.x.x", "ipv6": false, "ice-lite": false, "ice-tcp": false, "api_secret": false, "auth_token": false, "event_handlers": false, "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 }, "janus.transport.websockets": { "name": "JANUS WebSockets transport plugin", "author": "Meetecho s.r.l.", "description": "This transport plugin adds WebSockets support to the Janus API via libwebsockets.", "version_string": "0.0.1", "version": 1 } }, "events": {}, "plugins": { "janus.plugin.voicemail": { "name": "JANUS VoiceMail plugin", "author": "Meetecho s.r.l.", "description": "This is a plugin implementing a very simple VoiceMail service for Janus, recording Opus streams.", "version_string": "0.0.6", "version": 6 }, "janus.plugin.audiobridge": { "name": "JANUS AudioBridge plugin", "author": "Meetecho s.r.l.", "description": "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams.", "version_string": "0.0.10", "version": 10 }, "janus.plugin.echotest": { "name": "JANUS EchoTest plugin", "author": "Meetecho s.r.l.", "description": "This is a trivial EchoTest plugin for Janus, just used to showcase the plugin interface.", "version_string": "0.0.7", "version": 7 }, "janus.plugin.recordplay": { "name": "JANUS Record&Play plugin", "author": "Meetecho s.r.l.", "description": "This is a trivial Record&Play plugin for Janus, to record WebRTC sessions and replay them.", "version_string": "0.0.4", "version": 4 }, "janus.plugin.textroom": { "name": "JANUS TextRoom plugin", "author": "Meetecho s.r.l.", "description": "This is a plugin implementing a text-only room for Janus, using DataChannels.", "version_string": "0.0.2", "version": 2 }, "janus.plugin.videoroom": { "name": "JANUS VideoRoom plugin", "author": "Meetecho s.r.l.", "description": "This is a plugin implementing a videoconferencing SFU (Selective Forwarding Unit) for Janus, that is an audio/video router.", "version_string": "0.0.9", "version": 9 }, "janus.plugin.sipre": { "name": "JANUS SIPre plugin", "author": "Meetecho s.r.l.", "description": "This is a simple SIP plugin for Janus (based on libre instead of Sofia), allowing WebRTC peers to register at a SIP server and call SIP user agents through the gateway.", "version_string": "0.0.1", "version": 1 }, "janus.plugin.videocall": { "name": "JANUS VideoCall plugin", "author": "Meetecho s.r.l.", "description": "This is a simple video call plugin for Janus, allowing two WebRTC peers to call each other through the gateway.", "version_string": "0.0.6", "version": 6 }, "janus.plugin.streaming": { "name": "JANUS Streaming plugin", "author": "Meetecho s.r.l.", "description": "This is a streaming plugin for Janus, allowing WebRTC peers to watch/listen to pre-recorded files or media generated by gstreamer.", "version_string": "0.0.8", "version": 8 }, "janus.plugin.nosip": { "name": "JANUS NoSIP plugin", "author": "Meetecho s.r.l.", "description": "This is a simple RTP bridging plugin that leaves signalling details (e.g., SIP) up to the application.", "version_string": "0.0.1", "version": 1 }, "janus.plugin.sip": { "name": "JANUS SIP plugin", "author": "Meetecho s.r.l.", "description": "This is a simple SIP plugin for Janus, allowing WebRTC peers to register at a SIP server and call SIP user agents through the gateway.", "version_string": "0.0.7", "version": 7 } } }
ECHO Test
An Echo test is part of Janus and can be done via reached via deployed server url https://x.x.x.x:8084/echotest.html
For a valid SDP message notice the contact headers in chrome://webrtc-internals
Local Description (mungled)
O line represents origin type: offer, sdp: v=0 o=- 1331622865522329207 2 IN IP4 127.0.0.1 Audio Media stream in m line m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126 c=IN IP4 0.0.0.0 Video media stream in m line m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 c=IN IP4 0.0.0.0 Data m=application 9 UDP/DTLS/SCTP webrtc-datachannel c=IN IP4 0.0.0.0
Remote Description
Origin Line type: answer, sdp: v=0 o=- 6397148042001786590 2 IN IP4 54.193.51.199 Audio Stream m=audio 9 UDP/TLS/RTP/SAVPF 111 9 0 8 106 105 13 110 112 113 c=IN IP4 54.193.51.199 Video Stream m=video 9 UDP/TLS/RTP/SAVPF 96 98 100 102 127 125 108 97 99 101 122 121 107 109 c=IN IP4 54.193.51.199 Data m=application 0 UDP/DTLS/SCTP 0 c=IN IP4 54.193.51.199
VideoCall – https://x.x.x.x:8084/videocalltest.html
Run
./opt/janus/bin/janus

Plugin (above ) and then procceeds to join the room ( screenshot below)

After this Janus procced to do JSEP offer / answer signalling with ICE checks and then does keepalive checks for the duraion of the session .
Stream Types
Unicast
a=sendonly
a=recvonly
a=sendrecv
a=inactive
Simulcast
https://x.x.x.x:8084/videocalltest.html?simulcast=true
LD Libbary Path Exception
If you see an missing encryption exception , start janus with LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib && /opt/janus/bin/janus --debug-level=7 --stun-server=stun.l.google.com:19302 --event-handlers --full-trickle
ICE resolution in Runtime
Trickle ICE Command Line params give console output as
[janus.cfg] general: { debug_level: 7 } certificates: { } nat: { stun_server: stun.l.google.com stun_port: 19302 full_trickle: true } media: { } transports: { } plugins: { } events: { broadcast: yes } loggers: { }
With NAT 1:1 mapping
export LD_LIBRARY_PATH=/usr/lib && /opt/janus/bin/janus --debug-level=7 --nat-1-1=54.193.51.199 --stun-server=stun.l.google.com:19302 --rtp-port-range=20000-50000
1 to 1 NAT mpapping coordinates with amazon ec2
[janus.cfg] general: { debug_level: 7 } certificates: { } nat: { nat_1_1_mapping: 54.193.51.199 } media: { rtp_port_range: 20000-50000 } transports: { } plugins: { } events: { } loggers: { }
WebRTC Client for Janus System
Test client
Using the html sample clients
cd html
admin.html citeus.html e2etest.html index.html nosiptest.html siptest.html textroomtest.html voicemailtest.html audiobridgetest.html demos.html echotest.html multiopus.html recordplaytest.html streamingtest.html videocalltest.html vp9svctest.html canvas.html devicetest.html footer.html navbar.html screensharingtest.html support.html videoroomtest.html
check lsb release and then Install Nodejs to host client page
>> lsb_release -a
curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash - sudo apt-get install -y nodejs
Http WebServer
npm init npm install http-server node_modules/http-server/bin/http-server
To be able to compile native addons from npm you’ll need to install the development tools:
sudo apt install build-essential
open the client in webrtc supported browser at http://x.x.x.x:8080/videoroomtest.html
If you see a issues
No WebRTC media anymore; 0x7fbe20001a40 0x7fbe20002440 WebRTC resources freed; 0x7fbe20001a40 0x7fbe20001320 Handle and related resources freed; 0x7fbe20001a40 0x7fbe20001320
Then it is likley a NAT issues and you should look at jcfg config file to see whether the interface is specified corectly
# Generic settings interface = "x.x.x.x" # Interface to use (will be used in SDP) server_name = "WebrtcMCUJanus" # Public name of this Janus instance
Security consideration before taking janus live
Hide the dependencies
hide_dependencies = true
By default, a call to the “info” endpoint of either the Janus or Admin API now als returns the versions of the main dependencies (e.g., libnice, libsrtp, which crypto library is in use and so on). Should you want that info not to be disclose, set ‘hide_dependencies’ to true.
Common spam attack. source https://groups.google.com/g/meetecho-janus/c/IcJd3e4V1F8
Issues : Janus is throwing an error Invalid url /ws/v1/cluster/apps/new-application
Possible solution : changing port of http transport
References
- Meson quick start https://mesonbuild.com/Quick-guide.html
- Dockerfile for janus by atyenoria https://github.com/atyenoria/janus-webrtc-gateway-docker/blob/master/Dockerfile
- Janus as WebRTc “enabler” – Lorenzo Miniero at FOSDEM 2020 Real Time devroom 2nd February 2020, Brussels
To read more about Media Archietctures and topologies such as point-point , point-to-multipoint , multicast , translators, mixers and SFU goto :
Media Architecture, RTP topologies
With the sudden onset of Covid-19 and building trend of working-from-home , the demand for building scalable conferncing solution and virtual meeting room has skyrocketed . Here is my advice if you are building a auto- scalable conferencing solution
To read more on the topologies of conferencing systems ( Mesh vs Star , Unicast vs Multicast and SVC) read :
SIP conferencing and Media Bridges
SIP is the most popular signalling protocol in VOIP ecosystem. It is most suited to a caller-callee scenario , yet however supporting scalable conferences on VOIP is a market demand. It is desired that SIP must for multimedia stream but also provide conference control for building communication and collaboration apps for new and customisable solutions.