Turning a Raspberry Pi into a Mirroring Server

I recently needed to show some photos and videos on my phone on a screen. In the past, I used the youtube app to “cast” a video on my TV. However, this time it was different

  1. I needed to show videos on my phone’s gallery
  2. The screen I was casting to was not a “smart” one - that is, it did not support screen mirroring technologies such as Airplay, Chromecast or Miracast, etc

After some googling, I found some software but they were not free and some didn’t support embedded Linux devices such as the Raspberry Pi.

Enter RpiPlay

I own an iPhone and as far as I know, iOS devices do not support screen mirroring over Chromecast natively. iOS and macOS devices support screen mirroring natively via Airplay. Luckily, there is RpiPlay which is an open-source AirPlay mirroring server for the Raspberry Pi.

balena-ifying RpiPlay

Compiling RpiPlay was quite straightforward. The README has clear instructions and some tips on how to optimise for performance.

Lessons learned:

  1. RpiPlay requires VideoCore userspace libraries since it uses Broadcom’s OpenMAX stack as present in /opt/vc in Raspbian. Despite using the raspbian base image, these libraries were not present. ilclient can be downloaded from Raspberry Pi’s firmware repo or downloaded from raspbian sources. The library sources exist as examples and they are provided by the libraspberrypi-doc package.
  2. When RpiPlay runs, it advertises a device name which is configurable. Under the hood, it uses avahi to do this. Avahi already runs in the hostOS so for it to work, we can allow the container to use the avahi daemon via dbus. It simply required adding the dbus label and environment variable pointing to the dbus socket. This is explained in the docs

You can take a look at the app here : https://github.com/rahul-thakoor/air-pi-play

Running this app is as simple as deploying it to a balenaCloud fleet. You can do it in just one click by using the button below:

balena deploy button

Hardware required

  • iOS or macOS device capable of casting over Airplay
  • A Raspberry Pi - this project supports the Pi Zero but YMMV
  • Of course, an external screen, tv or projector to share to

Some screenshots

ToDo:

  • Make sure audio works over hdmi
  • Try to make app generic by compiling with gstreamer support - right now the app uses Raspberry Pi specific libraries.
  • Optimise the app size for the edge - the current size is ~ 500 MB!

Attribution

This app would not be possible without RpiPlay

Nice work @rahul-thakoor :smiley:

This would be great as an open fleet on balenaHub!

1 Like

This is some pretty nice stuff right here :slight_smile:

Would be cool to see it augmented with something like Miracast or RTSP to support more devices/apps.
I remember trying my hand at that years ago to support casting youtube, should see if I still have that project lying around somewhere…

1 Like

Thanks @chrisys

Sure, will turn it into an open fleet soon :slight_smile:

Thanks @TJvV

Yeah, right now it is Airplay only but hoping to add chromecast and miracast eventually.

I remember trying my hand at that years ago to support casting youtube, should see if I still have that project lying around somewhere…

This would be so great :slight_smile: Would highly appreciate a PR to add this. We can rename the app to be less “airplay specific”

Optimising the app size for the edge

Right now the app is ~500 MB. This is understandable since we are shipping artifacts that we don’t need - this includes build time tools and dependencies.

We can use multi-stage build to reduce the image size. Technically we only need the compiled rpiplay binary and it’s dependencies in the container. Unfortunately, it’s not a static binary, so we need to figure out which dependencies are required.

The crux of optimising the image size is figuring out exactly which dependencies are required by the binary. We could use tools such as ldd to manually figure it out but it can get tedious.

Dockerize to the rescue

Dockerize is an awesome tool which helps to pack up your dynamically linked ELF binaries and all their dependencies and turn them into a Docker image.

For our use case though, we will use the -n option such that no docker image is generated. Instead we specify the output directory where all files and dependencies are copied. We can then use the COPY command in a multi-stage build to copy over only these required files in the final stage! I’ve used this technique to optimise our fbcp block.

There you have it! The rpiplay and it’s dependencies only are packaged and shipped. The final image size is down from 500MB to 13.46MB! :tada:

Gotchas

After optimising the app, it threw the following error when trying to run it:

rpiplay: error while loading shared libraries: libbrcmGLESv2.so: cannot open shared object file: No such file or directory

This is a shared library that exists in /opt/vc/lib and is provided by the Raspberry Pi. After debugging, I confirmed that this shared library was discovered by dockerize when resolving the dependencies and it was indeed copied over to our output directory.

Also, I remembered vaguely that I encountered the same issue when optimising our fbcp block. It also required similar libraries. For fbcp I “hacked” my way around the problem by explicitly specifying the dependencies in the CMakeLists.txt file.

It turns out that since we are using the busybox base image, it does not know where to find those specific shared libraries. We can specify it using the LD_LIBRARY_PATH environment variable. In Linux, the environment variable LD_LIBRARY_PATH is a colon-separated set of directories where libraries should be searched for first, before the standard set of directories; this is useful when debugging a new library or using a nonstandard library for special purposes.

I added the required path in the start script using export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/vc/lib and `rpiplay started without any problem.

I will need to investigate if this works for our fbcp block too :microscope:

Hope this was helpful. You can check the code changes here.

1 Like

This is gold @rahul-thakoor. Terrible project (anti-apple jokes) but finally the world gets to learn from your dockerise smarts. :blush:

haha, thanks @phil-d-wilson

hopefully we can turn this project into a more generic screen mirroring app.

I have been digging around and sadly haven’t found my old project.
I think it died in a HDD crash a couple of years ago.

Did cause me to look back into DLNA/DIAL and the like.
I don’t have a lot of spare time to work on it, but will try to get something up and running in the coming month.

Thanks for looking into it @TJvV

I don’t have a lot of spare time to work on it, but will try to get something up and running in the coming month.

Looking forward to it. Hope you get some time to get this going :+1:

Published the app as an openfleet:
https://hub.balena.io/gh_rahul_thakoor/air-pi-play

Turn your Raspberry Pi into an Airplay server!