clean up flush detection code
This commit is contained in:
@@ -460,14 +460,6 @@ 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) {
|
||||
|
||||
// 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();
|
||||
conn->packet_count++;
|
||||
@@ -477,7 +469,7 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in
|
||||
if ((conn->flush_rtp_timestamp != 0) && (actual_timestamp != conn->flush_rtp_timestamp) &&
|
||||
(modulo_32_offset(actual_timestamp, conn->flush_rtp_timestamp) <
|
||||
conn->input_rate * 10)) { // if it's less than 10 seconds
|
||||
debug(3,
|
||||
debug(1,
|
||||
"Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRIu32
|
||||
", flushing to "
|
||||
"timestamp: %" PRIu32 ".",
|
||||
@@ -945,34 +937,97 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
conn->connection_state_to_output = rco;
|
||||
// change happening
|
||||
if (conn->connection_state_to_output == 0) { // going off
|
||||
debug(1, "request flush because connection_state_to_output is off");
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
conn->flush_requested = 1;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.output->is_running)
|
||||
if (config.output->is_running() != 0) { // if the back end isn't running for any reason
|
||||
debug(3, "not running");
|
||||
debug(1, "request flush because back end is not running");
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 0);
|
||||
conn->flush_requested = 1;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
debug_mutex_unlock(&conn->flush_mutex, 0);
|
||||
}
|
||||
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 0);
|
||||
if (conn->flush_requested == 1) {
|
||||
if (config.output->flush)
|
||||
config.output->flush(); // no cancellation points
|
||||
ab_resync(conn); // no cancellation points
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
conn->time_since_play_started = 0;
|
||||
conn->flush_requested = 0;
|
||||
have_sent_prefiller_silence = 0;
|
||||
dac_delay = 0;
|
||||
if (conn->flush_output_flushed == 0)
|
||||
if (config.output->flush) {
|
||||
config.output->flush(); // no cancellation points
|
||||
debug(1, "flush request: flush output device.");
|
||||
}
|
||||
conn->flush_output_flushed = 1;
|
||||
// now check to see it the flush request is for frames in the buffer or not
|
||||
// if the first_packet_timestamp is zero, don't check
|
||||
int flush_needed = 0;
|
||||
int drop_request = 0;
|
||||
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(1,"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, first_frame_in_buffer, last_frame_in_buffer);
|
||||
drop_request = 1;
|
||||
flush_needed = 1;
|
||||
} else {
|
||||
debug(1,"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, first_frame_in_buffer, last_frame_in_buffer);
|
||||
flush_needed = 1;
|
||||
}
|
||||
} else {
|
||||
debug(1,"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, first_frame_in_buffer, last_frame_in_buffer);
|
||||
drop_request = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug(2, "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);
|
||||
// leave flush request pending and don't do a buffer flush
|
||||
}
|
||||
}
|
||||
if (flush_needed) {
|
||||
debug(1, "flush request: flush done.");
|
||||
ab_resync(conn); // no cancellation points
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
conn->time_since_play_started = 0;
|
||||
have_sent_prefiller_silence = 0;
|
||||
dac_delay = 0;
|
||||
}
|
||||
if (drop_request) {
|
||||
debug(1, "flush request: request dropped.");
|
||||
conn->flush_requested = 0;
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
conn->flush_output_flushed = 0;
|
||||
}
|
||||
}
|
||||
debug_mutex_unlock(&conn->flush_mutex, 0);
|
||||
|
||||
if (conn->ab_synced) {
|
||||
curframe = conn->audio_buffer + BUFIDX(conn->ab_read);
|
||||
|
||||
@@ -992,35 +1047,9 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
debug(1, "Inconsistent sequence numbers detected");
|
||||
}
|
||||
}
|
||||
|
||||
// if (conn->flush_rtp_timestamp != 0)
|
||||
// debug(2,"flush_rtp_timestamp is %" PRIx32 " and curframe->given_timestamp is %" PRIx32
|
||||
// ".", conn->flush_rtp_timestamp , curframe->given_timestamp);
|
||||
|
||||
if ((conn->flush_rtp_timestamp != 0) &&
|
||||
(curframe->given_timestamp != conn->flush_rtp_timestamp) &&
|
||||
(modulo_32_offset(curframe->given_timestamp, conn->flush_rtp_timestamp) <
|
||||
conn->input_rate * 10)) { // if it's less than ten seconds
|
||||
debug(3,
|
||||
"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_request_number = 0;
|
||||
curframe = NULL; // this will be returned and will cause the loop to go around again
|
||||
conn->initial_reference_time = 0;
|
||||
conn->initial_reference_timestamp = 0;
|
||||
} else if ((conn->flush_rtp_timestamp != 0) &&
|
||||
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) >
|
||||
conn->input_rate / 5) &&
|
||||
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) <
|
||||
conn->input_rate * 10)) {
|
||||
debug(3, "Dropping flush request in buffer_get_frame");
|
||||
conn->flush_rtp_timestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((curframe) && (curframe->ready)) {
|
||||
notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
|
||||
if (conn->ab_buffering) { // if we are getting packets but not yet forwarding them to the
|
||||
@@ -1076,6 +1105,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
&should_be_time, conn);
|
||||
|
||||
conn->first_packet_time_to_play = should_be_time;
|
||||
debug(1,"first_packet_time set for frame %u.", conn->first_packet_timestamp);
|
||||
|
||||
|
||||
if (local_time_now > conn->first_packet_time_to_play) {
|
||||
uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
|
||||
@@ -1133,6 +1164,11 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
effective_latency, // this will go modulo 2^32
|
||||
&should_be_time, conn);
|
||||
|
||||
int64_t change_in_should_be_time = (int64_t)(should_be_time - conn->first_packet_time_to_play);
|
||||
|
||||
if (fabs(0.000001*change_in_should_be_time) > 0.001) // the clock drift estimation might be nudging the estimate, and we can ignore this unless if's more than a microsecond
|
||||
debug(1,"Change in estimated first_packet_time: %8.4f milliseconds.", 0.000001*change_in_should_be_time);
|
||||
|
||||
conn->first_packet_time_to_play = should_be_time;
|
||||
|
||||
if (local_time_now > conn->first_packet_time_to_play) {
|
||||
@@ -1665,6 +1701,9 @@ void *player_thread_func(void *arg) {
|
||||
conn->ab_synced = 0;
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->flush_requested = 0;
|
||||
conn->flush_output_flushed = 0; // only send a flush command to the output device once
|
||||
conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to
|
||||
// be used as a null operand, so we'll use it like that too
|
||||
conn->fix_volume = 0x10000;
|
||||
|
||||
if (conn->latency == 0) {
|
||||
@@ -1872,8 +1911,6 @@ void *player_thread_func(void *arg) {
|
||||
die("Failed to allocate memory for an output buffer.");
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0;
|
||||
conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to
|
||||
// be used as a null operand, so we'll use it like that too
|
||||
int sync_error_out_of_bounds =
|
||||
0; // number of times in a row that there's been a serious sync error
|
||||
|
||||
@@ -3020,15 +3057,12 @@ void player_volume(double airplay_volume, 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(1, "do_flush: flush to %u.", timestamp);
|
||||
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
|
||||
conn->flush_requested = 1;
|
||||
// if (timestamp!=0)
|
||||
conn->flush_rtp_timestamp = timestamp; // flush all packets up to (and including?) this
|
||||
// conn->play_segment_reference_frame = 0;
|
||||
reset_input_flow_metrics(conn);
|
||||
debug_mutex_unlock(&conn->flush_mutex, 3);
|
||||
debug(3, "Flush request made.");
|
||||
}
|
||||
|
||||
void player_flush(uint32_t timestamp, rtsp_conn_info *conn) {
|
||||
|
||||
@@ -161,6 +161,7 @@ typedef struct {
|
||||
int ab_buffering, ab_synced;
|
||||
int64_t first_packet_timestamp;
|
||||
int flush_requested;
|
||||
int flush_output_flushed; // true if the output device has been flushed.
|
||||
uint32_t flush_rtp_timestamp;
|
||||
uint64_t time_of_last_audio_packet;
|
||||
seq_t ab_read, ab_write;
|
||||
|
||||
Reference in New Issue
Block a user