Tuesday, May 18, 2021

[How To] Apache Websockets WSS in a Subfolder

 The following syntax can be used to run websocket connections in Apache in a subfolder : 

# /websocket1 to port 2085

RewriteCond %{REQUEST_URI} /websocket1 [NC]

RewriteCond %{HTTP:Upgrade} "(?i)websocket" [NC,OR]

RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]

RewriteRule ^/(.*)$ ws://127.0.0.1:2085/$1 [P,QSA,L]


# /websocket2 to port 3126

RewriteCond %{REQUEST_URI} /websocket2 [NC]

RewriteCond %{HTTP:Upgrade} "(?i)websocket" [NC,OR]

RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]

RewriteRule ^/(.*)$ ws://127.0.0.1:3126/$1 [P,QSA,L]

The above need to be used in a SSL virtualhost.

For a non-SSL virtualhost, one can simply use:

ProxyPass "/websocket1" "ws://127.0.0.1:2085/"
ProxyPass "/websocket2" "ws://127.0.0.1:3126/"

Tuesday, May 11, 2021

Stable Jitsi meet setup on Raspberry Pi 4 + TV + Webcam

 It feels much better to run meetings on a big screen TV rather than a phone or regular monitors.

Raspberry Pi 4 can be connected to a TV to run such meetings. The setup is not straightforward though, you may get an overloaded Pi with lags in meeting with the default configuration.

Here are the points to consider to make a stable setup:

1. The 3.5mm jack port on Pi 4 does NOT support microphone. You need to use a USB microphone or a 3.5mm jack headphone + a USB audio card. Cheap USB microphones / audio cards do not have an acceptable quality and you would get a noisy input. So you would either need to order a professional USB microphone which is expensive, or go for a logtech webcam which has a quite decent built-in microphone. A list of tested webcams on Pi is provided here.

I went for the latter and ordered Logitech C310 and it worked smoothly. 

A 4k HDMI cable is also needed to connect pi to a 4k TV. You may also enable 60fps for your 4k TV, I did not test it though as my TV was not 4K.

2. Streaming is resource consuming and you would need to get a fan for your Pi. Official Raspberry Pi Fan is a good choice as it can be configured to turn on whenever CPU temperature gets above a certain degree.

Also, get a powerful enough adapter for your Pi. I ordered Mi 27W adapter which can provide 3A 5V. With a good adapter and fan, you can overclock your Pi to get 2Ghz CPU cores / 700Mhz GPU cores.

Enable G2 GL for your Pi to get hardware acceleration, and set gpu_mem to max recommended

# /boot/config.txt 

# hdmi_force_hotplug is required for libcec https://github.com/Pulse-Eight/libcec#raspberry-pi

hdmi_force_hotplug=1

# Overclocking

over_voltage=6

arm_freq=2000

gpu_freq=700

[pi4]

# Enable DRM VC4 V3D driver on top of the dispmanx display stack

dtoverlay=vc4-fkms-v3d

max_framebuffers=2

[all]

dtoverlay=vc4-fkms-v3d

[all]

dtoverlay=gpio-fan,gpiopin=14,temp=60000

gpu_mem=256


disable xcompmgr composition manager to reduce screen tearing as mentioned here

sudo mv /etc/xdg/autostart/xcompmgr.desktop /home/pi/backup.xcompmgr.deskto

and reboot the Pi. Without this setting, you would see glitches in your jitsi calls.

You may also want to disable sceen blanking in raspi-config . 

3. Install v4l-utils package and add set raspberry pi to configure your webcam to its max res on startup

# /etc/rc.local

# /usr/bin/v4l2-ctl -d /dev/video0 --get-fmt-video 

# /usr/bin/v4l2-ctl -d /dev/video0 --list-formats-ext

/usr/bin/v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=1

Pi Camera v2 is not a good option to use as camera. Although it has a wider field of view, it does not include microphone, its cable and mounting are pain. It is said that Pi Camera connects to GPU and creates less CPU load for streaming however in my tests it caused about 2x higher CPU load compared to logitech C310 no matter what encoding was used in v4l2-ctl for the Pi camera.

4. Launch Chromium with these options :

/usr/bin/chromium-browser --use-fake-ui-for-media-stream --no-first-run --no-zygote --no-sandbox --disable-setuid-sandbox

in chrome://gpu you can see the status of gpu acceleration. You may use chrome://flags to enable more options for hardware acceleration such as "GPU rasterization", "Override software rendering list", "Hardware-accelerated video decode"

5. Add the following configuration to the end of your Jitsi Room URL :

https://Jitsi.Yourdomain/ROOM#config.disableSimulcast=true&config.enableLayerSuspension=true&config.disableSuspendVideo=true&config.disableAudioLevels=true&config.p2p.enabled=false&config.disableH264=false&config.preferH264=true

You need to ensure that everybody who joins the room uses these parameters. You can hover the mouse on top left signal bar on their thumbnail and ensure that participants are using H264 encoding.

I used Apache rewrite rules on my jitsi hosted server to force these parameters for everyone joining the room: 

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^https://Jitsi.Yourdomain/check.html [NC]
RewriteRule ^/?ROOM$ https://Jitsi.Yourdomain/check.html [R=302,NC,L,R,NE]

<Files check.html>
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>

or with nginx:

location ~ ^/ROOM {
    if ($http_referer !~* "https://Jitsi.Yourdomain/check.html") {
    rewrite ^/ROOM$ check.html redirect;
    }
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://127.0.0.1:8480;
}

location /check.html {
    add_header Last-Modified $date_gmt;
    add_header Cache-Control 'no-store, no-cache';
    if_modified_since off;
    expires off;
    etag off;
    root   /var/www/html;
    index  index.html index.htm;
}

This checks if the referrer of the URL to join the room is check.html or not. If it is not check.html, it redirects the page to check.html . Now in the check.html file we can set whatever parameters we want and redirect it to our ROOM :

<html>
  <head>
    <meta http-equiv="Cache-control" content="No-Cache">
  </head>
  <body>
    <form id="redirect" action="https://Jitsi.Yourdomain/ROOM#config.disableSimulcast=true&config.enableLayerSuspension=true&config.disableSuspendVideo=true&config.disableAudioLevels=true&config.p2p.enabled=false&config.disableH264=false&config.preferH264=true&videoQuality.preferredCodec=H264" method="get"></form>
    <script>
      document.getElementById("redirect").submit();
    </script>
  </body>
</html>

You may also add
 &config.webrtcIceUdpDisable=true&config.webrtcIceTcpDisable=false
to the check.html action URL and use JVB_TCP_HARVESTER_DISABLED=false in the .env file of your docker-jitsi-meet to disable UDP in jitsi.

At 720p, each camera requires an average of 200 KB/s (1.6 Mbps) of upload bandwidth and support for peak rates of 500 KB/s (4.0 Mbps) of upload bandwidth.

With the above settings, I was able to run Jitsi meetings quite smoothly on the Pi with HD streaming on both ends. Here is the server load on Pi after 20mins in the jitsi session:



How to disable Debian 12 sleep on production servers

 Debian 12 has power saver enabled by default which causes your server to go to sleep if there is no mouse / keyboard interaction. To resolv...