Screen streaming to multiple devices via network

kvaps

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 :)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade