From 953ad8ac147e487e5af0c5189138261477cf14eb Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sat, 8 May 2021 17:46:13 +0100 Subject: [PATCH] Move AP2 player termination code from handle_teardown into the player cleanup function so that cancelling the player thread cleans up properly. --- player.c | 166 ++++++++++++++++++++++-------------- player.h | 4 +- rtp.c | 27 +++--- rtsp.c | 111 ++++++++---------------- rtsp.h | 5 +- scripts/shairport-sync.conf | 2 +- shairport.c | 9 +- 7 files changed, 161 insertions(+), 163 deletions(-) diff --git a/player.c b/player.c index 24640c5a..bd1f2ce0 100644 --- a/player.c +++ b/player.c @@ -443,7 +443,7 @@ void player_put_packet(int original_format, seq_t seqno, uint32_t actual_timesta conn->ab_read = seqno; conn->ab_synced = 1; conn->first_packet_timestamp = 0; - debug(1,"synced by first packet"); + debug(1, "synced by first packet"); } else if (original_format == 0) { // if the packet is coming in original format, the sequence number is important // otherwise, ignore is by setting it equal to the expected sequence number in ab_write @@ -1541,12 +1541,12 @@ void player_thread_cleanup_handler(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; if (pthread_mutex_trylock(&playing_conn_lock) == 0) { - pthread_cleanup_push(mutex_unlock,&playing_conn_lock); - if (playing_conn == conn) { - if (config.output->stop) - config.output->stop(); - } - pthread_cleanup_pop(1); // unlock the mutex + pthread_cleanup_push(mutex_unlock, &playing_conn_lock); + if (playing_conn == conn) { + if (config.output->stop) + config.output->stop(); + } + pthread_cleanup_pop(1); // unlock the mutex } int oldState; @@ -1554,19 +1554,21 @@ void player_thread_cleanup_handler(void *arg) { debug(3, "Connection %d: player thread main loop exit via player_thread_cleanup_handler.", conn->connection_number); - 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; if (conn->frame_rate_status) - inform("Connection %d: Playback Stopped. Total playing time %02d:%02d:%02d. Input: %0.2f, output: %0.2f " - "frames per second.", conn->connection_number, - elapsedHours, elapsedMin, elapsedSec, conn->input_frame_rate, conn->frame_rate); + inform("Connection %d: Playback Stopped. Total playing time %02d:%02d:%02d. Input: %0.2f, " + "output: %0.2f " + "frames per second.", + conn->connection_number, elapsedHours, elapsedMin, elapsedSec, conn->input_frame_rate, + conn->frame_rate); else - inform("Connection %d: Playback Stopped. Total playing time %02d:%02d:%02d. Input: %0.2f frames per second.", conn->connection_number, - elapsedHours, elapsedMin, elapsedSec, conn->input_frame_rate); + inform("Connection %d: Playback Stopped. Total playing time %02d:%02d:%02d. Input: %0.2f " + "frames per second.", + conn->connection_number, elapsedHours, elapsedMin, elapsedSec, conn->input_frame_rate); } #ifdef CONFIG_DACP_CLIENT @@ -1576,57 +1578,92 @@ void player_thread_cleanup_handler(void *arg) { mdns_dacp_monitor_set_id(NULL); // say we're not interested in following that DACP id any more #endif -#ifdef CONFIG_AIRPORT_2 - if (conn->rtp_ap2_control_thread) { - debug(3, "Cancelling rtp_ap2_control_thread"); - pthread_cancel(conn->rtp_ap2_control_thread); - pthread_join(conn->rtp_ap2_control_thread, NULL); - } - if (conn->ap2_control_socket) { - close(conn->ap2_control_socket); - conn->ap2_control_socket = 0; - } + // four possibilities + // 1 -- regular AirPlay 1 + // 2 -- AirPlay 2 in AirPlay 1 mode + // 3 -- AirPlay 2 in Buffered Audio Mode + // 4 -- AirPlay 3 in Realtime Audio Mode. - // realtime stuff - if (conn->rtp_realtime_audio_thread) { - debug(3, "Cancelling rtp_realtime_audio_thread"); - pthread_cancel(conn->rtp_realtime_audio_thread); - pthread_join(conn->rtp_realtime_audio_thread, NULL); - } - if (conn->realtime_audio_socket) { - close(conn->realtime_audio_socket); - conn->realtime_audio_socket = 0; - } +#ifdef CONFIG_AIRPLAY_2 + if (conn->airplay_type == ap_2) { + debug(1, "In AP2 mode"); - // buffered stuff - if (conn->rtp_buffered_audio_thread) { - debug(3, "Cancelling rtp_buffered_audio_thread"); - pthread_cancel(conn->rtp_buffered_audio_thread); - pthread_join(conn->rtp_buffered_audio_thread, NULL); - } - if (conn->buffered_audio_socket) { - close(conn->buffered_audio_socket); - conn->buffered_audio_socket = 0; + if (conn->airplay_stream_type == realtime_stream) { + debug(2, "Connection %d: TEARDOWN Delete Realtime Audio Stream Thread", + conn->connection_number); + pthread_cancel(conn->rtp_realtime_audio_thread); + pthread_join(conn->rtp_realtime_audio_thread, NULL); + if (conn->realtime_audio_socket) + close(conn->realtime_audio_socket); + } else if (conn->airplay_stream_type == buffered_stream) { + debug(2, "Connection %d: TEARDOWN Delete Buffered Audio Stream Thread", + conn->connection_number); + pthread_cancel(conn->rtp_buffered_audio_thread); + pthread_join(conn->rtp_buffered_audio_thread, NULL); + if (conn->buffered_audio_socket) + close(conn->buffered_audio_socket); + } else { + die("Unrecognised Stream Type"); + } + + if (conn->rtp_ap2_control_thread) { + debug(1, "Cancelling rtp_ap2_control_thread"); + pthread_cancel(conn->rtp_ap2_control_thread); + pthread_join(conn->rtp_ap2_control_thread, NULL); + } + if (conn->ap2_control_socket) { + close(conn->ap2_control_socket); + conn->ap2_control_socket = 0; + conn->ap2_remote_control_socket_addr_length = + 0; // indicates to the control receiver thread that the socket address need to be + // recreated. + } + + if (conn->airplay_stream_type == realtime_stream) { + // realtime stuff + if (conn->rtp_realtime_audio_thread) { + debug(1, "Cancelling rtp_realtime_audio_thread"); + pthread_cancel(conn->rtp_realtime_audio_thread); + pthread_join(conn->rtp_realtime_audio_thread, NULL); + } + if (conn->realtime_audio_socket) { + close(conn->realtime_audio_socket); + conn->realtime_audio_socket = 0; + } + } else if (conn->airplay_stream_type == buffered_stream) { + // buffered stuff + if (conn->rtp_buffered_audio_thread) { + debug(3, "Cancelling rtp_buffered_audio_thread"); + pthread_cancel(conn->rtp_buffered_audio_thread); + pthread_join(conn->rtp_buffered_audio_thread, NULL); + } + if (conn->buffered_audio_socket) { + close(conn->buffered_audio_socket); + conn->buffered_audio_socket = 0; + } + } + } else { +#endif + debug(1, "Cancelling AP1 timing, control and audio threads..."); + debug(3, "Cancel timing thread."); + pthread_cancel(conn->rtp_timing_thread); + debug(3, "Join timing thread."); + pthread_join(conn->rtp_timing_thread, NULL); + debug(3, "Timing thread terminated."); + debug(3, "Cancel control thread."); + pthread_cancel(conn->rtp_control_thread); + debug(3, "Join control thread."); + pthread_join(conn->rtp_control_thread, NULL); + debug(3, "Control thread terminated."); + debug(3, "Cancel audio thread."); + pthread_cancel(conn->rtp_audio_thread); + debug(3, "Join audio thread."); + pthread_join(conn->rtp_audio_thread, NULL); + debug(3, "Audio thread terminated."); +#ifdef CONFIG_AIRPLAY_2 } #endif - debug(3, "Cancelling timing, control and audio threads..."); - debug(3, "Cancel timing thread."); - pthread_cancel(conn->rtp_timing_thread); - debug(3, "Join timing thread."); - pthread_join(conn->rtp_timing_thread, NULL); - debug(3, "Timing thread terminated."); - debug(3, "Cancel control thread."); - pthread_cancel(conn->rtp_control_thread); - debug(3, "Join control thread."); - pthread_join(conn->rtp_control_thread, NULL); - debug(3, "Control thread terminated."); - debug(3, "Cancel audio thread."); - pthread_cancel(conn->rtp_audio_thread); - debug(3, "Join audio thread."); - pthread_join(conn->rtp_audio_thread, NULL); - debug(3, "Audio thread terminated."); - if (conn->outbuf) { free(conn->outbuf); conn->outbuf = NULL; @@ -1649,6 +1686,7 @@ void player_thread_cleanup_handler(void *arg) { terminate_decoders(conn); reset_anchor_info(conn); + release_play_lock(conn); conn->rtp_running = 0; pthread_setcancelstate(oldState, NULL); } @@ -2282,7 +2320,8 @@ void *player_thread_func(void *arg) { int64_t filler_length = (int64_t)(config.resyncthreshold * config.output_rate); // number of samples if ((sync_error > 0) && (sync_error > filler_length)) { - debug(1, "Large positive sync error of: %" PRId64 " frames (%f seconds).", sync_error, (sync_error * 1.0)/config.output_rate); + debug(1, "Large positive sync error of: %" PRId64 " frames (%f seconds).", + sync_error, (sync_error * 1.0) / config.output_rate); int64_t local_frames_to_drop = sync_error / conn->output_sample_ratio; uint32_t frames_to_drop_sized = local_frames_to_drop; @@ -2295,9 +2334,10 @@ void *player_thread_func(void *arg) { } else if ((sync_error < 0) && ((-sync_error) > filler_length)) { debug(1, - "Large negative sync error of: %" PRId64 " frames (%f seconds), with should_be_frame_32 of %" PRIu32 - ", nt of %" PRId64 " and current_delay of %" PRId64 ".", - sync_error, (sync_error * 1.0)/config.output_rate, should_be_frame_32, + "Large negative sync error of: %" PRId64 + " frames (%f seconds), with should_be_frame_32 of %" PRIu32 ", nt of %" PRId64 + " and current_delay of %" PRId64 ".", + sync_error, (sync_error * 1.0) / config.output_rate, should_be_frame_32, inframe->given_timestamp * conn->output_sample_ratio, current_delay); int64_t silence_length = -sync_error; if (silence_length > (filler_length * 5)) diff --git a/player.h b/player.h index ab7eda9d..25003e5b 100644 --- a/player.h +++ b/player.h @@ -91,6 +91,7 @@ typedef struct { #ifdef CONFIG_AIRPLAY_2 typedef enum { ts_ntp, ts_ptp } timing_t; typedef enum { ap_1, ap_2 } airplay_t; +typedef enum { realtime_stream, buffered_stream } airplay_stream_t; typedef struct { uint8_t *data; @@ -259,7 +260,8 @@ typedef struct { #ifdef CONFIG_AIRPLAY_2 airplay_t airplay_type; // are we using AirPlay 1 or AirPlay 2 protocol on this connection? - timing_t timing_type; // are we using NTP or PTP on this connection? + airplay_stream_t airplay_stream_type; // is it realtime audio or buffered audio... + timing_t timing_type; // are we using NTP or PTP on this connection? pthread_t rtp_event_thread; pthread_t rtp_ap2_control_thread; diff --git a/rtp.c b/rtp.c index 182d19ba..84f0d800 100644 --- a/rtp.c +++ b/rtp.c @@ -120,7 +120,7 @@ void rtp_audio_receiver_cleanup_handler(__attribute__((unused)) void *arg) { } void *rtp_audio_receiver(void *arg) { - debug(1, "rtp_audio_receiver start"); + debug(3, "rtp_audio_receiver start"); pthread_cleanup_push(rtp_audio_receiver_cleanup_handler, arg); rtsp_conn_info *conn = (rtsp_conn_info *)arg; @@ -259,7 +259,7 @@ void rtp_control_handler_cleanup_handler(__attribute__((unused)) void *arg) { } void *rtp_control_receiver(void *arg) { - debug(1, "rtp_control_receiver start"); + debug(2, "rtp_control_receiver start"); pthread_cleanup_push(rtp_control_handler_cleanup_handler, arg); rtsp_conn_info *conn = (rtsp_conn_info *)arg; @@ -290,8 +290,8 @@ void *rtp_control_receiver(void *arg) { obfp += 2; }; *obfp = 0; - - + + // get raw timestamp information // I think that a good way to understand these timestamps is that // (1) the rtlt below is the timestamp of the frame that should be playing at the @@ -302,19 +302,19 @@ void *rtp_control_receiver(void *arg) { // Thus, (3) the latency can be calculated by subtracting the second from the // first. // There must be more to it -- there something missing. - + // In addition, it seems that if the value of the short represented by the second // pair of bytes in the packet is 7 // then an extra time lag is expected to be added, presumably by // the AirPort Express. - + // Best guess is that this delay is 11,025 frames. - + uint32_t rtlt = nctohl(&packet[4]); // raw timestamp less latency uint32_t rt = nctohl(&packet[16]); // raw timestamp - + uint32_t fl = nctohs(&packet[2]); // - + debug(1,"Sync Packet of %d bytes received: \"%s\", flags: %d, timestamps %u and %u, giving a latency of %d frames.",plen,obf,fl,rt,rtlt,rt-rtlt); //debug(1,"Monotonic timestamps are: %" PRId64 " and %" PRId64 " @@ -406,7 +406,7 @@ void *rtp_control_receiver(void *arg) { if (la != conn->latency) { conn->latency = la; - debug(1, + debug(2, "New latency: %" PRIu32 ", sync latency: %" PRIu32 ", minimum latency: %" PRIu32 ", maximum " "latency: %" PRIu32 ", fixed offset: %" PRIu32 @@ -508,7 +508,7 @@ void rtp_timing_sender_cleanup_handler(void *arg) { } void *rtp_timing_sender(void *arg) { - debug(1, "rtp_timing_sender start"); + debug(2, "rtp_timing_sender start"); pthread_cleanup_push(rtp_timing_sender_cleanup_handler, arg); rtsp_conn_info *conn = (rtsp_conn_info *)arg; struct timing_request { @@ -610,7 +610,7 @@ void rtp_timing_receiver_cleanup_handler(void *arg) { } void *rtp_timing_receiver(void *arg) { - debug(1, "rtp_timing_receiver start"); + debug(3, "rtp_timing_receiver start"); pthread_cleanup_push(rtp_timing_receiver_cleanup_handler, arg); rtsp_conn_info *conn = (rtsp_conn_info *)arg; @@ -2090,7 +2090,8 @@ void *rtp_buffered_audio_processor(void *arg) { 0) { int64_t lead_time = buffer_should_be_time - get_absolute_time_in_ns(); // debug(1,"lead time in buffered_audio is %f milliseconds.", lead_time * 0.000001); - if ((lead_time >= (int64_t)(reqested_lead_time * 1000000000)) || (streaming_has_started == 1)) { + if ((lead_time >= (int64_t)(reqested_lead_time * 1000000000)) || + (streaming_has_started == 1)) { if (streaming_has_started == 0) debug(1, "rtp lead time is %f ms.", 0.000001 * lead_time); streaming_has_started = 1; diff --git a/rtsp.c b/rtsp.c index 067749a8..dde6cff7 100644 --- a/rtsp.c +++ b/rtsp.c @@ -845,19 +845,20 @@ static ssize_t read_encrypted(int fd, ap2_pairing *ctx, void *buf, size_t count) return got; buf_add(&ctx->encrypted_buf, in, got); - ssize_t consumed = pair_decrypt(&plain, &plain_len, ctx->encrypted_buf.data, ctx->encrypted_buf.len, ctx->cipher_ctx); + ssize_t consumed = pair_decrypt(&plain, &plain_len, ctx->encrypted_buf.data, + ctx->encrypted_buf.len, ctx->cipher_ctx); if (consumed < 0) return -1; buf_drain(&ctx->encrypted_buf, consumed); } while (plain_len == 0); // Fast path, avoids some memcpy + allocs in case of the normal, small message -/* if (ctx->plain_buf.len == 0 && plain_len < count) { - memcpy(buf, plain, plain_len); - free(plain); - return plain_len; - } -*/ + /* if (ctx->plain_buf.len == 0 && plain_len < count) { + memcpy(buf, plain, plain_len); + free(plain); + return plain_len; + } + */ buf_add(&ctx->plain_buf, plain, plain_len); free(plain); @@ -868,7 +869,8 @@ static ssize_t write_encrypted(rtsp_conn_info *conn, const void *buf, size_t cou uint8_t *encrypted; size_t encrypted_len; - ssize_t ret = pair_encrypt(&encrypted, &encrypted_len, buf, count, conn->ap2_control_pairing.cipher_ctx); + ssize_t ret = + pair_encrypt(&encrypted, &encrypted_len, buf, count, conn->ap2_control_pairing.cipher_ctx); if (ret < 0) { debug(1, pair_cipher_errmsg(conn->ap2_control_pairing.cipher_ctx)); return -1; @@ -1245,7 +1247,8 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r debug(1, "GET /info Stage 1: response plist not created from XML!"); } else { plist_dict_set_item(response_plist, "features", plist_new_uint(config.airplay_features)); - plist_dict_set_item(response_plist, "statusFlags", plist_new_uint(config.airplay_statusflags)); + plist_dict_set_item(response_plist, "statusFlags", + plist_new_uint(config.airplay_statusflags)); plist_dict_set_item(response_plist, "deviceID", plist_new_string(config.airplay_device_id)); plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi)); plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name)); @@ -1446,7 +1449,8 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r req->contentlength); if (!conn->ap2_control_pairing.verify_ctx) { - conn->ap2_control_pairing.verify_ctx = pair_verify_new(PAIR_SERVER_HOMEKIT, NULL, NULL, NULL, config.airplay_device_id); + conn->ap2_control_pairing.verify_ctx = + pair_verify_new(PAIR_SERVER_HOMEKIT, NULL, NULL, NULL, config.airplay_device_id); if (!conn->ap2_control_pairing.verify_ctx) { debug(1, "Error creating verify context"); resp->respcode = 500; // Internal Server Error @@ -1454,7 +1458,8 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r } } - ret = pair_verify(&body, &body_len, conn->ap2_control_pairing.verify_ctx, (const uint8_t *)req->content, req->contentlength); + ret = pair_verify(&body, &body_len, conn->ap2_control_pairing.verify_ctx, + (const uint8_t *)req->content, req->contentlength); if (ret < 0) { debug(1, pair_verify_errmsg(conn->ap2_control_pairing.verify_ctx)); resp->respcode = 470; // Connection Authorization Required @@ -1463,14 +1468,15 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r ret = pair_verify_result(&result, conn->ap2_control_pairing.verify_ctx); if (ret == 0 && result->shared_secret_len > 0) { - conn->ap2_control_pairing.cipher_ctx = pair_cipher_new(PAIR_SERVER_HOMEKIT, 2, result->shared_secret, result->shared_secret_len); + conn->ap2_control_pairing.cipher_ctx = + pair_cipher_new(PAIR_SERVER_HOMEKIT, 2, result->shared_secret, result->shared_secret_len); if (!conn->ap2_control_pairing.cipher_ctx) { debug(1, "Error setting up rtsp control channel ciphering\n"); goto out; } } - out: +out: resp->content = (char *)body; // these will be freed when the data is sent resp->contentlength = body_len; if (body) @@ -1487,7 +1493,8 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re req->contentlength); if (!conn->ap2_control_pairing.setup_ctx) { - conn->ap2_control_pairing.setup_ctx = pair_setup_new(PAIR_SERVER_HOMEKIT, config.airplay_pin, NULL, NULL, config.airplay_device_id); + conn->ap2_control_pairing.setup_ctx = pair_setup_new(PAIR_SERVER_HOMEKIT, config.airplay_pin, + NULL, NULL, config.airplay_device_id); if (!conn->ap2_control_pairing.setup_ctx) { debug(1, "Error creating setup context"); resp->respcode = 500; // Internal Server Error @@ -1495,7 +1502,8 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re } } - ret = pair_setup(&body, &body_len, conn->ap2_control_pairing.setup_ctx, (const uint8_t *)req->content, req->contentlength); + ret = pair_setup(&body, &body_len, conn->ap2_control_pairing.setup_ctx, + (const uint8_t *)req->content, req->contentlength); if (ret < 0) { debug(1, pair_setup_errmsg(conn->ap2_control_pairing.setup_ctx)); resp->respcode = 470; // Connection Authorization Required @@ -1506,14 +1514,15 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re if (ret == 0 && result->shared_secret_len > 0) { // Transient pairing completed (pair-setup step 2), prepare encryption, but // don't activate yet, the response to this request is still plaintext - conn->ap2_control_pairing.cipher_ctx = pair_cipher_new(PAIR_SERVER_HOMEKIT, 2, result->shared_secret, result->shared_secret_len); + conn->ap2_control_pairing.cipher_ctx = + pair_cipher_new(PAIR_SERVER_HOMEKIT, 2, result->shared_secret, result->shared_secret_len); if (!conn->ap2_control_pairing.cipher_ctx) { debug(1, "Error setting up rtsp control channel ciphering\n"); goto out; } } - out: +out: resp->content = (char *)body; // these will be freed when the data is sent resp->contentlength = body_len; if (body) @@ -1722,68 +1731,12 @@ void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_messag if (streams) { // we are being asked to close a stream - // at present, we just close this one - debug(2, - "Connection %d: A \"streams\" array has been found -- stop the player, stop and delete " - "the control " - "and audio threads and close the ports", - conn->connection_number); - - // get stream[0] - plist_t stream0 = plist_array_get_item(streams, 0); - - plist_t item = plist_dict_get_item(stream0, "type"); - uint64_t item_value; - plist_get_uint_val(item, &item_value); - - switch (item_value) { - case 96: { - release_play_lock(conn); - debug(2, "Connection %d: TEARDOWN Delete Realtime Audio Stream Thread", - conn->connection_number); - pthread_cancel(conn->rtp_realtime_audio_thread); - pthread_join(conn->rtp_realtime_audio_thread, NULL); - if (conn->realtime_audio_socket) - close(conn->realtime_audio_socket); - } break; - case 103: { - release_play_lock(conn); // shoulda been released when stopped... - debug(2, "Connection %d: TEARDOWN Delete Buffered Audio Stream Thread", - conn->connection_number); - pthread_cancel(conn->rtp_buffered_audio_thread); - pthread_join(conn->rtp_buffered_audio_thread, NULL); - if (conn->buffered_audio_socket) - close(conn->buffered_audio_socket); - } break; - default: {} - } - - debug(2, "Connection %d: TEARDOWN Close Control Thread", conn->connection_number); - pthread_cancel(conn->rtp_ap2_control_thread); - pthread_join(conn->rtp_ap2_control_thread, NULL); - - debug(2, "Connection %d: TEARDOWN Close Control Socket.", conn->connection_number); - if (conn->ap2_control_socket) { - close(conn->ap2_control_socket); - conn->ap2_remote_control_socket_addr_length = - 0; // indicates to the control receiver thread that the socket address need to be - // recreated. - } - - debug(2, "Connection %d: TEARDOWN Stop the Player.", conn->connection_number); player_stop(conn); - if (conn->session_key) { free(conn->session_key); conn->session_key = NULL; } plist_free(streams); - - release_play_lock(conn); - - // if (ptp_shm_interface_close() != 0) - // warn("Error closing the nqptp interface."); - debug(2, "Connection %d: Stream TEARDOWN complete", conn->connection_number); } else { // we are being asked to disconnect @@ -1939,7 +1892,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) debug(1, "Connection %d. Realtime Audio Stream Detected.", conn->connection_number); debug_log_rtsp_message(2, "Realtime Audio Stream SETUP incoming message", req); get_play_lock(conn); - + conn->airplay_stream_type = realtime_stream; // bind a new UDP port and get a socket conn->local_realtime_audio_port = 0; // any port err = bind_socket_and_port(SOCK_DGRAM, conn->connection_ip_family, conn->self_ip_string, @@ -1992,6 +1945,8 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) case 103: { debug(1, "Connection %d. Buffered Audio Stream Detected.", conn->connection_number); debug_log_rtsp_message(2, "Buffered Audio Stream SETUP incoming message", req); + // for buffered audio, delay getting the play lock until we actually start playing... + conn->airplay_stream_type = buffered_stream; // get needed stuff // bind a new TCP port and get a socket @@ -2128,7 +2083,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) debug(1, "Can't find timingPeerInfo addresses"); } } else { - debug(1, "Can't find timingPeerInfo"); + debug_log_rtsp_message(1, "Unrecognised SETUP incoming message", req); } // make up the timing peer info list part of the response... @@ -4137,7 +4092,8 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { features_lo, features_hi); *p++ = featuresString; char statusflagsString[32]; - snprintf(statusflagsString, sizeof(statusflagsString), "flags=0x%" PRIx32, config.airplay_statusflags); + snprintf(statusflagsString, sizeof(statusflagsString), "flags=0x%" PRIx32, + config.airplay_statusflags); *p++ = statusflagsString; *p++ = "protovers=1.1"; *p++ = "acl=0"; @@ -4153,7 +4109,8 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { *p++ = "gcgl=0"; char pkString[128]; snprintf(pkString, sizeof(pkString), "pk="); - pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="), config.airplay_device_id); + pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="), + config.airplay_device_id); *p++ = pkString; *p++ = NULL; #else diff --git a/rtsp.h b/rtsp.h index 89f5e151..5222b8e2 100644 --- a/rtsp.h +++ b/rtsp.h @@ -8,10 +8,7 @@ extern rtsp_conn_info **conns; void *rtsp_listen_loop(__attribute((unused)) void *arg); -// void rtsp_shutdown_stream(void); -void rtsp_request_shutdown_stream(void); - -void cancel_all_RTSP_threads(void); +void release_play_lock(rtsp_conn_info *conn); // initialise and completely delete the metadata stuff diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index e7f9e748..f377c221 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -40,7 +40,7 @@ general = // volume_control_profile = "standard" ; // use this advanced setting to specify how the airplay volume is transferred to the mixer volume. // "standard" makes the volume change more quickly at lower volumes and slower at higher volumes. // "flat" makes the volume change at the same rate at all volumes. -// volume_range_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator. +// volume_control_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator. // run_this_when_volume_is_set = "/full/path/to/application/and/args"; // Run the specified application whenever the volume control is set or changed. // The desired AirPlay volume is appended to the end of the command line – leave a space if you want it treated as an extra argument. // AirPlay volume goes from 0 to -30 and -144 means "mute". diff --git a/shairport.c b/shairport.c index afe9ab4a..89fa5858 100644 --- a/shairport.c +++ b/shairport.c @@ -1577,10 +1577,11 @@ int main(int argc, char **argv) { // 496155702020608 this setting here is the source of both the plist features response and the // mDNS string. config.airplay_features = 0x1C340405F4A00; - // Advertised with mDNS and returned with GET /info, see https://openairplay.github.io/airplay-spec/status_flags.html - // 0x4: Audio cable attached, no PIN required (transient pairing), no Homekit access control - // 0x204: Audio cable attached, OneTimePairingRequired - // 0x604: Audio cable attached, OneTimePairingRequired, allow Homekit access control + // Advertised with mDNS and returned with GET /info, see + // https://openairplay.github.io/airplay-spec/status_flags.html 0x4: Audio cable attached, no PIN + // required (transient pairing), no Homekit access control 0x204: Audio cable attached, + // OneTimePairingRequired 0x604: Audio cable attached, OneTimePairingRequired, allow Homekit + // access control config.airplay_statusflags = 0x4; // Set to NULL to work with transient pairing config.airplay_pin = NULL;