From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Thu, 29 Apr 2021 15:51:29 +0000 (+0100) Subject: player.c compiles and everything builds and runs with the airplay 2 flag off. With... X-Git-Tag: 4.0-dev~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bdfb1c6ed6baebb65fa356967f30f86ec9439806;p=thirdparty%2Fshairport-sync.git player.c compiles and everything builds and runs with the airplay 2 flag off. With airplay_2 flag on, rtp.c won't build, but we know that. --- diff --git a/player.c b/player.c index ff889408..66637292 100644 --- a/player.c +++ b/player.c @@ -3,7 +3,7 @@ * Copyright (c) James Laird 2011, 2013 * All rights reserved. * - * Modifications for audio synchronisation + * Modifications for audio synchronisation, AirPlay 2 * and related work, copyright (c) Mike Brady 2014 -- 2021 * All rights reserved. * @@ -110,12 +110,7 @@ int64_t first_frame_early_bias = 8; // static abuf_t audio_buffer[BUFFER_FRAMES]; #define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES) -uint32_t modulo_32_offset(uint32_t from, uint32_t to) { - if (from <= to) - return to - from; - else - return UINT32_MAX - from + to + 1; -} +int32_t modulo_32_offset(uint32_t from, uint32_t to) { return to - from; } void do_flush(uint32_t timestamp, rtsp_conn_info *conn); @@ -141,79 +136,34 @@ static void ab_resync(rtsp_conn_info *conn) { // returns true if x is actually within the buffer int position_in_modulo_uint16_t_buffer(uint16_t x, uint16_t start, uint16_t end, uint16_t *pos) { - int response = 0; // not in the buffer - if (start <= end) { - if (x < start) { // this means that it's up around the wrap - if (pos) - *pos = UINT16_MAX - start + 1 + x; - } else { - if (pos) - *pos = x - start; - if (x < end) - response = 1; - } - } else if ((x >= start)) { // && (x <= UINT16_MAX)) { // always true + int response = 0; + + int16_t x_disp = x - start; + int16_t b_size = + end - start; // this will be positive as long as (a) start and end are within 2^15 of each + // other and (b) end is at or after start on the modulo wheel + if ((x_disp >= 0) && (x_disp < b_size)) response = 1; - if (pos) - *pos = x - start; - } else { - if (pos) - *pos = UINT16_MAX - start + 1 + x; - if (x < end) { - response = 1; - } - } return response; } +// wrapped number between two seq_t. +// as long as the two seq_t numbers are supposed to be within 2^15 of one another, +// that is, you go the shorter way around the 2^16 modulo wheel, +// this will return positive if b is equal to or after a and negative otherwise +int32_t seq_diff(seq_t a, seq_t b, seq_t base) { + int16_t d = b - a; + return d; +} -static inline seq_t SUCCESSOR(seq_t x) { return x + 1; } - -// a minus b -int16_t seq_diff(seq_t a, seq_t b) { - int16_t response; - seq_t diff = a - b; - seq_t invdiff = b - a; - if (diff < invdiff) - response = diff; - else - response = -invdiff; - return response; +// the sequence numbers will wrap pretty often. +// this returns true if the second arg is strictly after the first +static inline int seq_order(seq_t a, seq_t b, seq_t base) { + int16_t d = b - a; + return d > 0; } static inline seq_t seq_sum(seq_t a, seq_t b) { return a + b; } -// This orders u and v by picking the smaller of the two modulo differences -// in unsigned modulo arithmetic and setting the sign of the result accordingly. - -// if u - v gives the smaller modulo difference, then that modulo difference is returned -// otherwise the negative of the v - u modulo difference is returned. - -// (Think of a modulo ring starting at 0 and circling around clockwise finally to -// modulo-2, modulo-1 to 0 again. To determine the ordering of the two numbers, -// Find the shorter path between them around the ring. -// If you go from v to u in the positive (0, 1, 2 ... or clockwise) direction, -// then u is greater than (or "after") v.) - -// The result will always fit in an int64_t as it must be less or equal to half way -// around the ring. -// Due to the asymmetry of 2's complement representation, however, -// if the difference is equal to modulo / 2, it is ambiguous as to whether -// u is "after" or "before" (i.e. greater or less than) v. -// and will be returned as -modulo / 2, that is, "before". -// If that ever happens and there is a real ambiguity in the application, -// the modulo chosen is too small. - -int64_t int64_mod_difference(const uint64_t u, const uint64_t v, const uint64_t modulo) { - int64_t response; - uint64_t diff = (u - v) % modulo; - uint64_t invdiff = (v - u) % modulo; - if (diff < invdiff) - response = diff; - else - response = -invdiff; - return response; -} - void reset_input_flow_metrics(rtsp_conn_info *conn) { conn->play_number_after_flush = 0; conn->packet_count_since_flush = 0; @@ -444,8 +394,40 @@ static void free_audio_buffers(rtsp_conn_info *conn) { int first_possibly_missing_frame = -1; -void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, int len, - rtsp_conn_info *conn) { +void reset_buffer(rtsp_conn_info *conn) { + debug_mutex_lock(&conn->ab_mutex, 30000, 0); + ab_resync(conn); + debug_mutex_unlock(&conn->ab_mutex, 0); +} + +void get_audio_buffer_size_and_occupancy(unsigned int *size, unsigned int *occupancy, + rtsp_conn_info *conn) { + debug_mutex_lock(&conn->ab_mutex, 30000, 0); + *size = BUFFER_FRAMES; + if (conn->ab_synced) { + int16_t occ = + conn->ab_write - conn->ab_read; // will be zero or positive if read and write are within + // 2^15 of each other and write is at or after read + *occupancy = occ; + } else { + *occupancy = 0; + } + debug_mutex_unlock(&conn->ab_mutex, 0); +} + +void player_put_packet(int original_format, seq_t seqno, uint32_t actual_timestamp, uint8_t *data, + int len, rtsp_conn_info *conn) { + + // if it's original format, it has a valid seqno and must be decoded + // otherwise, it can take the next seqno and doesn't need decoding. + + // ignore a request to flush that has been made before the first packet... + if (conn->packet_count == 0) { + debug_mutex_lock(&conn->flush_mutex, 1000, 1); + conn->flush_requested = 0; + conn->flush_rtp_timestamp = 0; + debug_mutex_unlock(&conn->flush_mutex, 3); + } debug_mutex_lock(&conn->ab_mutex, 30000, 0); uint64_t time_now = get_absolute_time_in_ns(); @@ -453,77 +435,93 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in conn->packet_count_since_flush++; conn->time_of_last_audio_packet = time_now; if (conn->connection_state_to_output) { // if we are supposed to be processing these packets - abuf_t *abuf = 0; - if (!conn->ab_synced) { - // if this is the first packet... - debug(3, "syncing to seqno %u.", seqno); - conn->ab_write = seqno; - conn->ab_read = seqno; - conn->ab_synced = 1; - } - int16_t write_point_gap = seq_diff(seqno, conn->ab_write); // this is the difference between - // the incoming packet number and the packet number that was expected. - if (write_point_gap == - 0) { // if this is the expected packet (which could be the first packet...) - if (conn->input_frame_rate_starting_point_is_valid == 0) { - if ((conn->packet_count_since_flush >= 500) && (conn->packet_count_since_flush <= 510)) { - conn->frames_inward_measurement_start_time = time_now; - conn->frames_inward_frames_received_at_measurement_start_time = actual_timestamp; - conn->input_frame_rate_starting_point_is_valid = 1; // valid now - } + abuf_t *abuf = 0; + if (!conn->ab_synced) { + // if this is the first packet... + debug(3, "syncing to seqno %u.", seqno); + conn->ab_write = seqno; + conn->ab_read = seqno; + conn->ab_synced = 1; + } 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 + seqno = conn->ab_write; } - conn->frames_inward_measurement_time = time_now; - conn->frames_inward_frames_received_at_measurement_time = actual_timestamp; - abuf = conn->audio_buffer + BUFIDX(seqno); - conn->ab_write = SUCCESSOR(seqno); // move the write pointer to the next free space - } else if (write_point_gap > 0) { // newer than expected - // initialise the frames in between - int i; - for (i = 0; i < write_point_gap; i++) { - abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i)); - abuf->ready = 0; // to be sure, to be sure - abuf->resend_request_number = 0; - abuf->initialisation_time = - time_now; // this represents when the packet was noticed to be missing - abuf->status = 1 << 0; // signifying missing - abuf->resend_time = 0; - abuf->given_timestamp = 0; - abuf->sequence_number = 0; + if (conn->ab_write == + seqno) { // if this is the expected packet (which could be the first packet...) + if (conn->input_frame_rate_starting_point_is_valid == 0) { + if ((conn->packet_count_since_flush >= 500) && (conn->packet_count_since_flush <= 510)) { + conn->frames_inward_measurement_start_time = time_now; + conn->frames_inward_frames_received_at_measurement_start_time = actual_timestamp; + conn->input_frame_rate_starting_point_is_valid = 1; // valid now + } + } + conn->frames_inward_measurement_time = time_now; + conn->frames_inward_frames_received_at_measurement_time = actual_timestamp; + abuf = conn->audio_buffer + BUFIDX(seqno); + conn->ab_write = seqno + 1; // move the write pointer to the next free space + } else if (seq_order(conn->ab_write, seqno, conn->ab_read)) { // newer than expected + int32_t gap = seq_diff(conn->ab_write, seqno, conn->ab_read); + if (gap <= 0) + debug(1, "Unexpected gap size: %d.", gap); + int i; + for (i = 0; i < gap; i++) { + abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i)); + abuf->ready = 0; // to be sure, to be sure + abuf->resend_request_number = 0; + abuf->initialisation_time = + time_now; // this represents when the packet was noticed to be missing + abuf->status = 1 << 0; // signifying missing + abuf->resend_time = 0; + abuf->given_timestamp = 0; + abuf->sequence_number = 0; + } + // debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write); + abuf = conn->audio_buffer + BUFIDX(seqno); + // rtp_request_resend(ab_write, gap); + // resend_requests++; + conn->ab_write = seqno + 1; + } else if (seq_order(conn->ab_read, seqno, + conn->ab_read)) { // older than expected but not too late + conn->late_packets++; + abuf = conn->audio_buffer + BUFIDX(seqno); + } else { // too late. + conn->too_late_packets++; } - abuf = conn->audio_buffer + BUFIDX(seqno); - conn->ab_write = SUCCESSOR(seqno); - } else if (seq_diff(seqno, conn->ab_read) > 0) { // older than expected but still not too late - conn->late_packets++; - abuf = conn->audio_buffer + BUFIDX(seqno); - } else { // too late. - conn->too_late_packets++; - } - if (abuf) { - int datalen = conn->max_frames_per_packet; - abuf->initialisation_time = time_now; - abuf->resend_time = 0; - if (audio_packet_decode(abuf->data, &datalen, data, len, conn) == 0) { - abuf->ready = 1; - abuf->status = 0; // signifying that it was received - abuf->length = datalen; - abuf->given_timestamp = actual_timestamp; - abuf->sequence_number = seqno; - } else { - debug(1, "Bad audio packet detected and discarded."); - abuf->ready = 0; - abuf->status = 1 << 1; // bad packet, discarded - abuf->resend_request_number = 0; - abuf->given_timestamp = 0; - abuf->sequence_number = 0; + if (abuf) { + int datalen = conn->max_frames_per_packet; + abuf->initialisation_time = time_now; + abuf->resend_time = 0; + if ((original_format != 0) && + (audio_packet_decode(abuf->data, &datalen, data, len, conn) == 0)) { + abuf->ready = 1; + abuf->status = 0; // signifying that it was received + abuf->length = datalen; + abuf->given_timestamp = actual_timestamp; + abuf->sequence_number = seqno; + } else if (original_format == 0) { + memcpy(abuf->data, data, len * conn->input_bytes_per_frame); + abuf->ready = 1; + abuf->status = 0; // signifying that it was received + abuf->length = len; + abuf->given_timestamp = actual_timestamp; + abuf->sequence_number = seqno; + } else { + debug(1, "Bad audio packet detected and discarded."); + abuf->ready = 0; + abuf->status = 1 << 1; // bad packet, discarded + abuf->resend_request_number = 0; + abuf->given_timestamp = 0; + abuf->sequence_number = 0; + } } - } - int rc = pthread_cond_signal(&conn->flowcontrol); - if (rc) - debug(1, "Error signalling flowcontrol."); + int rc = pthread_cond_signal(&conn->flowcontrol); + if (rc) + debug(1, "Error signalling flowcontrol."); - // resend checks + // resend checks { uint64_t minimum_wait_time = (uint64_t)(config.resend_control_first_check_time * (uint64_t)1000000000); @@ -1252,6 +1250,29 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { if (local_time_now >= time_to_play) { do_wait = 0; } + // here, do a sanity check. if the time_to_play is not within a few seconds of the + // time now, the frame is probably not meant to be there, so let it go. + if (do_wait != 0) { + // this is a hack. + // we subtract two 2^n unsigned numbers and get a signed 2^n result. + // If we think of the calculation as occurring in modulo 2^n arithmetic + // then the signed result's magnitude represents the shorter distance around + // the modulo wheel of values from one number to the other. + // The sign indicates the direction: positive means clockwise (upwards) from the + // second number to the first (i.e. the first number comes "after" the second). + + int64_t time_difference = local_time_now - time_to_play; + if ((time_difference > 10000000000) || (time_difference < -10000000000)) { + debug(2, + "crazy time interval of %f seconds between time now: 0x%" PRIx64 + " and time of packet: %" PRIx64 ".", + 0.000000001 * time_difference, local_time_now, time_to_play); + debug(2, "packet rtptime: %u, reference_timestamp: %u", curframe->given_timestamp, + conn->anchor_rtptime); + + do_wait = 0; // let it go + } + } } } if (do_wait == 0) @@ -1307,7 +1328,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { } curframe->ready = 0; } - conn->ab_read = SUCCESSOR(conn->ab_read); + conn->ab_read++; pthread_cleanup_pop(1); return curframe; } @@ -1544,6 +1565,40 @@ 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; + } + + // 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; + } + + // 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; + } +#endif + debug(3, "Cancelling timing, control and audio threads..."); debug(3, "Cancel timing thread."); pthread_cancel(conn->rtp_timing_thread); @@ -1604,11 +1659,7 @@ void *player_thread_func(void *arg) { // be used as a null operand, so we'll use it like that too conn->fix_volume = 0x10000; - if (conn->latency == 0) { - debug(3, "No latency has (yet) been specified. Setting 88,200 (2 seconds) frames " - "as a default."); - conn->latency = 88200; - } + reset_anchor_info(conn); if (conn->stream.type == ast_apple_lossless) init_alac_decoder((int32_t *)&conn->stream.fmtp, @@ -1870,10 +1921,12 @@ void *player_thread_func(void *arg) { } } +#ifndef CONFIG_AIRPLAY_2 // create and start the timing, control and audio receiver threads pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn); pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn); pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn); +#endif pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far @@ -1910,10 +1963,10 @@ void *player_thread_func(void *arg) { debug(2, "Player has supplied a silent frame, (possibly frame %u) for play number %d, " "status 0x%X after %u resend requests.", - SUCCESSOR(conn->last_seqno_read), play_number, inframe->status, + conn->last_seqno_read + 1, play_number, inframe->status, inframe->resend_request_number); conn->last_seqno_read = - SUCCESSOR(conn->last_seqno_read); // manage the packet out of sequence minder + ((conn->last_seqno_read + 1) & 0xffff); // manage the packet out of sequence minder void *silence = malloc(conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio); @@ -2050,7 +2103,7 @@ void *player_thread_func(void *arg) { inframe->sequence_number; // int32_t from seq_t, i.e. uint16_t, so okay. else { conn->last_seqno_read = - SUCCESSOR(conn->last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay. + (conn->last_seqno_read + 1) & 0xffff; // int32_t from seq_t, i.e. uint16_t, so okay. if (inframe->sequence_number != conn->last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay debug(2, @@ -2061,7 +2114,8 @@ void *player_thread_func(void *arg) { } } - conn->buffer_occupancy = seq_diff(conn->ab_write, conn->ab_read); // int32_t from int16_t + conn->buffer_occupancy = + seq_diff(conn->ab_read, conn->ab_write, conn->ab_read); // int32_t from int32 if (conn->buffer_occupancy < minimum_buffer_occupancy) minimum_buffer_occupancy = conn->buffer_occupancy; @@ -2075,6 +2129,7 @@ void *player_thread_func(void *arg) { // If any of these are false, we don't do any synchronisation stuff int resp = -1; // use this as a flag -- if negative, we can't rely on a real known delay + current_delay = -1; // use this as a failure flag if (config.output->delay) { long l_delay; @@ -2929,13 +2984,46 @@ void player_flush(uint32_t timestamp, rtsp_conn_info *conn) { debug(3, "player_flush"); do_flush(timestamp, conn); #ifdef CONFIG_METADATA - debug(2, "pfls"); - char numbuf[32]; - snprintf(numbuf, sizeof(numbuf), "%u", timestamp); - send_ssnc_metadata('pfls', numbuf, strlen(numbuf), 1); // contains cancellation points +// only send a flush metadata message if the first packet has been seen -- it's a bogus message + // otherwise + if (conn->first_packet_timestamp) { + debug(2, "pfls"); + char numbuf[32]; + snprintf(numbuf, sizeof(numbuf), "%u", timestamp); + send_ssnc_metadata('pfls', numbuf, strlen(numbuf), 1); // contains cancellation points + } #endif } +void player_full_flush(rtsp_conn_info *conn) { + // this basically flushes everything from the player + // here, find the rtptime of the last from in the buffer and add 1 to it + // so as to ask to flush everything + int flush_needed = 0; + uint32_t rtpTimestamp; + debug_mutex_lock(&conn->ab_mutex, 30000, 0); + if ((conn->ab_synced != 0) && (conn->ab_write != conn->ab_read)) { + abuf_t *abuf = NULL; + seq_t last_seqno_written; + do { + last_seqno_written = conn->ab_write - 1; + abuf = conn->audio_buffer + BUFIDX(last_seqno_written); + } while ((abuf->ready == 0) && (last_seqno_written != conn->ab_read)); + if ((abuf != NULL) && (abuf->ready != 0)) { + debug(2, "full flush needed"); + rtpTimestamp = abuf->given_timestamp + abuf->length + 1; + flush_needed = 1; + } else { + debug(2, "full flush not needed"); + } + } else { + debug(2, "full flush not needed -- buffers empty or not synced"); + } + debug_mutex_unlock(&conn->ab_mutex, 0); + if (flush_needed) + player_flush(rtpTimestamp, conn); +} + int player_play(rtsp_conn_info *conn) { // need to use conn in place of stream below. Need to put the stream as a parameter to he if (conn->player_thread != NULL) diff --git a/player.h b/player.h index e8942710..22bbccf3 100644 --- a/player.h +++ b/player.h @@ -341,7 +341,7 @@ typedef struct { uint64_t dac_buffer_queue_minimum_length; } rtsp_conn_info; -uint32_t modulo_32_offset(uint32_t from, uint32_t to); +int32_t modulo_32_offset(uint32_t from, uint32_t to); int player_play(rtsp_conn_info *conn); int player_stop(rtsp_conn_info *conn); @@ -349,7 +349,7 @@ int player_stop(rtsp_conn_info *conn); void player_volume(double f, rtsp_conn_info *conn); void player_volume_without_notification(double f, rtsp_conn_info *conn); void player_flush(uint32_t timestamp, rtsp_conn_info *conn); -void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, int len, +void player_put_packet(int original_format, seq_t seqno, uint32_t actual_timestamp, uint8_t *data, int len, rtsp_conn_info *conn); int64_t monotonic_timestamp(uint32_t timestamp, rtsp_conn_info *conn); // add an epoch to the timestamp. The monotonic diff --git a/rtp.c b/rtp.c index b96a344d..34115c9b 100644 --- a/rtp.c +++ b/rtp.c @@ -222,7 +222,7 @@ void *rtp_audio_receiver(void *arg) { if (plen >= 16) { if ((config.diagnostic_drop_packet_fraction == 0.0) || (drand48() > config.diagnostic_drop_packet_fraction)) - player_put_packet(seqno, actual_timestamp, pktp, plen, + player_put_packet(1, seqno, actual_timestamp, pktp, plen, conn); // the '1' means is original format else debug(3, "Dropping audio packet %u to simulate a bad connection.", seqno); @@ -469,7 +469,7 @@ void *rtp_control_receiver(void *arg) { // check if packet contains enough content to be reasonable if (plen >= 16) { - player_put_packet(seqno, actual_timestamp, pktp, plen, + player_put_packet(1, seqno, actual_timestamp, pktp, plen, conn); // the '1' means is original format continue; } else { @@ -1114,6 +1114,99 @@ int local_ntp_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn return result; } +void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { + // debug(1, "rtp_request_resend of %u packets from sequence number %u.", count, first); + if (conn->rtp_running) { + // if (!request_sent) { + // debug(2, "requesting resend of %d packets starting at %u.", count, first); + // request_sent = 1; + //} + + char req[8]; // *not* a standard RTCP NACK + req[0] = 0x80; +#ifdef CONFIG_AIRPLAY_2 + if (conn->ap2_remote_control_socket_addr_length == 0) { + debug(2, "No remote socket -- skipping the resend"); + return; // hack + } + req[1] = 0xD5; // Airplay 2 'resend' +#else + req[1] = (char)0x55 | (char)0x80; // Apple 'resend' +#endif + *(unsigned short *)(req + 2) = htons(1); // our sequence number + *(unsigned short *)(req + 4) = htons(first); // missed seqnum + *(unsigned short *)(req + 6) = htons(count); // count +#ifndef CONFIG_AIRPLAY_2 + socklen_t msgsize = sizeof(struct sockaddr_in); +#ifdef AF_INET6 + if (conn->rtp_client_control_socket.SAFAMILY == AF_INET6) { + msgsize = sizeof(struct sockaddr_in6); + } +#endif +#endif + uint64_t time_of_sending_ns = get_absolute_time_in_ns(); + uint64_t resend_error_backoff_time = 300000000; // 0.3 seconds + if ((conn->rtp_time_of_last_resend_request_error_ns == 0) || + ((time_of_sending_ns - conn->rtp_time_of_last_resend_request_error_ns) > + resend_error_backoff_time)) { + if ((config.diagnostic_drop_packet_fraction == 0.0) || + (drand48() > config.diagnostic_drop_packet_fraction)) { + // put a time limit on the sendto + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 100000; +#ifdef CONFIG_AIRPLAY_2 + if (setsockopt(conn->ap2_control_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, + sizeof(timeout)) < 0) + debug(1, "Can't set timeout on resend request socket."); + if (sendto(conn->ap2_control_socket, req, sizeof(req), 0, + (struct sockaddr *)&conn->ap2_remote_control_socket_addr, + conn->ap2_remote_control_socket_addr_length) == -1) { +#else + if (setsockopt(conn->control_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, + sizeof(timeout)) < 0) + debug(1, "Can't set timeout on resend request socket."); + + if (sendto(conn->control_socket, req, sizeof(req), 0, + (struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) { +#endif + char em[1024]; + strerror_r(errno, em, sizeof(em)); + debug(2, "Error %d using sendto to request a resend: \"%s\".", errno, em); + conn->rtp_time_of_last_resend_request_error_ns = time_of_sending_ns; + } else { + conn->rtp_time_of_last_resend_request_error_ns = 0; + } + + } else { + debug(3, "Dropping resend request packet to simulate a bad network. Backing off for 0.3 " + "second."); + conn->rtp_time_of_last_resend_request_error_ns = time_of_sending_ns; + } + } else { + debug(1, + "Suppressing a resend request due to a resend sendto error in the last 0.3 seconds."); + } + } else { + // if (!request_sent) { + debug(2, "rtp_request_resend called without active stream!"); + // request_sent = 1; + //} + } +} + +int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn) { + return frame_to_ntp_local_time(timestamp, time, conn); +} + +int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn) { + return local_ntp_time_to_frame(time, frame, conn); +} + + +#ifdef CONFIG_AIRPLAY_2 + void set_ptp_anchor_info(rtsp_conn_info *conn, uint64_t clock_id, uint32_t rtptime, uint64_t networktime) { if (conn->anchor_clock != clock_id) @@ -1187,11 +1280,6 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, return response; } -int get_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP, - uint64_t *anchorLocalTime) { - return get_ptp_anchor_local_time_info(conn, anchorRTP,anchorLocalTime); -} - int have_ptp_timing_information(rtsp_conn_info *conn) { if (get_anchor_local_time_info(conn, NULL, NULL) == 0) return 1; @@ -1199,10 +1287,6 @@ int have_ptp_timing_information(rtsp_conn_info *conn) { return 0; } -int have_timing_information(rtsp_conn_info *conn) { - return have_ptp_timing_information(conn); -} - int frame_to_ptp_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn) { int result = -1; uint32_t anchor_rtptime; @@ -1221,10 +1305,6 @@ int frame_to_ptp_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info * return result; } -int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn) { - return frame_to_ntp_local_time(timestamp, time, conn); -} - int local_ptp_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn) { int result = -1; uint32_t anchor_rtptime; @@ -1244,95 +1324,6 @@ int local_ptp_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn return result; } -int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn) { - return local_ntp_time_to_frame(time, frame, conn); -} - -void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { - // debug(1, "rtp_request_resend of %u packets from sequence number %u.", count, first); - if (conn->rtp_running) { - // if (!request_sent) { - // debug(2, "requesting resend of %d packets starting at %u.", count, first); - // request_sent = 1; - //} - - char req[8]; // *not* a standard RTCP NACK - req[0] = 0x80; -#ifdef CONFIG_AIRPLAY_2 - if (conn->ap2_remote_control_socket_addr_length == 0) { - debug(2, "No remote socket -- skipping the resend"); - return; // hack - } - req[1] = 0xD5; // Airplay 2 'resend' -#else - req[1] = (char)0x55 | (char)0x80; // Apple 'resend' -#endif - *(unsigned short *)(req + 2) = htons(1); // our sequence number - *(unsigned short *)(req + 4) = htons(first); // missed seqnum - *(unsigned short *)(req + 6) = htons(count); // count -#ifndef CONFIG_AIRPLAY_2 - socklen_t msgsize = sizeof(struct sockaddr_in); -#ifdef AF_INET6 - if (conn->rtp_client_control_socket.SAFAMILY == AF_INET6) { - msgsize = sizeof(struct sockaddr_in6); - } -#endif -#endif - uint64_t time_of_sending_ns = get_absolute_time_in_ns(); - uint64_t resend_error_backoff_time = 300000000; // 0.3 seconds - if ((conn->rtp_time_of_last_resend_request_error_ns == 0) || - ((time_of_sending_ns - conn->rtp_time_of_last_resend_request_error_ns) > - resend_error_backoff_time)) { - if ((config.diagnostic_drop_packet_fraction == 0.0) || - (drand48() > config.diagnostic_drop_packet_fraction)) { - // put a time limit on the sendto - - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; -#ifdef CONFIG_AIRPLAY_2 - if (setsockopt(conn->ap2_control_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, - sizeof(timeout)) < 0) - debug(1, "Can't set timeout on resend request socket."); - if (sendto(conn->ap2_control_socket, req, sizeof(req), 0, - (struct sockaddr *)&conn->ap2_remote_control_socket_addr, - conn->ap2_remote_control_socket_addr_length) == -1) { -#else - if (setsockopt(conn->control_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, - sizeof(timeout)) < 0) - debug(1, "Can't set timeout on resend request socket."); - - if (sendto(conn->control_socket, req, sizeof(req), 0, - (struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) { -#endif - char em[1024]; - strerror_r(errno, em, sizeof(em)); - debug(2, "Error %d using sendto to request a resend: \"%s\".", errno, em); - conn->rtp_time_of_last_resend_request_error_ns = time_of_sending_ns; - } else { - conn->rtp_time_of_last_resend_request_error_ns = 0; - } - - } else { - debug(3, "Dropping resend request packet to simulate a bad network. Backing off for 0.3 " - "second."); - conn->rtp_time_of_last_resend_request_error_ns = time_of_sending_ns; - } - } else { - debug(1, - "Suppressing a resend request due to a resend sendto error in the last 0.3 seconds."); - } - } else { - // if (!request_sent) { - debug(2, "rtp_request_resend called without active stream!"); - // request_sent = 1; - //} - } -} - -#if 0 -#ifdef CONFIG_AIRPLAY_2 - void rtp_event_receiver_cleanup_handler(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; debug(2, "Connection %d: Event Receiver Cleanup.", conn->connection_number); @@ -1454,7 +1445,7 @@ int32_t decipher_player_put_packet(uint8_t *ciphered_audio_alt, ssize_t nread, if (new_payload_length > max_int) debug(1, "Madly long payload length!"); int plen = new_payload_length; // - player_put_packet(sequence_number, timestamp, m, plen, + player_put_packet(1, sequence_number, timestamp, m, plen, conn); // the '1' means is original format return sequence_number; } else { @@ -2094,8 +2085,7 @@ void *rtp_buffered_audio_processor(void *arg) { if (streaming_has_started == 0) debug(1, "rtp lead time is %f ms.", 0.000001 * lead_time); streaming_has_started = 1; -// player_put_packet(0, 0, pcm_buffer_read_point_rtptime, - player_put_packet(0, pcm_buffer_read_point_rtptime, + player_put_packet(0, 0, pcm_buffer_read_point_rtptime, pcm_buffer + pcm_buffer_read_point, 352, conn); } @@ -2373,5 +2363,3 @@ void *rtp_buffered_audio_processor(void *arg) { } #endif -#endif -