Try to fix modulo calculations
This commit is contained in:
@@ -99,60 +99,15 @@
|
||||
// static abuf_t audio_buffer[BUFFER_FRAMES];
|
||||
#define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES)
|
||||
|
||||
void do_flush(int64_t timestamp, rtsp_conn_info *conn);
|
||||
|
||||
// make timestamps and seqnos definitely monotonic
|
||||
|
||||
// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33
|
||||
// frames and continue up to 2^63-1 frames
|
||||
// if should never get into the negative range
|
||||
// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds or
|
||||
// over 50,000 years.
|
||||
// also, it won't reach zero until then, if ever, so we can safely say that a null monotonic
|
||||
// timestamp can mean something special
|
||||
int64_t monotonic_timestamp(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
int64_t previous_value;
|
||||
int64_t return_value;
|
||||
if (conn->timestamp_epoch == 0) {
|
||||
if (timestamp > conn->maximum_timestamp_interval)
|
||||
conn->timestamp_epoch = 1;
|
||||
else
|
||||
conn->timestamp_epoch = 2;
|
||||
previous_value = conn->timestamp_epoch;
|
||||
previous_value <<= 32;
|
||||
previous_value += timestamp;
|
||||
} else {
|
||||
previous_value = conn->timestamp_epoch;
|
||||
previous_value <<= 32;
|
||||
previous_value += conn->last_timestamp;
|
||||
if (timestamp < conn->last_timestamp) {
|
||||
// the incoming timestamp is less than the last one.
|
||||
// if the difference is more than a minute, assume it's really from the next epoch
|
||||
if ((conn->last_timestamp - timestamp) > conn->maximum_timestamp_interval)
|
||||
conn->timestamp_epoch++;
|
||||
} else {
|
||||
// the incoming timestamp is greater than the last one.
|
||||
// if the difference is more than a minute, assume it's really from the previous epoch
|
||||
if ((timestamp - conn->last_timestamp) > conn->maximum_timestamp_interval)
|
||||
conn->timestamp_epoch--;
|
||||
}
|
||||
}
|
||||
return_value = conn->timestamp_epoch;
|
||||
return_value <<= 32;
|
||||
return_value += timestamp;
|
||||
if (previous_value > return_value) {
|
||||
if ((previous_value - return_value) > conn->maximum_timestamp_interval)
|
||||
debug(2, "interval between successive rtptimes greater than allowed!");
|
||||
} else {
|
||||
if ((return_value - previous_value) > conn->maximum_timestamp_interval)
|
||||
debug(2, "interval between successive rtptimes greater than allowed!");
|
||||
}
|
||||
if (return_value < 0)
|
||||
debug(1, "monotonic rtptime is negative!");
|
||||
conn->last_timestamp = timestamp;
|
||||
return return_value;
|
||||
uint32_t rtp_frame_offset(uint32_t base, uint32_t frame_in_question) {
|
||||
if (base <= frame_in_question)
|
||||
return frame_in_question - base;
|
||||
else
|
||||
return UINT32_MAX - base + frame_in_question + 1;
|
||||
}
|
||||
|
||||
void do_flush(uint32_t timestamp, rtsp_conn_info *conn);
|
||||
|
||||
static void ab_resync(rtsp_conn_info *conn) {
|
||||
int i;
|
||||
for (i = 0; i < BUFFER_FRAMES; i++) {
|
||||
@@ -165,11 +120,36 @@ static void ab_resync(rtsp_conn_info *conn) {
|
||||
conn->ab_buffering = 1;
|
||||
}
|
||||
|
||||
// the sequence number is a 16-bit unsigned number which wraps pretty often
|
||||
// to work out if one seqno is 'after' another therefore depends whether wrap has occurred
|
||||
// this function works out the actual ordinate of the seqno, i.e. the distance up from
|
||||
// the zeroth element, at ab_read, taking due account of wrap.
|
||||
// given starting and ending points as unsigned 32-bit integers running modulo 2^32, returns the position of x in the interval in *pos
|
||||
// returns true if x is actually within the buffer
|
||||
|
||||
int position_in_modulo_uint32_t_buffer(uint32_t x, uint32_t start, uint32_t end, uint32_t *pos ) {
|
||||
int response = 0; // not in the buffer
|
||||
if (start <= end ) {
|
||||
if (x < start) {
|
||||
if (pos)
|
||||
*pos = UINT32_MAX - start + 1 + x;
|
||||
} else {
|
||||
if (pos)
|
||||
*pos = x - start;
|
||||
if (x < end)
|
||||
response = 1;
|
||||
}
|
||||
} else if ((x >= start) && (x <= UINT32_MAX)) {
|
||||
response = 1;
|
||||
if (pos)
|
||||
*pos = x - start;
|
||||
} else {
|
||||
if (pos)
|
||||
*pos = UINT32_MAX - start + 1 + x;
|
||||
if (x < end) {
|
||||
response = 1;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// this is used.
|
||||
static inline seq_t SUCCESSOR(seq_t x) {
|
||||
uint32_t p = x & 0xffff;
|
||||
p += 1;
|
||||
@@ -177,6 +157,7 @@ static inline seq_t SUCCESSOR(seq_t x) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// this is not used
|
||||
static inline seq_t PREDECESSOR(seq_t x) {
|
||||
uint32_t p = (x & 0xffff) + 0x10000;
|
||||
p -= 1;
|
||||
@@ -184,6 +165,8 @@ static inline seq_t PREDECESSOR(seq_t x) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// used in seq_diff and seq_order
|
||||
|
||||
// anything with ORDINATE in it must be proctected by the ab_mutex
|
||||
static inline int32_t ORDINATE(seq_t x, seq_t base) {
|
||||
int32_t p = x; // int32_t from seq_t, i.e. uint16_t, so okay
|
||||
@@ -458,14 +441,8 @@ static void free_audio_buffers(rtsp_conn_info *conn) {
|
||||
free(conn->audio_buffer[i].data);
|
||||
}
|
||||
|
||||
void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp, uint8_t *data,
|
||||
void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data,
|
||||
int len, rtsp_conn_info *conn) {
|
||||
// all timestamps are done at the output rate
|
||||
// the "actual_timestamp" is the one that comes in the packet, and is carried over for
|
||||
// debugging
|
||||
// and checking only.
|
||||
|
||||
int64_t ltimestamp = timestamp * conn->output_sample_ratio;
|
||||
|
||||
// ignore a request to flush that has been made before the first packet...
|
||||
if (conn->packet_count == 0) {
|
||||
@@ -483,22 +460,26 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
|
||||
// if (flush_rtp_timestamp != 0)
|
||||
// debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp);
|
||||
|
||||
if ((conn->flush_rtp_timestamp != 0) && (ltimestamp <= conn->flush_rtp_timestamp)) {
|
||||
debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRId64
|
||||
", flushing to "
|
||||
"timestamp: %" PRId64 ".",
|
||||
seqno, ltimestamp, conn->flush_rtp_timestamp);
|
||||
conn->initial_reference_time = 0;
|
||||
conn->initial_reference_timestamp = 0;
|
||||
|
||||
// now, if a flush_rtp_timestamp has been defined and the incoming timestamp is "before" it, drop it…
|
||||
|
||||
if ((conn->flush_rtp_timestamp != 0) && (rtp_frame_offset(actual_timestamp,conn->flush_rtp_timestamp) < 8820)) {// if it's less than 0.2 seconds
|
||||
debug(2, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRIu32
|
||||
", flushing to "
|
||||
"timestamp: %" PRIu32 ".",
|
||||
seqno, actual_timestamp, conn->flush_rtp_timestamp);
|
||||
conn->initial_reference_time = 0;
|
||||
conn->initial_reference_timestamp = 0;
|
||||
} else {
|
||||
if ((conn->flush_rtp_timestamp != 0x0) &&
|
||||
(ltimestamp > conn->flush_rtp_timestamp)) // if we have gone past the flush boundary time
|
||||
conn->flush_rtp_timestamp = 0x0;
|
||||
if ((conn->flush_rtp_timestamp != 0) && (rtp_frame_offset(conn->flush_rtp_timestamp,actual_timestamp) > 8820) && (rtp_frame_offset(conn->flush_rtp_timestamp,actual_timestamp) < 44100)) {
|
||||
debug(2,"Dropping flush request");
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -519,21 +500,21 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
conn->resend_interval = resend_interval;
|
||||
}
|
||||
|
||||
if (conn->ab_write == seqno) { // expected packet
|
||||
if (conn->ab_write == seqno) { // if this is the expected packet (which could be the first packet…)
|
||||
uint64_t reception_time = get_absolute_time_in_fp();
|
||||
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 = reception_time;
|
||||
conn->frames_inward_frames_received_at_measurement_start_time = timestamp;
|
||||
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 = reception_time;
|
||||
conn->frames_inward_frames_received_at_measurement_time = timestamp;
|
||||
conn->frames_inward_frames_received_at_measurement_time = actual_timestamp;
|
||||
|
||||
abuf = conn->audio_buffer + BUFIDX(seqno);
|
||||
conn->ab_write = SUCCESSOR(seqno);
|
||||
conn->ab_write = SUCCESSOR(seqno); // move the write pointer to the next free space
|
||||
} else if (seq_order(conn->ab_write, seqno, conn->ab_read)) { // newer than expected
|
||||
// if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8)
|
||||
// debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and
|
||||
@@ -547,7 +528,7 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i));
|
||||
abuf->ready = 0; // to be sure, to be sure
|
||||
abuf->resend_level = 0;
|
||||
abuf->timestamp = 0;
|
||||
// abuf->timestamp = 0;
|
||||
abuf->given_timestamp = 0;
|
||||
abuf->sequence_number = 0;
|
||||
}
|
||||
@@ -580,14 +561,14 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
if (alac_decode(abuf->data, &datalen, data, len, conn) == 0) {
|
||||
abuf->ready = 1;
|
||||
abuf->length = datalen;
|
||||
abuf->timestamp = ltimestamp;
|
||||
// abuf->timestamp = ltimestamp;
|
||||
abuf->given_timestamp = actual_timestamp;
|
||||
abuf->sequence_number = seqno;
|
||||
} else {
|
||||
debug(1, "Bad audio packet detected and discarded.");
|
||||
abuf->ready = 0;
|
||||
abuf->resend_level = 0;
|
||||
abuf->timestamp = 0;
|
||||
// abuf->timestamp = 0;
|
||||
abuf->given_timestamp = 0;
|
||||
abuf->sequence_number = 0;
|
||||
}
|
||||
@@ -621,12 +602,6 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
j)) { // prevent multiple requests from the same level of lookback
|
||||
check_buf->resend_level = j;
|
||||
if (config.disable_resend_requests == 0) {
|
||||
if (((int)(resend_interval * pow(j + 1, step_exponent)) + k) >=
|
||||
seq_diff(conn->ab_read, conn->ab_write, conn->ab_read))
|
||||
debug(3, "Last-ditch (#%d) resend request for packet %u in range %u to %u. "
|
||||
"Looking back %d packets.",
|
||||
j, next, conn->ab_read, conn->ab_write, back_step + k);
|
||||
debug_mutex_unlock(&conn->ab_mutex, 3);
|
||||
rtp_request_resend(next, 1, conn);
|
||||
conn->resend_requests++;
|
||||
debug_mutex_lock(&conn->ab_mutex, 20000, 1);
|
||||
@@ -877,20 +852,23 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
debug(1, "Inconsistent sequence numbers detected");
|
||||
}
|
||||
}
|
||||
|
||||
if ((conn->flush_rtp_timestamp != 0) &&
|
||||
(curframe->timestamp <= conn->flush_rtp_timestamp)) {
|
||||
debug(2, "Dropping flushed packet in buffer_get_frame seqno %u, timestamp %" PRId64 ".",
|
||||
curframe->sequence_number, curframe->timestamp);
|
||||
|
||||
if ((conn->flush_rtp_timestamp != 0) && (rtp_frame_offset(curframe->given_timestamp,conn->flush_rtp_timestamp) < 8820)) {// if it's less than 0.2 seconds
|
||||
debug(2, "Dropping flushed packet in buffer_get_frame, seqno %u, timestamp %" PRIu32
|
||||
", flushing to "
|
||||
"timestamp: %" PRIu32 ".",
|
||||
curframe->sequence_number, curframe->given_timestamp, conn->flush_rtp_timestamp);
|
||||
curframe->ready = 0;
|
||||
curframe->resend_level = 0;
|
||||
flush_limit++;
|
||||
flush_limit += curframe->length;
|
||||
conn->ab_read = SUCCESSOR(conn->ab_read);
|
||||
conn->initial_reference_time = 0;
|
||||
conn->initial_reference_timestamp = 0;
|
||||
}
|
||||
if (curframe->timestamp > conn->flush_rtp_timestamp)
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
if ((conn->flush_rtp_timestamp != 0) && (rtp_frame_offset(conn->flush_rtp_timestamp,curframe->given_timestamp) > 8820) && (rtp_frame_offset(conn->flush_rtp_timestamp,curframe->given_timestamp) < 44100)) {
|
||||
debug(2,"Dropping flush request");
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
}
|
||||
}
|
||||
} while ((conn->flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0));
|
||||
|
||||
@@ -921,7 +899,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
if (have_timestamp_timing_information(conn)) { // if we have a reference time
|
||||
// debug(1,"First frame seen with timestamp...");
|
||||
conn->first_packet_timestamp =
|
||||
curframe->timestamp; // we will keep buffering until we are
|
||||
curframe->given_timestamp; // we will keep buffering until we are
|
||||
// supposed to start playing this
|
||||
have_sent_prefiller_silence = 0;
|
||||
conn->packet_stream_established = 1;
|
||||
@@ -1174,7 +1152,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
// Note: the last three items are expressed in frames and must be converted to time.
|
||||
|
||||
int do_wait = 0; // don't wait unless we can really prove we must
|
||||
if ((conn->ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) {
|
||||
if ((conn->ab_synced) && (curframe) && (curframe->ready) && (curframe->given_timestamp)) {
|
||||
do_wait =
|
||||
1; // if the current frame exists and is ready, then wait unless it's time to let it go...
|
||||
|
||||
@@ -1184,7 +1162,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
|
||||
uint64_t time_to_play;
|
||||
frame_to_local_time(
|
||||
curframe->timestamp + conn->latency * conn->output_sample_ratio +
|
||||
(curframe->given_timestamp + conn->latency) * conn->output_sample_ratio +
|
||||
(int64_t)(config.audio_backend_latency_offset * config.output_rate) -
|
||||
config.audio_backend_buffer_desired_length * config.output_rate,
|
||||
&time_to_play, conn);
|
||||
@@ -1242,7 +1220,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
if (!curframe->ready) {
|
||||
// debug(1, "Supplying a silent frame for frame %u", read);
|
||||
conn->missing_packets++;
|
||||
curframe->timestamp = 0; // indicate a silent frame should be substituted
|
||||
curframe->given_timestamp = 0; // indicate a silent frame should be substituted
|
||||
}
|
||||
curframe->ready = 0;
|
||||
curframe->resend_level = 0;
|
||||
@@ -1791,7 +1769,7 @@ void *player_thread_func(void *arg) {
|
||||
// if (play_number % 100 == 0)
|
||||
// debug(3, "Play frame %d.", play_number);
|
||||
conn->play_number_after_flush++;
|
||||
if (inframe->timestamp == 0) {
|
||||
if (inframe->given_timestamp == 0) {
|
||||
debug(3, "Player has supplied a silent frame, (possibly frame %u) for play number %d.",
|
||||
SUCCESSOR(conn->last_seqno_read), play_number);
|
||||
conn->last_seqno_read = (SUCCESSOR(conn->last_seqno_read) &
|
||||
@@ -1925,14 +1903,16 @@ void *player_thread_func(void *arg) {
|
||||
// now, go back as far as the total latency less, say, 100 ms, and check the presence of
|
||||
// frames from then onwards
|
||||
|
||||
int64_t reference_timestamp;
|
||||
uint32_t reference_timestamp;
|
||||
uint64_t reference_timestamp_time, remote_reference_timestamp_time;
|
||||
get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
|
||||
&remote_reference_timestamp_time, conn); // types okay
|
||||
reference_timestamp *= conn->output_sample_ratio;
|
||||
int64_t rt, nt;
|
||||
rt = reference_timestamp; // uint32_t to int64_t
|
||||
nt = inframe->timestamp; // uint32_t to int64_t
|
||||
nt = inframe->given_timestamp; // uint32_t to int64_t
|
||||
rt *= conn->output_sample_ratio;
|
||||
nt *= conn->output_sample_ratio;
|
||||
|
||||
uint64_t local_time_now = get_absolute_time_in_fp(); // types okay
|
||||
// struct timespec tn;
|
||||
@@ -2056,7 +2036,7 @@ void *player_thread_func(void *arg) {
|
||||
if (abs_sync_error < 0)
|
||||
abs_sync_error = -abs_sync_error;
|
||||
|
||||
if ((config.no_sync == 0) && (inframe->timestamp != 0) &&
|
||||
if ((config.no_sync == 0) && (inframe->given_timestamp != 0) &&
|
||||
(config.resyncthreshold > 0.0) &&
|
||||
(abs_sync_error > config.resyncthreshold * config.output_rate)) {
|
||||
if (abs_sync_error > 3 * config.output_rate) {
|
||||
@@ -2282,7 +2262,7 @@ void *player_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
// mark the frame as finished
|
||||
inframe->timestamp = 0;
|
||||
inframe->given_timestamp = 0;
|
||||
inframe->sequence_number = 0;
|
||||
|
||||
// debug(1,"Sync error %lld frames. Amount to stuff %d." ,sync_error,amount_to_stuff);
|
||||
@@ -2726,7 +2706,7 @@ void player_volume(double airplay_volume, rtsp_conn_info *conn) {
|
||||
player_volume_without_notification(airplay_volume, conn);
|
||||
}
|
||||
|
||||
void do_flush(int64_t timestamp, rtsp_conn_info *conn) {
|
||||
void do_flush(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
|
||||
debug(3, "Flush requested up to %u. It seems as if 0 is special.", timestamp);
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
@@ -2755,7 +2735,7 @@ void do_flush(int64_t timestamp, rtsp_conn_info *conn) {
|
||||
debug(3, "Flush request made.");
|
||||
}
|
||||
|
||||
void player_flush(int64_t timestamp, rtsp_conn_info *conn) {
|
||||
void player_flush(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
debug(3, "player_flush");
|
||||
do_flush(timestamp, conn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user