Version 3.3.8 is 3.3.8rc7.

This commit is contained in:
Mike Brady
2021-04-26 11:23:13 +01:00
parent 6c628da897
commit b9854d3fdc
6 changed files with 116 additions and 87 deletions
+53 -28
View File
@@ -1455,19 +1455,31 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
int ret = snd_pcm_status(alsa_handle, alsa_snd_pcm_status);
if (ret == 0) {
// must be 1.1 or later to use snd_pcm_status_get_driver_htstamp
#if SND_LIB_MINOR == 0
snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp);
#else
snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &update_timestamp);
/*
// must be 1.1 or later to use snd_pcm_status_get_driver_htstamp
#if SND_LIB_MINOR != 0
snd_htimestamp_t driver_htstamp;
snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &driver_htstamp);
uint64_t driver_htstamp_ns = driver_htstamp.tv_sec;
driver_htstamp_ns = driver_htstamp_ns * 1000000000;
driver_htstamp_ns = driver_htstamp_ns + driver_htstamp.tv_nsec;
debug(1,"driver_htstamp: %f.", driver_htstamp_ns * 0.000000001);
#endif
*/
*state = snd_pcm_status_get_state(alsa_snd_pcm_status);
if ((*state == SND_PCM_STATE_RUNNING) || (*state == SND_PCM_STATE_DRAINING)) {
uint64_t update_timestamp_ns =
update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec;
// uint64_t update_timestamp_ns =
// update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec;
uint64_t update_timestamp_ns = update_timestamp.tv_sec;
update_timestamp_ns = update_timestamp_ns * 1000000000;
update_timestamp_ns = update_timestamp_ns + update_timestamp.tv_nsec;
// if the update_timestamp is zero, we take this to mean that the device doesn't report
// interrupt timings. (It could be that it's not a real hardware device.)
@@ -1497,7 +1509,7 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
if (update_timestamp_ns == 0) {
ret = snd_pcm_delay(alsa_handle, delay);
} else {
*delay = snd_pcm_status_get_delay(alsa_snd_pcm_status);
snd_pcm_sframes_t delay_temp = snd_pcm_status_get_delay(alsa_snd_pcm_status);
/*
// It seems that the alsa library uses CLOCK_REALTIME before 1.0.28, even though
@@ -1514,11 +1526,15 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
else
clock_gettime(CLOCK_REALTIME, &tn);
uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec;
// uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec;
uint64_t time_now_ns = tn.tv_sec;
time_now_ns = time_now_ns * 1000000000;
time_now_ns = time_now_ns + tn.tv_nsec;
// see if it's stalled
if ((stall_monitor_start_time != 0) && (stall_monitor_frame_count == *delay)) {
if ((stall_monitor_start_time != 0) && (stall_monitor_frame_count == delay_temp)) {
// hasn't outputted anything since the last call to delay()
if (((update_timestamp_ns - stall_monitor_start_time) > stall_monitor_error_threshold) ||
@@ -1539,19 +1555,27 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
}
} else {
stall_monitor_start_time = update_timestamp_ns;
stall_monitor_frame_count = *delay;
stall_monitor_frame_count = delay_temp;
}
if (ret == 0) {
uint64_t delta = time_now_ns - update_timestamp_ns;
uint64_t frames_played_since_last_interrupt =
((uint64_t)config.output_rate * delta) / 1000000000;
// uint64_t frames_played_since_last_interrupt =
// ((uint64_t)config.output_rate * delta) / 1000000000;
uint64_t frames_played_since_last_interrupt = config.output_rate;
frames_played_since_last_interrupt = frames_played_since_last_interrupt * delta;
frames_played_since_last_interrupt = frames_played_since_last_interrupt / 1000000000;
snd_pcm_sframes_t frames_played_since_last_interrupt_sized =
frames_played_since_last_interrupt;
*delay = *delay - frames_played_since_last_interrupt_sized;
if ((frames_played_since_last_interrupt_sized < 0) || ((uint64_t)frames_played_since_last_interrupt_sized != frames_played_since_last_interrupt))
debug(1,"overflow resizing frames_played_since_last_interrupt % " PRIx64 " to frames_played_since_last_interrupt %lx.", frames_played_since_last_interrupt, frames_played_since_last_interrupt_sized);
delay_temp = delay_temp - frames_played_since_last_interrupt_sized;
}
*delay = delay_temp;
}
} else { // not running, thus no delay information, thus can't check for
// stall
@@ -1582,25 +1606,26 @@ int delay(long *the_delay) {
// sps_extra_code_output_state_cannot_make_ready codes
int ret = 0;
*the_delay = 0;
int oldState;
snd_pcm_state_t state;
snd_pcm_sframes_t my_delay = 0; // this initialisation is to silence a clang warning
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
pthread_cleanup_debug_mutex_lock(&alsa_mutex, 10000, 0);
if (alsa_handle == NULL)
ret = ENODEV;
else {
int oldState;
snd_pcm_state_t state;
snd_pcm_sframes_t my_delay = 0; // this initialisation is to silence a clang warning
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
pthread_cleanup_debug_mutex_lock(&alsa_mutex, 10000, 0);
else
ret = delay_and_status(&state, &my_delay, NULL);
debug_mutex_unlock(&alsa_mutex, 0);
pthread_cleanup_pop(0);
pthread_setcancelstate(oldState, NULL);
debug_mutex_unlock(&alsa_mutex, 0);
pthread_cleanup_pop(0);
pthread_setcancelstate(oldState, NULL);
*the_delay = my_delay; // note: snd_pcm_sframes_t is a long
*the_delay = my_delay; // note: snd_pcm_sframes_t is a long
}
return ret;
}
+1 -1
View File
@@ -834,7 +834,7 @@ void command_set_volume(double volume) {
_exit(EXIT_FAILURE); /* only if execv fails */
}
}
_exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
} else {
if (config.cmd_blocking) { /* pid!=0 means parent process and if blocking is true, wait for
process to finish */
+8 -7
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.50])
AC_INIT([shairport-sync], [3.3.8rc3], [4265913+mikebrady@users.noreply.github.com])
AC_INIT([shairport-sync], [3.3.8], [4265913+mikebrady@users.noreply.github.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
@@ -147,17 +147,18 @@ AM_CONDITIONAL([USE_CUSTOMPIDDIR], [ test "x${with_piddir}" != "x" ])
# Look for libdaemon
AC_ARG_WITH(libdaemon,[AS_HELP_STRING([--with-libdaemon],[include support for daemonising in non-systemd systems])])
if test "x$with_libdaemon" = "x1"; then
if test "x$with_libdaemon" = "xyes"; then
AC_DEFINE([CONFIG_LIBDAEMON], 1, [Include libdaemon for daemonising in non-systemd systems])
if test "x${with_pkg_config}" = xyes ; then
PKG_CHECK_MODULES(
[DAEMON], [libdaemon],
[LIBS="${DAEMON_LIBS} ${LIBS}"])
[LIBS="${DAEMON_LIBS} ${LIBS}"],
[AC_MSG_ERROR(the libdaemon library has been selected but is missing -- libdaemon-dev suggested!)])
else
AC_CHECK_LIB([daemon],[daemon_fork], , AC_MSG_ERROR(libdaemon needed))
AC_CHECK_LIB([daemon],[daemon_fork], , AC_MSG_ERROR(the libdaemon library has been selected but is missing -- libdaemon-dev suggested!))
fi
fi
AM_CONDITIONAL([USE_LIBDAEMON], [test "x$with_libdaemon" = "x1"])
AM_CONDITIONAL([USE_LIBDAEMON], [test "x$with_libdaemon" = "xyes"])
# Check --with-ssl=argument
AC_ARG_WITH(ssl, [AS_HELP_STRING([--with-ssl=<argument>],[choose --with-ssl=openssl, --with-ssl=mbedtls or --with-ssl=polarssl (deprecated) for encryption services ])])
@@ -241,7 +242,7 @@ if test "x$with_alsa" = "xyes" ; then
else
AC_CHECK_LIB([asound], [snd_pcm_open], , AC_MSG_ERROR(ALSA support requires the asound library!))
fi
fi
fi
AM_CONDITIONAL([USE_ALSA], [test "x$with_alsa" = "xyes"])
# Look for jack flag
@@ -317,7 +318,7 @@ AM_CONDITIONAL([USE_DNS_SD], [test "x$with_dns_sd" = "xyes"])
# Look for dbus flag
AC_ARG_WITH(dbus-interface, [AS_HELP_STRING([--with-dbus-interface],[include support for the native Shairport Sync D-Bus interface])])
if test "x$with_dbus_interface" = "xyes" ; then
if test "x$with_dbus_interface" = "xyes" ; then
AC_DEFINE([CONFIG_DBUS_INTERFACE], 1, [Support the native Shairport Sync D-Bus interface])
# remember to include glib, below
fi
+4 -4
View File
@@ -446,11 +446,11 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
if (dacp_server.active_remote_id)
free(dacp_server.active_remote_id);
if (conn->dacp_active_remote)
dacp_server.active_remote_id =
strdup(conn->dacp_active_remote); // even if the dacp_id remains the same,
// the active remote will change.
dacp_server.active_remote_id =
strdup(conn->dacp_active_remote); // even if the dacp_id remains the same,
// the active remote will change.
else
dacp_server.active_remote_id = NULL;
dacp_server.active_remote_id = NULL;
debug(3, "set_dacp_server_information set active-remote id to %s.", dacp_server.active_remote_id);
pthread_cond_signal(&dacp_server_information_cv);
+49 -47
View File
@@ -1652,40 +1652,41 @@ void *metadata_mqtt_thread_function(__attribute__((unused)) void *ignore) {
#endif
void metadata_init(void) {
int ret;
if (config.metadata_enabled) {
// create the metadata pipe, if necessary
size_t pl = strlen(config.metadata_pipename) + 1;
char *path = malloc(pl + 1);
snprintf(path, pl + 1, "%s", config.metadata_pipename);
mode_t oldumask = umask(000);
if (mkfifo(path, 0666) && errno != EEXIST)
die("Could not create metadata pipe \"%s\".", path);
umask(oldumask);
debug(1, "metadata pipe name is \"%s\".", path);
int ret;
if (config.metadata_enabled) {
// create the metadata pipe, if necessary
size_t pl = strlen(config.metadata_pipename) + 1;
char *path = malloc(pl + 1);
snprintf(path, pl + 1, "%s", config.metadata_pipename);
mode_t oldumask = umask(000);
if (mkfifo(path, 0666) && errno != EEXIST)
die("Could not create metadata pipe \"%s\".", path);
umask(oldumask);
debug(1, "metadata pipe name is \"%s\".", path);
// try to open it
fd = try_to_open_pipe_for_writing(path);
// we check that it's not a "real" error. From the "man 2 open" page:
// "ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
// open for reading." Which is okay.
if ((fd == -1) && (errno != ENXIO)) {
char errorstring[1024];
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
(char *)errorstring, path);
warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
(char *)errorstring, path);
}
free(path);
int ret;
ret = pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata thread!");
// try to open it
fd = try_to_open_pipe_for_writing(path);
// we check that it's not a "real" error. From the "man 2 open" page:
// "ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
// open for reading." Which is okay.
if ((fd == -1) && (errno != ENXIO)) {
char errorstring[1024];
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
(char *)errorstring, path);
warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
(char *)errorstring, path);
}
free(path);
int ret;
ret = pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata thread!");
ret = pthread_create(&metadata_multicast_thread, NULL, metadata_multicast_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata multicast thread!");
ret =
pthread_create(&metadata_multicast_thread, NULL, metadata_multicast_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata multicast thread!");
}
#ifdef CONFIG_METADATA_HUB
ret = pthread_create(&metadata_hub_thread, NULL, metadata_hub_thread_function, NULL);
@@ -1715,19 +1716,19 @@ void metadata_stop(void) {
pthread_join(metadata_hub_thread, NULL);
// debug(2, "metadata stop hub done.");
#endif
if (config.metadata_enabled) {
// debug(2, "metadata stop multicast thread.");
if (metadata_multicast_thread) {
pthread_cancel(metadata_multicast_thread);
pthread_join(metadata_multicast_thread, NULL);
// debug(2, "metadata stop multicast done.");
}
if (metadata_thread) {
// debug(2, "metadata stop metadata_thread thread.");
pthread_cancel(metadata_thread);
pthread_join(metadata_thread, NULL);
// debug(2, "metadata_stop finished successfully.");
}
if (config.metadata_enabled) {
// debug(2, "metadata stop multicast thread.");
if (metadata_multicast_thread) {
pthread_cancel(metadata_multicast_thread);
pthread_join(metadata_multicast_thread, NULL);
// debug(2, "metadata stop multicast done.");
}
if (metadata_thread) {
// debug(2, "metadata stop metadata_thread thread.");
pthread_cancel(metadata_thread);
pthread_join(metadata_thread, NULL);
// debug(2, "metadata_stop finished successfully.");
}
}
}
}
@@ -1799,8 +1800,9 @@ int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rts
int block) {
int rc;
if (config.metadata_enabled) {
rc = send_metadata_to_queue(&metadata_queue, type, code, data, length, carrier, block);
rc = send_metadata_to_queue(&metadata_multicast_queue, type, code, data, length, carrier, block);
rc = send_metadata_to_queue(&metadata_queue, type, code, data, length, carrier, block);
rc =
send_metadata_to_queue(&metadata_multicast_queue, type, code, data, length, carrier, block);
}
#ifdef CONFIG_METADATA_HUB
+1
View File
@@ -134,6 +134,7 @@ sndio =
pa =
{
// server = "host"; // Set this to override the default pulseaudio server that should be used.
// sink = "Sink Name"; // Set this to override the default pulseaudio sink that should be used. (Untested)
// application_name = "Shairport Sync"; //Set this to the name that should appear in the Sounds "Applications" tab when Shairport Sync is active.
};