UxPlay: AirPlay Unix mirroring server

71
UxPlay: AirPlay Unix mirroring server

This project is a GPLv3 open source unix AirPlay2 Mirror server for Linux, macOS, and *BSD.
It is now hosted at the
github site https://github.com/FDH2/UxPlay (where development and user-assistance now takes place), although it initially was developed by
antimof using code
from RPiPlay, which in turn derives from
AirplayServer,
shairplay, and playfair. (The antimof site is
mainly inactive, but periodically posts updates pulled from the main UxPlay site).

Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients
(iPhones, iPads, MacBooks) in a window
on the server display (with the possibility of
sharing that window on screen-sharing applications such as Zoom)
on a host running Linux, macOS, or other unix. UxPlay supports a “legacy” form of Apple’s AirPlay Mirror protocol introduced
in iOS 12; client devices running iOS/iPadOS 12 or later are supported, as is a (nonfree) Windows-based
AirPlay-client software emulator, AirMyPC. Older (32-bit) client devices that can only run iOS 9.3 or iOS 10.3 are
currently partially supported by UxPlay: reports indicate that
screen-mirroring video works, audio is a work in progess.
(Details of what is publically known about Apple’s AirPlay2 protocol can be found
here and
here).

The UxPlay server and its client must be on the same local area network,
on which a Bonjour/Zeroconf mDNS/DNS-SD server is also running
(only DNS-SD “Service Discovery” service is strictly necessary, it is not necessary that the local network also be of the “.local” mDNS-based type).
On Linux and BSD Unix servers, this is usually provided by Avahi,
through the avahi-daemon service, and is included in most Linux distributions (this
service can also be provided by macOS, iOS or Windows servers).

Connections to the UxPlay server by
iOS/MacOS clients can be initiated both in AirPlay Mirror mode (which streams
lossily-compressed AAC audio while mirroring the client screen,
or in the alternative AirPlay Audio mode which streams
Apple Lossless (ALAC) audio without screen mirroring (the accompanying metadata and cover art in
this mode is not displayed). Switching between these two modes during an active connection is
possible: in Mirror mode, close the mirror window and start an Audio mode connection,
switch back by initiating a Mirror mode connection.
Note that Apple DRM
(as in Apple TV app content on the client) cannot be decrypted by UxPlay,
and (unlike with a true AppleTV), the client cannot run a http connection on the server
instead of streaming content from one on the client.

UxPlay uses GStreamer Plugins for rendering audio and video,
and does not offer the alternative Raspberry-Pi-specific
audio and video renderers available in RPiPlay.
It is tested on a number of systems, including (among others) Debian 11.2, Ubuntu 20.04 and 21.10, Linux Mint 20.2, OpenSUSE 15.3, macOS 10.15.7, FreeBSD 13.0.

Using Gstreamer means that video and audio are supported “out of the box”, using a choice of plugins.
Gstreamer decoding is plugin agnostic, and uses accelerated decoders if
available. For Intel integrated graphics, the VAAPI plugin is preferable, (but don’t use it with nVidia).

Note to packagers: OpenSSL-3.0.0 solves GPL v3 license issues.

Some Linux distributions such as Debian do not allow distribution of compiled
GPL code linked to OpenSSL-1.1.1 because its “dual OpenSSL/SSLeay” license
has some incompatibilites with GPL, unless all code authors have explicitly given an “exception” to allow
such linking (the historical origins of UxPlay make this impossible to obtain). Other distributions
treat OpenSSL as a “System Library” which the GPL allows linking to.

For “GPL-strict” distributions, UxPlay can be built using OpenSSL- 3.0.0, which has a
new GPLv3-compatible license.

Either download and unzip UxPlay-master.zip,
or (if git is installed): “git clone https://github.com/FDH2/UxPlay“.

*This is also a pull request on the
original site https://github.com/antimof/UxPlay ; that original
project is inactive, but the pull request with
changes up to 2021-12-10
were recently merged with the antimof tree (thank you antimof!).

Building UxPlay on Linux (or *BSD):

(Instructions for Debian/Ubuntu; adapt these for other Linuxes; for macOS, see below).

You need a C/C++ compiler (e.g. g++) with the standard development libraries installed.

Make sure that cmake>=3.4.1 and pkg-config are also installed: “sudo apt-get install cmake pkg-config”.
In a terminal window, change directories to the source directory of the
downloaded source code (“UxPlay-master” for zipfile downloads, “UxPlay” for “git clone” downloads), then do

  1. sudo apt-get install libssl-dev libplist-dev libavahi-compat-libdnssd-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-libav gstreamer1.0-plugins-bad
  2. sudo apt-get install gstreamer1.0-vaapi (For hardware-accelerated Intel graphics, but not nVidia graphics)
  3. sudo apt-get install libx11-dev (for the “ZOOMFIX” X11_display name fix for screen-sharing with e.g., ZOOM)
  4. cmake . (or “cmake -DZOOMFIX=ON .” to get a screen-sharing fix to
    make X11 mirror display windows visible to screen-sharing applications such as
    Zoom, see below).
  5. make
  6. sudo make install (you can afterwards uninstall with sudo make uninstall in the same directory in which this was run)

If you intend to modify the code, use a separate “build” directory: replacecmake [ ] . bymkdir build ; cd build ; cmake [ ] ..“; you can then clean
the build directory with
rm -rf build/* (run from within the UxPlay source directory) without affecting the source directories which contain your modifications.

The above script installs the executable file “uxplay” to /usr/local/bin, (and installs a manpage to somewhere like /usr/local/share/man/man1 and README
files to somewhere like /usr/local/share/doc/uxplay).
It can also be found in the build directory after the build
processs. Run uxplay in a terminal window.

Note libplist-dev (version 2.0 or greater) is a new dependency (the original antimof version UxPlay-1.2 supplied it). Older Linux
distributions may only supply libplist 1.x, which is too old. [Installing libplist-dev (with libplist3) from ubuntu 18.04 solves this problem on ubuntu 16.04.]

If you cannot find a libplist-2.x package that installs on your older distribution, you can get it at
https://github.com/libimobiledevice/libplist and build it from source.
(You will need build tools autoconf, automake, libtool, and may need to also install some libpython*-dev package).
By default, libplist installs in /usr/local/lib. If this is not in the library path (as in ubuntu), create a
file /etc/ld.so.conf.d/libplist.conf containing the text “/usr/local/lib”, and run “sudo ldconfig” to permanently add /usr/local/lib to the library path.

Red Hat, Fedora, CentOS:
(sudo yum install) openssl-devel libplist-devel avahi-compat-libdns_sd-devel (+libX11-devel for ZOOMFIX). The required
GStreamer packages are:
gstreamer1-devel gstreamer1-plugins-base-devel gstreamer1-libav gstreamer1-plugins-bad-free ( + gstreamer1-vaapi for intel graphics).

OpenSUSE:
(sudo zypper install) libopenssl-devel libplist-devel
avahi-compat-mDNSResponder-devel (+ libX11-devel for ZOOMFIX). The required
GStreamer packages are:
gstreamer-devel gstreamer-plugins-base-devel gstreamer-plugins-libav gstreamer-plugins-bad (+ gstreamer-plugins-vaapi for Intel graphics).

FreeBSD: (sudo pkg install) libplist gstreamer1, gstreamer1-libav, gstreamer1-plugins, gstreamer1-plugins-*
(* = core, good, bad, x, gtk, gl, vulkan, pulse …), (+ gstreamer1-vaapi for Intel graphics).
Either avahi-libdns or mDNSResponder must also be installed to provide the dns_sd library.
OpenSSL is already installed as a System Library. “ZOOMFIX” is untested; don’t try to use it on FreeBSD unless you need it.

Building UxPlay on macOS: (Only tested on Intel X86_64 Macs)

Note: A native AirPlay Server feature is included in macOS 12 Monterey, but is restricted to recent hardware.
UxPlay can run on older macOS systems that will not be able to run Monterey, or can run Monterey but not AirPlay.

These instructions for macOS asssume that the Xcode command-line developer tools are installed (if Xcode is installed, open the Terminal, type “sudo xcode-select –install” and accept the conditions).

It is also assumed that CMake >= 3.13 is installed:
this can be done with package managers MacPorts,
Fink or Homebrew, or by a download from
https://cmake.org/download/.

First get the latest macOS release of GStreamer-1.0
from https://gstreamer.freedesktop.org/download/.
Install both the macOS runtime and development installer packages. Assuming that the latest release is 1.18.5
they are gstreamer-1.0-1.18.5-x86_64.pkg and gstreamer-1.0-devel-1.18.5-x86_64.pkg.
Click on them to install (they install to
/Library/FrameWorks/GStreamer.framework).
It is recommended you use GStreamer.framework rather than install Gstreamer with Homebrew or MacPorts (see later).

Next install OpenSSL and libplist: these can be built from source (see below) but it is easier to get them using
MacPorts “sudo port install openssl libplist-devel” or Homebrew “brew install openssl libplist”. Only the
static forms of the two libraries will used for the macOS build, so they do not need to remain installed after you have built uxplay:
if you don’t have MacPorts or Homebrew installed, you can just install
one of these package-managers before building uxplay, and uninstall it afterwards if you do not want to keep it.
Unfortunately, Fink’s openssl11-dev package currently doesn’t supply the static (libcrypto.a) form of the
needed OpenSLL library libcrypto, and its libplist1 package is too old.

Finally, build and install uxplay (without ZOOMFIX): open a terminal and change into the UxPlay source directory
(“UxPlay-master” for zipfile downloads, “UxPlay” for “git clone” downloads) and build/install with
“cmake . ; make ; sudo make install ” (same as for Linux).

On the macOS build, autovideosink uses OpenGL, not X11, to create the mirror display window (equivalent to
“-vs glimagesink”; “-vs osxvideosink” can also be used).
The window title does not show the Airplay server name, but it is visible to
screen-sharing apps (e.g., Zoom). On macOS, The option -t timeout
cannot be used because if the GStreamer pipeline is destroyed while the mirror window is still open,
a segfault occurs (this is an issue with the GStreamer plugins, not UxPlay).
Also, the resolution settings “-s wxh” do not affect
the (small) initial OpenGL mirror window size, but the window can be expanded using the mouse or trackpad.
In contrast, a window created with “-vs osxvideosink” is initially big, but has the wrong aspect ratio (stretched image);
in this case the aspect ratio changes when the window width is changed by dragging its side.

Building OpenSSL and libplist from source on macOS

If you have have the standard GNU toolset (autoconf, automake, libtool, etc.) installed,
you can also download and compile the source code for these libraries from
https://www.openssl.org/source/,
https://github.com/libimobiledevice/libplist.
Install the downloaded
openssl by opening a terminal in your Downloads directory, and unpacking the source distribution openssl-3.0.0.tar.gz ,
(“tar -xvzf openssl-3.0.0.tar.gz ; cd openssl-3.0.0”). Then build/install with
“./config ; make ; sudo make install_dev” and clean up after building uxplay with “sudo make uninstall” in the same directory.
Similarly, for libplist, download the source as a zipfile from github as
libplist-master.zip, then
unpack (“unzip libplist-master.zip ; cd libplist-master”), build/install
(“./autogen.sh ; make ; sudo make install”) and clean up after uxplay is built with “sudo make uninstall” in the same directory.

Other ways (Homebrew, MacPorts) to install GStreamer on macOS (not recommended):

First make sure that pkgconfig is installed (Homebrew: “brew install pkgconfig” ; MacPorts: “sudo port install pkgconfig” ).

(a) with Homebrew: “brew install gst-plugins-base gst-plugins-good gst-plugins-bad gst-libav”. This appears to be functionally equivalent
to using GStreamer.framework, but causes a large number of extra packages to be installed by Homebrew as dependencies. (However, as of November 2021,
Homebrew offers a build of GStreamer for Apple Silicon, which then was not yet available on the offical GStreamer site.)

(b) with MacPorts: “sudo port install gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good gstreamer1-gst-plugins-bad gstreamer1-gst-libav”.
The MacPorts GStreamer is built to use X11, so must be run from an XQuartz terminal, can use ZOOMFIX, and needs
option “-vs ximagesink”. On an older unibody MacBook Pro, the default resolution wxh = 1920×1080 was too large for
the non-retina display, but using option “-s 800×600” worked; However, the GStreamer pipeline is fragile against attempts to change
the X11 window size, or to rotations that switch a connected client between portrait and landscape mode while uxplay is running.
Using the MacPorts X11 GStreamer is only viable if the image size is left unchanged from the initial “-s wxh” setting
(also use the iPad/iPhone setting that locks the screen orientation against switching between portrait and landscape mode
as the device is rotated).

Note: uxplay is run from a terminal command line, and informational messages are written to the terminal.

1. uxplay starts, but stalls after “Initialized server socket(s)” appears, without any server name showing on the client.

Stalling this way, with no server name showing on the client as available,
probably means that your network does not have a running Bonjour/zeroconf DNS-SD server.
On Linux, make sure Avahi is installed,
and start the avahi-daemon service on the system running uxplay (your distribution will document how to do this).
Some systems may instead use the mdnsd daemon as an alternative to provide DNS-SD service.
(FreeBSD offers both alternatives, but only Avahi was tested: one of the steps needed for
getting Avahi running on a FreeBSD system is to edit /usr/local/etc/avahi/avahi-daemon.conf to
uncomment a line for airplay support.
)

2. uxplay starts, but stalls after “Initialized server socket(s)” appears, with the server name showing on the client (but the client fails to connect when the UxPlay server is selected).

This shows that a dns_sd service is working, but a firewall on the server is probably blocking the connection request from the client.
(One user who insisted that the firewall had been turned off turned out to have had two active firewalls (firewalld and ufw)
both running on the server!) If possible, either turn off the firewall
to see if that is the problem, or get three consecutive network ports,
starting at port n, all three in the range 1024-65535, opened for both tcp and udp, and use “uxplay -p n”
(or open UDP 6000, 6001, 6011 TCP 7000,7001,7100 and use “uxplay -p”).

3. Problems after the client-server connection has been made:

For such problems, use “uxplay -d ” (debug log option) to see what is happening: it will show how far the connection process gets before
the failure occurs.

Most such problems are due to a GStreamer plugin that doesn’t work on your system: (by default,
GStreamer uses an algorithm to guess what is the “best
plugin to use on your system). A common case is that the GStreamer VAAPI plugin
(for hardware-accelerated intel graphics) is being used on a system with nVidia graphics,
If you use an
nVidia graphics card, make sure that the gstreamer1.0-vaapi
plugin for Intel graphics is NOT installed (uninstall it if it is installed!).
(You can test for this by explicitly choosing the GStreamer videosink with option
“-vs ximagesink” or “-vs xvimagesink”, to see if this fixes the problem, or “-vs vaapisink” to see if this
reproduces the problem.)

There are some reports of other GStreamer problems with hardware-accelerated Intel graphics. One user
(on Debian) solved this with “sudo apt install intel-media-va-driver-non-free”. This is a driver for 8’th (or later) generation
“*-lake” Intel chips, that seems to be related to VAAPI accelerated graphics.

You can try to fix audio problems by using the “-as audiosink” option to choose the GStreamer audiosink , rather than
have autoaudiosink pick one for you. The command “gst_inspect-1.0 | grep Sink | grep Audio” ” will show you which audiosinks are
available on your system. (Replace “Audio” by “Video” to see videosinks). Some possible audiosinks are pulsesink, alsasink, osssink, oss4sink,
and osxaudiosink (macOS).

If you ran cmake with “-DZOOMFIX=ON”, check if the problem is still there without ZOOMFIX.
ZOOMFIX is only applied to the default videosink choice (“autovideosink”) and the two X11 videosinks
“ximagesink” and “xvimagesink”. ZOOMFIX is only designed for these last two; if
autovideosink chooses a different videosink, ZOOMFIX is now ignored.
If you are using the X11 windowing system (standard on Linux), and have trouble with screen-sharing on Zoom, use
ZOOMFIX and “-vs xvimagesink” (or “-vs ximagesink” if the previous choice doesn’t work).

As other videosink choices are not affected by ZOOMFIX, they may or may not be visible to screen-sharing apps.
Cairo-based windows created on Linux with “-vs gtksink” are visible to screen-sharing aps without ZOOMFIX; windows on macOS created by
“-vs glimagesink” (default choice) and “-vs osximagesink” are also visible.

The “OpenGL renderer” window created on Linux by “-vs glimagesink” sometimes does not close properly when its “close” button is clicked.
(this is a GStreamer issue). You may need to terminate uxplay with Ctrl-C to close a “zombie” OpenGl window.

4. GStreamer issues (missing plugins, etc.):

To troubleshoot GStreamer execute “export GST_DEBUG=2”
to set the GStreamer debug-level environment-variable in the terminal
where you will run uxplay, so that you see warning and error messages;
(replace “2” by “4” to see much (much) more of what is happening inside
GStreamer). Run “gst-inspect-1.0” to see which GStreamer plugins are
installed on your system.

Some extra GStreamer packages for special plugins may need to be installed (or reinstalled: a user using a Wayland display system as an alternative to X11
reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstreamer1.0-x was installed, presumably for Wayland’s X11-compatibility mode).
Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in
other required GStreamer packages as dependencies, but will not install all possible plugins.

5. Failure to decrypt ALL video and audio streams from a particular (older) client:

This triggers an error message, and will be due to use of an incorrect protocol for getting the AES decryption key from the client.

Modern Apple clients use a more-encrypted protocol than older ones.
Which protocol is used by UxPlay depends on the client User-Agent string (reported by the client and now shown in the terminal output).
iOS 9 and 10 clients only use iTunes FairPlay encryption on the AES decryption key they send to the server.
Somewhere around iOS sourceVersion 330 (part of the User-Agent string) Apple started to further encrypt it by a sha-512 hash with a “shared secret” created
during the Server-Client pairing process. The sourceVersion 330 above which the extra decryption step is carried out is set in lib/global.h if you need to
change it. (This applies only to audio decryption; the AES key used for video decryption has had this extra encryption since iOS 9).

The third-party non-free Windows software AirMyPC (a commercial AirPlay emulator) uses an unhashed AES key for both audio and video encryption. AirMyPC has a distinctive
User-Agent string, which is detected using two other settings in lib/global.h that can be adjusted if necessary. These settings might be useful if
other AirPlay-emulators need support. Uxplay declares itself to be an AppleTV2,1 with sourceVersion 220.68; this can also be changed in global.h.

Options:

-n server_name (Default: UxPlay); server_name@hostname will be the name that appears offering
AirPlay services to your iPad, iPhone etc, where hostname is the name of the server running uxplay.
This will also now be the name shown above the mirror display (X11) window.

-nh Do not append “@hostname” at the end of the AirPlay server name.

-s wxh (e.g. -s 1920×1080 , which is the default ) sets the display resolution (width and height,
in pixels). (This may be a
request made to the AirPlay client, and perhaps will not
be the final resolution you get.) w and h are whole numbers with four
digits or less. Note that the height pixel size is the controlling
one used by the client for determining the streaming format; the width is
dynamically adjusted to the shape of the image (portrait or landscape
format, depending on how an iPad is held, for example).

-s wxh@r As above, but also informs the AirPlay client about the screen
refresh rate of the display. Default is r=60 (60 Hz); r is a whole number
with three digits or less. Values greater than 255 are invalid.

-fps n sets a maximum frame rate (in frames per second) for the AirPlay
client to stream video; n must be a whole number with 3 digits or less.
(The client may choose to serve video at any frame rate lower
than this; default is 30 fps.) A setting
below 30 fps might be useful to reduce latency if you are running more than
one instance of uxplay at the same time. Values greater than 255 are
ignored. This setting is only an advisory to the client device, so setting
a high value will not force a high framerate.
(You can test using “-vs fpsdisplaysink” to see what framerate is being
received.)

-o turns on an “overscanned” option for the display window. This
reduces the image resolution by using some of the pixels requested
by option -s wxh (or their default values 1920×1080) by adding an empty
boundary frame of unused pixels (which would be lost in a full-screen
display that overscans, and is not displayed by gstreamer).
Recommendation: don’t use this option unless there is some special
reason to use it.

-p allows you to select the network ports used by UxPlay (these need
to be opened if the server is behind a firewall). By itself, -p sets
“legacy” ports TCP 7100, 7000, 7001, UDP 6000, 6001, 7011. -p n (e.g. -p
35000) sets TCP and UDP ports n, n+1, n+2. -p n1,n2,n3 (comma-separated
values) sets each port separately; -p n1,n2 sets ports n1,n2,n2+1. -p tcp n
or -p udp n sets just the TCP or UDP ports. Ports must be in the range
[1024-65535].

If the -p option is not used, the ports are chosen dynamically (randomly),
which will not work if a firewall is running.

-m generates a random MAC address to use instead of the true hardware MAC
number of the computer’s network card. (Different server_name, MAC
addresses, and network ports are needed for each running uxplay if you
attempt to run two instances of uxplay on the same computer.)
If UxPlay fails to find the true MAC address of a network card, (more
specifically, the MAC address used by the first active network interface detected)
a random MAC address will be used even if option -m was not specifed.
(Note that a random MAC address will be different each time UxPlay is started).

Also: image transforms that had been added to RPiPlay have been ported to UxPlay:

-f {H|V|I} implements “videoflip” image transforms: H = horizontal flip
(right-left flip, or mirror image); V = vertical flip ; I =
180 degree rotation or inversion (which is the combination of H with V).

-r {R|L} 90 degree Right (clockwise) or Left (counter-clockwise)
rotations; these are carried out after any -f transforms.

-vs videosink chooses the GStreamer videosink, instead of letting
autovideosink pick it for you. Some videosink choices are: ximagesink, xvimagesink,
vaapisink (for intel graphics), gtksink, glimagesink, waylandsink, osximagesink (for macOS), or
fpsdisplaysink (which shows the streaming framerate in fps). Using quotes
“…” might allow some parameters to be included with the videosink name.
(Some choices of videosink might not work on your system.)

-vs 0 suppresses display of streamed video, but plays streamed audio. (The client’s screen
is still mirrored at a reduced rate of 1 frame per second, but is not rendered or displayed.) This
feature (which streams audio in AAC audio format) is now probably unneeded, as UxPlay can now
stream superior-quality Apple Lossless audio without video in Airplay non-mirror mode.

-as audiosink chooses the GStreamer audiosink, instead of letting
autoaudiosink pick it for you. Some audiosink choices are: pulsesink, alsasink,
osssink, oss4sink, and osxaudiosink (for macOS). Using quotes
“…” might allow some parameters to be included with the audiosink name.
(Some choices of audiosink might not work on your system.)

-as 0 (or just -a) suppresses playing of streamed audio, but displays streamed video.

-t timeout will cause the server to relaunch (without stopping uxplay) if no connections
have been present during the previous timeout seconds. You may wish to use this if the Server
is not visible to new Clients that were inactive when the Server was launched, and an idle Bonjour
registration eventually becomes unavailable for new connections (this is a workaround for what
may be due to a problem with your dns-sd or Avahi setup).


This option should not be used on macOS, as a window created
by GStreamer does not terminate correctly (it causes a segfault)
if it is still open when the GStreamer pipeline is closed.

1.44 2021-12-13 Omit hash of aeskey with ecdh_secret if sourceVersion <= 280.33 (this supports AirMyPC); internal rearrangement of where this hash is done. Replace decodebin by h264-specific elements in the GStreamer video pipeline. Fully report initial communications between
client and server in -d debug mode.

1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment
of informational/debug messages, etc., updated README.

1.42 2021-11-20 Fix MAC detection to work with modern Linux interface naming practices, MacOS and *BSD.

1.41 2021-1



Join the pack! Join 8000+ others registered users, and get chat, make groups, post updates and make friends around the world!
www.knowasiak.com/register/
Read More

Knowasiak
WRITTEN BY

Knowasiak

Hey! look, i give tutorials to all my users and i help them!

you're currently offline