Start using get_play_lock and release_play_lock and enable them to turn on and off the appropriate bonjour flags.

This commit is contained in:
Mike Brady
2025-12-08 09:50:54 +00:00
parent 5969896612
commit f2de7fadef
2 changed files with 59 additions and 60 deletions
+13 -4
View File
@@ -34,7 +34,7 @@
void ap2_event_receiver_cleanup_handler(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
debug(3, "Connection %d: AP2 Event Receiver Cleanup start.", conn->connection_number);
debug(1, "Connection %d: AP2 Event Receiver Cleanup start.", conn->connection_number);
// only update these things if you're (still) the principal conn
#ifdef CONFIG_METADATA
@@ -55,18 +55,24 @@ void ap2_event_receiver_cleanup_handler(void *arg) {
free(conn->ap2_client_name);
conn->ap2_client_name = NULL;
}
/*
pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
if (principal_conn)
debug(1, "principal_conn: %d.", principal_conn->connection_number);
else
debug(1, "principal_conn: is NULL.");
if (principal_conn == conn) {
config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
build_bonjour_strings(conn);
debug(3, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
debug(1, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
get_category_string(conn->airplay_stream_category));
mdns_update(NULL, secondary_txt_records);
principal_conn = NULL;
}
pthread_cleanup_pop(1); // release the principal_conn lock
debug(2, "Connection %d: AP2 Event Receiver Cleanup exit.", conn->connection_number);
*/
debug(1, "Connection %d: AP2 Event Receiver Cleanup exit.", conn->connection_number);
}
void *ap2_event_receiver(void *arg) {
@@ -77,6 +83,8 @@ void *ap2_event_receiver(void *arg) {
structured_buffer *sbuf = sbuf_new(4096);
if (sbuf != NULL) {
pthread_cleanup_push(sbuf_cleanup, sbuf);
/*
// only update these things if you're (still) the principal conn
pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
@@ -89,6 +97,7 @@ void *ap2_event_receiver(void *arg) {
mdns_update(NULL, secondary_txt_records);
}
pthread_cleanup_pop(1); // release the principal_conn lock
*/
pthread_cleanup_push(ap2_event_receiver_cleanup_handler, arg);
// listen(conn->event_socket, 5); // this is now done in the handle_setup_2 code
@@ -178,7 +187,7 @@ void *ap2_event_receiver(void *arg) {
debug(3, "Connection %d: Packet Received on Event Port with contents: \"%s\".",
conn->connection_number, packet);
} else {
debug(2, "Connection %d: Event Port connection closed by client",
debug(1, "Connection %d: Event Port connection closed by client",
conn->connection_number);
finished = 1;
}
+46 -56
View File
@@ -398,8 +398,18 @@ void release_play_lock(rtsp_conn_info *conn) {
// no need thread cancellation points in here
pthread_rwlock_wrlock(&principal_conn_lock);
if (principal_conn == conn) { // if we have the player
if (conn != NULL)
debug(2, "Connection %d: principal_conn released.", conn->connection_number);
if (conn != NULL) {
#ifdef CONFIG_AIRPLAY_2
config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
if (conn->airplay_gid) {
free(conn->airplay_gid);
conn->airplay_gid = NULL; // stop using the client's GID as our GID.
}
build_bonjour_strings(conn);
mdns_update(NULL, secondary_txt_records);
#endif
debug(1,"Connection %d: %s released principal_conn.", conn->connection_number, get_category_string(conn->airplay_stream_category));
}
principal_conn = NULL; // let it go
}
pthread_rwlock_unlock(&principal_conn_lock);
@@ -408,18 +418,20 @@ void release_play_lock(rtsp_conn_info *conn) {
// stop the current principal_conn from playing if necessary and make conn the principal_conn.
int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) {
debug(1,"Connection %d: %s get_play_lock.", conn->connection_number, get_category_string(conn->airplay_stream_category));
int response = 0;
pthread_rwlock_wrlock(&principal_conn_lock);
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
if (principal_conn != NULL)
debug(2, "Connection %d: is requested to relinquish principal_conn.",
debug(1, "Connection %d: is requested to relinquish principal_conn.",
principal_conn->connection_number);
if (conn != NULL)
debug(2, "Connection %d: request to acquire principal_conn.", conn->connection_number);
debug(1, "Connection %d: request to acquire principal_conn.", conn->connection_number);
// returns -1 if it failed, 0 if it succeeded and 1 if it succeeded but
// interrupted an existing session
if (principal_conn == NULL) {
principal_conn = conn;
config.airplay_statusflags |= (1 << 11); // DeviceSupportsRelay
} else if (principal_conn == conn) {
if (conn != NULL)
warn("Connection %d: request to re-acquire principal_conn!",
@@ -427,33 +439,32 @@ int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) {
} else if (allow_session_interruption != 0) {
rtsp_conn_info *previous_principal_conn = principal_conn;
// important -- demote the principal conn before cancelling it
if (principal_conn->fd > 0) {
debug(2,
"Connection %d: get_play_lock forced termination in favour of connection %d. Closing "
"Connection %d: has acquired play_lock and is forcing termination of Connection %d. Closing "
"RTSP connection socket %d: "
"from %s:%u to self at "
"%s:%u.",
principal_conn->connection_number, conn->connection_number, principal_conn->fd,
conn->connection_number, principal_conn->connection_number, principal_conn->fd,
principal_conn->client_ip_string, principal_conn->client_rtsp_port,
principal_conn->self_ip_string, principal_conn->self_rtsp_port);
close(principal_conn->fd);
// principal_conn->fd = 0;
}
principal_conn = NULL;
pthread_cancel(previous_principal_conn->thread);
// the previous principal thread will block on the principal conn lock when exiting
// so it's important not to wait for it here, e.g. don't put in a pthread_join here.
// threads are garbage-collected later
principal_conn = conn; // make the conn the new principal_conn
pthread_cancel(previous_principal_conn->thread); // cancel the previous one...
usleep(1000000); // don't know why this delay is needed.
principal_conn = conn; // make the conn the new principal_conn
#ifdef CONFIG_AIRPLAY_2
config.airplay_statusflags |= (1 << 11); // DeviceSupportsRelay
// build_bonjour_strings(conn);
// mdns_update(NULL, secondary_txt_records);
#endif
response = 1; // interrupted an existing session
} else {
response = -1; // can't get it...
}
if (principal_conn != NULL)
debug(3, "Connection %d has principal_conn.", principal_conn->connection_number);
debug(1,"Connection %d: %s has principal_conn.", conn->connection_number, get_category_string(conn->airplay_stream_category));
pthread_cleanup_pop(1); // release the principal_conn lock
return response;
}
@@ -2511,6 +2522,9 @@ void handle_options(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *
"OPTIONS, POST, GET, PUT");
}
// TEARDOWN and TEARDOWN for AP2 look the same!
void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
rtsp_message *resp) {
@@ -2532,38 +2546,19 @@ void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_messag
void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
rtsp_message *resp) {
debug(1, "Connection %d: TEARDOWN (Classic AirPlay)", conn->connection_number);
debug_log_rtsp_message(1, "TEARDOWN (Classic AirPlay) request", req);
debug(2, "Connection %d: TEARDOWN (Classic AirPlay)", conn->connection_number);
debug_log_rtsp_message(2, "TEARDOWN (Classic AirPlay) request", req);
// most of the cleanup here is done by the exiting player_thread, if any, and by the event receiver if and when it exits.
if (conn->player_thread) {
debug(1, "TEARDOWN is stopping a player...");
player_stop(conn); // this nulls the player_thread and cancels the threads...
activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
}
if (conn->dacp_active_remote != NULL) {
free(conn->dacp_active_remote);
conn->dacp_active_remote = NULL;
}
// only update these things if you're (still) the principal conn
pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
if (principal_conn == conn) {
#ifdef CONFIG_AIRPLAY_2
config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
build_bonjour_strings(conn);
mdns_update(NULL, secondary_txt_records);
#endif
principal_conn = NULL; // stop being principal_conn
}
pthread_cleanup_pop(1); // release the principal_conn lock
#ifdef CONFIG_FFMPEG
clear_decoding_chain(conn);
#endif
resp->respcode = 200;
msg_add_header(resp, "Connection", "close");
debug(3, "TEARDOWN: successful termination of playing thread of RTSP conversation thread %d.",
conn->connection_number);
// debug(1,"Bogus exit for valgrind -- remember to comment it out!.");
// exit(EXIT_SUCCESS);
}
@@ -2714,6 +2709,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
// airplay 2 always allows interruption, so should never return -1
if (get_play_lock(conn, 1) != -1) {
debug(1, "Connection %d: %s AP2 setup -- play lock acquired.", conn->connection_number, get_category_string(conn->airplay_stream_category));
#ifdef CONFIG_METADATA
send_ssnc_metadata('conn', conn->client_ip_string, strlen(conn->client_ip_string),
@@ -2880,6 +2876,13 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
debug(1, "SETUP on Connection %d: PTP setup -- no timingPeerInfo plist.",
conn->connection_number);
}
// since the GID from the client has been acquired, update the airplay bonjour strings.
build_bonjour_strings(conn);
debug(1, "Connection %d: SETUP mdns_update on %s.", conn->connection_number,
get_category_string(conn->airplay_stream_category));
mdns_update(NULL, secondary_txt_records);
#ifdef CONFIG_METADATA
check_and_send_plist_metadata(messagePlist, "name", 'snam');
@@ -4281,10 +4284,10 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
}
static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
debug(2, "Connection %d: ANNOUNCE", conn->connection_number);
debug(1, "Connection %d: ANNOUNCE", conn->connection_number);
int get_play_status = get_play_lock(conn, config.allow_session_interruption);
if (get_play_status != -1) {
debug(2, "Connection %d: ANNOUNCE has acquired play lock.", conn->connection_number);
debug(1, "Connection %d: ANNOUNCE has acquired play lock.", conn->connection_number);
// now, if this new session did not break in, then it's okay to reset the next UDP ports
// to the start of the range
@@ -4318,7 +4321,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
pthread_rwlock_rdlock(&principal_conn_lock); // don't let the principal_conn be changed
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
if (principal_conn == conn) {
config.airplay_statusflags |= 1 << 11; // DeviceSupportsRelay -- should this be on?
// config.airplay_statusflags |= 1 << 11; // DeviceSupportsRelay -- should this be on?
build_bonjour_strings(conn);
mdns_update(NULL, secondary_txt_records);
}
@@ -4852,20 +4855,6 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState);
debug(3, "Connection %d: %s rtsp_conversation_thread_func_cleanup_function called.",
conn->connection_number, get_category_string(conn->airplay_stream_category));
// only update these things if you're (still) the principal conn
pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed
pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock);
if (principal_conn == conn) {
#ifdef CONFIG_AIRPLAY_2
config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
build_bonjour_strings(conn);
mdns_update(NULL, secondary_txt_records);
#endif
principal_conn = NULL; // stop being principal_conn
}
pthread_cleanup_pop(1); // release the principal_conn lock
if (conn->player_thread) {
player_stop(conn); // this nulls the player_thread and cancels the threads...
@@ -4998,6 +4987,7 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
debug(3, "Connection %d: Closed.", conn->connection_number);
conn->running = 0; // for the garbage collector
release_play_lock(conn);
pthread_setcancelstate(oldState, NULL);
}
}