Screen streaming to multiple devices via network
I had a need to show dashboard with monitoring information on several screens in the office. There are several old Raspberry Pi Model B+ and a hypervisor with a virtually unlimited amount of resources.
Apparently the Raspberry Pi Model B+ does not have enough power to keep the browser running constantly and draw a large amount of graphics in it, which is why the page is partially buggy and often crashes.
I found a fairly simple and elegant solution, which I want to share with you.
As you know, all Raspberries have a quite powerful video processor, which is great for hardware video decoding. This is how the idea to launch a browser with dashboard somewhere else appeared, and to connect a stream with a rendered image to the respberry.
Plus, it should have simplified management, since in this case the whole setup will be performed on one virtual machine, which is easier to update and back up it.
No sooner said than done.
Server installation
We will use the ready Ubuntu Cloud Image. It does not require installation and contains everything you need to quickly deploy a virtual machine, Cloud Init Support helps you instantly configure your network, add ssh keys, and quickly prepare VM to run.
Now, let’s deploy a new virtual machine and install Xorg, nodm and fluxbox on it:
apt-get update
apt-get install -y xserver-xorg nodm fluxbox
sed -i 's/^NODM_USER=.*/NODM_USER=ubuntu/' /etc/default/nodm
Also we’ll use the config for Xorg, kindly provided by Diego Ongaro, and add the new resolution: 1920x1080, since all of our screens will use it:
cat > /etc/X11/xorg.conf <<\EOT
Section "Device"
Identifier "device"
Driver "vesa"
EndSection
Section "Screen"
Identifier "screen"
Device "device"
Monitor "monitor"
DefaultDepth 16
SubSection "Display"
Modes "1920x1080" "1280x1024" "1024x768" "800x600"
EndSubSection
EndSection
Section "Monitor"
Identifier "monitor"
HorizSync 20.0 - 50.0
VertRefresh 40.0 - 80.0
Option "DPMS"
EndSection
Section "ServerLayout"
Identifier "layout"
Screen "screen"
EndSection
EOT
systemctl restart nodm
Now we will install Firefox, we will run it as a systemd service, so we also should write a unit-file for it:
apt-get install -y firefox xdotool
cat > /etc/systemd/system/firefox.service <<\EOT
[Unit]
Description=Firefox
After=network.target
[Service]
Restart=always
User=ubuntu
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/ubuntu/.Xauthority"
ExecStart=/usr/bin/firefox -url 'http://example.org/mydashboard'
ExecStartPost=/usr/bin/xdotool search --sync --onlyvisible --class "Firefox" windowactivate key F11
[Install]
WantedBy=graphical.target
EOT
systemctl enable firefox
systemctl start firefox
Xdotool is needed to launch firefox in full screen at once.
Using the -url
parameter, you can specify any page so that it opens automatically when the browser starts.
At this stage, our kiosk is ready, and now we need to export the picture over the network to other screens and devices. To achieve this, we will use the Motion JPEG format, that is most commonly used for streaming video from most webcams.
We need two things: FFmpeg with the x11grab module, to capture the image from the X-server and streamEye, which will distribute it to our clients:
apt-get install -y make gcc ffmpeg
cd /tmp/
wget https://github.com/ccrisan/streameye/archive/master.tar.gz
tar xvf master.tar.gz
cd streameye-master/
make
make install
cat > /etc/systemd/system/streameye.service <<\EOT
[Unit]
Description=streamEye
After=network.target
[Service]
Restart=always
User=ubuntu
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/ubuntu/.Xauthority"
ExecStart=/bin/sh -c 'ffmpeg -f x11grab -s 1920x1080 -i :0 -r 1 -f mjpeg -q:v 5 - 2>/dev/null | streameye'
[Install]
WantedBy=graphical.target
EOT
systemctl enable streameye
systemctl start streameye
Since our picture does not require a quick refresh, I specified update rate: 1 frame per second (option -r 1
) and compression quality: 5 (option -q:v 5
)
Now we can try to go on http://your-vm:8080/, on the page you will see a constantly updated screenshot of the desktop. Cool! — that was what was needed.
Client installation
Luckily it’s even easier, as I said we will use the Raspberry Pi Model B+.
First we need to install Arch Linux ARM on it, for achieve this just follow the instruction on the official website.
We also need to allocate more memory for GPU chip, edit in /boot/config.txt
:
gpu_mem=128
Now let’s boot our new system and install OMXPlayer on it, do not forget to initialize the pacman keyring first:
pacman -Sy omxplayer
Remarkably, OMXPlayer can work without X-server, so all we need is to write a unit-file and run it:
cat > /etc/systemd/system/omxplayer.service <<\EOT
[Unit]
Description=OMXPlayer
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/omxplayer -r --live -b http://your-vm:8080/ --aspect-mode full
[Install]
WantedBy=multi-user.target
EOT
systemctl enable omxplayer
systemctl start omxplayer
We pass the URL of our server in the `-b http://your-vm:8080/` option.
That’s all, on the connected screen should immediately appear a picture from our server. In case of any problems, the stream will be automatically restarted, and clients will reconnect to it.
As a bonus, you can set this picture as a screensaver on all computers in the office. To do this, you need MPV and XScreenSaver:
mode: one
selected: 0
programs: \
"Monitoring Screen" mpv --really-quiet --no-audio --fs \
--loop=inf --no-stop-screensaver \
--wid=$XSCREENSAVER_WINDOW \
http://your-vm:8080/ \n\
maze -root \n\
electricsheep --root 1 \n\
Now your colleagues will be very surprised :)