Version 3.3.8 is 3.3.8rc7.
This commit is contained in:
+53
-28
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user