Add a new exit handler to enable Shairport Sync to exit cleanly — that is, on exit, to clean up everything, e.g. open files, ports, sockets, devices, threads, it has been using.
If cleanup isn’t finished after one second, exit will occur unconditionally. Use the new exit handler for normal exit, for SIGINT and SIGTERM handling, for abnormal exit after fatal errors, and for handling quit requests from the D-Bus and MPRIS interfaces. When an unfixable error occurs without an installed unfixable error handler, unlock the mutex protecting Shairport Sync’s alsa backend to permit a clean exit. Fix a very low-level mutex-locking error that interfered with debugging. Simplify much mutex lock handling. Remove lots of old and unused code, variables and definitions. Update audio_sndio.c to remove some harmless compiler warnings. Undo adding two seconds for messages to be output before _Exit() on die() to allow messages to be output... Undo making die() exit unconditionally.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* Modifications for audio synchronisation, AirPlay 2
|
||||
* and related work, copyright (c) Mike Brady 2014--2025
|
||||
* and related work, copyright (c) Mike Brady 2014--2026
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
@@ -332,7 +332,7 @@ static void free_audio_buffers(rtsp_conn_info *conn) {
|
||||
int first_possibly_missing_frame = -1;
|
||||
|
||||
void reset_buffer(rtsp_conn_info *conn) {
|
||||
pthread_cleanup_debug_mutex_lock(&conn->ab_mutex, 30000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->ab_mutex);
|
||||
ab_resync(conn);
|
||||
pthread_cleanup_pop(1);
|
||||
#if CONFIG_FFMPEG
|
||||
@@ -349,7 +349,7 @@ void reset_buffer(rtsp_conn_info *conn) {
|
||||
|
||||
size_t get_audio_buffer_occupancy(rtsp_conn_info *conn) {
|
||||
size_t response = 0;
|
||||
pthread_cleanup_debug_mutex_lock(&conn->ab_mutex, 30000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->ab_mutex);
|
||||
if (conn->ab_synced) {
|
||||
int16_t occ =
|
||||
conn->ab_write - conn->ab_read; // will be zero or positive if read and write are within
|
||||
@@ -1412,7 +1412,7 @@ seq_t get_revised_seqno(rtsp_conn_info *conn, uint32_t timestamp) {
|
||||
// go back through the buffers to find the first buffer following a buffer that predates
|
||||
// the given timestamp, if any.
|
||||
seq_t revised_seqno = conn->ab_write;
|
||||
pthread_cleanup_debug_mutex_lock(&conn->ab_mutex, 30000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->ab_mutex);
|
||||
int older_seqno_found = 0;
|
||||
while ((older_seqno_found == 0) && (revised_seqno != conn->ab_read)) {
|
||||
revised_seqno--;
|
||||
@@ -1478,18 +1478,18 @@ uint32_t player_put_packet(uint32_t ssrc, seq_t seqno, uint32_t actual_timestamp
|
||||
|
||||
// ignore a request to flush that has been made before the first packet...
|
||||
if (conn->packet_count == 0) {
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 4);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
conn->flush_requested = 0;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
debug_mutex_unlock(&conn->flush_mutex, 4);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_debug_mutex_lock(&conn->ab_mutex, 30000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->ab_mutex);
|
||||
uint64_t time_now = get_absolute_time_in_ns();
|
||||
conn->packet_count++;
|
||||
conn->packet_count_since_flush++;
|
||||
conn->time_of_last_audio_packet = time_now;
|
||||
if (conn->connection_state_to_output) { // if we are supposed to be processing these packets
|
||||
// if (conn->connection_state_to_output) { // if we are supposed to be processing these packets
|
||||
abuf_t *abuf = 0;
|
||||
if (!conn->ab_synced) {
|
||||
conn->ab_write = seqno;
|
||||
@@ -1795,7 +1795,7 @@ uint32_t player_put_packet(uint32_t ssrc, seq_t seqno, uint32_t actual_timestamp
|
||||
if (number_of_missing_frames == 0)
|
||||
first_possibly_missing_frame = conn->ab_write;
|
||||
}
|
||||
}
|
||||
// } // remove this
|
||||
pthread_cleanup_pop(1);
|
||||
// debug_mutex_unlock(&conn->ab_mutex, 0);
|
||||
return input_packets_used;
|
||||
@@ -2044,7 +2044,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn, int resync_requested) {
|
||||
abuf_t *curframe = NULL;
|
||||
int notified_buffer_empty = 0; // diagnostic only
|
||||
|
||||
pthread_cleanup_debug_mutex_lock(&conn->ab_mutex, 30000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->ab_mutex);
|
||||
|
||||
int wait;
|
||||
long dac_delay = 0; // long because alsa returns a long
|
||||
@@ -2059,6 +2059,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn, int resync_requested) {
|
||||
// we must have timing information before we can do anything here
|
||||
if ((have_timestamp_timing_information(conn)) && (conn->input_format_is_valid != 0)) {
|
||||
|
||||
/*
|
||||
int rco = get_requested_connection_state_to_output();
|
||||
|
||||
if (conn->connection_state_to_output != rco) {
|
||||
@@ -2066,23 +2067,23 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn, int resync_requested) {
|
||||
// change happening
|
||||
if (conn->connection_state_to_output == 0) { // going off
|
||||
debug(2, "request flush because connection_state_to_output is off");
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
conn->flush_requested = 1;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
if (config.output->is_running)
|
||||
if (config.output->is_running() != 0) { // if the back end isn't running for any reason
|
||||
debug(2, "request flush because back end is not running");
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 0);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
conn->flush_requested = 1;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
debug_mutex_unlock(&conn->flush_mutex, 0);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_debug_mutex_lock(&conn->flush_mutex, 1000, 0);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->flush_mutex);
|
||||
if (conn->flush_requested == 1) {
|
||||
if (conn->flush_output_flushed == 0) {
|
||||
#if CONFIG_FFMPEG
|
||||
@@ -3557,7 +3558,7 @@ void *player_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
conn->session_corrections = 0;
|
||||
conn->connection_state_to_output = get_requested_connection_state_to_output();
|
||||
// conn->connection_state_to_output = get_requested_connection_state_to_output();
|
||||
|
||||
int number_of_statistics, oldest_statistic, newest_statistic;
|
||||
uint32_t frames_since_last_stats_logged = 0;
|
||||
@@ -5017,7 +5018,7 @@ static void player_send_volume_metadata(uint8_t vol_mode_both, double airplay_vo
|
||||
}
|
||||
|
||||
void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) {
|
||||
debug_mutex_lock(&conn->volume_control_mutex, 5000, 4);
|
||||
pthread_mutex_lock(&conn->volume_control_mutex);
|
||||
// first, see if we are hw only, sw only, both with hw attenuation on the top or both with sw
|
||||
// attenuation on top
|
||||
|
||||
@@ -5235,7 +5236,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
|
||||
// here, store the volume for possible use in the future
|
||||
config.airplay_volume = airplay_volume;
|
||||
conn->own_airplay_volume = airplay_volume;
|
||||
debug_mutex_unlock(&conn->volume_control_mutex, 4);
|
||||
pthread_mutex_unlock(&conn->volume_control_mutex);
|
||||
}
|
||||
|
||||
void player_volume(double airplay_volume, rtsp_conn_info *conn) {
|
||||
@@ -5246,11 +5247,11 @@ void player_volume(double airplay_volume, rtsp_conn_info *conn) {
|
||||
void do_flush(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
|
||||
debug(3, "do_flush: flush to %u.", timestamp);
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
conn->flush_requested = 1;
|
||||
conn->flush_rtp_timestamp = timestamp; // flush all packets up to, but not including, this one.
|
||||
reset_input_flow_metrics(conn);
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
|
||||
void player_flush(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
@@ -5280,7 +5281,7 @@ int player_play(rtsp_conn_info *conn) {
|
||||
// access to the output device (i.e. knowing that it should not be in
|
||||
// use by another program at this time).
|
||||
|
||||
pthread_cleanup_debug_mutex_lock(&conn->player_create_delete_mutex, 5000, 1);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->player_create_delete_mutex);
|
||||
if (conn->player_thread == NULL) {
|
||||
pthread_t *pt = malloc(sizeof(pthread_t));
|
||||
if (pt == NULL)
|
||||
@@ -5307,7 +5308,7 @@ int player_stop(rtsp_conn_info *conn) {
|
||||
// note -- this may be called from another connection thread.
|
||||
debug(2, "Connection %d: player_stop.", conn->connection_number);
|
||||
int response = 0; // okay
|
||||
pthread_cleanup_debug_mutex_lock(&conn->player_create_delete_mutex, 5000, 4);
|
||||
pthread_mutex_lock_and_cleanup_push(&conn->player_create_delete_mutex);
|
||||
pthread_t *pt = conn->player_thread;
|
||||
if (pt) {
|
||||
debug(3, "player_thread cancel...");
|
||||
|
||||
Reference in New Issue
Block a user