From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sun, 30 May 2021 10:17:06 +0000 (+0100) Subject: Flush seems to be working properly and reliably. Some audio glitches removed too... X-Git-Tag: 4.1-dev~105 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a109b587ece049c1b2b26e99ac3d91c580832b2c;p=thirdparty%2Fshairport-sync.git Flush seems to be working properly and reliably. Some audio glitches removed too by dropping the first two AAC blocks of any passage. Crude. Flush diagnostic linked list stuff left in place. --- diff --git a/common.c b/common.c index 4bdb78ab..f87b7d29 100644 --- a/common.c +++ b/common.c @@ -93,8 +93,6 @@ #include #endif - - #ifdef CONFIG_ALSA void set_alsa_out_dev(char *); #endif @@ -1611,13 +1609,13 @@ char *get_version_string() { char *version_string = malloc(1024); if (version_string) { #ifdef CONFIG_USE_GIT_VERSION_STRING - if (git_version_string[0] != '\0') - strcpy(version_string, git_version_string); - else + if (git_version_string[0] != '\0') + strcpy(version_string, git_version_string); + else #endif - strcpy(version_string, PACKAGE_VERSION); + strcpy(version_string, PACKAGE_VERSION); #ifdef CONFIG_AIRPLAY_2 - strcat(version_string, "-AirPlay2"); + strcat(version_string, "-AirPlay2"); #endif #ifdef CONFIG_APPLE_ALAC strcat(version_string, "-alac"); @@ -1945,7 +1943,7 @@ int get_device_id(uint8_t *id, int int_length) { struct ifaddrs *ifa = NULL; int i = 0; uint8_t *t = id; - for (i = 0; i < int_length ; i++) { + for (i = 0; i < int_length; i++) { *t++ = 0; } diff --git a/common.h b/common.h index 48769527..26e9e17d 100644 --- a/common.h +++ b/common.h @@ -210,10 +210,10 @@ typedef struct { char *configfile; char *regtype; // The regtype is the service type followed by the protocol, separated by a dot, by // default “_raop._tcp.” for AirPlay 1. - char *regtype2; // The regtype is the service type followed by the protocol, separated by a dot, by - // default “_raop._tcp.” for AirPlay 2. - char *interface; // a string containg the interface name, or NULL if nothing specified - int interface_index; // only valid if the interface string is non-NULL + char *regtype2; // The regtype is the service type followed by the protocol, separated by a dot, + // by default “_raop._tcp.” for AirPlay 2. + char *interface; // a string containg the interface name, or NULL if nothing specified + int interface_index; // only valid if the interface string is non-NULL double audio_backend_buffer_desired_length; // this will be the length in seconds of the // audio backend buffer -- the DAC buffer for ALSA double audio_backend_buffer_interpolation_threshold_in_seconds; // below this, soxr interpolation @@ -498,7 +498,6 @@ int get_device_id(uint8_t *id, int int_length); extern char git_version_string[]; #endif - #endif // _COMMON_H #ifdef __cplusplus diff --git a/mdns.c b/mdns.c index 073e346c..4e44e38f 100644 --- a/mdns.c +++ b/mdns.c @@ -81,7 +81,8 @@ void mdns_register(char **txt_records, char **secondary_txt_records) { for (b = mdns_backends; *b; b++) { if (strcmp((*b)->name, config.mdns_name) != 0) // Not the one we are looking for continue; - int error = (*b)->mdns_register(ap1_service_name, config.service_name, config.port, txt_records, secondary_txt_records); + int error = (*b)->mdns_register(ap1_service_name, config.service_name, config.port, + txt_records, secondary_txt_records); if (error >= 0) { config.mdns = *b; } @@ -93,7 +94,8 @@ void mdns_register(char **txt_records, char **secondary_txt_records) { } else { // default -- pick the first back end for (b = mdns_backends; *b; b++) { - int error = (*b)->mdns_register(ap1_service_name, config.service_name, config.port, txt_records, secondary_txt_records); + int error = (*b)->mdns_register(ap1_service_name, config.service_name, config.port, + txt_records, secondary_txt_records); if (error >= 0) { config.mdns = *b; break; diff --git a/mdns.h b/mdns.h index 30900c78..dc6e30d9 100644 --- a/mdns.h +++ b/mdns.h @@ -17,7 +17,8 @@ void mdns_ls_backends(void); typedef struct { char *name; - int (*mdns_register)(char *ap1name, char *ap2name, int port, char **txt_records, char **secondary_txt_records); + int (*mdns_register)(char *ap1name, char *ap2name, int port, char **txt_records, + char **secondary_txt_records); void (*mdns_unregister)(void); void (*mdns_dacp_monitor_start)(); void (*mdns_dacp_monitor_set_id)(const char *); diff --git a/mdns_avahi.c b/mdns_avahi.c index 4873639c..bf24ddba 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -243,24 +243,24 @@ static void register_service(AvahiClient *c) { selected_interface = AVAHI_IF_UNSPEC; if (ap2_text_record_string_list) { ret = avahi_entry_group_add_service_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, - ap2_service_name, config.regtype2, NULL, NULL, port, - ap2_text_record_string_list); + ap2_service_name, config.regtype2, NULL, NULL, + port, ap2_text_record_string_list); } if ((ret == 0) && (text_record_string_list)) { ret = avahi_entry_group_add_service_strlst(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, service_name, config.regtype, NULL, NULL, port, text_record_string_list); } - if (ret == 0) { - ret = avahi_entry_group_commit(group); - debug(2, "avahi: avahi_entry_group_commit %d", ret); - if (ret < 0) - debug(1, "avahi: avahi_entry_group_commit failed"); - } else if (ret < 0) { - debug(1, "avahi: avahi_entry_group_add_service failed"); - } else { - debug(1, "avahi: unexpected positive return"); - } + if (ret == 0) { + ret = avahi_entry_group_commit(group); + debug(2, "avahi: avahi_entry_group_commit %d", ret); + if (ret < 0) + debug(1, "avahi: avahi_entry_group_commit failed"); + } else if (ret < 0) { + debug(1, "avahi: avahi_entry_group_add_service failed"); + } else { + debug(1, "avahi: unexpected positive return"); + } } } @@ -318,7 +318,8 @@ static void client_callback(AvahiClient *c, AvahiClientState state, } } -static int avahi_register(char *ap1name, char *ap2name, int srvport, char **txt_records,char **secondary_txt_records) { +static int avahi_register(char *ap1name, char *ap2name, int srvport, char **txt_records, + char **secondary_txt_records) { // debug(1, "avahi_register."); service_name = strdup(ap1name); if (ap2name != NULL) @@ -327,7 +328,8 @@ static int avahi_register(char *ap1name, char *ap2name, int srvport, char **txt_ text_record_string_list = avahi_string_list_new_from_array((const char **)txt_records, -1); if (secondary_txt_records != NULL) - ap2_text_record_string_list = avahi_string_list_new_from_array((const char **)secondary_txt_records, -1); + ap2_text_record_string_list = + avahi_string_list_new_from_array((const char **)secondary_txt_records, -1); port = srvport; @@ -390,7 +392,6 @@ static void avahi_unregister(void) { } else debug(1, "avahi attempt to free NULL text_record_string_list"); - if (ap2_text_record_string_list) { debug(2, "avahi free ap_2text_record_string_list"); avahi_string_list_free(ap2_text_record_string_list); diff --git a/player.c b/player.c index 46aa9d3e..c8402524 100644 --- a/player.c +++ b/player.c @@ -925,80 +925,83 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { int flush_needed = 0; int drop_request = 0; if (conn->flush_requested == 1) { - if (conn->flush_rtp_timestamp == 0) { - debug(1, "flush request: flush frame 0 -- flush assumed to be needed."); - flush_needed = 1; - drop_request = 1; - } else { - debug(1,"flush"); - if ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0)) { - abuf_t *firstPacket = conn->audio_buffer + BUFIDX(conn->ab_read); - abuf_t *lastPacket = conn->audio_buffer + BUFIDX(conn->ab_write - 1); - if ((firstPacket != NULL) && (firstPacket->ready)) { - // discard flushes more than 10 seconds into the future -- they are probably bogus - uint32_t first_frame_in_buffer = firstPacket->given_timestamp; - int32_t offset_from_first_frame = - (int32_t)(conn->flush_rtp_timestamp - first_frame_in_buffer); - if (offset_from_first_frame > (int)conn->input_rate * 10) { - debug(1, + if (conn->flush_rtp_timestamp == 0) { + debug(1, "flush request: flush frame 0 -- flush assumed to be needed."); + flush_needed = 1; + drop_request = 1; + } else { + if ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0)) { + abuf_t *firstPacket = conn->audio_buffer + BUFIDX(conn->ab_read); + abuf_t *lastPacket = conn->audio_buffer + BUFIDX(conn->ab_write - 1); + if ((firstPacket != NULL) && (firstPacket->ready)) { + // discard flushes more than 10 seconds into the future -- they are probably bogus + uint32_t first_frame_in_buffer = firstPacket->given_timestamp; + int32_t offset_from_first_frame = + (int32_t)(conn->flush_rtp_timestamp - first_frame_in_buffer); + if (offset_from_first_frame > (int)conn->input_rate * 10) { + debug( + 1, "flush request: sanity check -- flush frame %u is too far into the future from " "the first frame %u -- discarded.", conn->flush_rtp_timestamp, first_frame_in_buffer); - drop_request = 1; - } else { - if ((lastPacket != NULL) && (lastPacket->ready)) { - // we have enough information to check if the flush is needed or can be discarded - uint32_t last_frame_in_buffer = - lastPacket->given_timestamp + lastPacket->length - 1; - // now we have to work out if the flush frame is in the buffer - // if it is later than the end of the buffer, flush everything and keep the request - // active. if it is in the buffer, we need to flush part of the buffer. Actually we - // flush the entire buffer and drop the request. if it is before the buffer, no - // flush is needed. Drop the request. - if (offset_from_first_frame > 0) { - int32_t offset_to_last_frame = - (int32_t)(last_frame_in_buffer - conn->flush_rtp_timestamp); - if (offset_to_last_frame >= 0) { - debug(2, + drop_request = 1; + } else { + if ((lastPacket != NULL) && (lastPacket->ready)) { + // we have enough information to check if the flush is needed or can be discarded + uint32_t last_frame_in_buffer = + lastPacket->given_timestamp + lastPacket->length - 1; + // now we have to work out if the flush frame is in the buffer + // if it is later than the end of the buffer, flush everything and keep the + // request active. if it is in the buffer, we need to flush part of the buffer. + // Actually we flush the entire buffer and drop the request. if it is before the + // buffer, no flush is needed. Drop the request. + if (offset_from_first_frame > 0) { + int32_t offset_to_last_frame = + (int32_t)(last_frame_in_buffer - conn->flush_rtp_timestamp); + if (offset_to_last_frame >= 0) { + debug( + 2, "flush request: flush frame %u active -- buffer contains %u frames, from " "%u to %u", conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, last_frame_in_buffer); - drop_request = 1; - flush_needed = 1; + drop_request = 1; + flush_needed = 1; + } else { + debug(2, + "flush request: flush frame %u pending -- buffer contains %u frames, " + "from " + "%u to %u", + conn->flush_rtp_timestamp, + last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, + last_frame_in_buffer); + flush_needed = 1; + } } else { - debug( - 2, - "flush request: flush frame %u pending -- buffer contains %u frames, from " - "%u to %u", - conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, - first_frame_in_buffer, last_frame_in_buffer); - flush_needed = 1; + debug(2, + "flush request: flush frame %u expired -- buffer contains %u frames, " + "from %u " + "to %u", + conn->flush_rtp_timestamp, + last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer, + last_frame_in_buffer); + drop_request = 1; } - } else { - debug( - 2, - "flush request: flush frame %u expired -- buffer contains %u frames, from %u " - "to %u", - conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1, - first_frame_in_buffer, last_frame_in_buffer); - drop_request = 1; } } } + } else { + debug(3, + "flush request: flush frame %u -- buffer not synced or empty: synced: %d, " + "ab_read: " + "%u, ab_write: %u", + conn->flush_rtp_timestamp, conn->ab_synced, conn->ab_read, conn->ab_write); + conn->flush_requested = 0; // remove the request + // leave flush request pending and don't do a buffer flush, because there isn't one } - } else { - debug( - 3, - "flush request: flush frame %u -- buffer not synced or empty: synced: %d, ab_read: " - "%u, ab_write: %u", - conn->flush_rtp_timestamp, conn->ab_synced, conn->ab_read, conn->ab_write); - conn->flush_requested = 0; // remove the request - // leave flush request pending and don't do a buffer flush, because there isn't one } } - } if (flush_needed) { debug(2, "flush request: flush done."); ab_resync(conn); // no cancellation points @@ -1075,7 +1078,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { int64_t lt = conn->first_packet_time_to_play - local_time_now; - debug(1, "Connection %d: Lead time for first frame %" PRId64 ": %f seconds.", + debug(2, "Connection %d: Lead time for first frame %" PRId64 ": %f seconds.", conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001); int64_t lateness = local_time_now - conn->first_packet_time_to_play; @@ -1980,7 +1983,7 @@ void *player_thread_func(void *arg) { pthread_setcancelstate(oldState, NULL); double initial_volume = config.airplay_volume; // default - if (conn->initial_airplay_volume_set) // if we have been given an initial volume + if (conn->initial_airplay_volume_set) // if we have been given an initial volume initial_volume = conn->initial_airplay_volume; // set the default volume to whatever it was before, as stored in the config airplay_volume debug(2, "Set initial volume to %f.", initial_volume); @@ -2243,7 +2246,7 @@ void *player_thread_func(void *arg) { // remove the bias when reporting the error to make it the true error - debug(1, + debug(2, "first frame sync error (positive --> late): %" PRId64 " frames, %.3f mS at %d frames per second output.", sync_error + first_frame_early_bias, @@ -2309,8 +2312,11 @@ 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), with frame: %u.", - sync_error, (sync_error * 1.0) / config.output_rate, inframe->given_timestamp); + debug(1, + "Large positive sync error of: %" PRId64 + " frames (%f seconds), with frame: %u.", + sync_error, (sync_error * 1.0) / config.output_rate, + inframe->given_timestamp); int64_t local_frames_to_drop = sync_error / conn->output_sample_ratio; uint32_t frames_to_drop_sized = local_frames_to_drop; do_flush(inframe->given_timestamp + frames_to_drop_sized, conn); @@ -2318,7 +2324,8 @@ void *player_thread_func(void *arg) { debug(1, "Large negative sync error of: %" PRId64 " frames (%f seconds), with frame: %" PRIu32 ".", - sync_error, (sync_error * 1.0) / config.output_rate,inframe->given_timestamp); + sync_error, (sync_error * 1.0) / config.output_rate, + inframe->given_timestamp); int64_t silence_length = -sync_error; if (silence_length > (filler_length * 5)) silence_length = filler_length * 5; diff --git a/player.h b/player.h index d3f4e63c..fbffb04e 100644 --- a/player.h +++ b/player.h @@ -122,16 +122,17 @@ typedef struct { ap2_buffer plain_buf; } ap2_pairing; -/* -typedef struct file_cipher_context { - struct pair_cipher_context *cipher_context; - int active; // can be created during a pair setup but not activated until next read - int fd; - void *input_plaintext_buffer; - void *input_plaintext_buffer_toq; - size_t input_plaintext_buffer_bytes_occupied; -} file_cipher_context; -*/ +// flush requests are stored in order of flushFromSeq +// on the basis that block numbers are monotonic modulo 2^24 +typedef struct flush_request_t { + int flushNow; // if true, the flushFrom stuff is invalid + uint32_t flushFromSeq; + uint32_t flushFromTS; + uint32_t flushUntilSeq; + uint32_t flushUntilTS; + struct flush_request_t *next; +} flush_request_t; + #endif typedef struct { @@ -294,6 +295,7 @@ typedef struct { uint64_t last_anchor_time_of_update; ssize_t ap2_audio_buffer_size; + flush_request_t *flush_requests; // if non-null, there are flush requests, mutex protected int ap2_flush_requested; int ap2_flush_from_valid; uint32_t ap2_flush_from_rtp_timestamp; diff --git a/ptp-utilities.c b/ptp-utilities.c index 32225767..12a0890c 100644 --- a/ptp-utilities.c +++ b/ptp-utilities.c @@ -60,7 +60,8 @@ int get_nqptp_data(struct shm_structure *nqptp_data) { return response; } -int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *raw_offset, uint64_t *mastership_start_time) { +int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *raw_offset, + uint64_t *mastership_start_time) { int response = clock_ok; pthread_cleanup_debug_mutex_lock(&ptp_access_mutex, 10000, 1); if (actual_clock_id != NULL) diff --git a/ptp-utilities.h b/ptp-utilities.h index 1a7349fc..a0ce1604 100644 --- a/ptp-utilities.h +++ b/ptp-utilities.h @@ -29,7 +29,8 @@ #include "config.h" #include -int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *raw_offset, uint64_t *mastership_start_time); +int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *raw_offset, + uint64_t *mastership_start_time); void ptp_send_control_message_string(const char *msg); diff --git a/rtp.c b/rtp.c index b96bb5a4..a4994301 100644 --- a/rtp.c +++ b/rtp.c @@ -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 " @@ -1213,7 +1213,8 @@ void set_ptp_anchor_info(rtsp_conn_info *conn, uint64_t clock_id, uint32_t rtpti debug(2, "Connection %d: Set Anchor Clock: %" PRIx64 ".", conn->connection_number, clock_id); conn->anchor_clock_is_new = 1; } - // debug(1,"set anchor info clock: %" PRIx64", rtptime: %u, networktime: %" PRIx64 ".", clock_id, rtptime, networktime); + // debug(1,"set anchor info clock: %" PRIx64", rtptime: %u, networktime: %" PRIx64 ".", clock_id, + // rtptime, networktime); conn->anchor_remote_info_is_valid = 1; conn->anchor_rtptime = rtptime; conn->anchor_time = networktime; @@ -1247,7 +1248,8 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, // wait at least this time before using the new master clock if (duration_of_mastership < 700000000) { response = clock_not_ready; - } else if ((duration_of_mastership > 5000000000) || (conn->last_anchor_info_is_valid == 0)) { + } else if ((duration_of_mastership > 5000000000) || + (conn->last_anchor_info_is_valid == 0)) { // use the master clock if it's at least this old or we have no alternative // and at least it is the minimum age. conn->last_anchor_rtptime = conn->anchor_rtptime; @@ -1255,7 +1257,8 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, conn->last_anchor_time_of_update = get_absolute_time_in_ns(); conn->last_anchor_info_is_valid = 1; if (conn->anchor_clock_is_new != 0) - debug(1,"Connection %d: New anchor clock %" PRIx64 " recognised.", conn->connection_number, conn->anchor_clock); + debug(2, "Connection %d: New anchor clock %" PRIx64 " recognised.", + conn->connection_number, conn->anchor_clock); conn->anchor_clock_is_new = 0; } } else { @@ -1266,13 +1269,17 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, // so, if the anchor has not changed, it must be that the master clock has changed if (conn->anchor_clock_is_new != 0) - debug(1,"Connection %d: Anchor clock has changed to %" PRIx64 ", master clock is: %" PRIx64 ".", conn->connection_number, conn->anchor_clock, actual_clock_id); + debug(1, + "Connection %d: Anchor clock has changed to %" PRIx64 ", master clock is: %" PRIx64 + ".", + conn->connection_number, conn->anchor_clock, actual_clock_id); if ((conn->last_anchor_info_is_valid != 0) && (conn->anchor_clock_is_new == 0)) { int64_t time_since_last_update = get_absolute_time_in_ns() - conn->last_anchor_time_of_update; if (time_since_last_update > 5000000000) { - debug(1, "Connection %d: Master clock has changed to %" PRIx64 ".", conn->connection_number, actual_clock_id); + debug(1, "Connection %d: Master clock has changed to %" PRIx64 ".", + conn->connection_number, actual_clock_id); // here we adjust the time of the anchor rtptime // we know its local time, so we use the new clocks's offset to // calculate what time that must be on the new clock @@ -1280,7 +1287,7 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, conn->anchor_clock = actual_clock_id; } } else { - response = clock_not_valid; // no current clock information and no previous clock info + response = clock_not_valid; // no current clock information and no previous clock info } } } else { @@ -1296,7 +1303,8 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, actual_clock_id); break; case clock_not_ready: - debug(2, "Connection %d: NQPTP master clock %" PRIx64 " is available but not ready.", conn->connection_number, actual_clock_id); + debug(2, "Connection %d: NQPTP master clock %" PRIx64 " is available but not ready.", + conn->connection_number, actual_clock_id); break; case clock_service_unavailable: debug(1, "Connection %d: NQPTP clock is not available.", conn->connection_number); @@ -1310,7 +1318,7 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, debug(1, "Connection %d: Can not access NQPTP clock information.", conn->connection_number); break; case clock_no_master: - debug(1, "Connection %d: No NQPTP master clock.", conn->connection_number); + debug(2, "Connection %d: No NQPTP master clock.", conn->connection_number); break; case clock_no_anchor_info: debug(1, "Connection %d: No Clock Anchor.", conn->connection_number); @@ -1922,6 +1930,37 @@ void rtp_buffered_audio_cleanup_handler(__attribute__((unused)) void *arg) { debug(2, "Buffered Audio Receiver Cleanup Done."); } +// not used right now, but potentially useful for understanding flush requests +void display_flush_requests(int activeOnly, uint32_t currentSeq, uint32_t currentTS, + rtsp_conn_info *conn) { + if (conn->flush_requests == NULL) { + if (activeOnly == 0) + debug(1, "No flush requests."); + } else { + flush_request_t *t = conn->flush_requests; + do { + if (t->flushNow) { + debug(1, "immediate flush to untilSeq: %u, untilTS: %u.", t->flushUntilSeq, + t->flushUntilTS); + } else { + if (activeOnly == 0) + debug(1, "fromSeq: %u, fromTS: %u, to untilSeq: %u, untilTS: %u.", t->flushFromSeq, + t->flushFromTS, t->flushUntilSeq, t->flushUntilTS); + else if ((activeOnly == 1) && + (currentSeq >= + (t->flushFromSeq - + 1))) // the -1 is because you might have to trim the end of the previous block + debug(1, + "fromSeq: %u, fromTS: %u, to untilSeq: %u, untilTS: %u, with currentSeq: %u, " + "currentTS: %u.", + t->flushFromSeq, t->flushFromTS, t->flushUntilSeq, t->flushUntilTS, currentSeq, + currentTS); + } + t = t->next; + } while (t != NULL); + } +} + void *rtp_buffered_audio_processor(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; pthread_cleanup_push(rtp_buffered_audio_cleanup_handler, arg); @@ -2046,7 +2085,7 @@ void *rtp_buffered_audio_processor(void *arg) { int pcm_buffer_occupancy = 0; int pcm_buffer_read_point = 0; // offset to where the next buffer should come from uint32_t pcm_buffer_read_point_rtptime = 0; - uint32_t expected_rtptime; + // uint32_t expected_rtptime; uint64_t blocks_read = 0; int flush_requested = 0; @@ -2054,8 +2093,8 @@ void *rtp_buffered_audio_processor(void *arg) { int streaming_has_started = 0; int play_enabled = 0; uint32_t flush_from_timestamp; - int dump_block_info = 0; double requested_lead_time = 0.100; // normal lead time minimum + reset_buffer(conn); // in case there is any garbage in the player do { int flush_is_delayed = 0; int flush_newly_requested = 0; @@ -2068,12 +2107,11 @@ void *rtp_buffered_audio_processor(void *arg) { int flush_request_active = 0; if (conn->ap2_flush_requested) { - if (conn->ap2_flush_from_valid == 0) {// i.e. a flush from right now + if (conn->ap2_flush_from_valid == 0) { // i.e. a flush from right now flush_request_active = 1; flush_is_delayed = 0; } else { flush_is_delayed = 1; - dump_block_info = 1; flush_from_timestamp = conn->ap2_flush_from_rtp_timestamp; int32_t blocks_to_start_of_flush = conn->ap2_flush_from_sequence_number - seq_no; if (blocks_to_start_of_flush <= 0) { @@ -2086,29 +2124,29 @@ void *rtp_buffered_audio_processor(void *arg) { if (flush_requested == 0) { // here, a flush has been newly requested - debug(1,"Flush requested:"); + debug(2, "Flush requested."); if (conn->ap2_flush_from_valid) { - debug(1," fromTS: %u", conn->ap2_flush_from_rtp_timestamp); - debug(1," fromSeq: %u", conn->ap2_flush_from_sequence_number); - debug(1,"--"); + debug(2, " fromTS: %u", conn->ap2_flush_from_rtp_timestamp); + debug(2, " fromSeq: %u", conn->ap2_flush_from_sequence_number); + debug(2, "--"); } - debug(1," untilTS: %u", conn->ap2_flush_until_rtp_timestamp); - debug(1," untilSeq: %u", conn->ap2_flush_until_sequence_number); - debug(1,"--"); - debug(1," currentTS_Start: %u", pcm_buffer_read_point_rtptime); - uint32_t fib = (pcm_buffer_occupancy - pcm_buffer_read_point) / 4; - debug(1," framesInBuffer: %u", fib); - uint32_t endTS = fib + pcm_buffer_read_point_rtptime; - debug(1," currentTS_End: %u", endTS); // a frame occupies 4 bytes - debug(1," currentSeq: %u", seq_no); - - flush_newly_requested = 1; + debug(2, " untilTS: %u", conn->ap2_flush_until_rtp_timestamp); + debug(2, " untilSeq: %u", conn->ap2_flush_until_sequence_number); + debug(2, "--"); + debug(2, " currentTS_Start: %u", pcm_buffer_read_point_rtptime); + uint32_t fib = (pcm_buffer_occupancy - pcm_buffer_read_point) / 4; + debug(2, " framesInBuffer: %u", fib); + uint32_t endTS = fib + pcm_buffer_read_point_rtptime; + debug(2, " currentTS_End: %u", endTS); // a frame occupies 4 bytes + debug(2, " currentSeq: %u", seq_no); + + flush_newly_requested = 1; } // blocks_read to ensure seq_no is valid if ((blocks_read != 0) && (seq_no >= flushUntilSeq)) { // we have reached or overshot the flushUntilSeq block - // if (flushUntilSeq != seq_no) - debug(1,"flushUntilSeq %u reached or overshot at %u.", flushUntilSeq, seq_no); + if (flushUntilSeq != seq_no) + debug(1, "flushUntilSeq %u reached or overshot at %u.", flushUntilSeq, seq_no); conn->ap2_flush_requested = 0; flush_request_active = 0; flush_newly_requested = 0; @@ -2123,10 +2161,9 @@ void *rtp_buffered_audio_processor(void *arg) { play_enabled = conn->ap2_play_enabled; debug_mutex_unlock(&conn->flush_mutex, 3); - // do this outside the flush mutex if (flush_newly_complete) { - debug(1,"Flush Complete."); + debug(2, "Flush Complete."); blocks_read = 0; } @@ -2137,14 +2174,13 @@ void *rtp_buffered_audio_processor(void *arg) { reset_buffer(conn); if (flush_is_delayed == 0) { - debug(1,"Immediate Buffered Audio Flush Started."); - //player_full_flush(conn); + debug(2, "Immediate Buffered Audio Flush Started."); + // player_full_flush(conn); streaming_has_started = 0; pcm_buffer_occupancy = 0; pcm_buffer_read_point = 0; - dump_block_info = 0; } else { - debug(1,"Delayed Buffered Audio Flush Started."); + debug(2, "Delayed Buffered Audio Flush Started."); streaming_has_started = 0; pcm_buffer_occupancy = 0; pcm_buffer_read_point = 0; @@ -2182,22 +2218,26 @@ 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 (blocks_read > 1) { - if ((lead_time >= (int64_t)(requested_lead_time * 1000000000)) || - (streaming_has_started != 0)) { - if (streaming_has_started == 0) - debug(1, "Connection %d: buffered audio starting frame: %u, lead time: %f seconds.", conn->connection_number, pcm_buffer_read_point_rtptime, + if (blocks_read > 2) { + if ((lead_time >= (int64_t)(requested_lead_time * 1000000000)) || + (streaming_has_started != 0)) { + if (streaming_has_started == 0) + debug( + 2, + "Connection %d: buffered audio starting frame: %u, lead time: %f seconds.", + conn->connection_number, pcm_buffer_read_point_rtptime, 0.000000001 * lead_time); - //else { - //if (expected_rtptime != pcm_buffer_read_point_rtptime) - // debug(1,"actual rtptime is %u, expected rtptime is %u.", pcm_buffer_read_point_rtptime, expected_rtptime); - //} - expected_rtptime = pcm_buffer_read_point_rtptime + 352; - player_put_packet(0, 0, pcm_buffer_read_point_rtptime, - pcm_buffer + pcm_buffer_read_point, 352, conn); - streaming_has_started++; - usleep(2000); - } + // else { + // if (expected_rtptime != pcm_buffer_read_point_rtptime) + // debug(1,"actual rtptime is %u, expected rtptime is %u.", + // pcm_buffer_read_point_rtptime, expected_rtptime); + //} + // expected_rtptime = pcm_buffer_read_point_rtptime + 352; + player_put_packet(0, 0, pcm_buffer_read_point_rtptime, + pcm_buffer + pcm_buffer_read_point, 352, conn); + streaming_has_started++; + usleep(2000); + } } pcm_buffer_read_point_rtptime += 352; @@ -2273,38 +2313,6 @@ void *rtp_buffered_audio_processor(void *arg) { // uint8_t marker = 0; // uint8_t payload_type = 0; -/* - if (dump_block_info != 0) { - if ((flush_requested) && (seq_no < flushUntilSeq)) - debug(1, "block %u, rtptime %u, should be skipped.", seq_no, timestamp); - else - debug(1, "block %u, rtptime %u, should be decoded and used.", seq_no, timestamp); - - if (((flush_requested != 0) && (seq_no == flushUntilSeq)) || ((flush_requested == 0) && (new_buffer_needed))) { - debug(1, "block %u, rtptime %u, will be decoded and used.", seq_no, timestamp); - } - } -*/ - -/* - if ((blocks_read != 0) && (seq_no != previous_seq_no + 1)) { - if (previous_seq_no != 0) - debug(1, "block discontinuity: from sequence number %u to sequence number %u.", - previous_seq_no, seq_no); - if (pcm_buffer_occupancy != 0) { - debug(1, - "rtptime discontinuity! Existing pcm buffer contents with timestamp " - "%u, seq_no %u to new block with timestamp %u, seq_no %u", - pcm_buffer_read_point_rtptime, previous_seq_no, timestamp, seq_no); - pcm_buffer_occupancy = 0; - } - // if still playing, this is a problem -- need to reset the player - if (play_enabled) - player_full_flush(conn); - } -*/ - - // previous_seq_no = seq_no; // at this point, we can check if we can to flush this packet -- we won't have @@ -2313,18 +2321,21 @@ void *rtp_buffered_audio_processor(void *arg) { if ((flush_requested) && (seq_no >= flushUntilSeq)) { uint64_t should_be_time; - if ((frame_to_local_time(timestamp, &should_be_time, conn) == - 0) && (play_enabled)) { - // play enabled will be off when this is a full flush and the anchor information is not valid + if ((frame_to_local_time(timestamp, &should_be_time, conn) == 0) && (play_enabled)) { + // play enabled will be off when this is a full flush and the anchor information is not + // valid int64_t lead_time = should_be_time - get_absolute_time_in_ns(); - debug(1,"flush completed to seq: %u with rtptime: %u, lead time: 0x%" PRIx64 " nanoseconds, i.e. %f sec.", seq_no, timestamp, lead_time, lead_time * 0.000000001); + debug(2, + "flush completed to seq: %u with rtptime: %u, lead time: 0x%" PRIx64 + " nanoseconds, i.e. %f sec.", + seq_no, timestamp, lead_time, lead_time * 0.000000001); } else { - debug(1,"flush completed to seq: %u with rtptime: %u.", seq_no, timestamp); + debug(2, "flush completed to seq: %u with rtptime: %u.", seq_no, timestamp); } } - if (((flush_requested != 0) && (seq_no == flushUntilSeq)) || ((flush_requested == 0) && (new_buffer_needed))) { - + if (((flush_requested != 0) && (seq_no == flushUntilSeq)) || + ((flush_requested == 0) && (new_buffer_needed))) { // if we are here because of a flush request, it must be the case that // flushing the pcm buffer wasn't enough, as the request would have been turned off by now @@ -2337,11 +2348,11 @@ void *rtp_buffered_audio_processor(void *arg) { if (pcm_buffer_occupancy == 0) { // they should match and the read point should be zero - // if ((blocks_read != 0) && (pcm_buffer_read_point_rtptime != timestamp)) { + // if ((blocks_read != 0) && (pcm_buffer_read_point_rtptime != timestamp)) { // debug(2, "set pcm_buffer_read_point_rtptime from %u to %u.", // pcm_buffer_read_point_rtptime, timestamp); - pcm_buffer_read_point_rtptime = timestamp; - pcm_buffer_read_point = 0; + pcm_buffer_read_point_rtptime = timestamp; + pcm_buffer_read_point = 0; //} } @@ -2425,12 +2436,19 @@ void *rtp_buffered_audio_processor(void *arg) { // copy the PCM audio into the PCM buffer. // make sure it's big enough first - // also, check it if needs to be truncated but to an impending delayed flush_is_delayed + // also, check it if needs to be truncated but to an impending delayed + // flush_is_delayed if (flush_is_delayed) { // see if the flush_from_timestamp is in the buffer - int32_t samples_remaining = (flush_from_timestamp - pcm_buffer_read_point_rtptime); - if ((samples_remaining > 0) && ((samples_remaining * 4) < dst_bufsize)) { - debug(1,"samples remaining before flush: %d, number of samples %d. flushFromTS: %u, pcm_buffer_read_point_rtptime: %u.", samples_remaining, dst_bufsize/4, flush_from_timestamp, pcm_buffer_read_point_rtptime); + int32_t samples_remaining = + (flush_from_timestamp - pcm_buffer_read_point_rtptime); + if ((samples_remaining > 0) && + ((samples_remaining * 4) < dst_bufsize)) { + debug(2, + "samples remaining before flush: %d, number of samples %d. " + "flushFromTS: %u, pcm_buffer_read_point_rtptime: %u.", + samples_remaining, dst_bufsize / 4, flush_from_timestamp, + pcm_buffer_read_point_rtptime); dst_bufsize = samples_remaining * 4; } } diff --git a/rtsp.c b/rtsp.c index 3ef47ba1..88bf2125 100644 --- a/rtsp.c +++ b/rtsp.c @@ -513,6 +513,49 @@ void cleanup_threads(void) { } } +void add_flush_request(int flushNow, uint32_t flushFromSeq, uint32_t flushFromTS, + uint32_t flushUntilSeq, uint32_t flushUntilTS, rtsp_conn_info *conn) { + // immediate flush requests are added sequentially. Don't know how more than one could arise, TBH + flush_request_t **t = &conn->flush_requests; + int done = 0; + do { + flush_request_t *u = *t; + if ((u == NULL) || ((u->flushNow == 0) && (flushNow != 0)) || + (flushFromSeq < u->flushFromSeq) || + ((flushFromSeq == u->flushFromSeq) && (flushFromTS < u->flushFromTS))) { + flush_request_t *n = (flush_request_t *)calloc(sizeof(flush_request_t), 1); + n->flushNow = flushNow; + n->flushFromSeq = flushFromSeq; + n->flushFromTS = flushFromTS; + n->flushUntilSeq = flushUntilSeq; + n->flushUntilTS = flushUntilTS; + n->next = u; + *t = n; + done = 1; + } else { + t = &u->next; + } + } while (done == 0); +} + +void display_all_flush_requests(rtsp_conn_info *conn) { + if (conn->flush_requests == NULL) { + debug(1, "No flush requests."); + } else { + flush_request_t *t = conn->flush_requests; + do { + if (t->flushNow) { + debug(1, "immediate flush to untilSeq: %u, untilTS: %u.", t->flushUntilSeq, + t->flushUntilTS); + } else { + debug(1, "fromSeq: %u, fromTS: %u, to untilSeq: %u, untilTS: %u.", t->flushFromSeq, + t->flushFromTS, t->flushUntilSeq, t->flushUntilTS); + } + t = t->next; + } while (t != NULL); + } +} + // park a null at the line ending, and return the next line pointer // accept \r, \n, or \r\n static char *nextline(char *in, int inbuf) { @@ -1324,7 +1367,7 @@ void handle_flushbuffered(rtsp_conn_info *conn, rtsp_message *req, rtsp_message } else { plist_get_uint_val(item, &flushFromTS); if (flushFromValid == 0) - debug(1,"flushFromTS without flushFromSeq!"); + debug(1, "flushFromTS without flushFromSeq!"); debug(2, "flushFromTS is %" PRId64 ".", flushFromTS); } @@ -1345,23 +1388,52 @@ void handle_flushbuffered(rtsp_conn_info *conn, rtsp_message *req, rtsp_message } debug_mutex_lock(&conn->flush_mutex, 1000, 1); - conn->ap2_flush_from_valid = flushFromValid; - // a flush with from... components will not be followed by a setanchoe (i.e. a play) + // a flush with from... components will not be followed by a setanchor (i.e. a play) // if it's a flush that will be followed by a setanchor (i.e. a play) then stop play now. if (flushFromValid == 0) conn->ap2_play_enabled = 0; - conn->ap2_flush_from_sequence_number = flushFromSeq; - conn->ap2_flush_from_rtp_timestamp = flushFromTS; + // add the exact request as made to the linked list (not used for anything but diagnostics now) + // int flushNow = 0; + // if (flushFromValid == 0) + // flushNow = 1; + // add_flush_request(flushNow, flushFromSeq, flushFromTS, flushUntilSeq, flushUntilTS, conn); + + // now, if it's an immediate flush, replace the existing request, if any + // but it if's a deferred flush and there is an existing deferred request, + // only update the flushUntil stuff -- that seems to preserve + // the intended semantics + + // so, always replace these conn->ap2_flush_until_sequence_number = flushUntilSeq; conn->ap2_flush_until_rtp_timestamp = flushUntilTS; + + if ((conn->ap2_flush_requested != 0) && (conn->ap2_flush_from_valid != 0) && + (flushFromValid != 0)) { + // if there is a request already, and it's a deferred request, and the current request is also + // deferred... do nothing! -- leave the starting point in place. Yeah, yeah, we know de Morgan's + // Law, but this seems clearer + } else { + conn->ap2_flush_from_sequence_number = flushFromSeq; + conn->ap2_flush_from_rtp_timestamp = flushFromTS; + } + + conn->ap2_flush_from_valid = flushFromValid; conn->ap2_flush_requested = 1; + + // reflect the possibly updated flush request + // add_flush_request(flushNow, conn->ap2_flush_from_sequence_number, + // conn->ap2_flush_from_rtp_timestamp, conn->ap2_flush_until_sequence_number, + // conn->ap2_flush_until_rtp_timestamp, conn); + debug_mutex_unlock(&conn->flush_mutex, 3); if (flushFromValid) - debug(1,"Deferred Flush Requested"); + debug(2, "Deferred Flush Requested"); else - debug(1,"Immediate Flush Requested"); + debug(2, "Immediate Flush Requested"); + + // display_all_flush_requests(conn); resp->respcode = 200; } @@ -2316,7 +2388,8 @@ void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *req, if (!strncmp(cp, "volume: ", strlen("volume: "))) { float volume = atof(cp + strlen("volume: ")); - debug(1, "Connection %d: request to set AirPlay Volume to: %f.", conn->connection_number, volume); + debug(2, "Connection %d: request to set AirPlay Volume to: %f.", conn->connection_number, + volume); // if we are playing, go ahead and change the volume if (try_to_hold_play_lock(conn) == 0) { player_volume(volume, conn); @@ -2337,7 +2410,8 @@ void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *req, } else #endif { - debug(1, "Connection %d, unrecognised parameter: \"%s\" (%d)\n", conn->connection_number, cp, strlen(cp)); + debug(1, "Connection %d, unrecognised parameter: \"%s\" (%d)\n", conn->connection_number, cp, + strlen(cp)); } cp = next; } @@ -3058,7 +3132,8 @@ static void handle_get_parameter(__attribute__((unused)) rtsp_conn_info *conn, r if ((req->content) && (req->contentlength == strlen("volume\r\n")) && strstr(req->content, "volume") == req->content) { - debug(2,"Connection %d: Current volume (%.6f) requested", conn->connection_number, config.airplay_volume); + debug(2, "Connection %d: Current volume (%.6f) requested", conn->connection_number, + config.airplay_volume); char *p = malloc(128); // will be automatically deallocated with the response is deleted if (p) { resp->content = p; @@ -3153,11 +3228,13 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m // debug(2, "received parameters in SET_PARAMETER request."); handle_set_parameter_parameter(conn, req, resp); // this could be volume or progress } else { - debug(1, "Connection %d: received unknown Content-Type \"%s\" in SET_PARAMETER request.", conn->connection_number, ct); - debug_print_msg_headers(1,req); + debug(1, "Connection %d: received unknown Content-Type \"%s\" in SET_PARAMETER request.", + conn->connection_number, ct); + debug_print_msg_headers(1, req); } } else { - debug(1, "Connection %d: missing Content-Type header in SET_PARAMETER request.", conn->connection_number); + debug(1, "Connection %d: missing Content-Type header in SET_PARAMETER request.", + conn->connection_number); } resp->respcode = 200; } @@ -3449,7 +3526,7 @@ static void apple_challenge(int fd, rtsp_message *req, rtsp_message *resp) { char *hdr = msg_get_header(req, "Apple-Challenge"); if (!hdr) return; - debug(1,"Apple Challenge"); + debug(1, "Apple Challenge"); SOCKADDR fdsa; socklen_t sa_len = sizeof(fdsa); getsockname(fd, (struct sockaddr *)&fdsa, &sa_len); @@ -4119,8 +4196,8 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { maxfd = sockfd[i]; } - char **t1; // ap1 test records - char **t2; // two text records + char **t1; // ap1 test records + char **t2; // two text records t1 = NULL; t2 = NULL; @@ -4130,14 +4207,14 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { char **p = txt_records; t1 = p; // first set of text records -// make up a firmware version + // make up a firmware version char firmware_version[64]; #ifdef CONFIG_USE_GIT_VERSION_STRING - if (git_version_string[0] != '\0') - snprintf(firmware_version, sizeof(firmware_version), "fv=%s",git_version_string); - else + if (git_version_string[0] != '\0') + snprintf(firmware_version, sizeof(firmware_version), "fv=%s", git_version_string); + else #endif - snprintf(firmware_version, sizeof(firmware_version), "fv=%s",PACKAGE_VERSION); + snprintf(firmware_version, sizeof(firmware_version), "fv=%s", PACKAGE_VERSION); #ifdef CONFIG_AIRPLAY_2 char ap1_featuresString[64]; @@ -4152,7 +4229,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="), config.airplay_device_id); -// the ap1 text record is different if it is set up for ap2 + // the ap1 text record is different if it is set up for ap2 *p++ = "cn=0,1"; *p++ = "da=true"; *p++ = "et=0,4"; @@ -4198,7 +4275,6 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { *p++ = NULL; #endif - #ifdef CONFIG_AIRPLAY_2 // make up a secondary set of text records char *secondary_txt_records[64]; @@ -4233,8 +4309,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { *p++ = NULL; #endif - - mdns_register(t1,t2); + mdns_register(t1, t2); pthread_setcancelstate(oldState, NULL); int acceptfd; diff --git a/shairport.c b/shairport.c index b2d8886c..d143de66 100644 --- a/shairport.c +++ b/shairport.c @@ -1421,7 +1421,6 @@ void exit_function() { free(config.regtype2); #endif - #ifdef CONFIG_LIBDAEMON if (this_is_the_daemon_process) { daemon_retval_send(0); @@ -2038,39 +2037,34 @@ int main(int argc, char **argv) { pthread_create(&soxr_time_check_thread, NULL, &soxr_time_check, NULL); #endif -/* - uint8_t ap_md5[16]; - -#ifdef CONFIG_OPENSSL - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, config.service_name, strlen(config.service_name)); - MD5_Final(ap_md5, &ctx); -#endif - -#ifdef CONFIG_MBEDTLS -#if MBEDTLS_VERSION_MINOR >= 7 - mbedtls_md5_context tctx; - mbedtls_md5_starts_ret(&tctx); - mbedtls_md5_update_ret(&tctx, (unsigned char *)config.service_name, strlen(config.service_name)); - mbedtls_md5_finish_ret(&tctx, ap_md5); -#else - mbedtls_md5_context tctx; - mbedtls_md5_starts(&tctx); - mbedtls_md5_update(&tctx, (unsigned char *)config.service_name, strlen(config.service_name)); - mbedtls_md5_finish(&tctx, ap_md5); -#endif -#endif - -#ifdef CONFIG_POLARSSL - md5_context tctx; - md5_starts(&tctx); - md5_update(&tctx, (unsigned char *)config.service_name, strlen(config.service_name)); - md5_finish(&tctx, ap_md5); -#endif - - memcpy(config.hw_addr, ap_md5, sizeof(config.hw_addr)); -*/ + /* + uint8_t ap_md5[16]; + + #ifdef CONFIG_OPENSSL + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, config.service_name, strlen(config.service_name)); + MD5_Final(ap_md5, &ctx); + #endif + + #ifdef CONFIG_MBEDTLS + #if MBEDTLS_VERSION_MINOR >= 7 + mbedtls_md5_context tctx; + mbedtls_md5_starts_ret(&tctx); + mbedtls_md5_update_ret(&tctx, (unsigned char *)config.service_name, + strlen(config.service_name)); mbedtls_md5_finish_ret(&tctx, ap_md5); #else mbedtls_md5_context + tctx; mbedtls_md5_starts(&tctx); mbedtls_md5_update(&tctx, (unsigned char *)config.service_name, + strlen(config.service_name)); mbedtls_md5_finish(&tctx, ap_md5); #endif #endif + + #ifdef CONFIG_POLARSSL + md5_context tctx; + md5_starts(&tctx); + md5_update(&tctx, (unsigned char *)config.service_name, strlen(config.service_name)); + md5_finish(&tctx, ap_md5); + #endif + + memcpy(config.hw_addr, ap_md5, sizeof(config.hw_addr)); + */ #ifdef CONFIG_METADATA metadata_init(); // create the metadata pipe if necessary