warn("The output device \"%s\" is busy and can't be used by Shairport Sync at present.",
alsa_out_dev);
debug(2, "the alsa output_device \"%s\" is busy.", alsa_out_dev);
- } else if (ret == -ENOENT) {
- die("the alsa output_device \"%s\" can not be found.", alsa_out_dev);
} else {
- char errorstring[1024];
- strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
- die("alsa: error %d (\"%s\") opening alsa device \"%s\".", ret, (char *)errorstring,
- alsa_out_dev);
+ if (config.unfixable_error_reported == 0) {
+ config.unfixable_error_reported = 1;
+ char messageString[1024];
+ messageString[0] = '\0';
+ snprintf(messageString, sizeof(messageString), "output_device_error %d", -ret);
+ if (config.cmd_unfixable) {
+ command_execute(config.cmd_unfixable, messageString, 1);
+ } else {
+ die("an unrecoverable error, \"output_device_error %d\", has been "
+ "detected.", -ret);
+ }
+ }
}
alsa_handle_status = ret;
frames_sent_break_occurred = 1;
}
}
} else {
- char errorstring[1024];
- strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
- debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret,
- (char *)errorstring, samples);
+
+ if (ret == -ENODEV) {
+ if (config.unfixable_error_reported == 0) {
+ config.unfixable_error_reported = 1;
+ if (config.cmd_unfixable) {
+ command_execute(config.cmd_unfixable, "output_device_error 19", 1);
+ } else {
+ die("an unrecoverable error, \"output_device_error 19\", has been "
+ "detected.");
+ }
+ }
+ } else {
+ char errorstring[1024];
+ strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
+ debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret,
+ (char *)errorstring, samples);
+ }
}
}
}
static int fd = -1;
static int warned = 0;
-
static void start(__attribute__((unused)) int sample_rate,
__attribute__((unused)) int sample_format) {
fd = STDOUT_FILENO;
- warned = 0;
+ warned = 0;
}
static int play(void *buf, int samples, __attribute__((unused)) int sample_type,
typedef enum {
TOE_normal,
TOE_emergency,
- TOE_dbus // a request was made on a D-Bus interface (the native D-Bus or MPRIS interfaces)-- don't wait for the dbus thread to exit
+ TOE_dbus // a request was made on a D-Bus interface (the native D-Bus or MPRIS interfaces)-- don't
+ // wait for the dbus thread to exit
} type_of_exit_type;
#define sps_extra_code_output_stalled 32768
int mqtt_enable_remote;
char *mqtt_empty_payload_substitute;
#endif
- uint8_t ap1_prefix[6];
+ uint8_t ap1_prefix[6];
uint8_t hw_addr[8]; // only needs 6 but 8 is handy when converting this to a number
int port;
int udp_port_base;
char *airplay_pi; // UUID in the Bonjour advertisement and the GETINFO Plist
char *nqptp_shared_memory_interface_name; // client name for nqptp service
#endif
+ int unfixable_error_reported; // only report once.
} shairport_cfg;
// accessors to config for multi-thread access
th = shairport_sync_get_first_frame_position(shairportSyncSkeleton);
if ((th == NULL) || (strcasecmp(th, argc->first_frame_position_string) != 0)) {
// debug(1, "First frame position string should be changed");
- shairport_sync_set_first_frame_position(shairportSyncSkeleton, argc->first_frame_position_string);
+ shairport_sync_set_first_frame_position(shairportSyncSkeleton,
+ argc->first_frame_position_string);
}
}
if (string_update(&metadata_store.first_frame_position_string,
&metadata_store.first_frame_position_string_changed, cs)) {
changed = 1;
- debug(2, "MH First Frame Position String set to: \"%s\"", metadata_store.first_frame_position_string);
+ debug(2, "MH First Frame Position String set to: \"%s\"",
+ metadata_store.first_frame_position_string);
}
free(cs);
break;
char *server_ip; // IP number used by Shairport Sync
int server_ip_changed;
-
+
char *stream_type; // Realtime or Buffered
int stream_type_changed;
char *cover_art_pathname;
int cover_art_pathname_changed;
-
+
uint64_t item_id; // seems to be a track ID -- see itemid in DACP.c
int item_id_changed;
int item_id_is_valid;
int item_composite_id_changed;
int item_composite_id_is_valid;
-
int song_data_kind;
int song_data_kind_changed;
int song_data_kind_is_valid;
-
+
char *track_name;
int track_name_changed;
uint32_t songtime_in_milliseconds;
int songtime_in_milliseconds_changed;
int songtime_in_milliseconds_is_valid;
-
// end
// When the clock is inactive, it can stop running. This causes the offset to decrease.
// NQPTP clock smoothing would treat this as a network delay, causing true sync to be lost.
// To avoid this, when the clock goes from inactive to active,
-// NQPTP resets clock smoothing to the new offset.
-
+// NQPTP resets clock smoothing to the new offset.
#include <inttypes.h>
#include <pthread.h>
// default buffer size
// needs to be a power of 2 because of the way BUFIDX(seqno) works
-//#define BUFFER_FRAMES 512
+// #define BUFFER_FRAMES 512
#define MAX_PACKET 2048
// DAC buffer occupancy stuff
(uint64_t)(config.resend_control_first_check_time * (uint64_t)1000000000);
uint64_t resend_repeat_interval =
(uint64_t)(config.resend_control_check_interval_time * (uint64_t)1000000000);
- uint64_t minimum_remaining_time = (uint64_t)(
- (config.resend_control_last_check_time + config.audio_backend_buffer_desired_length) *
- (uint64_t)1000000000);
+ uint64_t minimum_remaining_time = (uint64_t)((config.resend_control_last_check_time +
+ config.audio_backend_buffer_desired_length) *
+ (uint64_t)1000000000);
uint64_t latency_time = (uint64_t)(conn->latency * (uint64_t)1000000000);
latency_time = latency_time / (uint64_t)conn->input_rate;
} else {
if (resp == sps_extra_code_output_stalled) {
- if (conn->unfixable_error_reported == 0) {
- conn->unfixable_error_reported = 1;
+ if (config.unfixable_error_reported == 0) {
+ config.unfixable_error_reported = 1;
if (config.cmd_unfixable) {
command_execute(config.cmd_unfixable, "output_device_stalled", 1);
} else {
die("an unrecoverable error, \"output_device_stalled\", has been "
- "detected.",
- conn->connection_number);
+ "detected.");
}
}
} else {
void *player_thread_func(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
#ifdef CONFIG_METADATA
- uint64_t time_of_last_metadata_progress_update = 0; // the assignment is to stop a compiler warning...
+ uint64_t time_of_last_metadata_progress_update =
+ 0; // the assignment is to stop a compiler warning...
#endif
uint64_t previous_frames_played = 0; // initialised to avoid a "possibly uninitialised" warning
uint64_t previous_raw_measurement_time =
debug(3, "Output frame bytes is %d.", conn->output_bytes_per_frame);
- conn->dac_buffer_queue_minimum_length = (uint64_t)(
- config.audio_backend_buffer_interpolation_threshold_in_seconds * config.output_rate);
+ conn->dac_buffer_queue_minimum_length =
+ (uint64_t)(config.audio_backend_buffer_interpolation_threshold_in_seconds *
+ config.output_rate);
debug(3, "dac_buffer_queue_minimum_length is %" PRIu64 " frames.",
conn->dac_buffer_queue_minimum_length);
conn->session_corrections = 0;
conn->connection_state_to_output = get_requested_connection_state_to_output();
// this is about half a minute
-//#define trend_interval 3758
+// #define trend_interval 3758
// this is about 8 seconds
#define trend_interval 1003
} else {
current_delay = 0;
if ((resp == sps_extra_code_output_stalled) &&
- (conn->unfixable_error_reported == 0)) {
- conn->unfixable_error_reported = 1;
+ (config.unfixable_error_reported == 0)) {
+ config.unfixable_error_reported = 1;
if (config.cmd_unfixable) {
warn("Connection %d: An unfixable error has been detected -- output device is "
"stalled. Executing the "
send_ssnc_metadata('styp', "Classic", strlen("Classic"), 1);
#endif
if (config.statistics_requested)
- inform("Connection %d: Playback started at frame %" PRId64 " -- Classic AirPlay (\"AirPlay 1\").",
+ inform("Connection %d: Playback started at frame %" PRId64
+ " -- Classic AirPlay (\"AirPlay 1\").",
conn->connection_number, inframe->given_timestamp);
#endif
}
volatile int stop;
volatile int running;
volatile uint64_t watchdog_bark_time;
- volatile int watchdog_barks; // number of times the watchdog has timed out and done something
- int unfixable_error_reported; // set when an unfixable error command has been executed.
+ volatile int watchdog_barks; // number of times the watchdog has timed out and done something
uint64_t playstart;
uint64_t connection_start_time; // the time the device is selected, which could be a long time
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
-#include <netinet/tcp.h>
#include <sys/ioctl.h>
conn->stop = 1;
pthread_cancel(conn->thread);
} else if (conn->watchdog_barks == 3) {
- if ((config.cmd_unfixable) && (conn->unfixable_error_reported == 0)) {
- conn->unfixable_error_reported = 1;
+ if ((config.cmd_unfixable) && (config.unfixable_error_reported == 0)) {
+ config.unfixable_error_reported = 1;
command_execute(config.cmd_unfixable, "unable_to_cancel_play_session", 1);
} else {
die("an unrecoverable error, \"unable_to_cancel_play_session\", has been detected.",
uint64_t time_to_wait_to = get_absolute_time_in_ns();
;
time_to_wait_to = time_to_wait_to + wait_time;
-
+
int flags = 1;
if (setsockopt(conn->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags))) {
- debug(1,"can't enable keepalive checking on the RTSP socket");
+ debug(1, "can't enable keepalive checking on the RTSP socket");
}
// remaining_time will be zero if wait_time is zero
// Note: the socket will be closed when the thread exits
goto shutdown;
}
-
+
// An ETIMEDOUT error usually means keepalive has failed.
if (nread < 0) {
uint8_t public_key[32];
struct pairings *next;
-} * pairings;
+} *pairings;
static struct pairings *pairing_find(const char *device_id) {
for (struct pairings *pairing = pairings; pairing; pairing = pairing->next) {
conn->connection_number, get_category_string(conn->airplay_stream_category));
if (conn->airplay_stream_category == ptp_stream) {
ptp_send_control_message_string("B"); // signify play is "B"eginning
-
+
// get stream[0]
plist_t stream0 = plist_array_get_item(streams, 0);
if (getsockname(conn->fd, (struct sockaddr *)&conn->local, &size_of_reply) == 0) {
// Thanks to https://holmeshe.me/network-essentials-setsockopt-SO_KEEPALIVE/ for this.
-
- // Turn on keepalive stuff -- wait for keepidle + (keepcnt * keepinttvl time) seconds before giving up
- // An ETIMEOUT error is returned if the keepalive check fails
+
+ // Turn on keepalive stuff -- wait for keepidle + (keepcnt * keepinttvl time) seconds
+ // before giving up An ETIMEOUT error is returned if the keepalive check fails
int keepAliveIdleTime = 10; // wait this many seconds before checking for a dropped client
- int keepAliveCount = 5; // check this many times
- int keepAliveInterval = 1; // wait this many seconds between checks
-
+ int keepAliveCount = 5; // check this many times
+ int keepAliveInterval = 1; // wait this many seconds between checks
#if defined COMPILE_FOR_BSD || defined COMPILE_FOR_OSX
- #define SOL_OPTION IPPROTO_TCP
+#define SOL_OPTION IPPROTO_TCP
#else
- #define SOL_OPTION SOL_TCP
+#define SOL_OPTION SOL_TCP
#endif
#ifdef COMPILE_FOR_OSX
- #define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPALIVE
+#define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPALIVE
#else
- #define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPIDLE
+#define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPIDLE
#endif
-
- if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION, (void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) {
- debug(1,"can't set the keepidle wait time");
+ if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION,
+ (void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) {
+ debug(1, "can't set the keepidle wait time");
}
- if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPCNT, (void *)&keepAliveCount, sizeof(keepAliveCount))) {
- debug(1,"can't set the keepidle missing count");
+ if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPCNT, (void *)&keepAliveCount,
+ sizeof(keepAliveCount))) {
+ debug(1, "can't set the keepidle missing count");
}
- if (setsockopt(conn->fd, SOL_OPTION , TCP_KEEPINTVL, (void *)&keepAliveInterval, sizeof(keepAliveInterval))) {
- debug(1,"can't set the keepidle missing count interval");
+ if (setsockopt(conn->fd, SOL_OPTION, TCP_KEEPINTVL, (void *)&keepAliveInterval,
+ sizeof(keepAliveInterval))) {
+ debug(1, "can't set the keepidle missing count interval");
};
-
+
// initialise the connection info
void *client_addr = NULL, *self_addr = NULL;
conn->connection_ip_family = conn->local.SAFAMILY;