Merge branch 'development'
Fix two memory leaks and start using `libgcrypt` again to avoid a memory leak in `libcrypto`. Fix a memory allocation error. Close output_device when AP2 Streamed Audio Pauses or Stops Close output_device when active period ends and `disable_standby_mode` is set to `"auto"`. Documentation updates.
This commit is contained in:
+3
-2
@@ -23,16 +23,17 @@ for timing and synchronisation in AirPlay 2. NQPTP must run as `root` and must h
|
||||
Lossless and High Definition Lossless material is transcoded to AAC before it reaches Shairport Sync.
|
||||
|
||||
## What You Need
|
||||
AirPlay 2 support needs a slightly more powerful CPU for decoding and synchronisation and more memory for bigger buffers and larger libraries. A Raspberry Pi 2 or Raspberry Pi Zero 2 W or better is recommended.
|
||||
AirPlay 2 support needs a slightly more powerful CPU for decoding and synchronisation and more memory for bigger buffers and larger libraries. A system with the power of a Raspberry Pi 2 or Raspberry Pi Zero 2 W, or better, is recommended.
|
||||
|
||||
Here are some guidelines:
|
||||
* Full access, including `root` privileges, to a system at least as powerful as a Raspberry Pi 2 or a Raspberry Pi Zero 2 W.
|
||||
* Ports 319 and 320 must be free to use (i.e. they must not be in use by another service such as a PTP service) and must not be blocked by a firewall.
|
||||
* An up-to-date Linux or FreeBSD. This is important, as some of the libraries must be the latest available.
|
||||
* Shairport Sync will not run on a Mac because NQPTP, on which it relies, needs ports 319 and 320, which are already used by macOS.
|
||||
* Shairport Sync will not run in AirPlay 2 mode on a Mac because NQPTP, on which it relies, needs ports 319 and 320, which are already used by macOS.
|
||||
* A version of the [FFmpeg](https://www.ffmpeg.org) library with an AAC decoder capable of decoding Floating Planar -- `fltp` -- material. There is a guide [here](TROUBLESHOOTING.md#aac-decoder-issues-airplay-2-only) to help you find out if your system has it.
|
||||
* An audio output, for example an ALSA device (or `sndio` in FreeBSD). The device must be capable of running at 44,100 frames per second. You can use an `sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to test the suitability of hardware ALSA audio devices on your device.
|
||||
Other backends continue to work as with "classic" Shairport Sync.
|
||||
- Multiple instances of the AirPlay 2 version of Shairport Sync can not be hosted on the same system. It seems that AirPlay 2 clients are confused by having multiple AirPlay 2 players at the same IP addresses.
|
||||
|
||||
## Guides
|
||||
* A building guide is available at [BUILD.md](BUILD.md).
|
||||
|
||||
@@ -39,7 +39,7 @@ Okay, now let's get the tools and libraries for building and installing Shairpor
|
||||
# apt upgrade # this is optional but recommended
|
||||
# apt install --no-install-recommends build-essential git xmltoman autoconf automake libtool \
|
||||
libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev \
|
||||
libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev uuid-dev xxd
|
||||
libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev uuid-dev libgcrypt-dev xxd
|
||||
```
|
||||
If you are building classic Shairport Sync, the list of packages is shorter:
|
||||
```
|
||||
@@ -54,7 +54,7 @@ For AirPlay 2 operation, _before you install the libraries_, please ensure the y
|
||||
# yum update
|
||||
# yum install make automake gcc gcc-c++ \
|
||||
git xmltoman autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \
|
||||
ffmpeg ffmpeg-devel libplist-devel libsodium-devel libuuid-devel vim-common \
|
||||
ffmpeg ffmpeg-devel libplist-devel libsodium-devel libgcrypt-dev libuuid-devel vim-common \
|
||||
alsa-lib-devel
|
||||
```
|
||||
If you are building classic Shairport Sync, the list of packages is shorter:
|
||||
@@ -121,7 +121,7 @@ Download, install, enable and start NQPTP from [here](https://github.com/mikebra
|
||||
|
||||
### Shairport Sync
|
||||
#### Build and Install
|
||||
Download Shairport Sync, configure, compile and install it. Before executing the commands, please note the following:
|
||||
Download Shairport Sync, check out the `development` branch and configure, compile and install it. Before executing the commands, please note the following:
|
||||
|
||||
* If building for FreeBSD, replace `--with-systemd` with `--with-os=freebsd --with-freebsd-service`.
|
||||
* Omit the `--with-airplay-2` from the `./configure` options if you are building classic Shairport Sync.
|
||||
@@ -130,6 +130,7 @@ Download Shairport Sync, configure, compile and install it. Before executing the
|
||||
```
|
||||
$ git clone https://github.com/mikebrady/shairport-sync.git
|
||||
$ cd shairport-sync
|
||||
$ git checkout development
|
||||
$ autoreconf -fi
|
||||
$ ./configure --sysconfdir=/etc --with-alsa \
|
||||
--with-soxr --with-avahi --with-ssl=openssl --with-systemd --with-airplay-2
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
SUBDIRS = man
|
||||
ARFLAGS = cr
|
||||
|
||||
lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_OPENSSL -pthread
|
||||
lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_GCRYPT -pthread
|
||||
lib_tinyhttp_a_CFLAGS = -pthread
|
||||
lib_dbus_interface_a_CFLAGS = -pthread
|
||||
lib_mpris_interface_a_CFLAGS = -pthread
|
||||
|
||||
+13
-2
@@ -116,6 +116,15 @@ You have installed Shairport Sync successfully, the daemon is running, you can s
|
||||
|
||||
You have to allow connections to your Shairport Sync device from remote devices. To do so, after re-enabling UFW (see last step of the previous section), enter the following commands in shell:
|
||||
|
||||
**Classic AirPlay:**
|
||||
```
|
||||
sudo ufw allow 3689/tcp
|
||||
sudo ufw allow 5353
|
||||
sudo ufw allow 5000/tcp
|
||||
sudo ufw allow 6000:6009/udp
|
||||
```
|
||||
|
||||
**AirPlay 2:**
|
||||
```
|
||||
sudo ufw allow 319:320/udp
|
||||
sudo ufw allow 3689/tcp
|
||||
@@ -123,9 +132,11 @@ sudo ufw allow 5353
|
||||
sudo ufw allow 5000/tcp
|
||||
sudo ufw allow 7000/tcp
|
||||
sudo ufw allow 6000:6009/udp
|
||||
sudo ufw allow 35000:65535/udp
|
||||
sudo ufw allow 32768:60999/udp
|
||||
sudo ufw allow 32768:60999/tcp
|
||||
```
|
||||
Ports 319 and 320 need to be opened for AirPlay 2 only.
|
||||
|
||||
The range `32768:60999` represents the [ephemeral port range](https://en.m.wikipedia.org/wiki/Ephemeral_port) which seems to be standardised on those values.
|
||||
|
||||
You can check UFW config by typing `sudo ufw status` in shell. Please make sure that UFW is active, especially if you have deactivated it previously for testing purposes. Check out the [ufw man pages](http://manpages.ubuntu.com/manpages/man8/ufw.8.html) for more.
|
||||
|
||||
|
||||
+2
-12
@@ -56,8 +56,7 @@ pthread_mutex_t activity_monitor_mutex;
|
||||
pthread_cond_t activity_monitor_cv;
|
||||
|
||||
void going_active(int block) {
|
||||
// debug(1, "activity_monitor: state transitioning to \"active\" with%s blocking", block ? "" :
|
||||
// "out");
|
||||
// debug(1, "activity_monitor: state transitioning to \"active\" with%s blocking", block ? "" : "out");
|
||||
if (config.cmd_active_start)
|
||||
command_execute(config.cmd_active_start, "", block);
|
||||
#ifdef CONFIG_METADATA
|
||||
@@ -71,17 +70,12 @@ void going_active(int block) {
|
||||
#endif
|
||||
|
||||
if (config.disable_standby_mode == disable_standby_auto) {
|
||||
#ifdef CONFIG_DBUS_INTERFACE
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
|
||||
#endif
|
||||
config.keep_dac_busy = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void going_inactive(int block) {
|
||||
// debug(1, "activity_monitor: state transitioning to \"inactive\" with%s blocking", block ? "" :
|
||||
// "out");
|
||||
// debug(1, "activity_monitor: state transitioning to \"inactive\" with%s blocking", block ? "" : "out");
|
||||
if (config.cmd_active_stop)
|
||||
command_execute(config.cmd_active_stop, "", block);
|
||||
#ifdef CONFIG_METADATA
|
||||
@@ -95,10 +89,6 @@ void going_inactive(int block) {
|
||||
#endif
|
||||
|
||||
if (config.disable_standby_mode == disable_standby_auto) {
|
||||
#ifdef CONFIG_DBUS_INTERFACE
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
|
||||
#endif
|
||||
config.keep_dac_busy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ static int play(__attribute__((unused)) void *buf, __attribute__((unused)) int s
|
||||
// sample code using some of the extra information
|
||||
if (sample_type == play_samples_are_timed) {
|
||||
int64_t lead_time = playtime - get_absolute_time_in_ns();
|
||||
debug(1, "leadtime for frame %u is %" PRId64 " nanoseconds, i.e. %f seconds.", timestamp,
|
||||
debug(2, "leadtime for frame %u is %" PRId64 " nanoseconds, i.e. %f seconds.", timestamp,
|
||||
lead_time, 0.000000001 * lead_time);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.50])
|
||||
AC_INIT([shairport-sync], [4.1-rc0], [4265913+mikebrady@users.noreply.github.com])
|
||||
AC_INIT([shairport-sync], [4.1-dev], [4265913+mikebrady@users.noreply.github.com])
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
AC_CONFIG_SRCDIR([shairport.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -412,6 +412,11 @@ if test "x$with_airplay_2" = "xyes" ; then
|
||||
])
|
||||
])
|
||||
PKG_CHECK_MODULES([libsodium], [libsodium],[CFLAGS="${libsodium_CFLAGS} ${CFLAGS}" LIBS="${libsodium_LIBS} ${LIBS}"],[AC_MSG_ERROR(AirPlay 2 support requires libsodium -- libsodium-dev suggested)])
|
||||
PKG_CHECK_MODULES([libgcrypt], [libgcrypt],[CFLAGS="${libgcrypt_CFLAGS} ${CFLAGS}" LIBS="${libgcrypt_LIBS} ${LIBS}"],[
|
||||
AC_CHECK_LIB([gcrypt], [gcry_control], [], [
|
||||
AC_MSG_ERROR([Airplay 2 support requires libgcrypt -- libgcrypt-dev suggested])
|
||||
])
|
||||
])
|
||||
PKG_CHECK_MODULES([libavutil], [libavutil],[CFLAGS="${libavutil_CFLAGS} ${CFLAGS}" LIBS="${libavutil_LIBS} ${LIBS}"],[
|
||||
AC_MSG_ERROR(AirPlay 2 support requires libavutil -- libavutil-dev suggested)])
|
||||
PKG_CHECK_MODULES([libavcodec], [libavcodec],[CFLAGS="${libavcodec_CFLAGS} ${CFLAGS}" LIBS="${libavcodec_LIBS} ${LIBS}"],[
|
||||
|
||||
@@ -1830,92 +1830,95 @@ void handle_flushbuffered(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
|
||||
uint64_t flushUntilTS = 0;
|
||||
int flushFromValid = 0;
|
||||
plist_t messagePlist = plist_from_rtsp_content(req);
|
||||
plist_t item = plist_dict_get_item(messagePlist, "flushFromSeq");
|
||||
if (item == NULL) {
|
||||
debug(2, "Can't find a flushFromSeq");
|
||||
} else {
|
||||
flushFromValid = 1;
|
||||
plist_get_uint_val(item, &flushFromSeq);
|
||||
debug(2, "flushFromSeq is %" PRId64 ".", flushFromSeq);
|
||||
}
|
||||
if (messagePlist != NULL) {
|
||||
plist_t item = plist_dict_get_item(messagePlist, "flushFromSeq");
|
||||
if (item == NULL) {
|
||||
debug(2, "Can't find a flushFromSeq");
|
||||
} else {
|
||||
flushFromValid = 1;
|
||||
plist_get_uint_val(item, &flushFromSeq);
|
||||
debug(2, "flushFromSeq is %" PRId64 ".", flushFromSeq);
|
||||
}
|
||||
|
||||
item = plist_dict_get_item(messagePlist, "flushFromTS");
|
||||
if (item == NULL) {
|
||||
if (flushFromValid != 0)
|
||||
debug(1, "flushFromSeq without flushFromTS!");
|
||||
else
|
||||
debug(2, "Can't find a flushFromTS");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushFromTS);
|
||||
item = plist_dict_get_item(messagePlist, "flushFromTS");
|
||||
if (item == NULL) {
|
||||
if (flushFromValid != 0)
|
||||
debug(1, "flushFromSeq without flushFromTS!");
|
||||
else
|
||||
debug(2, "Can't find a flushFromTS");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushFromTS);
|
||||
if (flushFromValid == 0)
|
||||
debug(1, "flushFromTS without flushFromSeq!");
|
||||
debug(2, "flushFromTS is %" PRId64 ".", flushFromTS);
|
||||
}
|
||||
|
||||
item = plist_dict_get_item(messagePlist, "flushUntilSeq");
|
||||
if (item == NULL) {
|
||||
debug(1, "Can't find the flushUntilSeq");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushUntilSeq);
|
||||
debug(2, "flushUntilSeq is %" PRId64 ".", flushUntilSeq);
|
||||
}
|
||||
|
||||
item = plist_dict_get_item(messagePlist, "flushUntilTS");
|
||||
if (item == NULL) {
|
||||
debug(1, "Can't find the flushUntilTS");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushUntilTS);
|
||||
debug(2, "flushUntilTS is %" PRId64 ".", flushUntilTS);
|
||||
}
|
||||
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
// a flush with from... components will not be followed by a setanchor (i.e. a play)
|
||||
// if it's a flush that will be followed by a setanchor (i.e. a play) then stop play now.
|
||||
if (flushFromValid == 0)
|
||||
debug(1, "flushFromTS without flushFromSeq!");
|
||||
debug(2, "flushFromTS is %" PRId64 ".", flushFromTS);
|
||||
conn->ap2_play_enabled = 0;
|
||||
|
||||
// add the exact request as made to the linked list (not used for anything but diagnostics now)
|
||||
// int flushNow = 0;
|
||||
// if (flushFromValid == 0)
|
||||
// flushNow = 1;
|
||||
// add_flush_request(flushNow, flushFromSeq, flushFromTS, flushUntilSeq, flushUntilTS, conn);
|
||||
|
||||
// now, if it's an immediate flush, replace the existing request, if any
|
||||
// but it if's a deferred flush and there is an existing deferred request,
|
||||
// only update the flushUntil stuff -- that seems to preserve
|
||||
// the intended semantics
|
||||
|
||||
// so, always replace these
|
||||
conn->ap2_flush_until_sequence_number = flushUntilSeq;
|
||||
conn->ap2_flush_until_rtp_timestamp = flushUntilTS;
|
||||
|
||||
if ((conn->ap2_flush_requested != 0) && (conn->ap2_flush_from_valid != 0) &&
|
||||
(flushFromValid != 0)) {
|
||||
// if there is a request already, and it's a deferred request, and the current request is also
|
||||
// deferred... do nothing! -- leave the starting point in place. Yeah, yeah, we know de Morgan's
|
||||
// Law, but this seems clearer
|
||||
} else {
|
||||
conn->ap2_flush_from_sequence_number = flushFromSeq;
|
||||
conn->ap2_flush_from_rtp_timestamp = flushFromTS;
|
||||
}
|
||||
|
||||
conn->ap2_flush_from_valid = flushFromValid;
|
||||
conn->ap2_flush_requested = 1;
|
||||
|
||||
// reflect the possibly updated flush request
|
||||
// add_flush_request(flushNow, conn->ap2_flush_from_sequence_number,
|
||||
// conn->ap2_flush_from_rtp_timestamp, conn->ap2_flush_until_sequence_number,
|
||||
// conn->ap2_flush_until_rtp_timestamp, conn);
|
||||
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
|
||||
if (flushFromValid)
|
||||
debug(2, "Deferred Flush Requested");
|
||||
else
|
||||
debug(2, "Immediate Flush Requested");
|
||||
|
||||
plist_free(messagePlist);
|
||||
// display_all_flush_requests(conn);
|
||||
}
|
||||
|
||||
item = plist_dict_get_item(messagePlist, "flushUntilSeq");
|
||||
if (item == NULL) {
|
||||
debug(1, "Can't find the flushUntilSeq");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushUntilSeq);
|
||||
debug(2, "flushUntilSeq is %" PRId64 ".", flushUntilSeq);
|
||||
}
|
||||
|
||||
item = plist_dict_get_item(messagePlist, "flushUntilTS");
|
||||
if (item == NULL) {
|
||||
debug(1, "Can't find the flushUntilTS");
|
||||
} else {
|
||||
plist_get_uint_val(item, &flushUntilTS);
|
||||
debug(2, "flushUntilTS is %" PRId64 ".", flushUntilTS);
|
||||
}
|
||||
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
// a flush with from... components will not be followed by a setanchor (i.e. a play)
|
||||
// if it's a flush that will be followed by a setanchor (i.e. a play) then stop play now.
|
||||
if (flushFromValid == 0)
|
||||
conn->ap2_play_enabled = 0;
|
||||
|
||||
// add the exact request as made to the linked list (not used for anything but diagnostics now)
|
||||
// int flushNow = 0;
|
||||
// if (flushFromValid == 0)
|
||||
// flushNow = 1;
|
||||
// add_flush_request(flushNow, flushFromSeq, flushFromTS, flushUntilSeq, flushUntilTS, conn);
|
||||
|
||||
// now, if it's an immediate flush, replace the existing request, if any
|
||||
// but it if's a deferred flush and there is an existing deferred request,
|
||||
// only update the flushUntil stuff -- that seems to preserve
|
||||
// the intended semantics
|
||||
|
||||
// so, always replace these
|
||||
conn->ap2_flush_until_sequence_number = flushUntilSeq;
|
||||
conn->ap2_flush_until_rtp_timestamp = flushUntilTS;
|
||||
|
||||
if ((conn->ap2_flush_requested != 0) && (conn->ap2_flush_from_valid != 0) &&
|
||||
(flushFromValid != 0)) {
|
||||
// if there is a request already, and it's a deferred request, and the current request is also
|
||||
// deferred... do nothing! -- leave the starting point in place. Yeah, yeah, we know de Morgan's
|
||||
// Law, but this seems clearer
|
||||
} else {
|
||||
conn->ap2_flush_from_sequence_number = flushFromSeq;
|
||||
conn->ap2_flush_from_rtp_timestamp = flushFromTS;
|
||||
}
|
||||
|
||||
conn->ap2_flush_from_valid = flushFromValid;
|
||||
conn->ap2_flush_requested = 1;
|
||||
|
||||
// reflect the possibly updated flush request
|
||||
// add_flush_request(flushNow, conn->ap2_flush_from_sequence_number,
|
||||
// conn->ap2_flush_from_rtp_timestamp, conn->ap2_flush_until_sequence_number,
|
||||
// conn->ap2_flush_until_rtp_timestamp, conn);
|
||||
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
|
||||
if (flushFromValid)
|
||||
debug(2, "Deferred Flush Requested");
|
||||
else
|
||||
debug(2, "Immediate Flush Requested");
|
||||
|
||||
// display_all_flush_requests(conn);
|
||||
|
||||
resp->respcode = 200;
|
||||
}
|
||||
|
||||
@@ -2003,6 +2006,10 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
|
||||
activity_monitor_signify_activity(0);
|
||||
conn->ap2_play_enabled = 0;
|
||||
reset_anchor_info(conn);
|
||||
if (config.output->stop) {
|
||||
debug(2, "Connection %d: Stop the output backend.", conn->connection_number);
|
||||
config.output->stop();
|
||||
}
|
||||
}
|
||||
pthread_cleanup_pop(1); // unlock the conn->flush_mutex
|
||||
}
|
||||
@@ -2218,7 +2225,7 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re
|
||||
uint8_t *body = NULL;
|
||||
size_t body_len = 0;
|
||||
struct pair_result *result;
|
||||
debug(2, "Connection %d: pair-setup Content-Length %d", conn->connection_number,
|
||||
debug(2, "Connection %d: handle_pair-setup Content-Length %d", conn->connection_number,
|
||||
req->contentlength);
|
||||
|
||||
if (!conn->ap2_pairing_context.setup_ctx) {
|
||||
@@ -2819,6 +2826,7 @@ static void check_and_send_plist_metadata(plist_t messagePlist, const char *plis
|
||||
plist_get_string_val(item, &value);
|
||||
if (value != NULL) {
|
||||
send_metadata('ssnc', metadata_code, value, strlen(value), NULL, 0);
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4169,19 +4177,22 @@ void metadata_stop(void) {
|
||||
int send_metadata_to_queue(pc_queue *queue, uint32_t type, uint32_t code, char *data,
|
||||
uint32_t length, rtsp_message *carrier, int block) {
|
||||
|
||||
// parameters: type, code, pointer to data or NULL, length of data or NULL,
|
||||
// the rtsp_message or
|
||||
// NULL
|
||||
// clang-format off
|
||||
// parameters:
|
||||
// type,
|
||||
// code,
|
||||
// pointer to data or NULL,
|
||||
// length of data or NULL,
|
||||
// the rtsp_message or NULL,
|
||||
|
||||
// the rtsp_message is sent for 'core' messages, because it contains the data
|
||||
// and must not be
|
||||
// freed until the data has been read. So, it is passed to send_metadata to be
|
||||
// retained,
|
||||
// sent to the thread where metadata is processed and released (and probably
|
||||
// freed).
|
||||
// and must not be freed until the data has been read.
|
||||
// So, it is passed to send_metadata to be retained, sent to the thread where metadata
|
||||
// is processed and released (and probably freed).
|
||||
|
||||
// The rtsp_message is also sent for certain non-'core' messages.
|
||||
|
||||
// The reading of the parameters is a bit complex
|
||||
// The reading of the parameters is a bit complex:
|
||||
// If the rtsp_message field is non-null, then it represents an rtsp_message
|
||||
// and the data pointer is assumed to point to something within it.
|
||||
// The reference counter of the rtsp_message is incremented here and
|
||||
@@ -4191,8 +4202,10 @@ int send_metadata_to_queue(pc_queue *queue, uint32_t type, uint32_t code, char *
|
||||
// If the rtsp_message is NULL, then if the pointer is non-null then the data it
|
||||
// points to, of the length specified, is memcpy'd and passed to the metadata
|
||||
// handler. The handler should free it when done.
|
||||
|
||||
// If the rtsp_message is NULL and the pointer is also NULL, nothing further
|
||||
// is done.
|
||||
// clang-format on
|
||||
|
||||
metadata_package pack;
|
||||
pack.type = type;
|
||||
|
||||
+24
-3
@@ -45,6 +45,7 @@
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
#include "ptp-utilities.h"
|
||||
#include <gcrypt.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <sodium.h>
|
||||
#include <uuid/uuid.h>
|
||||
@@ -570,7 +571,7 @@ int parse_options(int argc, char **argv) {
|
||||
uuid_t binuuid;
|
||||
uuid_generate_random(binuuid);
|
||||
|
||||
char *uuid = malloc(UUID_STR_LEN);
|
||||
char *uuid = malloc(UUID_STR_LEN + 1); // leave space for the NUL at the end
|
||||
// Produces a UUID string at uuid consisting of lower-case letters
|
||||
uuid_unparse_lower(binuuid, uuid);
|
||||
config.airplay_pi = uuid;
|
||||
@@ -1307,7 +1308,6 @@ int parse_options(int argc, char **argv) {
|
||||
// now, do the command line options again, but this time do them fully -- it's a unix convention
|
||||
// that command line
|
||||
// arguments have precedence over configuration file settings.
|
||||
|
||||
optind = argc;
|
||||
for (j = 0; j < argc; j++)
|
||||
if (strcmp(argv[j], "--") == 0)
|
||||
@@ -1652,7 +1652,6 @@ void exit_function() {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config.cfg)
|
||||
config_destroy(config.cfg);
|
||||
if (config.appName)
|
||||
@@ -2103,6 +2102,28 @@ int main(int argc, char **argv) {
|
||||
debug(1, "libsodium initialised.");
|
||||
}
|
||||
|
||||
// this code is based on
|
||||
// https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html
|
||||
|
||||
/* Version check should be the very first call because it
|
||||
makes sure that important subsystems are initialized.
|
||||
#define NEED_LIBGCRYPT_VERSION to the minimum required version. */
|
||||
|
||||
#define NEED_LIBGCRYPT_VERSION "1.5.4"
|
||||
|
||||
if (!gcry_check_version(NEED_LIBGCRYPT_VERSION)) {
|
||||
die("libgcrypt is too old (need %s, have %s).", NEED_LIBGCRYPT_VERSION,
|
||||
gcry_check_version(NULL));
|
||||
}
|
||||
|
||||
/* Disable secure memory. */
|
||||
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
|
||||
|
||||
/* ... If required, other initialization goes here. */
|
||||
|
||||
/* Tell Libgcrypt that initialization has completed. */
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
#endif
|
||||
|
||||
/* Mess around with the latency options */
|
||||
|
||||
Reference in New Issue
Block a user