Install Jitsi on CentOS 7
This page gives the needed steps to install and configure Jitsi on a CentOS server. If like me, you're not a big Docker fan, and you're happier with EL based systems, it might be useful to you. In this guide, you'll learn :
- How to build latest versions of all components
- Get a working install with prosody, jicofo, meet, videobridge
- Configure jigasi and integrate it with an Asterisk/FreePBX server to have both inbound and outbound phone call from a Jitsi conference
- Integrate Etherpad
Jitsi is composed of several components, and also relies on 3rd party ones. Here is a quick overview of which are using for what :
- An XMPP server is needed to route messages between all the components. We will use prosody for this
- Videobridge is the SFU1). It will receive all the video and audio streams, and handle relay to the other participants
- Jicofo is the component which will handle stream negociation and room management
- Meet is the user interface of Jitsi. It's also available as an mobile app and an Electron desktop app (but here we'll install the web interface only)
- Jigasi is a SIP gateway. It can register on a SIP server and bridge phones and Jitsi rooms. Both outbound (call phone numbers from Jitsi) and inbound (join Jitsi rooms from a phone) are possible
- ConferenceMapper API is a small daemon needed for inbound calls to work. It'll associate a PIN to each Jitsi room and is needed so that a phone call can be routed to the correct Jitsi room
In this example, we will use visio.fws.fr as jitsi domain name. You'll need to adapt this
Enable EPEL repo
If not already done
yum install epel-release
Install prosody
Prosody is available in EPEL, so we can install it easily
mkdir -p /opt/prosody/modules yum install prosody lua-ldap lua-cyrussasl
Jitsi can also use some 3rd party prosody modules
for MOD in ext_events.lib.lua \ util.lib.lua \ mod_speakerstats.lua \ mod_speakerstats_component.lua \ mod_turncredentials.lua \ mod_conference_duration.lua \ mod_conference_duration_component.lua; do wget -P /opt/prosody/modules \ https://raw.githubusercontent.com/jitsi/jitsi-meet/master/resources/prosody-plugins/$MOD done wget -P /opt/prosody/modules \ https://raw.githubusercontent.com/prosody-modules/mod_auth_ldap/master/mod_auth_ldap.lua
Now, lets configure it. Edit /etc/prosody/prosody.cfg.lua
- lua
plugin_paths = { "/opt/prosody/modules" } admins = { } modules_enabled = { "roster"; "saslauth"; "tls"; "dialback"; "disco"; "carbons"; "pep"; "private"; "blocklist"; "vcard4"; "vcard_legacy"; "version"; "uptime"; "time"; "ping"; "register"; "admin_adhoc"; "bosh"; "pubsub"; } modules_disabled = { } allow_registration = false c2s_require_encryption = true s2s_require_encryption = true s2s_secure_auth = false c2s_ports = { 5222, } s2s_port = { 5269, } http_port = { 5280, } component_ports = { 5347, } component_interface = "0.0.0.0" authentication = "internal_hashed" log = { info = "*syslog"; error = "*syslog"; } certificates = "/etc/pki/prosody/"; pidfile = "/run/prosody/prosody.pid"; daemonize = false; VirtualHost "localhost" Include "conf.d/*.cfg.lua"
Now edit /etc/prosody/conf.d/jitsi.cfg.lua
- lua
muc_mapper_domain_base = "visio.fws.fr"; admins = { "focus@auth.visio.fws.fr" } http_default_host = "visio.fws.fr" -- If you have a turn server, you can configure it here -- turncredentials_secret = "TURN_SECRET"; -- turncredentials = { -- { -- type = "turns", -- host = "turn.example.net", -- port = "3478", -- transport = "udp" -- } -- }; cross_domain_bosh = false; cross_domain_websocket = true; consider_bosh_secure = true; VirtualHost "visio.fws.fr" authentication = "anonymous" ssl = { key = "/etc/prosody/certs/jitsi.key"; certificate = "/etc/prosody/certs/jitsi.crt"; } modules_enabled = { "bosh"; "pubsub"; "ping"; "websocket"; "turncredentials"; "speakerstats"; "conference_duration"; } c2s_require_encryption = false allow_unencrypted_plain_auth = true speakerstats_component = "speakerstats.visio.fws.fr" conference_duration_component = "conferenceduration.visio.fws.fr" VirtualHost "auth.visio.fws.fr" ssl = { key = "/etc/prosody/certs/jitsi.key"; certificate = "/etc/prosody/certs/jitsi.crt"; } authentication = "internal_hashed" c2s_require_encryption = false Component "conference.visio.fws.fr" "muc" storage = "memory" modules_enabled = { "ping"; } muc_room_locking = false muc_room_default_public_jids = true Component "internal.auth.visio.fws.fr" "muc" storage = "memory" modules_enabled = { "ping"; } muc_room_cache_size = 1000 Component "focus.visio.fws.fr" component_secret = FOCUS_COMPONENT_SECRET" Component "speakerstats.visio.fws.fr" "speakerstats_component" muc_component = "conference.visio.fws.fr" Component "conferenceduration.visio.fws.fr" "conference_duration_component" muc_component = "conference.visio.fws.fr"
Now we can start and enable the daemon
systemctl enable --now prosody
And we have to create some xmpp user accounts which will be used by Jitsi (adapt the passwords of course)
prosodyctl register jvb auth.visio.fws.fr JVB_XMPP_PASS prosodyctl register focus auth.visio.fws.fr FOCUS_XMPP_PASS prosodyctl register jigasi auth.visio.fws.fr JIGASI_XMPP_PASS
Install a recent maven
Maven is available with yum, but its version is too old to build videobridge. So we'll install a newer one
yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel
mkdir -p /opt/maven/apache-maven/ wget https://miroir.univ-lorraine.fr/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz tar xvzf apache-maven-3.6.3-bin.tar.gz rsync -rvP --del apache-maven-3.6.3/ /opt/maven/apache-maven/ rm -rf apache-maven-3.6.3-bin.tar.gz apache-maven-3.6.3/ cat <<_EOF > /etc/profile.d/maven.sh #!/bin/sh export JAVA_HOME=/usr/lib/jvm/jre-openjdk export M2_HOME=/opt/maven/apache-maven export MAVEN_HOME=/opt/maven/apache-maven export PATH=${M2_HOME}/bin:${PATH} _EOF chmod +x /etc/profile.d/maven.sh exec bash
Create a jitsi user
useradd -d /opt/jitsi jitsi
Install Videobridge
yum install git
mkdir /opt/jitsi/{src,videobridge} cd /opt/jitsi/src git clone https://github.com/jitsi/jitsi-videobridge.git cd jitsi-videobridge /opt/maven/apache-maven/bin/mvn package -DskipTests -Dassembly.skipAssembly=false
unzip target/jitsi-videobridge-2.1-SNAPSHOT-archive.zip -d /tmp/ rsync -rvP --del /tmp/jitsi-videobridge-2.1-SNAPSHOT/ /opt/jitsi/videobridge/ rm -rf /tmp/jitsi-videobridge-2.1-SNAPSHOT/
Now we have to configure videobridge
mkdir -p /opt/jitsi/etc/videobridge cat <<_EOF > /opt/jitsi/etc/videobridge/videobridge.conf JVB_OPTS="--apis=rest" JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/opt/jitsi/etc -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=videobridge" _EOF cat <<_EOF > /opt/jitsi/etc/videobridge/sip-communicator.properties org.jitsi.impl.neomedia.transform.srtp.SRTPCryptoContext.checkReplay=false org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT=10000 org.jitsi.videobridge.TCP_HARVESTER_PORT=4443 org.jitsi.videobridge.DISABLE_TCP_HARVESTER=false org.ice4j.ipv6.DISABLED=true # If behind NAT, set your private, and public IP here # org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=10.99.2.19 # org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=10.11.12.13 org.jitsi.videobridge.ENABLE_STATISTICS=true org.jitsi.videobridge.STATISTICS_TRANSPORT=muc org.jitsi.videobridge.STATISTICS_INTERVAL=5000 org.jitsi.videobridge.xmpp.user.acc1.HOSTNAME=jitsi.fws.fr org.jitsi.videobridge.xmpp.user.acc1.DOMAIN=auth.visio.fws.fr org.jitsi.videobridge.xmpp.user.acc1.USERNAME=jvb org.jitsi.videobridge.xmpp.user.acc1.PASSWORD=JVB_PASSWORD org.jitsi.videobridge.xmpp.user.acc1.MUC_JIDS=JvbBrewery@internal.auth.visio.fws.fr # This is just a nickname for the videobridge. # If you run several videobridge instances, make sure each one uses a unique name org.jitsi.videobridge.xmpp.user.acc1.MUC_NICKNAME=jitsi.fws.fr _EOF
Now we'll create a systemd unit for the videobridge service
mkdir -p /etc/systemd/system cat <<_EOF > /etc/systemd/system/jitsi-videobridge.service [Unit] Description=Jitsi Videobridge After=network.target [Service] Type=simple SuccessExitStatus=143 EnvironmentFile=/opt/jitsi/etc/videobridge/videobridge.conf User=jitsi Group=jitsi PrivateTmp=true PrivateDevices=true ProtectHome=true ProtectSystem=full ReadOnlyDirectories=/opt/jitsi/etc /opt/jitsi/videobridge Restart=on-failure StartLimitInterval=0 RestartSec=30 # more threads for this process TasksMax=65000 # allow more open files for this process LimitNPROC=65000 LimitNOFILE=65000 ExecStart=/opt/jitsi/videobridge/jvb.sh ${JVB_OPTS} [Install] WantedBy=multi-user.target _EOF systemctl daemon-reload systemctl enable --now jitsi-videobridge
Install Jicofo
cd /opt/jitsi/src git clone https://github.com/jitsi/jicofo.git cd jicofo /opt/maven/apache-maven/bin/mvn package -DskipTests -Dassembly.skipAssembly=false unzip target/jicofo-1.1-SNAPSHOT-archive.zip -d /tmp mkdir -p /opt/jitsi/jicofo rsync -rvP --del /tmp/jicofo-1.1-SNAPSHOT/ /opt/jitsi/jicofo/
Now that jicofo is installed, it must be configured
mkdir -p /opt/jitsi/etc/jicofo cat <<_EOF > /opt/jitsi/etc/jicofo/jicofo.conf JICOFO_HOST=jitsi.fws.fr JICOFO_DOMAIN=visio.fws.fr JICOFO_USER=focus JICOFO_USERDOMAIN=auth.visio.fws.fr JICOFO_SECRET='FOCUS_COMPONENT_SECRET' JICOFO_USER_PASS='FOCUS_XMPP_PASS' JICOFO_OPTS='' JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/opt/jitsi/etc -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=jicofo" _EOF cat <<_EOF > /opt/jitsi/etc/jicofo/sip-communicator.properties org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.auth.visio.fws.fr # Comment this line if you do not intend to use Jigasi org.jitsi.jicofo.jigasi.BREWERY=JigasiBrewery@internal.auth.visio.fws.fr _EOF
Now we can create a systemd unit and start jicofo
cat <<_EOF > /etc/systemd/system/jitsi-jicofo.service [Unit] Description=Jitsi Conference Focus After=network.target [Service] Type=simple SuccessExitStatus=143 EnvironmentFile=/opt/jitsi/etc/jicofo/jicofo.conf User=jitsi Group=jitsi PrivateTmp=true PrivateDevices=true ProtectHome=true ProtectSystem=full ReadOnlyDirectories=/opt/jitsi/etc /opt/jitsi/jicofo Restart=on-failure StartLimitInterval=0 RestartSec=30 ExecStart=/opt/jitsi/jicofo/jicofo.sh \ --host=${JICOFO_HOST} \ --domain=${JICOFO_DOMAIN} \ --secret=${JICOFO_SECRET} \ --user_domain=${JICOFO_USERDOMAIN} \ --user_name=${JICOFO_USER} \ --user_password=${JICOFO_USER_PASS} \ ${JICOFO_OPT} [Install] WantedBy=multi-user.target _EOF systemctl daemon-reload systemctl enable --now jitsi-jicofo
You should check your logs now to be sure jicofo discover your videobridge.
Install Meet
It's time to install the Meet interface now.
cat <<_EOF > /etc/yum.repos.d/nodejs.repo [nodejs] baseurl = https://rpm.nodesource.com/pub_12.x/el/7/$basearch gpgcheck = 1 gpgkey = https://rpm.nodesource.com/pub/el/NODESOURCE-GPG-SIGNING-KEY-EL name = Node.js Packages for Enterprise Linux _EOF yum install nodejs
cd /opt/jitsi/src/ git clone https://github.com/jitsi/jitsi-meet.git cd jitsi-meet npm i make
This should build Jitsi Meet. We now can put it somewhere to be served by a web server :
mkdir -p /opt/jitsi/meet rm -rf /opt/jitsi/meet/* mkdir -p /opt/jitsi/meet/css cp -r *.js *.html connection_optimization favicon.ico fonts images libs static sounds LICENSE lang /opt/jitsi/meet/ cp css/all.css /opt/jitsi/meet/css/
Serving this from your webserver is a bit out of scope for this how to because it can be done in a lot of different ways depending on your infra. Here's a sample nginx conf :
<hideen Here's a sample nginx config>
server { listen 443 ssl http2; server_name visio.fws.fr; ssl_certificate_key /etc/prosody/certs/jitsi.key; ssl_certificate /etc/prosody/certs/jitsi.crt; if ($request_method !~ ^(GET|POST|HEAD)$ ) { return 405; } root /opt/jitsi/meet; index index.html; # conferenceMapper endpoint location ~ ^/(phoneNumberList|conferenceMapper) { proxy_pass http://localhost:8823; proxy_socket_keepalive on; } # BOSH endpoint location /http-bind { proxy_socket_keepalive on; proxy_pass http://localhost:5280/http-bind; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; } # Websocket endpoint location /xmpp-websocket { proxy_pass http://localhost:5280/xmpp-websocket?$args; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $remote_addr; tcp_nodelay on; } # Conference rooms location ~ ^/([a-zA-Z0-9=\?]+)$ { rewrite ^/(.*)$ / break; } location / { ssi on; limit_req zone=limit_req_std burst=100 nodelay; limit_conn limit_conn_std 80; } allow 0.0.0.0/0; deny all; }
</hidden>
You also have to edit /opt/jitsi/meet/config.js and adapt it to your needs.
Now you should be able to reach the Meet interface and join a conference.
Install Jigasi
Now that we have a working Jitsi install, we may want to integrate it with our telephony system. With this, we'll be able to join phone numbers to jitsi conference. Jigasi is the component doing this bridge. It connects to your SIP server just as a phone, and also on prosody as an XMPP user. It can send connect calls to Jitsi Videobridge.
For outbound calls, it's quite easy. Once configured and enabled, you'll get a small + in Meet interface from where you can type the number you want to call. The call will be made by Jigasi and routed by your SIP server. If the phone answer, it'll be imédiatly joined in the conf.
Inbound calls are a bit trickier, and the general workflow is the following
- Jitsi will associate a PIN for every conference, and register the mapping in the confmapper API server (see below)
- You need a dedicated number for Jitsi (it can be done with an internal number only, but wouldn't have a lot of sense)
- Calls to this number must be routed to a special IVR which will ask the caller to enter the PIN of the conference he wants to join
- Asterisk will query the confmapper API to get the name of the conference matching the PIN
- If a match is found, Asterisk adds the name of the conference to join in a SIP header, and route the call to jigasi
- Jigasi answer the call, get the room from the SIP header, and join the corresponding room
But first, lets install Jigasi
mkdir -p /opt/jitsi/jigasi cd /opt/jitsi/src git clone https://github.com/jitsi/jigasi.git cd jigasi /opt/maven/apache-maven/bin/mvn package -DskipTests -Dassembly.skipAssembly=false unzip jigasi/target/jigasi-linux-x64-1.1-SNAPSHOT.zip -d /tmp rsync -rvP --del /tmp/jigasi-linux-x64-1.1-SNAPSHOT/ /opt/jitsi/jigasi/
Now, we have to configure it. In this example, the SIP server on which we register is ast.fws.fr and we'll use SIP extension 304 with secret SIP_SECRET (we'll see later in this how to how to craete the extension through FreePBHX web interface)
mkdir -p /opt/jitsi/etc/jigasi cat <<_EOF > /opt/jitsi/jigasi/jigasi.conf JIGASI_OPTS='' JAVA_SYS_PROPS='' _EOF cat <<_EOF > /opt/jitsi/jigasi/sip-communicator.properties # Default room to which inbound called without a Jitsi-Conference-Room header org.jitsi.jigasi.DEFAULT_JVB_ROOM_NAME=sip net.java.sip.communicator.impl.protocol.SingleCallInProgressPolicy.enabled=false # Disable packet capture net.java.sip.communicator.packetlogging.PACKET_LOGGING_ENABLED=false # Enable brewery org.jitsi.jigasi.BREWERY_ENABLED=true org.jitsi.jigasi.MUC_SERVICE_ADDRESS=conference.visio.fws.fr # SIP acount net.java.sip.communicator.impl.protocol.sip.acc=acc net.java.sip.communicator.impl.protocol.sip.acc.ACCOUNT_UID=SIP\:304 # THis is the base64 encoded SIP secret. Obtained with # echo -n SIP_SECRET | base64 net.java.sip.communicator.impl.protocol.sip.acc.PASSWORD=U0lQX1NFQ1JFVA== net.java.sip.communicator.impl.protocol.sip.acc.PROTOCOL_NAME=SIP net.java.sip.communicator.impl.protocol.sip.acc.SERVER_ADDRESS=ast.fws.fr net.java.sip.communicator.impl.protocol.sip.acc.USER_ID=304 net.java.sip.communicator.impl.protocol.sip.acc.KEEP_ALIVE_INTERVAL=25 net.java.sip.communicator.impl.protocol.sip.acc.KEEP_ALIVE_METHOD=OPTIONS net.java.sip.communicator.impl.protocol.sip.acc.VOICEMAIL_ENABLED=false net.java.sip.communicator.impl.protocol.sip.acc.OVERRIDE_ENCODINGS=false net.java.sip.communicator.impl.protocol.sip.acc.DOMAIN_BASE=visio.fws.fr net.java.sip.communicator.impl.protocol.sip.acc.PROXY_ADDRESS=ast.fws.fr net.java.sip.communicator.impl.protocol.sip.acc.PROXY_AUTO_CONFIG=false net.java.sip.communicator.impl.protocol.sip.acc.PROXY_PORT=5060 net.java.sip.communicator.impl.protocol.sip.acc.PREFERRED_TRANSPORT=UDP # XMPP account net.java.sip.communicator.impl.protocol.jabber.acc=acc net.java.sip.communicator.impl.protocol.jabber.acc.ACCOUNT_UID=Jabber:jigasi@auth.visio.fws.fr net.java.sip.communicator.impl.protocol.jabber.acc.USER_ID=jigasi@auth.visio.fws.fr net.java.sip.communicator.impl.protocol.jabber.acc.IS_SERVER_OVERRIDDEN=true net.java.sip.communicator.impl.protocol.jabber.acc.SERVER_ADDRESS=jitsi.fws.fr # This is the base64 encoded XMPP secret # obtained with echo -n JIGASI_XMPP_PASS | base64 net.java.sip.communicator.impl.protocol.jabber.acc.PASSWORD=SklHQVNJX1hNUFBfUEFTUw== net.java.sip.communicator.impl.protocol.jabber.acc.RESOURCE_PRIORITY=30 net.java.sip.communicator.impl.protocol.jabber.acc.BREWERY=JigasiBrewery@internal.auth.visio.fws.fr net.java.sip.communicator.impl.protocol.jabber.acc.DOMAIN_BASE=visio.fws.fr org.jitsi.jigasi.xmpp.acc.USER_ID=jigasi@auth.visio.fws.fr org.jitsi.jigasi.xmpp.acc.PASS=JIGASI_XMPP_PASS org.jitsi.jigasi.xmpp.acc.ANONYMOUS_AUTH=false org.jitsi.jigasi.xmpp.acc.IS_SERVER_OVERRIDDEN=true org.jitsi.jigasi.xmpp.acc.SERVER_ADDRESS=jitsi.fws.fr org.jitsi.jigasi.xmpp.acc.JINGLE_NODES_ENABLED=false org.jitsi.jigasi.xmpp.acc.AUTO_DISCOVER_STUN=false org.jitsi.jigasi.xmpp.acc.IM_DISABLED=true org.jitsi.jigasi.xmpp.acc.SERVER_STORED_INFO_DISABLED=true org.jitsi.jigasi.xmpp.acc.IS_FILE_TRANSFER_DISABLED=true _EOF
Now we can create a systemd unit and start the service
cat <<_EOF > /etc/systemd/system/jitsi-jigasi.service [Unit] Description=Jitsi Gateway to SIP After=network.target [Service] Type=simple SuccessExitStatus=143 EnvironmentFile=/opt/jitsi/etc/jigasi/jigasi.conf User=jitsi Group=jitsi PrivateTmp=true PrivateDevices=true ProtectHome=true ProtectSystem=full Restart=on-failure StartLimitInterval=0 RestartSec=30 ExecStart=/opt/jitsi/jigasi/jigasi.sh \ --configdir=/opt/jitsi/etc \ --configdirname=jigasi \ --nocomponent=true \ ${JIGASI_OPT} [Install] WantedBy=multi-user.target _EOF systemctl daemon-reload systemctl enable --now jitsi-jigasi
Jigasi is now running, but it's not yet ready to be used.
Install confmapper daemon
The confmapper daemon is a small tool to register Jitsi room name ↔ PIN. We'll use https://github.com/gronke/jitsi-conferencemapper-api as it's a simple and lightweigt daemon in python, using an SQLite database to store the mappings
yum install python3
mkdir -p /opt/jitsi/{data,confmapper} chown jitsi:jitsi /opt/jitsi/data chmod 700 /opt/jitsi/data wget -P /opt/jitsi/confmapper/ \ https://raw.githubusercontent.com/gronke/jitsi-conferencemapper-api/master/daemon.py chmod 755 /opt/jitsi/confmapper/daemon.py
Now, lets configure it
cat <<_EOF > /opt/jitsi/confmapper/config.json { "db_file": "/opt/jitsi/data/confmapper.sqlite", "expire_seconds": 86400, "host": "0.0.0.0", "id_max_length": 4, "numbers": { "FR": [ "0510101010" ] }, "port": 8823 } _EOF
Here :
- The daemon listens on 0.0.0.0:8823. You should configure a reverse proxy to make it accessible over HTTPS. The sample nginx configuration does it
- Room mappings will be kept for 1 day
- PIN will be created with 4 digits
- The number 0510101010 is dedicated and will be announced in Jitsi interface. You can set several numbers, including different numbers for different countries
In any case, make sure requests to https://visio.fws.fr/conferenceMapper and https://visio.fws.fr/phoneNumberList are routed to this daemon (because those are the URL configured in Jitsi meet
Now, we can create a systemd unit and start the service
cat <<_EOF > /etc/systemd/system/jitsi-confmapper.service [Unit] Description=Jitsi Conference Mapper After=network.target [Service] Type=simple User=jitsi Group=jitsi PrivateTmp=true PrivateDevices=true ProtectHome=true ProtectSystem=full Restart=on-failure StartLimitInterval=0 RestartSec=30 ExecStart=/opt/jitsi/confmapper/daemon.py [Install] WantedBy=multi-user.target _EOF systemctl daemon-reload systemctl enable --now jitsi-confmapper
Configure Asterisk/FreePBX
Create a SIP extension
Now, we have to configure Asterisk. First step is to create an SIP extension for Jigasi. So we create a PJSIP extension, with ID 304 and secret SIP_SECRET (this is what we've configured in jigasi). In the advanced tab of the extension, there's a few things we can change
- You might want to change the Outbound CID to advertize the 0510101010 number
- You might change the context to outbound-allroutes if you don't want conference user to be able to call internal numbers. The default context is from-internal
- Restrict codecs to alaw and ulaw (I had sound issues with opus and g722, so better to restrict this to known working codecs). For this, type all in the Disallowed Codecs field, and alaw&ulaw in the Allowed Codec field
- You should also disable the Direct Media option
Create a custom IVR
Now, we have to create a custom IVR which will ask callers the PIN of the room they want to join. you can put it in /etc/asterisk/extension_custom.conf
[jitsi-ivr] exten => s,1,Answer exten => s,n,Set(IVR_MSG=conf-getpin) exten => s,n,Set(TIMEOUT(digit)=3) exten => s,n,Read(JITSI_PIN,${IVR_MSG}) ; Fetch the conf name from the PIN entered exten => s,n,AGI(jitsi_conf_pin,"https://visio.fws.fr/conferenceMapper",${JITSI_PIN} ; If we got a result, dial JIGASI SIP account, else, loop and ask again exten => s,n,GotoIf($["${JITSI_ROOM}" != "error"]?jitsi,1) exten => s,n(error),Playback(conf-invalid) exten => s,n,Goto(s,1) ; We got a result, lets join jitsi room exten => jitsi,1,Verbose(PIN ${JITSI_PIN} maps to Jitsi room ${JITSI_ROOM}) exten => jitsi,n,Dial(PJSIP/304,,b(jitsi-conference-room-header^addheader^1(${JITSI_ROOM})))
Create an AGI script to lookup roomname from their PIN
We have to create an AGI script so that asterisk can query the confmapper daemon to get the name of a room from the PIN. For this, create the script /usr/share/asterisk/agi-bin/jitsi_conf_pin with the following content :
#!/usr/bin/perl use warnings; use strict; use LWP::UserAgent; use JSON; my $ret = 'error'; my $url = $ARGV[0] . '?id=' . $ARGV[1]; my $ua = LWP::UserAgent->new(timeout => 10); $ua->env_proxy; my $response = $ua->get($url); if ($response->is_success){ my $json = from_json($response->content); if (defined $json and defined $json->{conference}){ $ret = $json->{conference}; $ret =~ s/@.*//; } } print "SET VARIABLE JITSI_ROOM $ret\n";
The script must be executable
chmod +x /usr/share/asterisk/agi-bin/jitsi_conf_pin
Create a Custom Destination pointing on your custom IVR
OK, now we need to way to route calls to our new custom IVR. For this, we'll create a Custom Destination in FreePBX. Just set the target to jitsi-ivr,s,1
This Custom Destination make the IVR available in all the FreePBX routing logic.
Assign an internal number to the IVR to test
We can assign it an internal number to test it with a new Misc Application :
You can now try it. Create a new room in Jitsi, and if you click on the small i button (bottom right), you should see a popup with the number to dial and the PIN
So, this conf has PIN 4845
Now, call your internal test number, which points on the custom IVR (381 in the previous screenshot). You should be prompted to enter a PIN. Once typed, asterisk will lookup on the confmapper daemon to find to which room this PIN maps. If found, you'll join the conference right away. If a wrong PI is entered, you'll be prompted again to enter the PIN.
Now, all you have to do is to define a new Inbound Route which points on the same Custom Destination
Integrate with Etherpad
Deploying an Etherpad instance is out of scope for this guide (but we also have an ansible role for this). But, say you have it available at https://etherpad.fws.fr. All you have to do is to indicate it in /opt/jitsi/meet/config.js
[...] "etherpad_base": "https://etherpad.fws.fr/p/", [...]
Note on reverse proxy and Content-Security-Policy
We use a reverse proxy to serve all the web resources, and this reverse proxy insert CSP headers to response. In this case, we have to allow a few things to get everything working :
- In img-src you have to add https://img.youtube.com and https://i.ytimg.com
- In script-src you have to add https://www.youtube.com and https://s.ytimg.com
- In frame-src you have to add https://etherpad.fws.fr wss:etherpad.fws.fr and https://www.youtube.com * In connect-src you have to add https://storage.googleapis.com