Merge pull request #152 from FDH2/master

UxPlay 1.68
This commit is contained in:
antimof
2024-01-02 13:08:57 +03:00
committed by GitHub
15 changed files with 509 additions and 115 deletions

View File

@@ -1,6 +1,6 @@
<h1
id="uxplay-1.67-airplay-mirror-and-airplay-audio-server-for-linux-macos-and-unix-now-also-runs-on-windows.">UxPlay
1.67: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix
id="uxplay-1.68-airplay-mirror-and-airplay-audio-server-for-linux-macos-and-unix-now-also-runs-on-windows.">UxPlay
1.68: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix
(now also runs on Windows).</h1>
<h3
id="now-developed-at-the-github-site-httpsgithub.comfdh2uxplay-where-all-user-issues-should-be-posted-and-latest-versions-can-be-found.">Now
@@ -9,9 +9,13 @@ href="https://github.com/FDH2/UxPlay">https://github.com/FDH2/UxPlay</a>
(where ALL user issues should be posted, and latest versions can be
found).</h3>
<ul>
<li><em><strong>NEW in v1.67</strong>: support for one-time Apple-style
“pin” code client authentication (“client-server pairing”) when the
option “-pin” is used.</em></li>
<li><em><strong>NEW in v1.68</strong>: Volume-control improvements, plus
improved support for Apple-style one-time “pin” codes introduced in
1.67: a register of pin-registered clients can now optionally be
maintained to check returning clients; a simpler method for generating a
persistent public key (based on the MAC address, which can be set in the
UxPlay startup file) is now the default. (The OpenSSL “pem-file” method
introduced in 1.67 is still available with the -key” option.)</em></li>
</ul>
<h2 id="highlights">Highlights:</h2>
<ul>
@@ -461,12 +465,17 @@ clients to “pair” with the UxPlay server the first time they connect to
it, by entering a 4-digit pin code that is displayed on the UxPlay
terminal. (This is optional, but sometimes required if the client is a
corporately-owned and -managed device with MDM Mobile Device
Management.) Pairing occurs just once, is curently only recorded in the
client, and persists unless the UxPlay public key (stored in
$HOME/.uxplay.pem, or elsewhere if option
<code>-key &lt;filename&gt;</code> is used) is moved or deleted, after
which a new key is generated. (Non-Apple clients might not implement the
persistence feature.)</p></li>
Management.) Pairing occurs just once, is currently only recorded by the
client unless the -reg option is used, and persists until the UxPlay
public key is changed. By default (since v1.68) the public key is now
generated using the “Device ID”, which is either the servers hardware
MAC address, or can be set with the -m option (most conveniently using
the startup option file). (Storage of a more securely-generated
persistent key as an OpenSSL “pem” file is still available with the -key
option). For use of uxplay in a more public environment, a list of
previously-registered clients can (since v1.68) be optionally-maintained
using the -reg option: without this option, returning clients claiming
to be registered are just trusted and not checked.</p></li>
<li><p>By default, UxPlay is locked to its current client until that
client drops the connection; since UxPlay-1.58, the option
<code>-nohold</code> modifies this behavior so that when a new client
@@ -508,6 +517,13 @@ on the client to match audio on the server, so leads to a slight delay
before a pause or track-change initiated on the client takes effect on
the audio played by the server.</li>
</ul>
<p>AirPlay volume-control attenuates volume (gain) by up to -30dB: the
range -30dB:0dB can be rescaled from <em>Low</em>:0, or
<em>Low</em>:<em>High</em>, using the option <code>-db</code> (“-db
<em>Low</em>” or “-db <em>Low</em>:<em>High</em>”), <em>Low</em> must be
negative. Rescaling is linear in decibels. The option
<code>-taper</code> provides a “tapered” AirPlay volume-control profile
some users may prefer.</p>
<p>The -vsync and -async options also allow an optional positive (or
negative) audio-delay adjustment in <em>milliseconds</em> for
fine-tuning : <code>-vsync 20.5</code> delays audio relative to video by
@@ -895,6 +911,14 @@ UxPlay startups. As long as this file is not deleted or moved, a client
will not have to re-authenticate after an initial authentication.
<em>(Add a “pin” entry in the UxPlay startup file if you wish the UxPlay
server to use this protocol).</em></p>
<p><strong>-reg [<em>filename</em>]</strong>: (since v1.68). This option
maintains a list of previously-pin-registered clients in
$HOME/.uxplay.register (or optionally, in <em>filename</em>). Without
this option, returning clients claiming to be already pin-registered are
trusted and not checked. (This option may be useful if UxPlay is used in
a more public environment, to record client details; the register is
text, one line per client, with clients public key (base-64 format),
Device ID, and Device name.)</p>
<p><strong>-vsync [x]</strong> (In Mirror mode:) this option
(<strong>now the default</strong>) uses timestamps to synchronize audio
with video on the server, with an optional audio delay in (decimal)
@@ -924,6 +948,24 @@ have any effect</em>.</p>
Audio-only mode, but this option may be useful as a command-line option
to switch off a <code>-async</code> option set in a “uxplayrc”
configuration file.</p>
<p><strong>-db <em>low</em>[:<em>high</em>]</strong> Rescales the
AirPlay volume-control attenuation (gain) from -30dB:0dB to
<em>low</em>:0dB or <em>low</em>:<em>high</em>. The lower limit
<em>low</em> must be negative (attenuation); the upper limit
<em>high</em> can be either sign. (GStreamer restricts
volume-augmentation by <em>high</em> so that it cannot exceed +20dB).
The rescaling is “flat”, so that for -db -50:10, a change in Airplay
attenuation by -7dB is translated to a -7 x (60/30) = -14dB attenuation,
and the maximum volume (AirPlay 0dB) is a 10dB augmentation, and Airplay
-30dB would become -50dB. Note that the minimum AirPlay value (-30dB
exactly) is translated to “mute”.</p>
<p><strong>-taper</strong> Provides a “tapered” Airplay volume-control
profile (matching the one called “dasl-tapering” in <a
href="https://github.com/mikebrady/shairport-sync">shairport-sync</a>):
each time the length of the volume slider (or the number of steps above
mute, where 16 steps = full volume) is reduced by 50%, the perceived
volume is halved (a 10dB attenuation). (This is modified at low volumes,
to use the “untapered” volume if it is louder.)</p>
<p><strong>-s wxh</strong> (e.g. -s 1920x1080 , 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
@@ -1107,13 +1149,27 @@ card, (more specifically, the MAC address used by the first active
network interface detected) a random MAC address will be used even if
option <strong>-m</strong> was not specified. (Note that a random MAC
address will be different each time UxPlay is started).</p>
<p><strong>-key [<em>filename</em>]</strong>: By default, the storage of
the Server private key is in the file $HOME/.uxplay.pem. Use the “-key
<em>filename</em>” option to change this location. This option should be
set in the UxPlay startup file as a line “<code>key filename</code>” (no
initial “-”), where <code>filename</code> is a full path. The filename
may be enclosed in quotes (<code>"...."</code>), (and must be, if the
filename has any blank spaces).</p>
<p><strong>-key [<em>filename</em>]</strong>: This (more secure) option
for generating and storing a persistant public key (needed for the -pin
option) has been replaced by default with a (less secure) method which
generates a key from the servers “device ID” (MAC address, which can be
changed with the -m option, conveniently as a startup file option). When
the -key option is used, a securely generated keypair is generated and
stored in <code>$HOME/.uxplay.pem</code>, if that file does not exist,
or read from it, if it exists. (Optionally, the key can be stored in
<em>filename</em>.) This method is more secure than the new default
method, (because the Device ID is broadcast in the DNS_SD announcement)
but still leaves the private key exposed to anyone who can access the
pem file. Because the default (but “less-secure”) “Device ID” method is
simpler, and security of client access to uxplay is unlikely to be an
important issue, the -key option is no longer recommended.</p>
<p>By default, the storage of the Server private key is in the file
$HOME/.uxplay.pem. Use the “-key <em>filename</em>” option to change
this location. This option should be set in the UxPlay startup file as a
line “<code>key filename</code>” (no initial “-”), where
<code>filename</code> is a full path. The filename may be enclosed in
quotes (<code>"...."</code>), (and must be, if the filename has any
blank spaces).</p>
<p><strong>-dacp [<em>filename</em>]</strong>: Export current client
DACP-ID and Active-Remote key to file: default is $HOME/.uxplay.dacp.
(optionally can be changed to <em>filename</em>). Can be used by remote
@@ -1463,6 +1519,14 @@ an AppleTV6,2 with sourceVersion 380.20.1 (an AppleTV 4K 1st gen,
introduced 2017, running tvOS 12.2.1), so it does not seem to matter
what version UxPlay claims to be.</p>
<h1 id="changelog">Changelog</h1>
<p>1.68 2023-12-31 New simpler (default) method for generating a
persistent public key from the server MAC address (which can now be set
with the -m option). (The previous method is still available with -key
option). New option -reg to maintain a register of pin-authenticated
clients. Corrected volume-control: now interprets AirPlay volume range
-30dB:0dB as decibel gain attenuation, with new option -db low[:high]
for “flat” rescaling of the dB range. Add -taper option for a “tapered”
AirPlay volume-control profile.</p>
<p>1.67 2023-11-30 Add support for Apple-style one-time pin
authentication of clients with option “-pin”: (uses SRP6a authentication
protocol and public key persistence). Detection with error message of

View File

@@ -1,9 +1,12 @@
# UxPlay 1.67: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
# UxPlay 1.68: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
### Now developed at the GitHub site [https://github.com/FDH2/UxPlay](https://github.com/FDH2/UxPlay) (where ALL user issues should be posted, and latest versions can be found).
* _**NEW in v1.67**: support for one-time Apple-style "pin" code client authentication ("client-server
pairing") when the option "-pin" is used._
* _**NEW in v1.68**: Volume-control improvements, plus improved support for Apple-style one-time "pin" codes introduced in 1.67: a
register of pin-registered clients can now optionally be maintained to check returning clients; a simpler method for generating
a persistent public key (based on the MAC address, which can be set in the UxPlay startup file) is now the default. (The OpenSSL
"pem-file" method introduced in 1.67 is still available with the '-key" option.)_
## Highlights:
@@ -375,10 +378,14 @@ help with this or other problems.
* Since v 1.67, the UxPlay option "`-pin`" allows clients to "pair" with the UxPlay server
the first time they connect to it, by entering
a 4-digit pin code that is displayed on the UxPlay terminal. (This is optional, but sometimes required if the client is a
corporately-owned and -managed device with MDM Mobile Device Management.) Pairing occurs just once, is curently only
recorded in the client, and persists unless the
UxPlay public key (stored in $HOME/.uxplay.pem, or elsewhere if option `-key <filename>` is used) is moved or deleted, after
which a new key is generated. (Non-Apple clients might not implement the persistence feature.)
corporately-owned and -managed device with MDM Mobile Device Management.) Pairing occurs just once, is currently only
recorded by the client unless the -reg option is used, and persists until the
UxPlay public key is changed. By default (since v1.68) the public key is now generated using the "Device ID", which is either the server's
hardware MAC address, or
can be set with the -m option (most conveniently using the startup option file). (Storage of a more securely-generated
persistent key as an OpenSSL "pem" file is still available with the -key option). For use of uxplay in a more public environment, a
list of previously-registered clients can (since v1.68) be optionally-maintained using the -reg option: without this
option, returning clients claiming to be registered are just trusted and not checked.
* By default, UxPlay is locked to
its current client until that client drops the connection; since UxPlay-1.58, the option `-nohold` modifies this
@@ -408,6 +415,10 @@ if you want to follow the Apple Music lyrics on the client while listening to su
delays the video on the client to match audio on the server, so leads to
a slight delay before a pause or track-change initiated on the client takes effect on the audio played by the server.
AirPlay volume-control attenuates volume (gain) by up to -30dB: the range -30dB:0dB can be rescaled from _Low_:0, or _Low_:_High_, using the
option `-db` ("-db _Low_ " or "-db _Low_:_High_ "), _Low_ must be negative. Rescaling is linear in decibels. The option ```-taper``` provides a "tapered" AirPlay volume-control
profile some users may prefer.
The -vsync and -async options
also allow an optional positive (or negative) audio-delay adjustment in _milliseconds_ for fine-tuning : `-vsync 20.5`
delays audio relative to video by 0.0205 secs; a negative value advances it.)
@@ -708,6 +719,12 @@ with "`#`" are treated as comments, and ignored. Command line options supersede
client will not have to re-authenticate after an initial authentication. _(Add a "pin" entry in the UxPlay startup file if you wish the
UxPlay server to use this protocol)._
**-reg [_filename_]**: (since v1.68). This option maintains a list of previously-pin-registered clients in $HOME/.uxplay.register (or optionally, in _filename_).
Without this option, returning clients claiming to be already pin-registered are trusted and not checked. (This option may be useful if UxPlay is used
in a more public environment, to record client details; the register is text, one line per client, with client's public
key (base-64 format), Device ID, and Device name.)
**-vsync [x]** (In Mirror mode:) this option (**now the default**) uses timestamps to synchronize audio with video on the server,
with an optional audio delay in (decimal) milliseconds (_x_ = "20.5" means 0.0205 seconds delay: positive or
negative delays less than a second are allowed.) It is needed on low-power systems such as Raspberry Pi without hardware
@@ -728,6 +745,18 @@ using UxPlay as a second monitor for a mac computer, or monitoring a webcam; wit
**-async no**. This is the still the default behavior in Audio-only mode, but this option may be useful as a command-line option to switch off a
`-async` option set in a "uxplayrc" configuration file.
**-db _low_[:_high_]** Rescales the AirPlay volume-control attenuation (gain) from -30dB:0dB to _low_:0dB or _low_:_high_. The lower limit _low_
must be negative (attenuation); the upper limit _high_ can be either sign. (GStreamer restricts volume-augmentation by _high_ so that it
cannot exceed +20dB).
The rescaling is "flat", so that for -db -50:10, a change in Airplay attenuation by -7dB is translated to a -7 x (60/30) = -14dB attenuation,
and the maximum volume (AirPlay 0dB) is a 10dB augmentation, and Airplay -30dB would become -50dB. Note that the minimum AirPlay value (-30dB exactly)
is translated to "mute".
**-taper** Provides a "tapered" Airplay volume-control profile (matching the one called "dasl-tapering"
in [shairport-sync](https://github.com/mikebrady/shairport-sync)): each time the length of the
volume slider (or the number of steps above mute, where 16 steps = full volume) is reduced by 50%, the perceived volume is halved (a 10dB attenuation).
(This is modified at low volumes, to use the "untapered" volume if it is louder.)
**-s wxh** (e.g. -s 1920x1080 , 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
@@ -891,7 +920,16 @@ which will not work if a firewall is running.
a random MAC address will be used even if option **-m** was not specified.
(Note that a random MAC address will be different each time UxPlay is started).
**-key [_filename_]**: By default, the storage of the Server private key is in the file $HOME/.uxplay.pem. Use
**-key [_filename_]**: This (more secure) option for generating and storing a persistant public key (needed for
the -pin option) has been replaced by default with a (less secure) method which generates a key from the server's "device ID"
(MAC address, which can be changed with the -m option, conveniently as a startup file option).
When the -key option is used, a securely generated keypair is generated and stored in `$HOME/.uxplay.pem`, if that file does not exist,
or read from it, if it exists. (Optionally, the key can be stored in _filename_.) This method is more secure than the new default method,
(because the Device ID is broadcast in the DNS_SD announcement) but still leaves the private key exposed to anyone who can access the pem file.
Because the default (but "less-secure") "Device ID" method is simpler, and security of client access to uxplay is unlikely to be an important issue,
the -key option is no longer recommended.
By default, the storage of the Server private key is in the file $HOME/.uxplay.pem. Use
the "-key _filename_" option to change this location. This option should be set in the UxPlay startup file
as a line "`key filename`" (no initial "-"), where ``filename`` is a full path. The filename may be enclosed
in quotes (`"...."`), (and must be, if the filename has any blank spaces).
@@ -1156,6 +1194,13 @@ tvOS 12.2.1), so it does not seem to matter what version UxPlay claims to be.
# Changelog
1.68 2023-12-31 New simpler (default) method for generating a persistent public key from the server MAC
address (which can now be set with the -m option). (The previous method is still available
with -key option). New option -reg to maintain a register of pin-authenticated clients. Corrected
volume-control: now interprets AirPlay volume range -30dB:0dB as decibel gain attenuation,
with new option -db low[:high] for "flat" rescaling of the dB range. Add -taper option for a "tapered"
AirPlay volume-control profile.
1.67 2023-11-30 Add support for Apple-style one-time pin authentication of clients with option "-pin":
(uses SRP6a authentication protocol and public key persistence). Detection with error message
of (currently) unsupported H265 video when requesting high resolution over wired ethernet.

View File

@@ -1,10 +1,15 @@
# UxPlay 1.67: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
# UxPlay 1.68: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
### Now developed at the GitHub site <https://github.com/FDH2/UxPlay> (where ALL user issues should be posted, and latest versions can be found).
- ***NEW in v1.67**: support for one-time Apple-style "pin" code
client authentication ("client-server pairing") when the option
"-pin" is used.*
- ***NEW in v1.68**: Volume-control improvements, plus improved
support for Apple-style one-time "pin" codes introduced in 1.67: a
register of pin-registered clients can now optionally be maintained
to check returning clients; a simpler method for generating a
persistent public key (based on the MAC address, which can be set in
the UxPlay startup file) is now the default. (The OpenSSL "pem-file"
method introduced in 1.67 is still available with the '-key"
option.)*
## Highlights:
@@ -451,11 +456,18 @@ below for help with this or other problems.
entering a 4-digit pin code that is displayed on the UxPlay
terminal. (This is optional, but sometimes required if the client is
a corporately-owned and -managed device with MDM Mobile Device
Management.) Pairing occurs just once, is curently only recorded in
the client, and persists unless the UxPlay public key (stored in
\$HOME/.uxplay.pem, or elsewhere if option `-key <filename>` is
used) is moved or deleted, after which a new key is generated.
(Non-Apple clients might not implement the persistence feature.)
Management.) Pairing occurs just once, is currently only recorded by
the client unless the -reg option is used, and persists until the
UxPlay public key is changed. By default (since v1.68) the public
key is now generated using the "Device ID", which is either the
server's hardware MAC address, or can be set with the -m option
(most conveniently using the startup option file). (Storage of a
more securely-generated persistent key as an OpenSSL "pem" file is
still available with the -key option). For use of uxplay in a more
public environment, a list of previously-registered clients can
(since v1.68) be optionally-maintained using the -reg option:
without this option, returning clients claiming to be registered are
just trusted and not checked.
- By default, UxPlay is locked to its current client until that client
drops the connection; since UxPlay-1.58, the option `-nohold`
@@ -498,6 +510,12 @@ helped to prevent this previously when timestamps were not being used.)
slight delay before a pause or track-change initiated on the client
takes effect on the audio played by the server.
AirPlay volume-control attenuates volume (gain) by up to -30dB: the
range -30dB:0dB can be rescaled from *Low*:0, or *Low*:*High*, using the
option `-db` ("-db *Low*" or "-db *Low*:*High*"), *Low* must be
negative. Rescaling is linear in decibels. The option `-taper` provides
a "tapered" AirPlay volume-control profile some users may prefer.
The -vsync and -async options also allow an optional positive (or
negative) audio-delay adjustment in *milliseconds* for fine-tuning :
`-vsync 20.5` delays audio relative to video by 0.0205 secs; a negative
@@ -895,6 +913,14 @@ re-authenticate after an initial authentication. *(Add a "pin" entry in
the UxPlay startup file if you wish the UxPlay server to use this
protocol).*
**-reg \[*filename*\]**: (since v1.68). This option maintains a list of
previously-pin-registered clients in \$HOME/.uxplay.register (or
optionally, in *filename*). Without this option, returning clients
claiming to be already pin-registered are trusted and not checked. (This
option may be useful if UxPlay is used in a more public environment, to
record client details; the register is text, one line per client, with
client's public key (base-64 format), Device ID, and Device name.)
**-vsync \[x\]** (In Mirror mode:) this option (**now the default**)
uses timestamps to synchronize audio with video on the server, with an
optional audio delay in (decimal) milliseconds (*x* = "20.5" means
@@ -925,6 +951,24 @@ changing this does not seem to have any effect*.
mode, but this option may be useful as a command-line option to switch
off a `-async` option set in a "uxplayrc" configuration file.
**-db *low*\[:*high*\]** Rescales the AirPlay volume-control attenuation
(gain) from -30dB:0dB to *low*:0dB or *low*:*high*. The lower limit
*low* must be negative (attenuation); the upper limit *high* can be
either sign. (GStreamer restricts volume-augmentation by *high* so that
it cannot exceed +20dB). The rescaling is "flat", so that for -db
-50:10, a change in Airplay attenuation by -7dB is translated to a -7 x
(60/30) = -14dB attenuation, and the maximum volume (AirPlay 0dB) is a
10dB augmentation, and Airplay -30dB would become -50dB. Note that the
minimum AirPlay value (-30dB exactly) is translated to "mute".
**-taper** Provides a "tapered" Airplay volume-control profile (matching
the one called "dasl-tapering" in
[shairport-sync](https://github.com/mikebrady/shairport-sync)): each
time the length of the volume slider (or the number of steps above mute,
where 16 steps = full volume) is reduced by 50%, the perceived volume is
halved (a 10dB attenuation). (This is modified at low volumes, to use
the "untapered" volume if it is louder.)
**-s wxh** (e.g. -s 1920x1080 , 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
@@ -1125,12 +1169,27 @@ network interface detected) a random MAC address will be used even if
option **-m** was not specified. (Note that a random MAC address will be
different each time UxPlay is started).
**-key \[*filename*\]**: By default, the storage of the Server private
key is in the file \$HOME/.uxplay.pem. Use the "-key *filename*" option
to change this location. This option should be set in the UxPlay startup
file as a line "`key filename`" (no initial "-"), where `filename` is a
full path. The filename may be enclosed in quotes (`"...."`), (and must
be, if the filename has any blank spaces).
**-key \[*filename*\]**: This (more secure) option for generating and
storing a persistant public key (needed for the -pin option) has been
replaced by default with a (less secure) method which generates a key
from the server's "device ID" (MAC address, which can be changed with
the -m option, conveniently as a startup file option). When the -key
option is used, a securely generated keypair is generated and stored in
`$HOME/.uxplay.pem`, if that file does not exist, or read from it, if it
exists. (Optionally, the key can be stored in *filename*.) This method
is more secure than the new default method, (because the Device ID is
broadcast in the DNS_SD announcement) but still leaves the private key
exposed to anyone who can access the pem file. Because the default (but
"less-secure") "Device ID" method is simpler, and security of client
access to uxplay is unlikely to be an important issue, the -key option
is no longer recommended.
By default, the storage of the Server private key is in the file
\$HOME/.uxplay.pem. Use the "-key *filename*" option to change this
location. This option should be set in the UxPlay startup file as a line
"`key filename`" (no initial "-"), where `filename` is a full path. The
filename may be enclosed in quotes (`"...."`), (and must be, if the
filename has any blank spaces).
**-dacp \[*filename*\]**: Export current client DACP-ID and
Active-Remote key to file: default is \$HOME/.uxplay.dacp. (optionally
@@ -1497,6 +1556,15 @@ what version UxPlay claims to be.
# Changelog
1.68 2023-12-31 New simpler (default) method for generating a persistent
public key from the server MAC address (which can now be set with the -m
option). (The previous method is still available with -key option). New
option -reg to maintain a register of pin-authenticated clients.
Corrected volume-control: now interprets AirPlay volume range -30dB:0dB
as decibel gain attenuation, with new option -db low\[:high\] for "flat"
rescaling of the dB range. Add -taper option for a "tapered" AirPlay
volume-control profile.
1.67 2023-11-30 Add support for Apple-style one-time pin authentication
of clients with option "-pin": (uses SRP6a authentication protocol and
public key persistence). Detection with error message of (currently)

View File

@@ -35,6 +35,8 @@
#include "utils.h"
#define SALT_PK "UxPlay-Persistent-Not-Secure-Public-Key"
struct aes_ctx_s {
EVP_CIPHER_CTX *cipher_ctx;
uint8_t key[AES_128_BLOCK_SIZE];
@@ -352,7 +354,7 @@ struct ed25519_key_s {
EVP_PKEY *pkey;
};
ed25519_key_t *ed25519_key_generate(const char *keyfile, int *result) {
ed25519_key_t *ed25519_key_generate(const char *device_id, const char *keyfile, int *result) {
ed25519_key_t *key;
EVP_PKEY_CTX *pctx;
BIO *bp;
@@ -379,7 +381,15 @@ ed25519_key_t *ed25519_key_generate(const char *keyfile, int *result) {
new_pk = true;
}
} else {
new_pk = true;
/* generate (insecure) persistent keypair using device_id */
unsigned char hash[SHA512_DIGEST_LENGTH];
char salt[] = SALT_PK;
sha_ctx_t *ctx = sha_init();
sha_update(ctx, (const unsigned char *) salt, (unsigned int) strlen(salt));
sha_update(ctx, (const unsigned char *) device_id, (unsigned int) strlen(device_id));
sha_final(ctx, hash, NULL);
sha_destroy(ctx);
key->pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, (const unsigned char *) hash, ED25519_KEY_SIZE);
}
if (new_pk) {
@@ -546,3 +556,27 @@ void sha_destroy(sha_ctx_t *ctx) {
int get_random_bytes(unsigned char *buf, int num) {
return RAND_bytes(buf, num);
}
#include <stdio.h>
void pk_to_base64(const unsigned char *pk, int pk_len, char *pk_base64, int len) {
memset(pk_base64, 0, len);
int len64 = (4 * (pk_len /3)) + (pk_len % 3 ? 4 : 0);
assert (len > len64);
BIO *b64 = BIO_new(BIO_f_base64());
BIO *bio = BIO_new(BIO_s_mem());
BUF_MEM *bufferPtr;
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, pk, pk_len);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
BIO_free_all(bio);
memcpy(pk_base64,(*bufferPtr).data, len64);
}

View File

@@ -67,6 +67,7 @@ x25519_key_t *x25519_key_from_raw(const unsigned char data[X25519_KEY_SIZE]);
void x25519_key_get_raw(unsigned char data[X25519_KEY_SIZE], const x25519_key_t *key);
void x25519_key_destroy(x25519_key_t *key);
int get_random_bytes(unsigned char *buf, int num);
void pk_to_base64(const unsigned char *pk, int pk_len, char *pk_base64, int len);
void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_key_t *ours, const x25519_key_t *theirs);
@@ -82,7 +83,7 @@ int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *pl
typedef struct ed25519_key_s ed25519_key_t;
ed25519_key_t *ed25519_key_generate(const char * keyfile, int * result);
ed25519_key_t *ed25519_key_generate(const char *device_id, const char * keyfile, int * result);
ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]);
void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key);
/*

View File

@@ -84,7 +84,7 @@ derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsig
}
pairing_t *
pairing_init_generate(const char * keyfile, int *result)
pairing_init_generate(const char *device_id, const char *keyfile, int *result)
{
pairing_t *pairing;
*result = 0;
@@ -93,7 +93,7 @@ pairing_init_generate(const char * keyfile, int *result)
return NULL;
}
pairing->ed = ed25519_key_generate(keyfile, result);
pairing->ed = ed25519_key_generate(device_id, keyfile, result);
return pairing;
}
@@ -136,7 +136,7 @@ pairing_session_init(pairing_t *pairing)
session->status = STATUS_INITIAL;
session->srp = NULL;
session->pair_setup = false;
return session;
}
@@ -447,8 +447,20 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
return epk_len;
}
void access_client_session_data(pairing_session_t *session, char **username, unsigned char **client_pk, bool *setup) {
*username = session->username;
*client_pk = session->client_pk;
void access_client_session_data(pairing_session_t *session, char **username, char **client_pk64, bool *setup) {
int len64 = 4 * (1 + (ED25519_KEY_SIZE / 3)) + 1;
setup = &(session->pair_setup);
*username = session->username;
if (setup) {
*client_pk64 = (char *) malloc(len64);
pk_to_base64(session->client_pk, ED25519_KEY_SIZE, *client_pk64, len64);
} else {
*client_pk64 = NULL;
}
}
void ed25519_pk_to_base64(const unsigned char *pk, char **pk64) {
int len64 = 4 * (1 + (ED25519_KEY_SIZE / 3)) + 1;
*pk64 = (char *) malloc(len64);
pk_to_base64(pk, ED25519_KEY_SIZE, *pk64, len64);
}

View File

@@ -36,7 +36,7 @@
typedef struct pairing_s pairing_t;
typedef struct pairing_session_s pairing_session_t;
pairing_t *pairing_init_generate(const char * keyfile, int *result);
pairing_t *pairing_init_generate(const char *device_id, const char *keyfile, int *result);
void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE]);
pairing_session_t *pairing_session_init(pairing_t *pairing);
@@ -60,5 +60,6 @@ int srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const uns
int len_A, unsigned char *proof, int client_proof_len, int proof_len);
int srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing, unsigned char *epk,
unsigned char *auth_tag);
void access_client_session_data(pairing_session_t *session, char **username, unsigned char **client_pk, bool *setup);
void access_client_session_data(pairing_session_t *session, char **username, char **client_pk, bool *setup);
void ed25519_pk_to_base64(const unsigned char *pk, char **pk64);
#endif

View File

@@ -411,7 +411,7 @@ conn_destroy(void *ptr) {
}
raop_t *
raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile) {
raop_init(int max_clients, raop_callbacks_t *callbacks, const char *device_id, const char *keyfile) {
raop_t *raop;
pairing_t *pairing;
httpd_t *httpd;
@@ -443,7 +443,7 @@ raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile) {
/* create a new public key for pairing */
int new_key;
pairing = pairing_init_generate(keyfile, &new_key);
pairing = pairing_init_generate(device_id, keyfile, &new_key);
if (!pairing) {
free(raop);
return NULL;

View File

@@ -60,7 +60,7 @@ struct raop_callbacks_s {
void (*video_report_size)(void *cls, float *width_source, float *height_source, float *width, float *height);
void (*report_client_request) (void *cls, char *deviceid, char *model, char *name, bool *admit);
void (*display_pin) (void *cls, char * pin);
void (*register_client) (void *cls, const char *device_id, const char *pk_str);
void (*register_client) (void *cls, const char *device_id, const char *pk_str, const char *name);
bool (*check_register) (void *cls, const char *pk_str);
void (*export_dacp) (void *cls, const char *active_remote, const char *dacp_id);
};
@@ -68,7 +68,7 @@ typedef struct raop_callbacks_s raop_callbacks_t;
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len,
unsigned short timing_rport, timing_protocol_t *time_protocol);
RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile);
RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks, const char *device_id, const char *keyfile);
RAOP_API void raop_set_log_level(raop_t *raop, int level);
RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls);
RAOP_API int raop_set_plist(raop_t *raop, const char *plist_item, const int value);

View File

@@ -341,15 +341,6 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_ERR, "pair-pin-setup (step 3): client authentication failed\n");
goto authentication_failed;
} else {
bool client_pair_setup;
char *client_device_id;
unsigned char *client_pk;
access_client_session_data(conn->session, &client_device_id, &client_pk, &client_pair_setup);
char * client_pk_str = utils_pk_to_string(client_pk, ED25519_KEY_SIZE);
if (conn->raop->callbacks.register_client) {
conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk_str);
}
free (client_pk_str);
logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-pin-setup success\n");
}
pairing_session_set_setup_status(conn->session);
@@ -442,12 +433,15 @@ raop_handler_pairverify(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ED25519 signature");
}
if (register_check) {
char *pk_str = utils_pk_to_string((const unsigned char *)(data + 4 + X25519_KEY_SIZE), ED25519_KEY_SIZE);
bool registered_client = true;
if (conn->raop->callbacks.check_register) {
registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk_str);
if (conn->raop->callbacks.check_register) {
const unsigned char *pk = data + 4 + X25519_KEY_SIZE;
char *pk64;
ed25519_pk_to_base64(pk, &pk64);
registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk64);
free (pk64);
}
free (pk_str);
if (!registered_client) {
return;
}
@@ -584,12 +578,32 @@ raop_handler_setup(raop_conn_t *conn,
if (conn->raop->callbacks.report_client_request) {
conn->raop->callbacks.report_client_request(conn->raop->callbacks.cls, deviceID, model, name, &admit_client);
}
free (deviceID);
deviceID = NULL;
free (model);
model = NULL;
free (name);
name = NULL;
if (admit_client && deviceID && name && conn->raop->callbacks.register_client) {
bool pending_registration;
char *client_device_id;
char *client_pk; /* encoded as null-terminated base64 string*/
access_client_session_data(conn->session, &client_device_id, &client_pk, &pending_registration);
if (pending_registration) {
if (client_pk && !strcmp(deviceID, client_device_id)) {
conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk, name);
}
}
if (client_pk) {
free (client_pk);
}
}
if (deviceID) {
free (deviceID);
deviceID = NULL;
}
if (model) {
free (model);
model = NULL;
}
if (name) {
free (name);
name = NULL;
}
if (admit_client == false) {
/* client is not authorized to connect */
plist_free(res_root_node);

View File

@@ -37,7 +37,7 @@ void audio_renderer_init(logger_t *logger, const char* audiosink, const bool *au
void audio_renderer_start(unsigned char* compression_type);
void audio_renderer_stop();
void audio_renderer_render_buffer(unsigned char* data, int *data_len, unsigned short *seqnum, uint64_t *ntp_time);
void audio_renderer_set_volume(float volume);
void audio_renderer_set_volume(double volume);
void audio_renderer_flush();
void audio_renderer_destroy();

View File

@@ -132,7 +132,7 @@ void audio_renderer_init(logger_t *render_logger, const char* audiosink, const b
g_object_set(clock, "clock-type", GST_CLOCK_TYPE_REALTIME, NULL);
logger = render_logger;
aac = check_plugin_feature (avdec_aac);
alac = check_plugin_feature (avdec_alac);
@@ -355,12 +355,10 @@ void audio_renderer_render_buffer(unsigned char* data, int *data_len, unsigned s
}
}
void audio_renderer_set_volume(float volume) {
float avol;
if (fabs(volume) < 28) {
avol=floorf(((28-fabs(volume))/28)*10)/10;
g_object_set(renderer->volume, "volume", avol, NULL);
}
void audio_renderer_set_volume(double volume) {
volume = (volume > 10.0) ? 10.0 : volume;
volume = (volume < 0.0) ? 0.0 : volume;
g_object_set(renderer->volume, "volume", volume, NULL);
}
void audio_renderer_flush() {

View File

@@ -1,11 +1,11 @@
.TH UXPLAY "1" "November 2023" "1.67" "User Commands"
.TH UXPLAY "1" "December 2023" "1.68" "User Commands"
.SH NAME
uxplay \- start AirPlay server
.SH SYNOPSIS
.B uxplay
[\fI\,-n name\/\fR] [\fI\,-s wxh\/\fR] [\fI\,-p \/\fR[\fI\,n\/\fR]] [more \fI OPTIONS \/\fR ...]
.SH DESCRIPTION
UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server:
UxPlay 1.68: An open\-source AirPlay mirroring (+ audio streaming) server:
.SH OPTIONS
.TP
.B
@@ -17,6 +17,10 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server:
.IP
without option, pin is random: optionally use fixed pin xxxx.
.TP
\fB\-reg\fI [fn]\fR Keep a register in $HOME/.uxplay.register to verify returning
.IP
client pin-registration; (option: use file "fn" for this)
.TP
\fB\-vsync\fI[x]\fR Mirror mode: sync audio to video using timestamps (default)
.IP
\fIx\fR is optional audio delay: millisecs, decimal, can be neg.
@@ -27,6 +31,13 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server:
.TP
\fB\-async\fR no Switch off audio/(client)video timestamp synchronization.
.TP
\fB\-db\fI l[:h]\fR Set minumum volume attenuation to l dB (decibels, negative);
.IP
optional: set maximum to h dB (+ or -); default -30.0:0.0
.PP
.TP
\fB\-taper\fR Use a "tapered" AirPlay volume-control profile.
.TP
\fB\-s\fR wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]
.TP
\fB\-o\fR Set display "overscanned" mode on (not usually needed)
@@ -106,9 +117,13 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server:
.TP
\fB\-r\fR {R|L} Rotate 90 degrees Right (cw) or Left (ccw)
.TP
\fB\-m\fR Use random MAC address (use for concurrent UxPlay's)
\fB\-m\fI [mac]\fR Set MAC address (also Device ID); use for concurrent UxPlays
.IP
if mac xx:xx:xx:xx:xx:xx is not given, a random MAC is used.
.PP
.TP
\fB\-key\fI fn \fR Store private key in file fn (Default: $HOME/.uxplay.pem)
\fB\-key\fI [fn]\fR Store private key in $HOME/.uxplay.pem (or in file "fn")
.PP
.TP
\fB\-dacp\fI [fn]\fRExport client DACP information to file $HOME/.uxplay.dacp
.IP
@@ -140,13 +155,9 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server:
\fB\-h\fR Displays help information
.SH
FILES
Private key stored (for persistence) in $HOME/.uxplay.pem (can be changed)
.TP
(transient) storage of client DACP info: $HOME/uxplay.dacp (can be changed)
.TP
Options in one of $UXPLAYRC, or ~/.uxplayrc, or ~/.config/uxplayrc
.TP
are applied first (command-line options may modify them). uxplayrc format:
are applied first (command-line options may modify them). Format:
.TP
one option per line,\fI no\fR initial "-"; lines beginning with "#" ignored.
.SH

View File

@@ -26,6 +26,7 @@
#include <unistd.h>
#include <ctype.h>
#include <string>
#include <algorithm>
#include <vector>
#include <fstream>
#include <sstream>
@@ -33,6 +34,7 @@
#include <sys/stat.h>
#include <cstdio>
#include <stdarg.h>
#include <math.h>
#ifdef _WIN32 /*modifications for Windows compilation */
#include <glib.h>
@@ -60,7 +62,7 @@
#include "renderers/video_renderer.h"
#include "renderers/audio_renderer.h"
#define VERSION "1.67"
#define VERSION "1.68"
#define SECOND_IN_USECS 1000000
#define SECOND_IN_NSECS 1000000000UL
@@ -132,6 +134,13 @@ static unsigned short pin = 0;
static std::string keyfile = "";
static std::string mac_address = "";
static std::string dacpfile = "";
static bool registration_list = false;
static std::string pairing_register = "";
static std::vector <std::string> registered_keys;
static double db_low = -30.0;
static double db_high = 0.0;
static bool taper_volume = true;
/* logging */
static void log(int level, const char* format, ...) {
@@ -561,12 +570,17 @@ static void print_info (char *name) {
printf("-n name Specify the network name of the AirPlay server\n");
printf("-nh Do not add \"@hostname\" at the end of AirPlay server name\n");
printf("-pin[xxxx]Use a 4-digit pin code to control client access (default: no)\n");
printf(" without option, pin is random: optionally use fixed pin xxxx\n");
printf(" default pin is random: optionally use fixed pin xxxx\n");
printf("-reg [fn] Keep a register in $HOME/.uxplay.register to verify returning\n");
printf(" client pin-registration; (option: use file \"fn\" for this)\n");
printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n");
printf(" x is optional audio delay: millisecs, decimal, can be neg.\n");
printf("-vsync no Switch off audio/(server)video timestamp synchronization \n");
printf("-async [x]Audio-Only mode: sync audio to client video (default: no)\n");
printf("-async no Switch off audio/(client)video timestamp synchronization\n");
printf("-db l[:h] Set minimum volume attenuation to l dB (decibels, negative);\n");
printf(" optional: set maximum to h dB (+ or -) default: -30.0:0.0 dB\n");
printf("-taper Use a \"tapered\" AirPlay volume-control profile\n");
printf("-s wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]\n");
printf("-o Set display \"overscanned\" mode on (not usually needed)\n");
printf("-fs Full-screen (only works with X11, Wayland and VAAPI)\n");
@@ -607,8 +621,8 @@ static void print_info (char *name) {
printf("-f {H|V|I}Horizontal|Vertical flip, or both=Inversion=rotate 180 deg\n");
printf("-r {R|L} Rotate 90 degrees Right (cw) or Left (ccw)\n");
printf("-m [mac] Set MAC address (also Device ID);use for concurrent UxPlays\n");
printf(" if mac xx:xx:xx:xx:xx:xx is not given, a random mac is used\n");
printf("-key <fn> Store private key in file <fn> (default:$HOME/.uxplay.pem)\n");
printf(" if mac xx:xx:xx:xx:xx:xx is not given, a random MAC is used\n");
printf("-key [fn] Store private key in $HOME/.uxplay.pem (or in file \"fn\")\n");
printf("-dacp [fn]Export client DACP information to file $HOME/.uxplay.dacp\n");
printf(" (option to use file \"fn\" instead); used for client remote\n");
printf("-vdmp [n] Dump h264 video output to \"fn.h264\"; fn=\"videodump\",change\n");
@@ -1030,7 +1044,7 @@ static void parse_arguments (int argc, char *argv[]) {
continue;
}
}
fprintf(stderr, "invalid argument -al %s: must be a decimal time offset in seconds, range [0,10]\n"
fprintf(stderr, "invalid -al %s: value must be a decimal time offset in seconds, range [0,10]\n"
"(like 5 or 4.8, which will be converted to a whole number of microseconds)\n", argv[i]);
exit(1);
} else if (arg == "-pin") {
@@ -1044,6 +1058,17 @@ static void parse_arguments (int argc, char *argv[]) {
}
pin = n + 10000;
}
} else if (arg == "-reg") {
registration_list = true;
pairing_register.erase();
if (i < argc - 1 && *argv[i+1] != '-') {
pairing_register.append(argv[++i]);
const char * fn = pairing_register.c_str();
if (!file_has_write_access(fn)) {
fprintf(stderr, "%s cannot be written to:\noption \"-key <fn>\" must be to a file with write access\n", fn);
exit(1);
}
}
} else if (arg == "-key") {
keyfile.erase();
if (i < argc - 1 && *argv[i+1] != '-') {
@@ -1054,8 +1079,10 @@ static void parse_arguments (int argc, char *argv[]) {
exit(1);
}
} else {
fprintf(stderr, "option \"-key <fn>\" requires a path <fn> to a file for persistent key storage\n");
exit(1);
// fprintf(stderr, "option \"-key <fn>\" requires a path <fn> to a file for persistent key storage\n");
// exit(1);
keyfile.erase();
keyfile.append("0");
}
} else if (arg == "-dacp") {
dacpfile.erase();
@@ -1070,6 +1097,34 @@ static void parse_arguments (int argc, char *argv[]) {
dacpfile.append(get_homedir());
dacpfile.append("/.uxplay.dacp");
}
} else if (arg == "-taper") {
taper_volume = true;
} else if (arg == "-db") {
bool db_bad = true;
double db1, db2;
char *start = NULL;
if ( i < argc -1) {
char *end1, *end2;
start = argv[i+1];
db1 = strtod(start, &end1);
if (end1 > start && *end1 == ':') {
db2 = strtod(++end1, &end2);
if ( *end2 == '\0' && end2 > end1 && db1 < 0 && db1 < db2) {
db_bad = false;
}
} else if (*end1 =='\0' && end1 > start && db1 < 0 ) {
db_bad = false;
db2 = 0.0;
}
}
if (db_bad) {
fprintf(stderr, "invalid %s %s: db value must be \"low\" or \"low:high\", low < 0 and high > low are decibel gains\n", argv[i], start);
exit(1);
}
i++;
db_low = db1;
db_high = db2;
printf("db range %f:%f\n", db_low, db_high);
} else {
fprintf(stderr, "unknown option %s, stopping (for help use option \"-h\")\n",argv[i]);
exit(1);
@@ -1454,9 +1509,48 @@ extern "C" void video_flush (void *cls) {
}
extern "C" void audio_set_volume (void *cls, float volume) {
if (use_audio) {
audio_renderer_set_volume(volume);
double db, db_flat, frac, gst_volume;
if (!use_audio) {
return;
}
/* convert from AirPlay dB volume in range {-30dB : 0dB}, to GStreamer volume */
if (volume == -144.0f) { /* AirPlay "mute" signal */
frac = 0.0;
} else if (volume < -30.0f) {
LOGE(" invalid AirPlay volume %f", volume);
frac = 0.0;
} else if (volume > 0.0f) {
LOGE(" invalid AirPlay volume %f", volume);
frac = 1.0;
} else if (volume == -30.0f) {
frac = 0.0;
} else if (volume == 0.0f) {
frac = 1.0;
} else {
frac = (double) ( (30.0f + volume) / 30.0f);
frac = (frac > 1.0) ? 1.0 : frac;
}
/* frac is length of volume slider as fraction of max length */
/* also (steps/16) where steps is number of discrete steps above mute (16 = full volume) */
if (frac == 0.0) {
gst_volume = 0.0;
} else {
/* flat rescaling of decibel range from {-30dB : 0dB} to {db_low : db_high} */
db_flat = db_low + (db_high-db_low) * frac;
if (taper_volume) {
/* taper the volume reduction by the (rescaled) Airplay {-30:0} range so each reduction of
* the remaining slider length by 50% reduces the perceived volume by 50% (-10dB gain)
* (This is the "dasl-tapering" scheme offered by shairport-sync) */
db = db_high + 10.0 * (log10(frac) / log10(2.0));
db = (db > db_flat) ? db : db_flat;
} else {
db = db_flat;
}
/* conversion from (gain) decibels to GStreamer's linear volume scale */
gst_volume = pow(10.0, 0.05*db);
}
audio_renderer_set_volume(gst_volume);
}
extern "C" void audio_get_format (void *cls, unsigned char *ct, unsigned short *spf, bool *usingScreen, bool *isMedia, uint64_t *audioFormat) {
@@ -1541,15 +1635,36 @@ extern "C" void audio_set_metadata(void *cls, const void *buffer, int buflen) {
}
}
extern "C" void register_client(void *cls, const char *device_id, const char *client_pk_str) {
/* pair-setup-pin client registration by the server is not implemented here, do nothing*/
LOGD("registered new client: DeviceID = %s\nPK = \"%s\"", device_id, client_pk_str);
extern "C" void register_client(void *cls, const char *device_id, const char *client_pk, const char *client_name) {
if (!registration_list) {
/* we are not maintaining a list of registered clients */
return;
}
LOGI("registered new client: %s DeviceID = %s PK = \n%s", client_name, device_id, client_pk);
registered_keys.push_back(client_pk);
if (strlen(pairing_register.c_str())) {
FILE *fp = fopen(pairing_register.c_str(), "a");
if (fp) {
fprintf(fp, "%s,%s,%s\n", client_pk, device_id, client_name);
fclose(fp);
}
}
}
extern "C" bool check_register(void *cls, const char *client_pk_str) {
/* pair-setup-pin client registration by the server is not implemented here, return "true"*/
LOGD("register check returning client:\nPK = \"%s\"", client_pk_str);
return true;
extern "C" bool check_register(void *cls, const char *client_pk) {
if (!registration_list) {
/* we are not maintaining a list of registered clients */
return true;
}
LOGD("check returning client's pairing registration");
std::string pk = client_pk;
if (std::find(registered_keys.rbegin(), registered_keys.rend(), pk) != registered_keys.rend()) {
LOGD("registration found: PK=%s", client_pk);
return true;
} else {
LOGE("returning client's pairing registration not found: PK=%s", client_pk);
return false;
}
}
extern "C" void log_callback (void *cls, int level, const char *msg) {
@@ -1600,7 +1715,7 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
raop_cbs.export_dacp = export_dacp;
/* set max number of connections = 2 to protect against capture by new client */
raop = raop_init(max_connections, &raop_cbs, keyfile.c_str());
raop = raop_init(max_connections, &raop_cbs, mac_address.c_str(), keyfile.c_str());
if (raop == NULL) {
LOGE("Error initializing raop!");
return -1;
@@ -1825,14 +1940,46 @@ int main (int argc, char *argv[]) {
video_parser.append(BT709_FIX);
}
if (require_password && keyfile == "") {
if (require_password && registration_list) {
if (pairing_register == "") {
const char * homedir = get_homedir();
if (homedir) {
pairing_register = homedir;
pairing_register.append("/.uxplay.register");
}
}
}
/* read in public keys that were previously registered with pair-setup-pin */
if (require_password && registration_list && strlen(pairing_register.c_str())) {
size_t len = 0;
std::string key;
int clients = 0;
std::ifstream file(pairing_register);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
/*32 bytes pk -> base64 -> strlen(pk64) = 44 chars = line[0:43]; add '\0' at line[44] */
line[44] = '\0';
std::string pk = line.c_str();
registered_keys.push_back(key.assign(pk));
clients ++;
}
if (clients) {
LOGI("Register %s lists %d pin-registered clients", pairing_register.c_str(), clients);
}
file.close();
}
}
if (require_password && keyfile == "0") {
const char * homedir = get_homedir();
if (homedir) {
keyfile.erase();
keyfile = homedir;
keyfile.append("/.uxplay.pem");
} else {
LOGE("could not determine $HOME: public key wiil no be saved, and so will not be persistent");
LOGE("could not determine $HOME: public key wiil not be saved, and so will not be persistent");
}
}
@@ -1883,7 +2030,6 @@ int main (int argc, char *argv[]) {
LOGI("using randomly-generated MAC address %s",mac_address.c_str());
}
parse_hw_addr(mac_address, server_hw_addr);
mac_address.clear();
if (coverart_filename.length()) {
LOGI("any AirPlay audio cover-art will be written to file %s",coverart_filename.c_str());

View File

@@ -1,5 +1,5 @@
Name: uxplay
Version: 1.67
Version: 1.68.1
Release: 1%{?dist}
%global gittag v%{version}
@@ -11,7 +11,7 @@ Source0: https://github.com/FDH2/UxPlay/archive/%{gittag}/%{name}-%{versi
Packager: UxPlay maintainer
BuildRequires: cmake >= 3.4.1
BuildRequires: cmake >= 3.5
BuildRequires: make
BuildRequires: gcc
BuildRequires: gcc-c++
@@ -135,7 +135,7 @@ cd build
%{_docdir}/%{name}/llhttp/LICENSE-MIT
%changelog
* Wed Nov 29 2023 UxPlay maintainer <https://github.com/FDH2/UxPlay>
* Fri Dec 29 2023 UxPlay maintainer <https://github.com/FDH2/UxPlay>
Initial uxplay.spec: tested on Fedora 38, Rocky Linux 9.2, OpenSUSE
Leap 15.5, Mageia 9, OpenMandriva ROME, PCLinuxOS
-