Add quit commands to the MPRIS and native D-Bus command set. Not tested ecologically.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define _COMMON_H
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -79,6 +80,7 @@ typedef struct {
|
||||
char *password;
|
||||
char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running
|
||||
// on host %h"
|
||||
|
||||
#ifdef CONFIG_PA
|
||||
char *pa_application_name; // the name under which Shairport Sync shows up as an "Application" in
|
||||
// the Sound Preferences in most desktop Linuxes.
|
||||
@@ -263,6 +265,9 @@ uint64_t fp_time_at_startup, fp_time_at_last_debug_message;
|
||||
long endianness;
|
||||
uint32_t uatoi(const char *nptr);
|
||||
|
||||
// this is for allowing us to cancel the whole program
|
||||
pthread_t main_thread_id;
|
||||
|
||||
shairport_cfg config;
|
||||
config_t config_file_stuff;
|
||||
|
||||
|
||||
+7
-4
@@ -545,9 +545,13 @@ gboolean notify_loop_status_callback(ShairportSyncAdvancedRemoteControl *skeleto
|
||||
}
|
||||
|
||||
static gboolean on_handle_quit(ShairportSync *skeleton, GDBusMethodInvocation *invocation,
|
||||
__attribute__((unused)) const gchar *command,
|
||||
__attribute__((unused)) gpointer user_data) {
|
||||
__attribute__((unused)) const gchar *command,
|
||||
__attribute__((unused)) gpointer user_data) {
|
||||
debug(1, "quit requested (native interface)");
|
||||
if (main_thread_id)
|
||||
debug(1, "Cancelling main thread results in %d.", pthread_cancel(main_thread_id));
|
||||
else
|
||||
debug(1, "Main thread ID is NULL.");
|
||||
shairport_sync_complete_quit(skeleton, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -597,8 +601,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
|
||||
g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold",
|
||||
G_CALLBACK(notify_loudness_threshold_callback), NULL);
|
||||
|
||||
g_signal_connect(shairportSyncSkeleton, "handle-quit",
|
||||
G_CALLBACK(on_handle_quit), NULL);
|
||||
g_signal_connect(shairportSyncSkeleton, "handle-quit", G_CALLBACK(on_handle_quit), NULL);
|
||||
|
||||
g_signal_connect(shairportSyncSkeleton, "handle-remote-command",
|
||||
G_CALLBACK(on_handle_remote_command), NULL);
|
||||
|
||||
+2
-1
@@ -185,7 +185,8 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused)
|
||||
|
||||
static gboolean on_handle_quit(MediaPlayer2 *skeleton, GDBusMethodInvocation *invocation,
|
||||
__attribute__((unused)) gpointer user_data) {
|
||||
debug(1,"quit requested (MPRIS interface).");
|
||||
debug(1, "quit requested (MPRIS interface).");
|
||||
pthread_cancel(main_thread_id);
|
||||
media_player2_complete_quit(skeleton, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -785,12 +785,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
int notified_buffer_empty = 0; // diagnostic only
|
||||
|
||||
debug_mutex_lock(&conn->ab_mutex, 30000, 1);
|
||||
|
||||
|
||||
|
||||
int wait;
|
||||
long dac_delay = 0; // long because alsa returns a long
|
||||
|
||||
pthread_cleanup_push(buffer_get_frame_cleanup_handler, (void *)conn); // undo what's been done so far
|
||||
|
||||
pthread_cleanup_push(buffer_get_frame_cleanup_handler,
|
||||
(void *)conn); // undo what's been done so far
|
||||
do {
|
||||
// get the time
|
||||
local_time_now = get_absolute_time_in_fp(); // type okay
|
||||
@@ -830,7 +830,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
if (conn->flush_requested == 1) {
|
||||
if (config.output->flush)
|
||||
config.output->flush(); // no cancellation points
|
||||
ab_resync(conn); // no cancellation points
|
||||
ab_resync(conn); // no cancellation points
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
conn->time_since_play_started = 0;
|
||||
@@ -1215,7 +1215,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
time_of_wakeup.tv_sec = sec;
|
||||
time_of_wakeup.tv_nsec = nsec;
|
||||
// pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup);
|
||||
int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup); // this is a pthread cancellation point
|
||||
int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex,
|
||||
&time_of_wakeup); // this is a pthread cancellation point
|
||||
if (rc != 0)
|
||||
debug(3, "pthread_cond_timedwait returned error code %d.", rc);
|
||||
#endif
|
||||
@@ -1231,17 +1232,17 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
} while (wait);
|
||||
|
||||
// seq_t read = conn->ab_read;
|
||||
if (!curframe->ready) {
|
||||
// debug(1, "Supplying a silent frame for frame %u", read);
|
||||
conn->missing_packets++;
|
||||
curframe->timestamp = 0; // indicate a silent frame should be substituted
|
||||
}
|
||||
curframe->ready = 0;
|
||||
curframe->resend_level = 0;
|
||||
conn->ab_read = SUCCESSOR(conn->ab_read);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
return curframe;
|
||||
if (!curframe->ready) {
|
||||
// debug(1, "Supplying a silent frame for frame %u", read);
|
||||
conn->missing_packets++;
|
||||
curframe->timestamp = 0; // indicate a silent frame should be substituted
|
||||
}
|
||||
curframe->ready = 0;
|
||||
curframe->resend_level = 0;
|
||||
conn->ab_read = SUCCESSOR(conn->ab_read);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
return curframe;
|
||||
}
|
||||
|
||||
static inline short shortmean(short a, short b) {
|
||||
@@ -1435,7 +1436,8 @@ void player_thread_cleanup_handler(void *arg) {
|
||||
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
|
||||
relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more...
|
||||
relinquish_dacp_server_information(
|
||||
conn); // say it doesn't belong to this conversation thread any more...
|
||||
|
||||
#else
|
||||
// stop watching for DACP port number stuff
|
||||
@@ -1468,11 +1470,11 @@ void player_thread_cleanup_handler(void *arg) {
|
||||
if (conn->outbuf) {
|
||||
free(conn->outbuf);
|
||||
conn->outbuf = NULL;
|
||||
}
|
||||
}
|
||||
if (conn->sbuf) {
|
||||
free(conn->sbuf);
|
||||
conn->sbuf = NULL;
|
||||
}
|
||||
}
|
||||
if (conn->tbuf) {
|
||||
free(conn->tbuf);
|
||||
conn->tbuf = NULL;
|
||||
@@ -1647,15 +1649,17 @@ void *player_thread_func(void *arg) {
|
||||
// if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) {
|
||||
// debug(1,"Define tbuf of length
|
||||
// %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
|
||||
conn->tbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
conn->tbuf =
|
||||
malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
if (conn->tbuf == NULL)
|
||||
die("Failed to allocate memory for the transition buffer.");
|
||||
|
||||
// initialise this, because soxr stuffing might be chosen later
|
||||
|
||||
conn->sbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
conn->sbuf =
|
||||
malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
if (conn->sbuf == NULL)
|
||||
die("Failed to allocate memory for the sbuf buffer.");
|
||||
|
||||
@@ -1685,7 +1689,7 @@ void *player_thread_func(void *arg) {
|
||||
if (conn->dapo_private_storage)
|
||||
debug(1, "DACP monitor already initialised?");
|
||||
else
|
||||
// this does not have pthread cancellation points in it (assuming avahi doesn't)
|
||||
// this does not have pthread cancellation points in it (assuming avahi doesn't)
|
||||
conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id); // ??
|
||||
#endif
|
||||
|
||||
@@ -1734,12 +1738,12 @@ void *player_thread_func(void *arg) {
|
||||
debug(3, "Set initial volume to %f.", config.airplay_volume);
|
||||
player_volume(config.airplay_volume, conn); // ??
|
||||
int64_t frames_to_drop = 0;
|
||||
|
||||
// create and start the timing, control and audio receiver threads
|
||||
|
||||
// create and start the timing, control and audio receiver threads
|
||||
pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn);
|
||||
pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn);
|
||||
pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn);
|
||||
|
||||
|
||||
pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far
|
||||
|
||||
// debug(1, "Play begin");
|
||||
@@ -2144,9 +2148,9 @@ void *player_thread_func(void *arg) {
|
||||
case ST_soxr:
|
||||
#ifdef HAVE_LIBSOXR
|
||||
// if (amount_to_stuff) debug(1,"Soxr stuff...");
|
||||
play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf, inbuflength,
|
||||
config.output_format, conn->outbuf, amount_to_stuff,
|
||||
enable_dither, conn);
|
||||
play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf,
|
||||
inbuflength, config.output_format, conn->outbuf,
|
||||
amount_to_stuff, enable_dither, conn);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -2201,8 +2205,9 @@ void *player_thread_func(void *arg) {
|
||||
} else {
|
||||
// if there is no delay procedure, or it's not working or not allowed, there can be no
|
||||
// synchronising
|
||||
play_samples = stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
|
||||
conn->outbuf, 0, enable_dither, conn);
|
||||
play_samples =
|
||||
stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
|
||||
conn->outbuf, 0, enable_dither, conn);
|
||||
if (conn->outbuf == NULL)
|
||||
debug(1, "NULL outbuf to play -- skipping it.");
|
||||
else
|
||||
@@ -2275,26 +2280,26 @@ void *player_thread_func(void *arg) {
|
||||
if (at_least_one_frame_seen) {
|
||||
if ((config.output->delay)) {
|
||||
if (config.no_sync == 0) {
|
||||
inform(
|
||||
"|%*.1f," /* Sync error in milliseconds */
|
||||
"%*.1f," /* net correction in ppm */
|
||||
"%*.1f," /* corrections in ppm */
|
||||
"%*d," /* total packets */
|
||||
"%*llu," /* missing packets */
|
||||
"%*llu," /* late packets */
|
||||
"%*llu," /* too late packets */
|
||||
"%*llu," /* resend requests */
|
||||
"%*lli," /* min DAC queue size */
|
||||
"%*d," /* min buffer occupancy */
|
||||
"%*d", /* max buffer occupancy */
|
||||
10,
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
10, moving_average_correction * 1000000 / (352 * conn->output_sample_ratio),
|
||||
10, moving_average_insertions_plus_deletions * 1000000 /
|
||||
(352 * conn->output_sample_ratio),
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size,
|
||||
5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
inform("|%*.1f," /* Sync error in milliseconds */
|
||||
"%*.1f," /* net correction in ppm */
|
||||
"%*.1f," /* corrections in ppm */
|
||||
"%*d," /* total packets */
|
||||
"%*llu," /* missing packets */
|
||||
"%*llu," /* late packets */
|
||||
"%*llu," /* too late packets */
|
||||
"%*llu," /* resend requests */
|
||||
"%*lli," /* min DAC queue size */
|
||||
"%*d," /* min buffer occupancy */
|
||||
"%*d", /* max buffer occupancy */
|
||||
10,
|
||||
1000 * moving_average_sync_error / config.output_rate, 10,
|
||||
moving_average_correction * 1000000 / (352 * conn->output_sample_ratio),
|
||||
10, moving_average_insertions_plus_deletions * 1000000 /
|
||||
(352 * conn->output_sample_ratio),
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 7,
|
||||
minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5,
|
||||
maximum_buffer_occupancy);
|
||||
} else {
|
||||
inform("|%*.1f," /* Sync error in milliseconds */
|
||||
"%*d," /* total packets */
|
||||
@@ -2306,11 +2311,10 @@ void *player_thread_func(void *arg) {
|
||||
"%*d," /* min buffer occupancy */
|
||||
"%*d", /* max buffer occupancy */
|
||||
10,
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 7,
|
||||
minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5,
|
||||
maximum_buffer_occupancy);
|
||||
1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
|
||||
conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7,
|
||||
conn->resend_requests, 7, minimum_dac_queue_size, 5,
|
||||
minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
}
|
||||
} else {
|
||||
inform("|%*.1f," /* Sync error in milliseconds */
|
||||
@@ -2322,10 +2326,10 @@ void *player_thread_func(void *arg) {
|
||||
"%*d," /* min buffer occupancy */
|
||||
"%*d", /* max buffer occupancy */
|
||||
10,
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 5,
|
||||
minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
|
||||
conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7,
|
||||
conn->resend_requests, 5, minimum_buffer_occupancy, 5,
|
||||
maximum_buffer_occupancy);
|
||||
}
|
||||
} else {
|
||||
inform("No frames received in the last sampling interval.");
|
||||
@@ -2339,73 +2343,74 @@ void *player_thread_func(void *arg) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(1,"This should never be called.");
|
||||
|
||||
/* all done in the cleanup...
|
||||
debug(1, "This should never be called.");
|
||||
|
||||
debug(3, "Connection %d: player thread main loop exit.", conn->connection_number);
|
||||
/* all done in the cleanup...
|
||||
|
||||
if (config.statistics_requested) {
|
||||
int rawSeconds = (int)difftime(time(NULL), conn->playstart);
|
||||
int elapsedHours = rawSeconds / 3600;
|
||||
int elapsedMin = (rawSeconds / 60) % 60;
|
||||
int elapsedSec = rawSeconds % 60;
|
||||
inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin,
|
||||
elapsedSec);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
debug(3, "Connection %d: player thread main loop exit.", conn->connection_number);
|
||||
|
||||
relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more...
|
||||
if (config.statistics_requested) {
|
||||
int rawSeconds = (int)difftime(time(NULL), conn->playstart);
|
||||
int elapsedHours = rawSeconds / 3600;
|
||||
int elapsedMin = (rawSeconds / 60) % 60;
|
||||
int elapsedSec = rawSeconds % 60;
|
||||
inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin,
|
||||
elapsedSec);
|
||||
}
|
||||
|
||||
#else
|
||||
// stop watching for DACP port number stuff
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
if (conn->dapo_private_storage) {
|
||||
mdns_dacp_dont_monitor(conn->dapo_private_storage);
|
||||
conn->dapo_private_storage = NULL;
|
||||
} else {
|
||||
debug(2, "DACP Monitor already stopped");
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
|
||||
debug(2, "Cancelling timing, control and audio threads...");
|
||||
debug(2, "Cancel timing thread.");
|
||||
pthread_cancel(rtp_timing_thread);
|
||||
debug(2, "Join timing thread.");
|
||||
pthread_join(rtp_timing_thread, NULL);
|
||||
debug(2, "Timing thread terminated.");
|
||||
debug(2, "Cancel control thread.");
|
||||
pthread_cancel(rtp_control_thread);
|
||||
debug(2, "Join control thread.");
|
||||
pthread_join(rtp_control_thread, NULL);
|
||||
debug(2, "Control thread terminated.");
|
||||
debug(2, "Cancel audio thread.");
|
||||
pthread_cancel(rtp_audio_thread);
|
||||
debug(2, "Join audio thread.");
|
||||
pthread_join(rtp_audio_thread, NULL);
|
||||
debug(2, "Audio thread terminated.");
|
||||
clear_reference_timestamp(conn);
|
||||
conn->rtp_running = 0;
|
||||
relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread
|
||||
any more...
|
||||
|
||||
debug(3, "Connection %d: stopping output device.", conn->connection_number);
|
||||
#else
|
||||
// stop watching for DACP port number stuff
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
if (conn->dapo_private_storage) {
|
||||
mdns_dacp_dont_monitor(conn->dapo_private_storage);
|
||||
conn->dapo_private_storage = NULL;
|
||||
} else {
|
||||
debug(2, "DACP Monitor already stopped");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config.output->stop)
|
||||
config.output->stop();
|
||||
debug(2, "Cancelling timing, control and audio threads...");
|
||||
debug(2, "Cancel timing thread.");
|
||||
pthread_cancel(rtp_timing_thread);
|
||||
debug(2, "Join timing thread.");
|
||||
pthread_join(rtp_timing_thread, NULL);
|
||||
debug(2, "Timing thread terminated.");
|
||||
debug(2, "Cancel control thread.");
|
||||
pthread_cancel(rtp_control_thread);
|
||||
debug(2, "Join control thread.");
|
||||
pthread_join(rtp_control_thread, NULL);
|
||||
debug(2, "Control thread terminated.");
|
||||
debug(2, "Cancel audio thread.");
|
||||
pthread_cancel(rtp_audio_thread);
|
||||
debug(2, "Join audio thread.");
|
||||
pthread_join(rtp_audio_thread, NULL);
|
||||
debug(2, "Audio thread terminated.");
|
||||
clear_reference_timestamp(conn);
|
||||
conn->rtp_running = 0;
|
||||
|
||||
debug(2, "Freeing audio buffers and decoders.");
|
||||
debug(3, "Connection %d: stopping output device.", conn->connection_number);
|
||||
|
||||
free_audio_buffers(conn);
|
||||
terminate_decoders(conn);
|
||||
debug(2, "Connection %d: player thread terminated.", conn->connection_number);
|
||||
if (outbuf)
|
||||
free(outbuf);
|
||||
if (tbuf)
|
||||
free(tbuf);
|
||||
if (sbuf)
|
||||
free(sbuf);
|
||||
*/
|
||||
if (config.output->stop)
|
||||
config.output->stop();
|
||||
|
||||
debug(2, "Freeing audio buffers and decoders.");
|
||||
|
||||
free_audio_buffers(conn);
|
||||
terminate_decoders(conn);
|
||||
debug(2, "Connection %d: player thread terminated.", conn->connection_number);
|
||||
if (outbuf)
|
||||
free(outbuf);
|
||||
if (tbuf)
|
||||
free(tbuf);
|
||||
if (sbuf)
|
||||
free(sbuf);
|
||||
*/
|
||||
pthread_cleanup_pop(1);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
@@ -2413,7 +2418,8 @@ void *player_thread_func(void *arg) {
|
||||
// takes the volume as specified by the airplay protocol
|
||||
void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) {
|
||||
|
||||
// no cancellation points here if we assume that the mute call to the back end has no cancellation points
|
||||
// no cancellation points here if we assume that the mute call to the back end has no cancellation
|
||||
// points
|
||||
|
||||
// The volume ranges -144.0 (mute) or -30 -- 0. See
|
||||
// http://git.zx2c4.com/Airtunes2/about/#setting-volume
|
||||
@@ -2578,9 +2584,9 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
|
||||
if (config.ignore_volume_control == 1)
|
||||
scaled_attenuation = max_db;
|
||||
else if (config.volume_control_profile == VCP_standard)
|
||||
scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points
|
||||
scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points
|
||||
else if (config.volume_control_profile == VCP_flat)
|
||||
scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
|
||||
scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
|
||||
else
|
||||
debug(1, "Unrecognised volume control profile");
|
||||
|
||||
@@ -2615,7 +2621,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
|
||||
// %f",software_attenuation,temp_fix_volume,airplay_volume);
|
||||
|
||||
conn->fix_volume = temp_fix_volume;
|
||||
memory_barrier(); // no cancellation points
|
||||
memory_barrier(); // no cancellation points
|
||||
|
||||
if (config.loudness)
|
||||
loudness_set_volume(software_attenuation / 100);
|
||||
|
||||
@@ -74,9 +74,9 @@ typedef struct {
|
||||
// otherwise
|
||||
int64_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero
|
||||
// otherwise
|
||||
|
||||
|
||||
int fd;
|
||||
int authorized; // set if a password is required and has been supplied
|
||||
int authorized; // set if a password is required and has been supplied
|
||||
char *auth_nonce; // the session nonce, if needed
|
||||
stream_cfg stream;
|
||||
SOCKADDR remote, local;
|
||||
|
||||
@@ -1889,7 +1889,7 @@ authenticate:
|
||||
}
|
||||
|
||||
void rtsp_conversation_thread_cleanup_function(void *arg) {
|
||||
debug(1,"rtsp_conversation_thread_func_cleanup_function called.");
|
||||
debug(1, "rtsp_conversation_thread_func_cleanup_function called.");
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
|
||||
if (conn->fd > 0)
|
||||
close(conn->fd);
|
||||
@@ -1923,10 +1923,10 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
|
||||
rc = pthread_mutex_destroy(&conn->flush_mutex);
|
||||
if (rc)
|
||||
debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
|
||||
}
|
||||
}
|
||||
|
||||
void msg_cleanup_function(void *arg) {
|
||||
debug(1,"msg_cleanup_function called.");
|
||||
debug(1, "msg_cleanup_function called.");
|
||||
msg_free((rtsp_message *)arg);
|
||||
}
|
||||
|
||||
@@ -1961,14 +1961,14 @@ static void *rtsp_conversation_thread_func(void *pconn) {
|
||||
int rtsp_read_request_attempt_count = 1; // 1 means exit immediately
|
||||
rtsp_message *req, *resp;
|
||||
|
||||
pthread_cleanup_push(rtsp_conversation_thread_cleanup_function,(void *)conn);
|
||||
pthread_cleanup_push(rtsp_conversation_thread_cleanup_function, (void *)conn);
|
||||
while (conn->stop == 0) {
|
||||
int debug_level = 3; // for printing the request and response
|
||||
reply = rtsp_read_request(conn,&req);
|
||||
reply = rtsp_read_request(conn, &req);
|
||||
if (reply == rtsp_read_request_response_ok) {
|
||||
pthread_cleanup_push(msg_cleanup_function,(void*)req);
|
||||
pthread_cleanup_push(msg_cleanup_function, (void *)req);
|
||||
resp = msg_init();
|
||||
pthread_cleanup_push(msg_cleanup_function,(void*)resp);
|
||||
pthread_cleanup_push(msg_cleanup_function, (void *)resp);
|
||||
resp->respcode = 400;
|
||||
|
||||
if (strcmp(req->method, "OPTIONS") !=
|
||||
@@ -2176,6 +2176,7 @@ void rtsp_listen_loop(void) {
|
||||
int acceptfd;
|
||||
struct timeval tv;
|
||||
do {
|
||||
pthread_testcancel();
|
||||
tv.tv_sec = 60;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
|
||||
+45
-16
@@ -60,6 +60,11 @@
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "rtp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
#if defined(HAVE_DACP_CLIENT)
|
||||
#include "dacp.h"
|
||||
#endif
|
||||
@@ -80,11 +85,6 @@
|
||||
#include "mpris-service.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "rtp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
#include <libdaemon/dexec.h>
|
||||
#include <libdaemon/dfork.h>
|
||||
#include <libdaemon/dlog.h>
|
||||
@@ -1131,7 +1131,7 @@ const char *pid_file_proc(void) {
|
||||
}
|
||||
|
||||
void exit_function() {
|
||||
// debug(1, "exit function called...");
|
||||
debug(1, "exit function called...");
|
||||
if (config.cfg)
|
||||
config_destroy(config.cfg);
|
||||
if (config.appName)
|
||||
@@ -1139,7 +1139,19 @@ void exit_function() {
|
||||
// probably should be freeing malloc'ed memory here, including strdup-created strings...
|
||||
}
|
||||
|
||||
void main_cleanup_handler(__attribute__((unused)) void *arg) {
|
||||
|
||||
debug(1, "main cleanup handler called.");
|
||||
shairport_shutdown();
|
||||
daemon_log(LOG_NOTICE, "Unexpected exit...");
|
||||
daemon_retval_send(0);
|
||||
daemon_pid_file_remove();
|
||||
daemon_signal_done();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
memset((void *)&main_thread_id, 0, sizeof(main_thread_id));
|
||||
fp_time_at_startup = get_absolute_time_in_fp();
|
||||
fp_time_at_last_debug_message = fp_time_at_startup;
|
||||
// debug(1,"startup");
|
||||
@@ -1362,10 +1374,11 @@ int main(int argc, char **argv) {
|
||||
/* Close FDs */
|
||||
if (daemon_close_all(-1) < 0) {
|
||||
daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
|
||||
|
||||
/* Send the error condition to the parent process */
|
||||
daemon_retval_send(1);
|
||||
goto finish;
|
||||
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the PID file if required */
|
||||
@@ -1376,12 +1389,16 @@ int main(int argc, char **argv) {
|
||||
if ((result != 0) && (result != -EEXIST)) {
|
||||
// error creating or accessing the PID file directory
|
||||
daemon_retval_send(3);
|
||||
goto finish;
|
||||
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
}
|
||||
if (daemon_pid_file_create() < 0) {
|
||||
daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
|
||||
|
||||
daemon_retval_send(2);
|
||||
goto finish;
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1391,11 +1408,22 @@ int main(int argc, char **argv) {
|
||||
/* end libdaemon stuff */
|
||||
}
|
||||
|
||||
// int old_cancel_state = 0;
|
||||
// pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||
// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
|
||||
main_thread_id = pthread_self();
|
||||
if (main_thread_id)
|
||||
debug(1, "Main thread ID set up.");
|
||||
else
|
||||
debug(1, "Main thread is set up to be NULL!");
|
||||
|
||||
signal_setup();
|
||||
|
||||
// make sure the program can create files that group and world can read
|
||||
umask(S_IWGRP | S_IWOTH);
|
||||
|
||||
pthread_cleanup_push(main_cleanup_handler, NULL);
|
||||
|
||||
config.output = audio_get_output(config.output_name);
|
||||
if (!config.output) {
|
||||
audio_ls_outputs();
|
||||
@@ -1587,10 +1615,11 @@ int main(int argc, char **argv) {
|
||||
rtsp_listen_loop();
|
||||
|
||||
// should not reach this...
|
||||
shairport_shutdown();
|
||||
finish:
|
||||
daemon_log(LOG_NOTICE, "Unexpected exit...");
|
||||
daemon_retval_send(255);
|
||||
daemon_pid_file_remove();
|
||||
return 1;
|
||||
// shairport_shutdown();
|
||||
// daemon_log(LOG_NOTICE, "Unexpected exit...");
|
||||
// daemon_retval_send(0);
|
||||
// daemon_pid_file_remove();
|
||||
pthread_cleanup_pop(1);
|
||||
debug(1, "Odd exit point");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user