Begin to use a unified and more accurate scheme for translating between local time and rtp timestamp, taking clock drift and actualt source rate into account if available. Not dealing with highes output rates yet.
This commit is contained in:
@@ -45,8 +45,8 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint64_t local_to_remote_time_jitters;
|
||||
uint64_t local_to_remote_time_jitters_count;
|
||||
uint64_t local_to_remote_time_jitter;
|
||||
uint64_t local_to_remote_time_jitter_count;
|
||||
|
||||
void rtp_initialise(rtsp_conn_info *conn) {
|
||||
conn->rtp_time_of_last_resend_request_error_fp = 0;
|
||||
@@ -65,6 +65,27 @@ void rtp_terminate(rtsp_conn_info *conn) {
|
||||
debug(1, "Error destroying reference_time_mutex variable.");
|
||||
}
|
||||
|
||||
uint64_t local_to_remote_time_difference_now(rtsp_conn_info *conn) {
|
||||
// this is an attempt to compensate for clock drift since the last time ping that was used
|
||||
// so, if we have a non-zero clock drift, we will calculate the drift there would
|
||||
// be from the time of the last time ping
|
||||
uint64_t local_time_now_fp = get_absolute_time_in_fp();
|
||||
uint64_t time_since_last_local_to_remote_time_difference_measurement = local_time_now_fp - conn->local_to_remote_time_difference_measurement_time;
|
||||
|
||||
uint64_t remote_time_since_last_local_to_remote_time_difference_measurement = (uint64_t)(conn->local_to_remote_time_gradient*time_since_last_local_to_remote_time_difference_measurement);
|
||||
|
||||
double drift;
|
||||
if (remote_time_since_last_local_to_remote_time_difference_measurement >= time_since_last_local_to_remote_time_difference_measurement)
|
||||
drift = (1.0*(remote_time_since_last_local_to_remote_time_difference_measurement - time_since_last_local_to_remote_time_difference_measurement))/(uint64_t)0x100000000;
|
||||
else
|
||||
drift = -((1.0*(time_since_last_local_to_remote_time_difference_measurement - remote_time_since_last_local_to_remote_time_difference_measurement))/(uint64_t)0x100000000);
|
||||
|
||||
double interval_ms = 1.0*(((time_since_last_local_to_remote_time_difference_measurement)*1000)>>32);
|
||||
// debug(1,"Measurement drift is %.2f microseconds (0x%" PRIx64 " in 64-bit fp) over %.2f milliseconds with drift of %.2f ppm.",drift*1000000,(uint64_t)(drift*(uint64_t)0x100000000),interval_ms,(1.0-conn->local_to_remote_time_gradient)*1000000);
|
||||
// return conn->local_to_remote_time_difference + (uint64_t)(drift*(uint64_t 0x100000000));
|
||||
return conn->local_to_remote_time_difference + (uint64_t)(drift*(uint64_t)0x100000000);
|
||||
}
|
||||
|
||||
void rtp_audio_receiver_cleanup_handler(void *arg) {
|
||||
debug(3, "Audio Receiver Cleanup.");
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
|
||||
@@ -246,7 +267,7 @@ void *rtp_control_receiver(void *arg) {
|
||||
// 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 packe is 7
|
||||
// pair of bytes in the packet is 7
|
||||
// then an extra time lag is expected to be added, presumably by
|
||||
// the AirPort Express.
|
||||
|
||||
@@ -337,28 +358,30 @@ void *rtp_control_receiver(void *arg) {
|
||||
debug_mutex_lock(&conn->reference_time_mutex, 1000, 1);
|
||||
|
||||
// this is for debugging
|
||||
// uint64_t old_remote_reference_time = conn->remote_reference_timestamp_time;
|
||||
// int64_t old_reference_timestamp = conn->reference_timestamp;
|
||||
// int64_t old_latency_delayed_timestamp = conn->latency_delayed_timestamp;
|
||||
uint64_t old_remote_reference_time = conn->remote_reference_timestamp_time;
|
||||
int64_t old_reference_timestamp = conn->reference_timestamp;
|
||||
int64_t old_latency_delayed_timestamp = conn->latency_delayed_timestamp;
|
||||
|
||||
conn->remote_reference_timestamp_time = remote_time_of_sync;
|
||||
conn->reference_timestamp_time =
|
||||
remote_time_of_sync - conn->local_to_remote_time_difference;
|
||||
//conn->reference_timestamp_time =
|
||||
// remote_time_of_sync - local_to_remote_time_difference_now(conn);
|
||||
conn->reference_timestamp = sync_rtp_timestamp;
|
||||
conn->latency_delayed_timestamp = rtp_timestamp_less_latency;
|
||||
debug_mutex_unlock(&conn->reference_time_mutex, 3);
|
||||
|
||||
conn->reference_to_previous_time_difference = remote_time_of_sync - old_remote_reference_time;
|
||||
if (old_reference_timestamp==0)
|
||||
conn->reference_to_previous_frame_difference = 0;
|
||||
else
|
||||
conn->reference_to_previous_frame_difference = sync_rtp_timestamp - old_reference_timestamp;
|
||||
|
||||
// this is for debugging
|
||||
int64_t delayed_frame_difference = rtp_timestamp_less_latency - old_latency_delayed_timestamp;
|
||||
|
||||
/*
|
||||
uint64_t time_difference = remote_time_of_sync - old_remote_reference_time;
|
||||
int64_t reference_frame_difference = sync_rtp_timestamp - old_reference_timestamp;
|
||||
int64_t delayed_frame_difference = rtp_timestamp_less_latency -
|
||||
old_latency_delayed_timestamp;
|
||||
|
||||
if (old_remote_reference_time)
|
||||
debug(1,"Time difference: %" PRIu64 " reference and delayed frame differences: %"
|
||||
PRId64 "
|
||||
and %" PRId64 ", giving rates of %f and %f respectively.",
|
||||
(time_difference*1000000)>>32,reference_frame_difference,delayed_frame_difference,(1.0*(reference_frame_difference*10000000))/((time_difference*10000000)>>32),(1.0*(delayed_frame_difference*10000000))/((time_difference*10000000)>>32));
|
||||
debug(1,"Time difference: %" PRIu64 " reference and delayed frame differences: %" PRId64 " and %" PRId64 ", giving rates _at source!!_ of %f and %f respectively.",
|
||||
(conn->reference_to_previous_time_difference*1000000)>>32,conn->reference_to_previous_frame_difference,delayed_frame_difference,
|
||||
(1.0*(conn->reference_to_previous_frame_difference*10000000))/((conn->reference_to_previous_time_difference*10000000)>>32),(1.0*(delayed_frame_difference*10000000))/((conn->reference_to_previous_time_difference*10000000)>>32));
|
||||
else
|
||||
debug(1,"First sync received");
|
||||
*/
|
||||
@@ -493,14 +516,21 @@ void *rtp_timing_receiver(void *arg) {
|
||||
pthread_create(&conn->timer_requester, NULL, &rtp_timing_sender, arg);
|
||||
// struct timespec att;
|
||||
uint64_t distant_receive_time, distant_transmit_time, arrival_time, return_time;
|
||||
local_to_remote_time_jitters = 0;
|
||||
local_to_remote_time_jitters_count = 0;
|
||||
local_to_remote_time_jitter = 0;
|
||||
local_to_remote_time_jitter_count = 0;
|
||||
// uint64_t first_remote_time = 0;
|
||||
uint64_t first_local_time = 0;
|
||||
// uint64_t first_local_time = 0;
|
||||
|
||||
uint64_t first_local_to_remote_time_difference = 0;
|
||||
// uint64_t first_local_to_remote_time_difference_time;
|
||||
// uint64_t l2rtd = 0;
|
||||
int sequence_number = 0;
|
||||
|
||||
// for getting mean and sd of return times
|
||||
int32_t stat_n = 0;
|
||||
double stat_mean = 0.0;
|
||||
double stat_M2 = 0.0;
|
||||
|
||||
while (1) {
|
||||
nread = recv(conn->timing_socket, packet, sizeof(packet), 0);
|
||||
|
||||
@@ -548,151 +578,175 @@ void *rtp_timing_receiver(void *arg) {
|
||||
distant_transmit_time = (uint64_t)nctohl(&packet[24]) << 32;
|
||||
distant_transmit_time += nctohl(&packet[28]);
|
||||
|
||||
// processing_time = distant_transmit_time - distant_receive_time;
|
||||
|
||||
// debug(1,"Return trip time: %lluuS, remote processing time:
|
||||
// %lluuS.",(return_time*1000000)>>32,(processing_time*1000000)>>32);
|
||||
|
||||
uint64_t remote_processing_time = distant_transmit_time - distant_receive_time;
|
||||
|
||||
//debug(1,"Return trip time: %" PRIu64 " uS, remote processing time: %" PRIu64 " uS.",(return_time*1000000)>>32,(remote_processing_time*1000000)>>32);
|
||||
|
||||
uint64_t local_time_by_remote_clock = distant_transmit_time + return_time / 2;
|
||||
|
||||
// remove the remote processing time from the record of the return time, as long at the processing time looks sensible.
|
||||
|
||||
if ((remote_processing_time > 0) && (remote_processing_time < return_time))
|
||||
return_time -= remote_processing_time;
|
||||
else
|
||||
debug(1,"Non-sensical remote processing time -- ignored.");
|
||||
|
||||
unsigned int cc;
|
||||
int cc;
|
||||
for (cc = time_ping_history - 1; cc > 0; cc--) {
|
||||
conn->time_pings[cc] = conn->time_pings[cc - 1];
|
||||
//if ((conn->time_ping_count) && (conn->time_ping_count < 10))
|
||||
// conn->time_pings[cc].dispersion =
|
||||
// conn->time_pings[cc].dispersion * pow(2.14, 1.0/conn->time_ping_count);
|
||||
conn->time_pings[cc].dispersion =
|
||||
(conn->time_pings[cc].dispersion * 110) /
|
||||
100; // make the dispersions 'age' by this rational factor
|
||||
(conn->time_pings[cc].dispersion * 110) / 100; // make the dispersions 'age' by this rational factor
|
||||
}
|
||||
// these are for diagnostics only -- not used
|
||||
// these are used for doing a least squares calculation to get the drift
|
||||
conn->time_pings[0].local_time = arrival_time;
|
||||
conn->time_pings[0].remote_time = distant_transmit_time;
|
||||
conn->time_pings[0].remote_time = distant_transmit_time;
|
||||
conn->time_pings[0].sequence_number = sequence_number++;
|
||||
conn->time_pings[0].chosen = 0;
|
||||
|
||||
|
||||
|
||||
conn->time_pings[0].local_to_remote_difference =
|
||||
local_time_by_remote_clock - arrival_time;
|
||||
conn->time_pings[0].dispersion = return_time;
|
||||
if (conn->time_ping_count < time_ping_history)
|
||||
conn->time_ping_count++;
|
||||
|
||||
uint64_t local_time_chosen = arrival_time;
|
||||
|
||||
|
||||
// here, calculate the mean and standard deviation of the return times
|
||||
|
||||
// mean and variance calculations from "online_variance" algorithm at
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
|
||||
|
||||
double rtfus = 1.0*((return_time * 1000000) >> 32);
|
||||
stat_n += 1;
|
||||
double stat_delta = rtfus - stat_mean;
|
||||
stat_mean += stat_delta / stat_n;
|
||||
stat_M2 += stat_delta * (rtfus - stat_mean);
|
||||
//debug(1, "Timing packet return time stats: current, mean and standard deviation over %d packets: %.1f, %.1f, %.1f (microseconds).",
|
||||
// stat_n,rtfus,stat_mean, sqrtf(stat_M2 / (stat_n - 1)));
|
||||
|
||||
// here, pick the record with the least dispersion, and record that it's been chosen
|
||||
|
||||
// uint64_t local_time_chosen = arrival_time;
|
||||
// uint64_t remote_time_chosen = distant_transmit_time;
|
||||
// now pick the timestamp with the lowest dispersion
|
||||
uint64_t l2rtd = conn->time_pings[0].local_to_remote_difference;
|
||||
uint64_t lt = conn->time_pings[0].local_time;
|
||||
uint64_t tld = conn->time_pings[0].dispersion;
|
||||
// chosen = 0;
|
||||
int chosen = 0;
|
||||
for (cc = 1; cc < conn->time_ping_count; cc++)
|
||||
if (conn->time_pings[cc].dispersion < tld) {
|
||||
chosen = cc;
|
||||
l2rtd = conn->time_pings[cc].local_to_remote_difference;
|
||||
// chosen = cc;
|
||||
lt = conn->time_pings[cc].local_time;
|
||||
tld = conn->time_pings[cc].dispersion;
|
||||
local_time_chosen = conn->time_pings[cc].local_time;
|
||||
// local_time_chosen = conn->time_pings[cc].local_time;
|
||||
// remote_time_chosen = conn->time_pings[cc].remote_time;
|
||||
}
|
||||
// int64_t ji;
|
||||
// debug(1,"Record %d has the lowest dispersion with %0.2f us dispersion.",chosen,1.0*((tld * 1000000) >> 32));
|
||||
conn->time_pings[chosen].chosen = 1; // record the fact that it has been used for timing
|
||||
|
||||
// calculate the jitter -- the absolute time between the current local_to_remote_time_difference and the new one and add it to the total jitter count
|
||||
int64_t ji;
|
||||
int64_t ltd =0; // local time difference for the jitter
|
||||
|
||||
if (conn->time_ping_count > 1) {
|
||||
if (l2rtd > conn->local_to_remote_time_difference) {
|
||||
local_to_remote_time_jitters =
|
||||
local_to_remote_time_jitters + l2rtd - conn->local_to_remote_time_difference;
|
||||
// ji = l2rtd - conn->local_to_remote_time_difference;
|
||||
local_to_remote_time_jitter =
|
||||
local_to_remote_time_jitter + l2rtd - conn->local_to_remote_time_difference;
|
||||
ji = l2rtd - conn->local_to_remote_time_difference; // this is the difference between the present local-to-remote-time-difference and the new one, i.e. the jitter step
|
||||
} else {
|
||||
local_to_remote_time_jitters =
|
||||
local_to_remote_time_jitters + conn->local_to_remote_time_difference - l2rtd;
|
||||
// ji = -(conn->local_to_remote_time_difference - l2rtd);
|
||||
local_to_remote_time_jitter =
|
||||
local_to_remote_time_jitter + conn->local_to_remote_time_difference - l2rtd;
|
||||
ji = -(conn->local_to_remote_time_difference - l2rtd);
|
||||
}
|
||||
local_to_remote_time_jitters_count += 1;
|
||||
local_to_remote_time_jitter_count += 1;
|
||||
}
|
||||
// uncomment below to print jitter between client's clock and oour clock
|
||||
// int64_t rtus = (tld*1000000)>>32; ji = (ji*1000000)>>32; debug(1,"Choosing time
|
||||
// difference
|
||||
// with dispersion of %lld us with delta of %lld us",rtus,ji);
|
||||
|
||||
conn->local_to_remote_time_difference = l2rtd;
|
||||
if (conn->local_to_remote_time_difference_measurement_time < lt)
|
||||
ltd = lt-conn->local_to_remote_time_difference_measurement_time;
|
||||
else
|
||||
ltd = -(conn->local_to_remote_time_difference_measurement_time-lt);
|
||||
|
||||
/*
|
||||
if (ltd) {
|
||||
debug(1,"Jitter: %" PRId64 " microseconds in %" PRId64 " microseconds.", (ji * (int64_t)1000000)>>32, (ltd * (int64_t)1000000)>>32);
|
||||
debug(1,"Source clock to local clock drift: %.2f ppm.",((1.0*ji)/ltd)*1000000.0);
|
||||
}
|
||||
// uncomment below to print jitter between client's clock and our clock
|
||||
*/
|
||||
|
||||
/*
|
||||
if (ji) {
|
||||
int64_t rtus = (tld*1000000)>>32;
|
||||
debug(1,"Choosing time difference[%d] with dispersion of %" PRId64 " us with an adjustment of %" PRId64 " us",chosen, rtus, (ji*1000000)>>32);
|
||||
}
|
||||
*/
|
||||
conn->local_to_remote_time_difference = l2rtd; // make this the new local-to-remote-time-difference
|
||||
conn->local_to_remote_time_difference_measurement_time = lt; // done at this time.
|
||||
|
||||
if (first_local_to_remote_time_difference == 0) {
|
||||
first_local_to_remote_time_difference = conn->local_to_remote_time_difference;
|
||||
// first_local_to_remote_time_difference_time = get_absolute_time_in_fp();
|
||||
}
|
||||
|
||||
// int64_t clock_drift;
|
||||
// int64_t clock_drift_in_usec;
|
||||
// double clock_drift_ppm = 0.0;
|
||||
if (first_local_time == 0) {
|
||||
first_local_time = local_time_chosen;
|
||||
// first_remote_time = remote_time_chosen;
|
||||
// clock_drift = 0;
|
||||
// here, let's try to use the timing pings that were selected because of their short return times to
|
||||
// estimate a figure for drift between the local clock (x) and the remote clock (y)
|
||||
|
||||
// if we plug in a local interval, we will get back what that is in remote time
|
||||
|
||||
// calculate the line of best fit for relating the local time and the remote time
|
||||
// we will calculate the slope, which is the drift
|
||||
// see https://www.varsitytutors.com/hotmath/hotmath_help/topics/line-of-best-fit
|
||||
|
||||
double m,drift;
|
||||
|
||||
drift = 0.0;
|
||||
|
||||
uint64_t y_bar = 0; // remote timestamp average
|
||||
uint64_t x_bar = 0; // local timestamp average
|
||||
int sample_count = 0;
|
||||
|
||||
|
||||
for (cc = 0; cc < conn->time_ping_count; cc++)
|
||||
if ((conn->time_pings[cc].chosen) && (conn->time_pings[cc].sequence_number>9)) { // wait for a minute or so....
|
||||
y_bar += (conn->time_pings[cc].remote_time>>12); //precision is down to 1/4th of a microsecond
|
||||
x_bar += (conn->time_pings[cc].local_time>>12);
|
||||
sample_count++;
|
||||
}
|
||||
|
||||
y_bar = y_bar/sample_count;
|
||||
x_bar = x_bar/sample_count;
|
||||
|
||||
int64_t xid, yid;
|
||||
int64_t mtl, mbl;
|
||||
mtl=0;mbl=0;
|
||||
for (cc = 0; cc < conn->time_ping_count; cc++)
|
||||
if ((conn->time_pings[cc].chosen) && (conn->time_pings[cc].sequence_number>9)) {
|
||||
|
||||
uint64_t slt = conn->time_pings[cc].local_time>>12;
|
||||
if (slt > x_bar)
|
||||
xid = slt - x_bar;
|
||||
else
|
||||
xid = -(x_bar - slt);
|
||||
|
||||
uint64_t srt = conn->time_pings[cc].remote_time>>12;
|
||||
if (srt > y_bar)
|
||||
yid = srt - y_bar;
|
||||
else
|
||||
yid = -(y_bar - srt);
|
||||
|
||||
mtl = mtl + xid*yid;
|
||||
mbl = mbl + xid*xid;
|
||||
}
|
||||
if (sample_count > 2) {
|
||||
conn->local_to_remote_time_gradient = (1.0*mtl)/mbl;
|
||||
// debug(1,"Drift is %12.2f ppm, based on %d samples.",(1.0-conn->local_to_remote_time_gradient)*1000000,sample_count);
|
||||
} else {
|
||||
// uint64_t local_time_change = local_time_chosen - first_local_time;
|
||||
// uint64_t remote_time_change = remote_time_chosen - first_remote_time;
|
||||
|
||||
/*
|
||||
if (remote_time_change >= local_time_change)
|
||||
clock_drift = remote_time_change - local_time_change;
|
||||
else
|
||||
clock_drift = -(local_time_change - remote_time_change);
|
||||
*/
|
||||
/*
|
||||
if (clock_drift >= 0)
|
||||
clock_drift_in_usec = (clock_drift * 1000000) >> 32;
|
||||
else
|
||||
clock_drift_in_usec = -(((-clock_drift) * 1000000) >> 32);
|
||||
*/
|
||||
|
||||
// clock_drift_ppm = (1.0 * clock_drift_in_usec) / (local_time_change >> 32);
|
||||
conn->local_to_remote_time_gradient = 1.0;
|
||||
}
|
||||
|
||||
int64_t source_drift_usec;
|
||||
if (conn->play_segment_reference_frame != 0) {
|
||||
int64_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);
|
||||
uint64_t frame_difference = 0;
|
||||
if (reference_timestamp >= conn->play_segment_reference_frame)
|
||||
frame_difference =
|
||||
(uint64_t)reference_timestamp - (uint64_t)conn->play_segment_reference_frame;
|
||||
else // rollover
|
||||
frame_difference = (uint64_t)reference_timestamp + 0x100000000 -
|
||||
(uint64_t)conn->play_segment_reference_frame;
|
||||
uint64_t frame_time_difference_calculated =
|
||||
(((uint64_t)frame_difference << 32) / 44100);
|
||||
uint64_t frame_time_difference_actual =
|
||||
remote_reference_timestamp_time -
|
||||
conn->play_segment_reference_frame_remote_time; // this is all done by reference
|
||||
// to
|
||||
// the
|
||||
// sources' system clock
|
||||
// debug(1,"%llu frames since play started, %llu usec calculated, %llu usec
|
||||
// actual",frame_difference, (frame_time_difference_calculated*1000000)>>32,
|
||||
// (frame_time_difference_actual*1000000)>>32);
|
||||
if (frame_time_difference_calculated >=
|
||||
frame_time_difference_actual) // i.e. if the time it should have taken to send the
|
||||
// packets is greater than the actual time difference
|
||||
// measured on the source clock
|
||||
// then the source DAC's clock is running fast relative to the source system clock
|
||||
source_drift_usec = frame_time_difference_calculated - frame_time_difference_actual;
|
||||
else
|
||||
// otherwise the source DAC's clock is running slow relative to the source system
|
||||
// clock
|
||||
source_drift_usec =
|
||||
-(frame_time_difference_actual - frame_time_difference_calculated);
|
||||
} else
|
||||
source_drift_usec = 0;
|
||||
source_drift_usec = (source_drift_usec * 1000000) >> 32; // turn it to microseconds
|
||||
|
||||
// long current_delay = 0;
|
||||
// if (config.output->delay) {
|
||||
// config.output->delay(¤t_delay);
|
||||
//}
|
||||
// Useful for troubleshooting:
|
||||
// debug(1, "clock_drift_ppm %f\tchosen %5d\tsource_drift_usec
|
||||
// %10.1lld\treturn_time_in_usec
|
||||
// %10.1llu",
|
||||
// clock_drift_ppm,
|
||||
// chosen,
|
||||
//(session_corrections*1000000)/44100,
|
||||
// current_delay,
|
||||
// source_drift_usec,
|
||||
// buffer_occupancy,
|
||||
//(return_time*1000000)>>32);
|
||||
} else {
|
||||
debug(2, "Time ping turnaround time: %lld us -- it looks like a timing ping was lost.",
|
||||
(return_time * 1000000) >> 32);
|
||||
@@ -902,21 +956,103 @@ void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time,
|
||||
// types okay
|
||||
debug_mutex_lock(&conn->reference_time_mutex, 1000, 1);
|
||||
*timestamp = conn->reference_timestamp;
|
||||
*timestamp_time = conn->reference_timestamp_time;
|
||||
*remote_timestamp_time = conn->remote_reference_timestamp_time;
|
||||
*timestamp_time = conn->remote_reference_timestamp_time - local_to_remote_time_difference_now(conn);
|
||||
// if ((*timestamp == 0) && (*timestamp_time == 0)) {
|
||||
// debug(1,"Reference timestamp is invalid.");
|
||||
//}
|
||||
*remote_timestamp_time = conn->remote_reference_timestamp_time;
|
||||
debug_mutex_unlock(&conn->reference_time_mutex, 3);
|
||||
}
|
||||
|
||||
void clear_reference_timestamp(rtsp_conn_info *conn) {
|
||||
debug_mutex_lock(&conn->reference_time_mutex, 1000, 1);
|
||||
conn->reference_timestamp = 0;
|
||||
conn->reference_timestamp_time = 0;
|
||||
conn->remote_reference_timestamp_time = 0;
|
||||
debug_mutex_unlock(&conn->reference_time_mutex, 3);
|
||||
}
|
||||
|
||||
int have_timestamp_timing_information(rtsp_conn_info *conn) {
|
||||
if (conn->reference_timestamp==0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sanitised_source_rate_information(int64_t *frames, uint64_t *time, rtsp_conn_info *conn) {
|
||||
int result = 0;
|
||||
*frames = conn->input_rate;
|
||||
*time = (uint64_t)(0x100000000); // one second in fp form
|
||||
int64_t local_frames = conn->reference_to_previous_frame_difference;
|
||||
uint64_t local_time = conn->reference_to_previous_time_difference;
|
||||
if ((local_frames == 0) || (local_time == 0)) {
|
||||
result = 1;
|
||||
} else {
|
||||
double calculated_frame_rate = ((1.0*local_frames)/local_time)*(uint64_t)0x100000000;
|
||||
if (((calculated_frame_rate/conn->input_rate) > 1.001) || ((calculated_frame_rate/conn->input_rate) < 0.999)) {
|
||||
result = 1;
|
||||
} else {
|
||||
*frames = local_frames;
|
||||
*time = local_time;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int frame_to_local_time(int64_t timestamp, uint64_t *time, rtsp_conn_info *conn) {
|
||||
debug_mutex_lock(&conn->reference_time_mutex, 1000, 1);
|
||||
int result = 0;
|
||||
uint64_t time_difference;
|
||||
int64_t frame_difference;
|
||||
result = sanitised_source_rate_information(&frame_difference,&time_difference,conn);
|
||||
|
||||
int64_t timestamp_interval = timestamp - conn->reference_timestamp; // we could be dealing with multiples of 44100 (nominally)
|
||||
// debug(1, "Timestamp interval: %" PRId64 " frames with reference timestamp %" PRId64 ".",timestamp_interval,conn->reference_timestamp);
|
||||
uint64_t timestamp_interval_time;
|
||||
uint64_t remote_time_of_timestamp;
|
||||
if (timestamp_interval>=0) {
|
||||
timestamp_interval_time = (timestamp_interval * time_difference)/frame_difference; // this is the nominal time, based on the fps specified between current and previous sync frame.
|
||||
remote_time_of_timestamp = conn->remote_reference_timestamp_time + timestamp_interval_time; // based on the reference timestamp time plus the time interval calculated based on the specified fps.
|
||||
} else {
|
||||
timestamp_interval_time = ((-timestamp_interval) * time_difference)/frame_difference; // this is the nominal time, based on the fps specified between current and previous sync frame.
|
||||
remote_time_of_timestamp = conn->remote_reference_timestamp_time - timestamp_interval_time; // based on the reference timestamp time plus the time interval calculated based on the specified fps.
|
||||
}
|
||||
*time = remote_time_of_timestamp - local_to_remote_time_difference_now(conn);
|
||||
debug_mutex_unlock(&conn->reference_time_mutex, 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
int local_time_to_frame(uint64_t time, int64_t *frame, rtsp_conn_info *conn) {
|
||||
debug_mutex_lock(&conn->reference_time_mutex, 1000, 1);
|
||||
int result = 0;
|
||||
|
||||
uint64_t time_difference;
|
||||
int64_t frame_difference;
|
||||
result = sanitised_source_rate_information(&frame_difference,&time_difference,conn);
|
||||
|
||||
// first, get from [local] time to remote time.
|
||||
uint64_t remote_time = time + local_to_remote_time_difference_now(conn);
|
||||
// next, get the remote time interval from the remote_time to the reference time
|
||||
uint64_t time_interval;
|
||||
|
||||
if (remote_time >= conn->remote_reference_timestamp_time)
|
||||
time_interval = remote_time - conn->remote_reference_timestamp_time;
|
||||
else
|
||||
time_interval = conn->remote_reference_timestamp_time - remote_time;
|
||||
|
||||
// now, convert the remote time interval into frames
|
||||
int64_t frame_interval = (time_interval * frame_difference)/time_difference;
|
||||
if (remote_time >= conn->remote_reference_timestamp_time) {
|
||||
// debug(1,"Frame interval is %" PRId64 " frames.",frame_interval);
|
||||
*frame = conn->reference_timestamp+frame_interval;
|
||||
} else {
|
||||
// debug(1,"Frame interval is %" PRId64 " frames.",-frame_interval);
|
||||
*frame = conn->reference_timestamp-frame_interval;
|
||||
}
|
||||
debug_mutex_unlock(&conn->reference_time_mutex, 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) {
|
||||
if (conn->rtp_running) {
|
||||
// if (!request_sent) {
|
||||
|
||||
Reference in New Issue
Block a user