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.)
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
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) ||
}
} 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
// sps_extra_code_output_state_cannot_make_ready codes
int ret = 0;
*the_delay = 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
+ int oldState;
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
- pthread_cleanup_debug_mutex_lock(&alsa_mutex, 10000, 0);
+ 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
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;
}
_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 */
# 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])
# 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 ])])
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
# 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
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);
#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);
-
- // 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!");
+ 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!");
+
+ 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);
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.");
+ }
}
}
}
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
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.
};