Ansible polaybooks set is used to deploy the jibri virtual machine, but i can`t publish them.
I will briefly describe the main points included in these playbooks (i use google translate, excuse me):
- seems to be, load for one sip video session with video\audio h264\ulaw <-> vp8\opus codecs need take 8 CPU and 3-4 Gb RAM
- Ubuntu 20.04.4 LTS kernel 5.4.0-107-generic
- Install packages [‘mc’, ‘bind9’, ‘traceroute’, ‘apt-transport-https’, ‘ca-certificates-java’, ‘debconf-utils’, ‘ncdu’, ‘open-vm-tools’, ’ git’, ‘lua-cjson’, ‘lua-luaossl’]
- else [‘openjdk-8-jre’, ‘openjdk-8-jdk’, ‘maven’]
- and more [‘linux-image-extra-virtual’, ‘ffmpeg’, ‘libv4l-0’, ‘libgl1-mesa-dri’, ‘unclutter’, ‘psmisc’ ]
- and more [‘default-jre-headless’, ‘curl’, ‘alsa-utils’, ‘icewm’, ‘xdotool’, ‘xserver-xorg-video-dummy’]
- change /usr/share/alsa/alsa.conf removing surrounds and sysdefault - this was done, because without this, ALSA gave out more than 32 devices, but by default it does not automatically pick up more than 32, I removed what was superfluous. As a result, I get 24 devices
- load the snd-aloop module with the addition of options: options snd-aloop enable=1,1 index=0,1
- Install chrome from deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome-keyring.gpg] http://dl.google.com/linux /chrome/deb/ stable main
- Here - /etc/opt/chrome/policies/managed/managed_policies.json should be: {CommandLineFlagSecurityWarningsEnabled": false }
- Download the desired version of chromedriver: CHROME_DRIVER_VERSION=
curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE
&& wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip
unpack to /usr/local/bin/
- replace the link /usr/bin/google-chrome with the script , it is taken from here, but something went wrong with running ffmpeg and I moved this part to systemd unit
script
#!/bin/bash
shopt -s huponexit
#set -o pipefail
#set -o errexit
_term() {
local SIGNAL=$1
if [ ! -z "${CHILD}" ]; then
kill -${SIGNAL} "${CHILD}"
fi
exit 111
}
trap "_term SIGHUP" SIGHUP SIGINT SIGTRAP SIGBUS SIGFPE SIGUSR1 SIGUSR2 SIGSTKFLT SIGCHLD SIGCONT SIGTSTP SIGTTIN SIGTTOU SIGURG SIGPIPE SIGALRM
trap "_term SIGABRT" SIGABRT
trap "_term SIGTERM" SIGTERM
trap "_term SIGKILL" SIGKILL
trap "_term SIGQUIT" SIGQUIT
trap "_term SIGSTOP" SIGSTOP
trap "_term STOP" STOP
# start ffmpeg cross capturing X displays to video devices
/usr/bin/ffmpeg -re -f x11grab -r 60 -s 1920x1080 -i :0 -f x11grab -r 60 -s 1920x1080 -i :1 \
-map 0 -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video1 \
-map 1 -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 2> /tmp/ffmpeg-jibri.log &
CHILD=$!
wait ${CHILD} || exit 1
exit 0
put as /usr/local/bin/ffmpeg-jibri.sh to run ffmpeg in systemd
- install [‘v4l2loopback-utils’]
- Load v4l2loopback module with options: options v4l2loopback devices=2 video_nr=0, 1 exclusive_caps=1,1 card_label=“PJSUA,Chrome” (neither chrome nor pjsua will see these capture devices until these devices broadcast something in the appropriate format, which is ensured by running ffmpeg BEFORE chrome and pjsua start)
- Add jitsi repository - deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/
- Install packages [‘jibri’, ‘jitsi-upload-integrations’, ‘jq’]
- Add jibri to groups adm,audio,video,plugdev,users
- Copy your jibri config
my ansible template for jibri config
jibri {
// A unique identifier for this Jibri
// TODO: eventually this will be required with no default
id = ""
// Whether or not Jibri should return to idle state after handling
// (successfully or unsuccessfully) a request. A value of 'true'
// here means that a Jibri will NOT return back to the IDLE state
// and will need to be restarted in order to be used again.
single-use-mode = false
api {
http {
external-api-port = 2222
internal-api-port = 3333
}
xmpp {
// See example_xmpp_envs.conf for an example of what is expected here
environments = [
{
name = "test environment"
xmpp-server-hosts = ["{{ jms_domain }}"]
xmpp-domain = "{{ jms_domain }}"
control-muc {
domain = "internal.auth.{{ jms_domain }}"
room-name = "JibriBrewery"
nickname = "{{ inventory_hostname_short }}"
}
control-login {
domain = "auth.{{ jms_domain }}"
username = "jibri-sip"
password = "{{ jibri_sip_password }}"
}
call-login {
domain = "jibri-sip.{{ jms_domain }}"
username = "jibri-sip"
password = "{{ jibri_sip_password }}"
}
// An (optional) MUC configuration where we'll
// join to announce SIP gateway services
sip-control-muc {
domain = "conference.{{ jms_domain }}"
room-name = "TheSipBrewery"
nickname = "{{ inventory_hostname_short }}"
}
strip-from-room-domain = "conference."
usage-timeout = 0
trust-all-xmpp-certs = true
}]
}
}
recording {
# recordings-directory = "/srv/recordings"
# TODO: make this an optional param and remove the default
# finalize-script = "/srv/recordings/finalize_recording.sh"
}
streaming {
// A list of regex patterns for allowed RTMP URLs. The RTMP URL used
// when starting a stream must match at least one of the patterns in
// this list.
rtmp-allow-list = [
// By default, all services are allowed
".*"
]
}
ffmpeg {
resolution = "1920x1080"
// The audio source that will be used to capture audio on Linux
audio-source = "alsa"
// The audio device that will be used to capture audio on Linux
audio-device = "plug:bsnoop"
}
chrome {
// The flags which will be passed to chromium when launching
flags = [
"--use-fake-ui-for-media-stream",
"--start-maximized",
"--kiosk",
"--enabled",
"--disable-infobars",
"--autoplay-policy=no-user-gesture-required"
// "--alsa-input-device=plug:asnoop"
]
}
stats {
enable-stats-d = true
}
webhook {
// A list of subscribers interested in receiving webhook events
subscribers = []
}
jwt-info {
// The path to a .pem file which will be used to sign JWT tokens used in webhook
// requests. If not set, no JWT will be added to webhook requests.
//# signing-key-path = "/path/to/key.pem"
// The kid to use as part of the JWT
# kid = "key-id"
// The issuer of the JWT
# issuer = "issuer"
// The audience of the JWT
# audience = "audience"
// The TTL of each generated JWT. Can't be less than 10 minutes.
# ttl = 1 hour
}
call-status-checks {
// If all clients have their audio and video muted and if Jibri does not
// detect any data stream (audio or video) comming in, it will stop
// recording after NO_MEDIA_TIMEOUT expires.
no-media-timeout = 3 minutes
// If all clients have their audio and video muted, Jibri consideres this
// as an empty call and stops the recording after ALL_MUTED_TIMEOUT expires.
all-muted-timeout = 10 minutes
// When detecting if a call is empty, Jibri takes into consideration for how
// long the call has been empty already. If it has been empty for more than
// DEFAULT_CALL_EMPTY_TIMEOUT, it will consider it empty and stop the recording.
default-call-empty-timeout = 30 seconds
// If ICE hasn't completed, or stays in a state other than "connected" for this amount of time, Jibri will stop.
ice-connection-timeout = 30 seconds
}
}
- Modify /opt/jitsi/jibri/pjsua.sh to get away from invalid --id format when pjsua starts
my pjsua template
#!/bin/bash
/usr/bin/sudo -E /usr/local/bin/pjsua --config-file /etc/jitsi/jibri/pjsua.config --id="sip:{{ inventory_hostname_short }}@{{ inventory_hostname }}" --auto-answer-timer=60 --auto-answer=200 > /dev/null
#exec /usr/local/bin/pjsua --config-file /etc/jitsi/jibri/pjsua.config "$@"
- Copy your pjsua.config (can get from here but need to change for playback-dev and capture-dev)
- add a restart of the jibri service to /opt/jitsi/jibri/finalize_sip.sh because in some undefined cases, strange errors occur after the call is completed and a new call is not accepted
- In case of custom cert signed your local CA, add your CA to chrome - certutil -d sql:/home/jibri/.pki/nssdb -A -t TC -n “Custom CA” -i /usr/local/share/ca-certificates/custom_ca.pem.crt (before that, you need to run chrome at least once to create this certificate database)
- I add systemd units to run under the jibri user:
- pjsua-xorg: /usr/bin/Xorg -nocursor -noreset +extension RANDR +extension RENDER -logfile /var/log/jitsi/jibri/pjsua xorg.log -config /etc/jitsi/jibri/xorg-video-dummy-pjsua.conf :1 with Environment=DISPLAY=:1
- ffmpeg-jibri: /usr/local/bin/ffmpeg-jibri.sh
- pjsua-icewm: /usr/bin/icewm-session --notray --display=:1 with Environment=DISPLAY=:1
- Install packages before compiling pjsua: [‘build-essential’, ‘libv4l-dev’, ‘libsdl2-dev’, ‘libavcodec-dev’, ‘libavdevice-dev’, ‘libavfilter-dev’, ‘libavformat-dev’, ’ libavresample-dev’, ‘libavutil-dev’, ‘libswresample-dev’, ‘libswscale-dev’, ‘libasound2-dev’, ‘libopus-dev’, ‘libvpx-dev’, ‘libsdl-dev’]
- Compiling GitHub - jitsi/pjproject: PJSIP fork used in Jibri https://github.com/jitsi/jibri version jibri-2.10-dev1
- Copy pjsip-apps/bin/pjsua-x86_64-unknown-linux-gnu as /usr/local/bin/pjsua
- Copy pjsip-apps/bin/pjsystest-x86_64-unknown-linux-gnu as /usr/local/bin/pjsystest
- I launch pjsua via sudo because there was an error Unable to increase thread priority, root access needed when running under the jibri user, (although this may have been due incorrectly specified the device id in pjsua the config.), in any case, need to run pjsystest same way as pjsua to find out the correct playback-id and capture-id, on this screenshot is --capture-dev=15 and --playback-dev=22:
Alsa device list screenshot

- about Jibri it`s all
To initiate a jibri session on an incoming call, I added an asterisk setup to the JMS with the following call instructions:
Asterisk Dial plan
[test]
exten => test1,1,Dial(SIP/test1,30)
exten => test2,1,Dial(SIP/test2,30)
exten => test3,1,Dial(SIP/test3,30)
exten => test4,1,Dial(SIP/test4,30)
exten => jibri-sip1,1,Dial(SIP/jibri-sip1@jibri-sip1.example.com:5060,30)
exten => h,1,Hangup()
exten => s,1,Hangup()
exten => _.,1,Verbose("Run Call Jibri jibri-sip1 for ROOM = ${EXTEN}")
exten => _.,n,AGI(call_jibri_api.sh,${EXTEN},jibri-sip1.example.com)
exten => _.,n,Wait(5)
exten => _.,n,Dial(SIP/jibri-sip1@jibri-sip1.example.com:5060,30)
Thus , it is enough to have an sip account on this asterisk and call the desired conference room.
Script start Jibri session for called room via http api:
ansible template script for start Jibri call session
#!/bin/bash
JITSI_ROOM="$1"
JIBRI_NODE="$2"
JIBRI_NODE_NAME=${JIBRI_NODE%%.*}
if [ "$JITSI_ROOM" = "" ]; then
JITSI_ROOM="JitsiSIPTest"
fi
if [ "$JIBRI_NODE" = "" ]; then
JIBRI_NODE="jibri-sip1.example.com"
JIBRI_NODE_NAME=${JIBRI_NODE%%.*}
fi
SESSION_ID=`shuf -i 1000000-9999999 -n 1`
curl -s --header 'Content-Type: application/json' --request 'POST' --data '{"sessionId": "'"$SESSION_ID"'","callParams": { "callUrlInfo": {"baseUrl": "https://{{ jms_domain }}", "callName": "'"$JITSI_ROOM"'" } }, "sinkType": "gateway", "sipClientParams": { "sipAddress": "'"sip:$JIBRI_NODE_NAME@$JIBRI_NODE"'", "autoAnswer": true } }' http://$JIBRI_NODE:2222/jibri/api/v1.0/startService
it`s works.