}
// note: connection numbers start at 1, so an except_this_one value of zero means "all threads"
-void cancel_all_RTSP_threads(airplay_stream_c stream_category, int except_this_one) {
+void cancel_all_RTSP_threads(__attribute((unused)) airplay_stream_c stream_category, int except_this_one) {
// if the stream category is unspecified_stream_category
// all categories are elegible for cancellation
// otherwise just the category itself
int i;
for (i = 0; i < nconns; i++) {
if ((conns[i] != NULL) && (conns[i]->running != 0) &&
- (conns[i]->connection_number != except_this_one) &&
- ((stream_category == unspecified_stream_category) ||
- (stream_category == conns[i]->airplay_stream_category))) {
+ (conns[i]->connection_number != except_this_one)) {
pthread_cancel(conns[i]->thread);
- debug(1, "Connection %d: cancelled.", conns[i]->connection_number);
+ debug(1, "Connection %d: %s cancelled.", conns[i]->connection_number, get_category_string(conns[i]->airplay_stream_category));
}
}
for (i = 0; i < nconns; i++) {
- if ((conns[i] != NULL) && (conns[i]->running != 0) &&
- (conns[i]->connection_number != except_this_one) &&
- ((stream_category == unspecified_stream_category) ||
- (stream_category == conns[i]->airplay_stream_category))) {
- debug(1, "Connection %d: joining...", conns[i]->connection_number);
+ if ((conns[i] != NULL) &&
+ (conns[i]->connection_number != except_this_one)) {
+ debug(1, "Connection %d: %s joining....", conns[i]->connection_number, get_category_string(conns[i]->airplay_stream_category));
pthread_join(conns[i]->thread, NULL);
- debug(1, "Connection %d: joined.", conns[i]->connection_number);
+ debug(1, "Connection %d: %s joined.", conns[i]->connection_number, get_category_string(conns[i]->airplay_stream_category));
free(conns[i]);
conns[i] = NULL;
}
return count;
}
-/*
-static ssize_t write_encrypted(rtsp_conn_info *conn, const void *buf, size_t count) {
- uint8_t *encrypted;
- size_t encrypted_len;
-
- ssize_t ret =
- pair_encrypt(&encrypted, &encrypted_len, buf, count, conn->ap2_pairing_context.cipher_ctx);
- if (ret < 0) {
- debug(1, pair_cipher_errmsg(conn->ap2_pairing_context.cipher_ctx));
- return -1;
- }
-
- size_t remain = encrypted_len;
- while (remain > 0) {
- ssize_t wrote = write(conn->fd, encrypted + (encrypted_len - remain), remain);
- if (wrote <= 0) {
- free(encrypted);
- return wrote;
- }
- remain -= wrote;
- }
- free(encrypted);
- return count;
-}
-*/
#endif
ssize_t read_from_rtsp_connection(rtsp_conn_info *conn, void *buf, size_t count) {
conn->connection_number, flushUntilTS, flushUntilSeq & 0x7fffff);
conn->ap2_play_enabled = 0; // stop trying to play audio
ptp_send_control_message_string(
- "P"); // signify clock no longer valid and will be restarted by a subsequent play
+ "P"); // "P"ause signify clock no longer valid and will be restarted by a subsequent play
} else {
// look for a record slot that isn't in use
unsigned int i = 0;
"OPTIONS, POST, GET, PUT");
}
-/*
-void teardown_phase_one(rtsp_conn_info *conn) {
- // this can be called more than once on the same connection --
- // by the player itself but also by the play session being killed
- if (conn->player_thread) {
- player_stop(conn); // this nulls the player_thread
- activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
- }
- if (conn->session_key) {
- free(conn->session_key);
- conn->session_key = NULL;
- }
-}
-
-void teardown_phase_two(rtsp_conn_info *conn) {
- // we are being asked to disconnect
- // this can be called more than once on the same connection --
- // by the player itself but also by the play seesion being killed
- debug(3, "Connection %d: TEARDOWN %s connection.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- // if (conn->airplay_stream_category == remote_control_stream) {
- if (conn->rtp_data_thread) {
- debug(3, "Connection %d: TEARDOWN %s Delete Data Thread.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- pthread_cancel(*conn->rtp_data_thread);
- pthread_join(*conn->rtp_data_thread, NULL);
- free(conn->rtp_data_thread);
- conn->rtp_data_thread = NULL;
- }
- if (conn->data_socket) {
- debug(3, "Connection %d: TEARDOWN %s Close Data Socket.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- close(conn->data_socket);
- conn->data_socket = 0;
- }
- //}
-
- if (conn->rtp_event_thread) {
- debug(3, "Connection %d: TEARDOWN %s Delete Event Thread.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- pthread_cancel(*conn->rtp_event_thread);
- pthread_join(*conn->rtp_event_thread, NULL);
- free(conn->rtp_event_thread);
- debug(3, "Connection %d: TEARDOWN %s Event Thread deleted.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- conn->rtp_event_thread = NULL;
- }
- if (conn->event_socket) {
- debug(3, "Connection %d: TEARDOWN %s Close Event Socket.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- close(conn->event_socket);
- conn->event_socket = 0;
- }
-
- // if we are closing a PTP stream only, do this
- if (conn->airplay_stream_category == ptp_stream) {
- if (conn->airplay_gid != NULL) {
- free(conn->airplay_gid);
- conn->airplay_gid = NULL;
-
-#ifdef CONFIG_METADATA
- // this is here to ensure it's only performed once during a teardown of a ptp stream
- send_ssnc_metadata('disc', conn->client_ip_string, strlen(conn->client_ip_string), 1);
-#endif
- }
- conn->groupContainsGroupLeader = 0;
- if (conn->dacp_active_remote != NULL) {
- free(conn->dacp_active_remote);
- conn->dacp_active_remote = NULL;
- }
- if (conn->ap2_client_name) {
- free(conn->ap2_client_name);
- conn->ap2_client_name = NULL;
- }
-#ifdef CONFIG_FFMPEG
- clear_decoding_chain(conn);
-#endif
- clear_ptp_clock();
- }
-
- // 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) {
- if (conn->airplay_stream_category == ptp_stream) {
- config.airplay_statusflags &= (0xffffffff - (1 << 11)); // DeviceSupportsRelay
- build_bonjour_strings(conn);
- debug(3, "Connection %d: teardown mdns_update on %s.", conn->connection_number,
- get_category_string(conn->airplay_stream_category));
- mdns_update(NULL, secondary_txt_records);
- }
- principal_conn = NULL; // stop being principal_conn
- }
- pthread_cleanup_pop(1); // release the principal_conn lock
-}
-*/
-
void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
rtsp_message *resp) {
}
#endif
-void teardown(rtsp_conn_info *conn) {
- debug(2, "Connection %d: TEARDOWN (Classic AirPlay).", conn->connection_number);
- player_stop(conn);
- activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
+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);
+
+ if (conn->player_thread) {
+ 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;
principal_conn = NULL; // stop being principal_conn
}
pthread_cleanup_pop(1); // release the principal_conn lock
-}
-
-void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
- rtsp_message *resp) {
- debug(1, "Connection %d: TEARDOWN", conn->connection_number);
- debug_log_rtsp_message(1, "TEARDOWN request", req);
-
- debug(3,
- "TEARDOWN: synchronously terminating the player thread of RTSP conversation thread %d (2).",
- conn->connection_number);
- teardown(conn);
+
#ifdef CONFIG_FFMPEG
clear_decoding_chain(conn);
#endif
// debug(1,"initial timing peer command: \"%s\".", timing_list_message);
// ptp_send_control_message_string(timing_list_message);
- set_client_as_ptp_clock(conn);
- ptp_send_control_message_string("B"); // signify clock dependability period is
+ // deferring this until play is about to start
+ // set_client_as_ptp_clock(conn);
+ // ptp_send_control_message_string("B"); // signify clock dependability period is
// "B"eginning (or continuing)
plist_dict_set_item(timingPeerInfoPlist, "Addresses", addresses);
plist_dict_set_item(timingPeerInfoPlist, "ID",
activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
}
+ set_client_as_ptp_clock(conn);
ptp_send_control_message_string(
"B"); // signify clock dependability period is "B"eginning (or continuing)
plist_t stream0 = plist_array_get_item(streams, 0);
free(conn->session_key);
conn->session_key = NULL;
}
-
+
+ // give the event receiver a chance to exit normally
+ uint64_t event_receiver_start_wait_time = get_absolute_time_in_ns();
+ int64_t event_receiver_wait_time = 0;
+ do {
+ if (conn->ap2_event_receiver_exited == 0)
+ usleep(50000);
+ event_receiver_wait_time = get_absolute_time_in_ns() - event_receiver_start_wait_time;
+ } while ((conn->ap2_event_receiver_exited == 0) && (event_receiver_wait_time < 2000000000L));
+
if (conn->ap2_event_receiver_exited == 0) {
- debug(3, "waiting for event receiver to exit");
- usleep(2000000);
- if (conn->ap2_event_receiver_exited == 0) {
- debug(1, "Connection %d: %s event receiver has not exited, so cancelling it.",
- conn->connection_number, get_category_string(conn->airplay_stream_category));
- pthread_cancel(*conn->rtp_event_thread);
- }
+ debug(1, "Connection %d: %s event receiver has not exited, so cancelling it.",
+ conn->connection_number, get_category_string(conn->airplay_stream_category));
+ pthread_cancel(*conn->rtp_event_thread);
}
pthread_join(*conn->rtp_event_thread, NULL);
free(conn->rtp_event_thread);