mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
convert all times from micro to nano secs
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#define SECOND_IN_NSECS 1000000000UL
|
||||
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
@@ -96,23 +98,23 @@ void byteutils_put_int(unsigned char* b, int offset, uint32_t value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an ntp timestamp and returns it as micro seconds since the Unix epoch
|
||||
* Reads an ntp timestamp and returns it as nano seconds since the Unix epoch
|
||||
*/
|
||||
uint64_t byteutils_get_ntp_timestamp(unsigned char *b, int offset) {
|
||||
uint64_t seconds = ntohl(((unsigned int) byteutils_get_int(b, offset))) - SECONDS_FROM_1900_TO_1970;
|
||||
uint64_t fraction = ntohl((unsigned int) byteutils_get_int(b, offset + 4));
|
||||
return (seconds * 1000000L) + ((fraction * 1000000L) >> 32);
|
||||
return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a time given as micro seconds since the Unix time epoch as an ntp timestamp
|
||||
* Writes a time given as nano seconds since the Unix time epoch as an ntp timestamp
|
||||
* into the buffer at position offset
|
||||
*/
|
||||
void byteutils_put_ntp_timestamp(unsigned char *b, int offset, uint64_t us_since_1970) {
|
||||
uint64_t seconds = us_since_1970 / 1000000L;
|
||||
uint64_t microseconds = us_since_1970 % 1000000L;
|
||||
void byteutils_put_ntp_timestamp(unsigned char *b, int offset, uint64_t ns_since_1970) {
|
||||
uint64_t seconds = ns_since_1970 / SECOND_IN_NSECS;
|
||||
uint64_t nanoseconds = ns_since_1970 % SECOND_IN_NSECS;
|
||||
seconds += SECONDS_FROM_1900_TO_1970;
|
||||
uint64_t fraction = (microseconds << 32) / 1000000L;
|
||||
uint64_t fraction = (nanoseconds << 32) / SECOND_IN_NSECS;
|
||||
|
||||
// Write in big endian!
|
||||
byteutils_put_int(b, offset, htonl(seconds));
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "byteutils.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SECOND_IN_NSECS 1000000000UL
|
||||
#define RAOP_NTP_DATA_COUNT 8
|
||||
#define RAOP_NTP_PHI_PPM 15ull // PPM
|
||||
#define RAOP_NTP_R_RHO ((1ull << 32) / 1000u) // packet precision
|
||||
@@ -284,7 +285,8 @@ raop_ntp_thread(void *arg)
|
||||
byteutils_put_ntp_timestamp(request, 24, send_time);
|
||||
int send_len = sendto(raop_ntp->tsock, (char *)request, sizeof(request), 0,
|
||||
(struct sockaddr *) &raop_ntp->remote_saddr, raop_ntp->remote_saddr_len);
|
||||
logger_log(raop_ntp->logger, LOGGER_DEBUG, "\nraop_ntp send_len = %d, now = %llu", send_len, send_time);
|
||||
logger_log(raop_ntp->logger, LOGGER_DEBUG, "\nraop_ntp send_len = %d, now = %8.6f", send_len,
|
||||
(double) send_time / SECOND_IN_NSECS);
|
||||
if (send_len < 0) {
|
||||
logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp error sending request");
|
||||
} else {
|
||||
@@ -305,7 +307,6 @@ raop_ntp_thread(void *arg)
|
||||
} else {
|
||||
//local time of the server when the NTP response packet returns
|
||||
int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp);
|
||||
|
||||
timeout_counter = 0;
|
||||
char *str = utils_data_to_string(response, response_len, 16);
|
||||
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp receive time type_t=%d packetlen = %d\n%s",
|
||||
@@ -321,15 +322,15 @@ raop_ntp_thread(void *arg)
|
||||
// Local time of the client when the response message leaves the client
|
||||
int64_t t2 = (int64_t) byteutils_get_ntp_timestamp(response, 24);
|
||||
|
||||
// The iOS client device sends its time in micro seconds relative to an arbitrary Epoch (the last boot).
|
||||
// For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970 * 1000000 us.
|
||||
// The iOS client device sends its time in seconds relative to an arbitrary Epoch (the last boot).
|
||||
// For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970.
|
||||
// This means we have to expect some rather huge offset, but its growth or shrink over time should be small.
|
||||
|
||||
raop_ntp->data_index = (raop_ntp->data_index + 1) % RAOP_NTP_DATA_COUNT;
|
||||
raop_ntp->data[raop_ntp->data_index].time = t3;
|
||||
raop_ntp->data[raop_ntp->data_index].offset = ((t1 - t0) + (t2 - t3)) / 2;
|
||||
raop_ntp->data[raop_ntp->data_index].delay = ((t3 - t0) - (t2 - t1));
|
||||
raop_ntp->data[raop_ntp->data_index].dispersion = RAOP_NTP_R_RHO + RAOP_NTP_S_RHO + (t3 - t0) * RAOP_NTP_PHI_PPM / 1000000u;
|
||||
raop_ntp->data[raop_ntp->data_index].dispersion = RAOP_NTP_R_RHO + RAOP_NTP_S_RHO + (t3 - t0) * RAOP_NTP_PHI_PPM / SECOND_IN_NSECS;
|
||||
|
||||
// Sort by delay
|
||||
memcpy(data_sorted, raop_ntp->data, sizeof(data_sorted));
|
||||
@@ -341,7 +342,7 @@ raop_ntp_thread(void *arg)
|
||||
|
||||
// Calculate dispersion
|
||||
for(int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
|
||||
unsigned long long disp = raop_ntp->data[i].dispersion + (t3 - raop_ntp->data[i].time) * RAOP_NTP_PHI_PPM / 1000000u;
|
||||
unsigned long long disp = raop_ntp->data[i].dispersion + (t3 - raop_ntp->data[i].time) * RAOP_NTP_PHI_PPM / SECOND_IN_NSECS;
|
||||
dispersion += disp / two_pow_n[i];
|
||||
}
|
||||
|
||||
@@ -454,54 +455,54 @@ raop_ntp_stop(raop_ntp_t *raop_ntp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from a little endian ntp timestamp to micro seconds since the Unix epoch.
|
||||
* Converts from a little endian ntp timestamp to nano seconds since the Unix epoch.
|
||||
* Does the same thing as byteutils_get_ntp_timestamp, except its input is an uint64_t
|
||||
* and expected to already be in little endian.
|
||||
* Please note this just converts to a different representation, the clock remains the
|
||||
* same.
|
||||
*/
|
||||
uint64_t raop_ntp_timestamp_to_micro_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff) {
|
||||
uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff) {
|
||||
uint64_t seconds = ((ntp_timestamp >> 32) & 0xffffffff) - (account_for_epoch_diff ? SECONDS_FROM_1900_TO_1970 : 0);
|
||||
uint64_t fraction = (ntp_timestamp & 0xffffffff);
|
||||
return (seconds * 1000000) + ((fraction * 1000000) >> 32);
|
||||
return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in micro seconds according to the local wall clock.
|
||||
* Returns the current time in nano seconds according to the local wall clock.
|
||||
* The system Unix time is used as the local wall clock.
|
||||
*/
|
||||
uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) {
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_REALTIME, &time);
|
||||
return (uint64_t)time.tv_sec * 1000000L + (uint64_t)(time.tv_nsec / 1000);
|
||||
return ((uint64_t)time.tv_sec) * SECOND_IN_NSECS + (uint64_t)(time.tv_nsec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in micro seconds according to the remote wall clock.
|
||||
* Returns the current time in nano seconds according to the remote wall clock.
|
||||
*/
|
||||
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp) {
|
||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||
int64_t offset = raop_ntp->sync_offset;
|
||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||
return (uint64_t) ((int64_t) raop_ntp_get_local_time(raop_ntp)) + ((int64_t) offset);
|
||||
return (uint64_t) (((int64_t) raop_ntp_get_local_time(raop_ntp)) + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local wall clock time in micro seconds for the given point in remote clock time
|
||||
* Returns the local wall clock time in nano seconds for the given point in remote clock time
|
||||
*/
|
||||
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time) {
|
||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||
uint64_t offset = raop_ntp->sync_offset;
|
||||
int64_t offset = raop_ntp->sync_offset;
|
||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||
return (uint64_t) ((int64_t) remote_time) - ((int64_t) offset);
|
||||
return (uint64_t) (((int64_t) remote_time) - offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remote wall clock time in micro seconds for the given point in local clock time
|
||||
* Returns the remote wall clock time in nano seconds for the given point in local clock time
|
||||
*/
|
||||
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time) {
|
||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||
uint64_t offset = raop_ntp->sync_offset;
|
||||
int64_t offset = raop_ntp->sync_offset;
|
||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||
return (uint64_t) ((int64_t) local_time) + ((int64_t) offset);
|
||||
return (uint64_t) (((int64_t) local_time) + offset);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ unsigned short raop_ntp_get_port(raop_ntp_t *raop_ntp);
|
||||
|
||||
void raop_ntp_destroy(raop_ntp_t *raop_rtp);
|
||||
|
||||
uint64_t raop_ntp_timestamp_to_micro_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff);
|
||||
uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff);
|
||||
|
||||
uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp);
|
||||
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp);
|
||||
|
||||
@@ -32,12 +32,13 @@
|
||||
|
||||
#define NO_FLUSH (-42)
|
||||
|
||||
#define RAOP_RTP_SAMPLE_RATE (44100.0 / 1000000.0)
|
||||
#define SECOND_IN_NSECS 1000000000UL
|
||||
#define RAOP_RTP_SAMPLE_RATE (44100.0 / SECOND_IN_NSECS)
|
||||
#define RAOP_RTP_SYNC_DATA_COUNT 8
|
||||
#define SEC 1000000
|
||||
#define SEC SECOND_IN_NSECS
|
||||
|
||||
#define DELAY_AAC 500000 //empirical, matches audio latency of about -0.5 sec after first clock sync event
|
||||
#define DELAY_ALAC 2000000 //empirical, matches audio latency of about -2.0 sec after first clock sync event
|
||||
#define DELAY_AAC 500000000 //empirical, matches audio latency of about -0.5 sec after first clock sync event
|
||||
#define DELAY_ALAC 200000000 //empirical, matches audio latency of about -2.0 sec after first clock sync event
|
||||
|
||||
/* note: it is unclear what will happen in the unlikely event that this code is running at the time of the unix-time
|
||||
* epoch event on 2038-01-19 at 3:14:08 UTC ! (but Apple will surely have removed AirPlay "legacy pairing" by then!) */
|
||||
@@ -550,7 +551,7 @@ raop_rtp_thread_udp(void *arg)
|
||||
have_synced = true;
|
||||
}
|
||||
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
|
||||
uint64_t sync_ntp_remote = raop_ntp_timestamp_to_micro_seconds(sync_ntp_raw, true);
|
||||
uint64_t sync_ntp_remote = raop_ntp_timestamp_to_nano_seconds(sync_ntp_raw, true);
|
||||
uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote);
|
||||
int64_t shift;
|
||||
switch (raop_rtp->ct) {
|
||||
@@ -631,12 +632,12 @@ raop_rtp_thread_udp(void *arg)
|
||||
offset_estimate_initialized = true;
|
||||
switch (raop_rtp->ct) {
|
||||
case 0x02:
|
||||
delay = DELAY_ALAC; /* DELAY = 2000000 (2.0 sec) is empirical choice for ALAC */
|
||||
delay = DELAY_ALAC; /* DELAY = 2000000000 (2.0 sec) is empirical choice for ALAC */
|
||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "Audio is ALAC: using initial latency estimate -%8.6f sec",
|
||||
((double) delay) / SEC);
|
||||
break;
|
||||
case 0x08:
|
||||
delay = DELAY_AAC; /* DELAY = 500000 (0.5 sec) is empirical choice for AAC-ELD */
|
||||
delay = DELAY_AAC; /* DELAY = 500000000 (0.5 sec) is empirical choice for AAC-ELD */
|
||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "Audio is AAC: using initial latency estimate -%8.6f sec",
|
||||
((double) delay ) / SEC);
|
||||
break;
|
||||
@@ -682,7 +683,7 @@ raop_rtp_thread_udp(void *arg)
|
||||
free(payload);
|
||||
uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp->ntp);
|
||||
int64_t latency = ((int64_t) ntp_now) - ((int64_t) audio_data.ntp_time);
|
||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp audio: now = %8.6f, npt = %8.6f, latency = %8.6f, rtp_time=%u seqnum = %u",
|
||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp audio: now = %8.6f, ntp = %8.6f, latency = %8.6f, rtp_time=%u seqnum = %u",
|
||||
((double) ntp_now ) / SEC, ((double) audio_data.ntp_time) / SEC, ((double) latency) / SEC, (uint32_t) rtp64_timestamp,
|
||||
seqnum);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
#define CAST
|
||||
#endif
|
||||
|
||||
#define SEC 1000000
|
||||
#define SECOND_IN_NSECS 1000000000UL
|
||||
#define SEC SECOND_IN_NSECS
|
||||
|
||||
/* for MacOS, where SOL_TCP and TCP_KEEPIDLE are not defined */
|
||||
#if !defined(SOL_TCP) && defined(IPPROTO_TCP)
|
||||
@@ -359,9 +360,9 @@ raop_rtp_mirror_thread(void *arg)
|
||||
// Conveniently, the video data is already stamped with the remote wall clock time,
|
||||
// so no additional clock syncing needed. The only thing odd here is that the video
|
||||
// ntp time stamps don't include the SECONDS_FROM_1900_TO_1970, so it's really just
|
||||
// counting micro seconds since last boot.
|
||||
// counting nano seconds since last boot.
|
||||
ntp_timestamp_raw = byteutils_get_long(packet, 8);
|
||||
uint64_t ntp_timestamp_remote = raop_ntp_timestamp_to_micro_seconds(ntp_timestamp_raw, false);
|
||||
uint64_t ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
|
||||
uint64_t ntp_timestamp = raop_ntp_convert_remote_time(raop_rtp_mirror->ntp, ntp_timestamp_remote);
|
||||
|
||||
uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp_mirror->ntp);
|
||||
|
||||
Reference in New Issue
Block a user