mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
raop_rtp fixes/cleanups to remove unneeded ntp use
This commit is contained in:
@@ -15,6 +15,8 @@ until advertisements have finished or been skipped before clicking the
|
|||||||
YouTube airplay icon.) <strong>Please report any issues with this new
|
YouTube airplay icon.) <strong>Please report any issues with this new
|
||||||
feature of UxPlay</strong>.</li>
|
feature of UxPlay</strong>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p><strong><em>NEWS</em></strong>: macOS Sequoia 15.2 has an AirPlay
|
||||||
|
bug: update to macOS 15.3 for mirroring screen with UxPlay.</p>
|
||||||
<h2 id="highlights">Highlights:</h2>
|
<h2 id="highlights">Highlights:</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>GPLv3, open source.</li>
|
<li>GPLv3, open source.</li>
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
YouTube airplay icon.) **Please report any issues with this new
|
YouTube airplay icon.) **Please report any issues with this new
|
||||||
feature of UxPlay**.
|
feature of UxPlay**.
|
||||||
|
|
||||||
|
***NEWS***: macOS Sequoia 15.2 has an AirPlay bug: update to macOS 15.3
|
||||||
|
for mirroring screen with UxPlay.
|
||||||
|
|
||||||
## Highlights:
|
## Highlights:
|
||||||
|
|
||||||
- GPLv3, open source.
|
- GPLv3, open source.
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
YouTube airplay icon.) **Please report any issues with this new
|
YouTube airplay icon.) **Please report any issues with this new
|
||||||
feature of UxPlay**.
|
feature of UxPlay**.
|
||||||
|
|
||||||
|
***NEWS***: macOS Sequoia 15.2 has an AirPlay bug: update to macOS 15.3
|
||||||
|
for mirroring screen with UxPlay.
|
||||||
|
|
||||||
## Highlights:
|
## Highlights:
|
||||||
|
|
||||||
- GPLv3, open source.
|
- GPLv3, open source.
|
||||||
|
|||||||
@@ -765,3 +765,7 @@ void raop_destroy_airplay_video(raop_t *raop) {
|
|||||||
raop->airplay_video = NULL;
|
raop->airplay_video = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t get_local_time() {
|
||||||
|
return raop_ntp_get_local_time();
|
||||||
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ int airplay_video_service_init(raop_t *raop, unsigned short port, const char *se
|
|||||||
bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video);
|
bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video);
|
||||||
airplay_video_t *get_airplay_video(raop_t *raop);
|
airplay_video_t *get_airplay_video(raop_t *raop);
|
||||||
airplay_video_t *deregister_airplay_video(raop_t *raop);
|
airplay_video_t *deregister_airplay_video(raop_t *raop);
|
||||||
|
uint64_t get_local_time();
|
||||||
|
|
||||||
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
|
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
|
||||||
RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile);
|
RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile);
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ typedef struct {
|
|||||||
/* Data available */
|
/* Data available */
|
||||||
int filled;
|
int filled;
|
||||||
|
|
||||||
|
uint64_t packet_arrival_time;
|
||||||
|
|
||||||
/* RTP header */
|
/* RTP header */
|
||||||
unsigned short seqnum;
|
unsigned short seqnum;
|
||||||
uint64_t rtp_timestamp;
|
uint32_t rtp_timestamp;
|
||||||
uint64_t ntp_timestamp;
|
|
||||||
|
|
||||||
/* Payload data */
|
/* Payload data */
|
||||||
unsigned int payload_size;
|
unsigned int payload_size;
|
||||||
@@ -165,7 +166,7 @@ raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum) {
|
raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, int use_seqnum) {
|
||||||
unsigned char empty_packet_marker[] = { 0x00, 0x68, 0x34, 0x00 };
|
unsigned char empty_packet_marker[] = { 0x00, 0x68, 0x34, 0x00 };
|
||||||
assert(raop_buffer);
|
assert(raop_buffer);
|
||||||
|
|
||||||
@@ -206,8 +207,7 @@ raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned sh
|
|||||||
|
|
||||||
/* Update the raop_buffer entry header */
|
/* Update the raop_buffer entry header */
|
||||||
entry->seqnum = seqnum;
|
entry->seqnum = seqnum;
|
||||||
entry->rtp_timestamp = *rtp_timestamp;
|
entry->rtp_timestamp = byteutils_get_int_be(data, 4);
|
||||||
entry->ntp_timestamp = *ntp_timestamp;
|
|
||||||
entry->filled = 1;
|
entry->filled = 1;
|
||||||
|
|
||||||
entry->payload_data = malloc(payload_size);
|
entry->payload_data = malloc(payload_size);
|
||||||
@@ -228,7 +228,7 @@ raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned sh
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend) {
|
raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint32_t *rtp_timestamp, unsigned short *seqnum, int no_resend) {
|
||||||
assert(raop_buffer);
|
assert(raop_buffer);
|
||||||
|
|
||||||
/* Calculate number of entries in the current buffer */
|
/* Calculate number of entries in the current buffer */
|
||||||
@@ -261,7 +261,6 @@ raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *
|
|||||||
|
|
||||||
/* Return entry payload buffer */
|
/* Return entry payload buffer */
|
||||||
*rtp_timestamp = entry->rtp_timestamp;
|
*rtp_timestamp = entry->rtp_timestamp;
|
||||||
*ntp_timestamp = entry->ntp_timestamp;
|
|
||||||
*seqnum = entry->seqnum;
|
*seqnum = entry->seqnum;
|
||||||
*length = entry->payload_size;
|
*length = entry->payload_size;
|
||||||
entry->payload_size = 0;
|
entry->payload_size = 0;
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ typedef int (*raop_resend_cb_t)(void *opaque, unsigned short seqno, unsigned sho
|
|||||||
raop_buffer_t *raop_buffer_init(logger_t *logger,
|
raop_buffer_t *raop_buffer_init(logger_t *logger,
|
||||||
const unsigned char *aeskey,
|
const unsigned char *aeskey,
|
||||||
const unsigned char *aesiv);
|
const unsigned char *aesiv);
|
||||||
int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum);
|
int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, int use_seqnum);
|
||||||
void *raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend);
|
void *raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint32_t *rtp_timestamp, unsigned short *seqnum, int no_resend);
|
||||||
void raop_buffer_handle_resends(raop_buffer_t *raop_buffer, raop_resend_cb_t resend_cb, void *opaque);
|
void raop_buffer_handle_resends(raop_buffer_t *raop_buffer, raop_resend_cb_t resend_cb, void *opaque);
|
||||||
void raop_buffer_flush(raop_buffer_t *raop_buffer, int next_seq);
|
void raop_buffer_flush(raop_buffer_t *raop_buffer, int next_seq);
|
||||||
|
|
||||||
|
|||||||
@@ -94,8 +94,17 @@ struct raop_ntp_s {
|
|||||||
timing_protocol_t time_protocol;
|
timing_protocol_t time_protocol;
|
||||||
bool client_time_received;
|
bool client_time_received;
|
||||||
|
|
||||||
|
uint64_t video_arrival_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* for use in syncing audio before a first rtp_sync */
|
||||||
|
void raop_ntp_set_video_arrival_offset(raop_ntp_t* raop_ntp, const uint64_t *offset) {
|
||||||
|
raop_ntp->video_arrival_offset = *offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t raop_ntp_get_video_arrival_offset(raop_ntp_t* raop_ntp) {
|
||||||
|
return raop_ntp->video_arrival_offset;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used for sorting the data array by delay
|
* Used for sorting the data array by delay
|
||||||
@@ -155,6 +164,8 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
|||||||
raop_ntp->timing_rport = timing_rport;
|
raop_ntp->timing_rport = timing_rport;
|
||||||
raop_ntp->client_time_received = false;
|
raop_ntp->client_time_received = false;
|
||||||
|
|
||||||
|
raop_ntp->video_arrival_offset = 0;
|
||||||
|
|
||||||
if (raop_ntp_parse_remote(raop_ntp, remote, remote_addr_len) < 0) {
|
if (raop_ntp_parse_remote(raop_ntp, remote, remote_addr_len) < 0) {
|
||||||
free(raop_ntp);
|
free(raop_ntp);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -166,7 +177,7 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
|||||||
raop_ntp->running = 0;
|
raop_ntp->running = 0;
|
||||||
raop_ntp->joined = 1;
|
raop_ntp->joined = 1;
|
||||||
|
|
||||||
uint64_t time = raop_ntp_get_local_time(raop_ntp);
|
uint64_t time = raop_ntp_get_local_time();
|
||||||
|
|
||||||
for (int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
|
for (int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
|
||||||
raop_ntp->data[i].offset = 0ll;
|
raop_ntp->data[i].offset = 0ll;
|
||||||
@@ -289,7 +300,7 @@ raop_ntp_thread(void *arg)
|
|||||||
raop_ntp_flush_socket(raop_ntp->tsock);
|
raop_ntp_flush_socket(raop_ntp->tsock);
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
uint64_t send_time = raop_ntp_get_local_time(raop_ntp);
|
uint64_t send_time = raop_ntp_get_local_time();
|
||||||
byteutils_put_ntp_timestamp(request, 24, send_time);
|
byteutils_put_ntp_timestamp(request, 24, send_time);
|
||||||
int send_len = sendto(raop_ntp->tsock, (char *)request, sizeof(request), 0,
|
int send_len = sendto(raop_ntp->tsock, (char *)request, sizeof(request), 0,
|
||||||
(struct sockaddr *) &raop_ntp->remote_saddr, raop_ntp->remote_saddr_len);
|
(struct sockaddr *) &raop_ntp->remote_saddr, raop_ntp->remote_saddr_len);
|
||||||
@@ -315,7 +326,7 @@ raop_ntp_thread(void *arg)
|
|||||||
raop_ntp->client_time_received = true;
|
raop_ntp->client_time_received = true;
|
||||||
}
|
}
|
||||||
//local time of the server when the NTP response packet returns
|
//local time of the server when the NTP response packet returns
|
||||||
int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp);
|
int64_t t3 = (int64_t) raop_ntp_get_local_time();
|
||||||
|
|
||||||
// Local time of the server when the NTP request packet leaves the server
|
// Local time of the server when the NTP request packet leaves the server
|
||||||
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
|
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
|
||||||
@@ -484,7 +495,7 @@ uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t ti
|
|||||||
* Returns the current time in nano 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.
|
* The system Unix time is used as the local wall clock.
|
||||||
*/
|
*/
|
||||||
uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) {
|
uint64_t raop_ntp_get_local_time() {
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
clock_gettime(CLOCK_REALTIME, &time);
|
clock_gettime(CLOCK_REALTIME, &time);
|
||||||
return ((uint64_t) time.tv_nsec) + (uint64_t) time.tv_sec * SECOND_IN_NSECS;
|
return ((uint64_t) time.tv_nsec) + (uint64_t) time.tv_sec * SECOND_IN_NSECS;
|
||||||
@@ -494,16 +505,22 @@ uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) {
|
|||||||
* Returns the current time in nano 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) {
|
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp) {
|
||||||
|
if (!raop_ntp->client_time_received) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||||
int64_t offset = raop_ntp->sync_offset;
|
int64_t offset = raop_ntp->sync_offset;
|
||||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||||
return (uint64_t) ((int64_t) raop_ntp_get_local_time(raop_ntp) + offset);
|
return (uint64_t) ((int64_t) raop_ntp_get_local_time() + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local wall clock time in nano 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) {
|
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time) {
|
||||||
|
if (!raop_ntp->client_time_received) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||||
int64_t offset = raop_ntp->sync_offset;
|
int64_t offset = raop_ntp->sync_offset;
|
||||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||||
@@ -514,6 +531,9 @@ uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time
|
|||||||
* Returns the remote wall clock time in nano 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) {
|
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time) {
|
||||||
|
if (!raop_ntp->client_time_received) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
MUTEX_LOCK(raop_ntp->sync_params_mutex);
|
||||||
int64_t offset = raop_ntp->sync_offset;
|
int64_t offset = raop_ntp->sync_offset;
|
||||||
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
|
||||||
|
|||||||
@@ -38,9 +38,12 @@ void raop_ntp_destroy(raop_ntp_t *raop_rtp);
|
|||||||
uint64_t raop_ntp_timestamp_to_nano_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_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp);
|
uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp);
|
||||||
|
|
||||||
uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp);
|
uint64_t raop_ntp_get_local_time();
|
||||||
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp);
|
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp);
|
||||||
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time);
|
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time);
|
||||||
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time);
|
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time);
|
||||||
|
|
||||||
|
void raop_ntp_set_video_arrival_offset(raop_ntp_t* raop_ntp, const uint64_t *offset);
|
||||||
|
uint64_t raop_ntp_get_video_arrival_offset(raop_ntp_t* raop_ntp);
|
||||||
|
|
||||||
#endif //RAOP_NTP_H
|
#endif //RAOP_NTP_H
|
||||||
|
|||||||
225
lib/raop_rtp.c
225
lib/raop_rtp.c
@@ -36,10 +36,9 @@
|
|||||||
#define NO_FLUSH (-42)
|
#define NO_FLUSH (-42)
|
||||||
|
|
||||||
#define SECOND_IN_NSECS 1000000000
|
#define SECOND_IN_NSECS 1000000000
|
||||||
#define RAOP_RTP_SYNC_DATA_COUNT 8
|
|
||||||
#define SEC SECOND_IN_NSECS
|
#define SEC SECOND_IN_NSECS
|
||||||
|
|
||||||
#define DELAY_AAC 0.275 //empirical, matches audio latency of about -0.25 sec after first clock sync event
|
#define DELAY_AAC 0.20 //empirical, matches audio latency of about -0.25 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
|
/* 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!) */
|
* epoch event on 2038-01-19 at 3:14:08 UTC ! (but Apple will surely have removed AirPlay "legacy pairing" by then!) */
|
||||||
@@ -56,14 +55,16 @@ struct raop_rtp_s {
|
|||||||
// Time and sync
|
// Time and sync
|
||||||
raop_ntp_t *ntp;
|
raop_ntp_t *ntp;
|
||||||
double rtp_clock_rate;
|
double rtp_clock_rate;
|
||||||
int64_t rtp_sync_offset;
|
|
||||||
raop_rtp_sync_data_t sync_data[RAOP_RTP_SYNC_DATA_COUNT];
|
|
||||||
int sync_data_index;
|
|
||||||
uint64_t ntp_start_time;
|
uint64_t ntp_start_time;
|
||||||
uint64_t rtp_start_time;
|
uint64_t rtp_start_time;
|
||||||
uint64_t rtp_time;
|
uint64_t rtp_time;
|
||||||
bool rtp_clock_started;
|
bool rtp_clock_started;
|
||||||
|
|
||||||
|
uint32_t rtp_sync;
|
||||||
|
uint64_t client_ntp_sync;
|
||||||
|
bool initial_sync;
|
||||||
|
|
||||||
// Transmission Stats, could be used if a playout buffer is needed
|
// Transmission Stats, could be used if a playout buffer is needed
|
||||||
// float interarrival_jitter; // As defined by RTP RFC 3550, Section 6.4.1
|
// float interarrival_jitter; // As defined by RTP RFC 3550, Section 6.4.1
|
||||||
// unsigned int last_packet_transit_time;
|
// unsigned int last_packet_transit_time;
|
||||||
@@ -161,12 +162,10 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, co
|
|||||||
raop_rtp->logger = logger;
|
raop_rtp->logger = logger;
|
||||||
raop_rtp->ntp = ntp;
|
raop_rtp->ntp = ntp;
|
||||||
|
|
||||||
raop_rtp->rtp_sync_offset = 0;
|
raop_rtp->rtp_sync = 0;
|
||||||
raop_rtp->sync_data_index = 0;
|
raop_rtp->client_ntp_sync = 0;
|
||||||
for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; ++i) {
|
raop_rtp->initial_sync = false;
|
||||||
raop_rtp->sync_data[i].ntp_time = 0;
|
|
||||||
raop_rtp->sync_data[i].rtp_time = 0;
|
|
||||||
}
|
|
||||||
raop_rtp->ntp_start_time = 0;
|
raop_rtp->ntp_start_time = 0;
|
||||||
raop_rtp->rtp_start_time = 0;
|
raop_rtp->rtp_start_time = 0;
|
||||||
raop_rtp->rtp_clock_started = false;
|
raop_rtp->rtp_clock_started = false;
|
||||||
@@ -386,59 +385,22 @@ raop_rtp_process_events(raop_rtp_t *raop_rtp, void *cb_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void raop_rtp_sync_clock(raop_rtp_t *raop_rtp, uint64_t *ntp_time, uint64_t *rtp_time) {
|
static uint64_t rtp_time_to_client_ntp(raop_rtp_t *raop_rtp, uint32_t *rtp32) {
|
||||||
/* ntp_time = (uint64_t)(((int64_t)(raop_rtp->rtp_clock_rate * rtp_time)) + raop_rtp->rtp_sync_offset) */
|
if (!raop_rtp->initial_sync) {
|
||||||
int latest, valid_data_count = 0;
|
return 0;
|
||||||
uint64_t ntp_sum = 0, rtp_sum = 0;
|
|
||||||
double offset = ((double) *ntp_time) - raop_rtp->rtp_clock_rate * *rtp_time;
|
|
||||||
int64_t correction = 0;
|
|
||||||
|
|
||||||
raop_rtp->sync_data_index = (raop_rtp->sync_data_index + 1) % RAOP_RTP_SYNC_DATA_COUNT;
|
|
||||||
latest = raop_rtp->sync_data_index;
|
|
||||||
raop_rtp->sync_data[latest].rtp_time = *rtp_time;
|
|
||||||
raop_rtp->sync_data[latest].ntp_time = *ntp_time;
|
|
||||||
|
|
||||||
for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) {
|
|
||||||
if (raop_rtp->sync_data[i].ntp_time == 0) continue;
|
|
||||||
valid_data_count++;
|
|
||||||
if (i == latest) continue;
|
|
||||||
ntp_sum += *ntp_time - raop_rtp->sync_data[i].ntp_time;
|
|
||||||
rtp_sum += *rtp_time - raop_rtp->sync_data[i].rtp_time;
|
|
||||||
}
|
}
|
||||||
|
uint64_t client_ntp = raop_rtp->client_ntp_sync;
|
||||||
if (valid_data_count > 1) {
|
if (*rtp32 >= raop_rtp->rtp_sync) {
|
||||||
correction -= raop_rtp->rtp_sync_offset;
|
client_ntp += (uint64_t) raop_rtp->rtp_clock_rate * (*rtp32 - raop_rtp->rtp_sync);
|
||||||
offset += (((double) ntp_sum) - raop_rtp->rtp_clock_rate * rtp_sum) / valid_data_count;
|
|
||||||
}
|
|
||||||
raop_rtp->rtp_sync_offset = (int64_t) offset;
|
|
||||||
correction += raop_rtp->rtp_sync_offset;
|
|
||||||
|
|
||||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "dataset %d raop_rtp sync correction=%lld, rtp_sync_offset = %lld ",
|
|
||||||
valid_data_count, correction, raop_rtp->rtp_sync_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t rtp64_time (raop_rtp_t *raop_rtp, const uint32_t *rtp32) {
|
|
||||||
/* convert from 32-bit to 64-bit rtp time:
|
|
||||||
* the rtp_time 32-bit epoch at 44.1kHz has length of about 27 hours
|
|
||||||
* using 64-bit rtp time avoids any epoch issues.
|
|
||||||
* initial call sets epoch to 1; subsequent calls maintain consistent epoch.
|
|
||||||
* (assumes successive calls are close in time) */
|
|
||||||
|
|
||||||
if (raop_rtp->rtp_clock_started) {
|
|
||||||
uint32_t diff1 = *rtp32 - ((uint32_t) raop_rtp->rtp_time);
|
|
||||||
uint32_t diff2 = ((uint32_t) raop_rtp->rtp_time) - *rtp32;
|
|
||||||
if (diff1 <= diff2) {
|
|
||||||
raop_rtp->rtp_time += (uint64_t) diff1;
|
|
||||||
} else {
|
|
||||||
raop_rtp->rtp_time -= (uint64_t) diff2;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
raop_rtp->rtp_time = (0x01ULL << 32 ) + (uint64_t) *rtp32;
|
uint64_t ntp_shift = (uint64_t) raop_rtp->rtp_clock_rate * (raop_rtp->rtp_sync - *rtp32);
|
||||||
raop_rtp->rtp_start_time = raop_rtp->rtp_time;
|
if (client_ntp > ntp_shift) {
|
||||||
raop_rtp->rtp_clock_started = true;
|
client_ntp -= ntp_shift;
|
||||||
|
} else {
|
||||||
|
client_ntp = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//assert(*rtp32 == (uint32_t) raop_rtp->rtp_time);
|
return client_ntp;
|
||||||
return raop_rtp->rtp_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static THREAD_RETVAL
|
static THREAD_RETVAL
|
||||||
@@ -450,22 +412,15 @@ raop_rtp_thread_udp(void *arg)
|
|||||||
struct sockaddr_storage saddr;
|
struct sockaddr_storage saddr;
|
||||||
socklen_t saddrlen;
|
socklen_t saddrlen;
|
||||||
bool got_remote_control_saddr = false;
|
bool got_remote_control_saddr = false;
|
||||||
|
uint64_t video_arrival_offset = 0;
|
||||||
|
|
||||||
/* for initial rtp to ntp conversions */
|
/* initial audio stream has no data */
|
||||||
bool have_synced = false;
|
|
||||||
bool no_data_yet = true;
|
|
||||||
unsigned char no_data_marker[] = {0x00, 0x68, 0x34, 0x00 };
|
unsigned char no_data_marker[] = {0x00, 0x68, 0x34, 0x00 };
|
||||||
int rtp_count = 0;
|
|
||||||
double sync_adjustment = 0;
|
|
||||||
unsigned short seqnum1 = 0, seqnum2 = 0;
|
|
||||||
|
|
||||||
assert(raop_rtp);
|
assert(raop_rtp);
|
||||||
bool logger_debug = (logger_get_level(raop_rtp->logger) >= LOGGER_DEBUG);
|
bool logger_debug = (logger_get_level(raop_rtp->logger) >= LOGGER_DEBUG);
|
||||||
raop_rtp->ntp_start_time = raop_ntp_get_local_time(raop_rtp->ntp);
|
raop_rtp->ntp_start_time = raop_ntp_get_local_time();
|
||||||
raop_rtp->rtp_clock_started = false;
|
raop_rtp->rtp_clock_started = false;
|
||||||
for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) {
|
|
||||||
raop_rtp->sync_data[i].ntp_time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int no_resend = (raop_rtp->control_rport == 0); /* true when control_rport is not set */
|
int no_resend = (raop_rtp->control_rport == 0); /* true when control_rport is not set */
|
||||||
|
|
||||||
@@ -526,14 +481,8 @@ raop_rtp_thread_udp(void *arg)
|
|||||||
unsigned int resent_packetlen = packetlen - 4;
|
unsigned int resent_packetlen = packetlen - 4;
|
||||||
unsigned short seqnum = byteutils_get_short_be(resent_packet, 2);
|
unsigned short seqnum = byteutils_get_short_be(resent_packet, 2);
|
||||||
if (resent_packetlen >= 12) {
|
if (resent_packetlen >= 12) {
|
||||||
uint32_t timestamp = byteutils_get_int_be(resent_packet, 4);
|
|
||||||
uint64_t rtp_time = rtp64_time(raop_rtp, ×tamp);
|
|
||||||
uint64_t ntp_time = 0;
|
|
||||||
if (have_synced) {
|
|
||||||
ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time));
|
|
||||||
}
|
|
||||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp resent audio packet: seqnum=%u", seqnum);
|
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp resent audio packet: seqnum=%u", seqnum);
|
||||||
int result = raop_buffer_enqueue(raop_rtp->buffer, resent_packet, resent_packetlen, &ntp_time, &rtp_time, 1);
|
int result = raop_buffer_enqueue(raop_rtp->buffer, resent_packet, resent_packetlen, 1);
|
||||||
assert(result >= 0);
|
assert(result >= 0);
|
||||||
} else if (logger_debug) {
|
} else if (logger_debug) {
|
||||||
/* type_c = 0x56 packets with length 8 have been reported */
|
/* type_c = 0x56 packets with length 8 have been reported */
|
||||||
@@ -553,24 +502,30 @@ raop_rtp_thread_udp(void *arg)
|
|||||||
* next_rtp = sync_rtp + 77175 = 441 * 175 (1.75 sec) for ALAC */
|
* next_rtp = sync_rtp + 77175 = 441 * 175 (1.75 sec) for ALAC */
|
||||||
|
|
||||||
// The unit for the rtp clock is 1 / sample rate = 1 / 44100
|
// The unit for the rtp clock is 1 / sample rate = 1 / 44100
|
||||||
uint32_t sync_rtp = byteutils_get_int_be(packet, 4);
|
uint64_t client_ntp_sync_prev = 0;
|
||||||
uint64_t sync_rtp64 = rtp64_time(raop_rtp, &sync_rtp);
|
uint64_t rtp_sync_prev = 0;
|
||||||
if (have_synced == false) {
|
if (!raop_rtp->initial_sync) {
|
||||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "first audio rtp sync");
|
logger_log(raop_rtp->logger, LOGGER_DEBUG, "first audio rtp sync");
|
||||||
have_synced = true;
|
raop_rtp->initial_sync = true;
|
||||||
}
|
} else {
|
||||||
|
client_ntp_sync_prev = raop_rtp->client_ntp_sync;
|
||||||
|
rtp_sync_prev = raop_rtp->rtp_sync;
|
||||||
|
}
|
||||||
|
raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
|
||||||
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
|
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
|
||||||
uint64_t sync_ntp_remote = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
|
raop_rtp->client_ntp_sync = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
|
||||||
|
|
||||||
if (logger_debug) {
|
if (logger_debug) {
|
||||||
uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote);
|
double offset_change = ((double) raop_rtp->client_ntp_sync) - raop_rtp->rtp_clock_rate * raop_rtp->rtp_sync;
|
||||||
|
offset_change -= ((double) client_ntp_sync_prev) - raop_rtp->rtp_clock_rate * rtp_sync_prev;
|
||||||
|
uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, raop_rtp->rtp_sync);
|
||||||
char *str = utils_data_to_string(packet, packetlen, 20);
|
char *str = utils_data_to_string(packet, packetlen, 20);
|
||||||
logger_log(raop_rtp->logger, LOGGER_DEBUG,
|
logger_log(raop_rtp->logger, LOGGER_DEBUG,
|
||||||
"raop_rtp sync: client ntp=%8.6f, ntp = %8.6f, ntp_start_time %8.6f\nts_client = %8.6f sync_rtp=%u\n%s",
|
"raop_rtp sync: ntp = %8.6f, ntp_start_time %8.6f\nts_client = %8.6f sync_rtp=%u offset change = %8.6f\n%s",
|
||||||
(double) sync_ntp_remote / SEC, (double) sync_ntp_local / SEC,
|
(double) sync_ntp_local / SEC, (double) raop_rtp->ntp_start_time / SEC,
|
||||||
(double) raop_rtp->ntp_start_time / SEC, (double) sync_ntp_remote / SEC, sync_rtp, str);
|
(double) raop_rtp->client_ntp_sync / SEC, raop_rtp->rtp_sync, offset_change / SEC, str);
|
||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
raop_rtp_sync_clock(raop_rtp, &sync_ntp_remote, &sync_rtp64);
|
|
||||||
} else if (logger_debug) {
|
} else if (logger_debug) {
|
||||||
char *str = utils_data_to_string(packet, packetlen, 16);
|
char *str = utils_data_to_string(packet, packetlen, 16);
|
||||||
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp unknown udp control packet\n%s", str);
|
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp unknown udp control packet\n%s", str);
|
||||||
@@ -615,6 +570,9 @@ raop_rtp_thread_udp(void *arg)
|
|||||||
|
|
||||||
|
|
||||||
if (FD_ISSET(raop_rtp->dsock, &rfds)) {
|
if (FD_ISSET(raop_rtp->dsock, &rfds)) {
|
||||||
|
if (!raop_rtp->initial_sync && !video_arrival_offset) {
|
||||||
|
video_arrival_offset = raop_ntp_get_video_arrival_offset(raop_rtp->ntp);
|
||||||
|
}
|
||||||
//logger_log(raop_rtp->logger, LOGGER_INFO, "Would have data packet in queue");
|
//logger_log(raop_rtp->logger, LOGGER_INFO, "Would have data packet in queue");
|
||||||
// Receiving audio data here
|
// Receiving audio data here
|
||||||
saddrlen = sizeof(saddr);
|
saddrlen = sizeof(saddr);
|
||||||
@@ -633,83 +591,58 @@ raop_rtp_thread_udp(void *arg)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t rtp_timestamp = byteutils_get_int_be(packet, 4);
|
if (!raop_rtp->initial_sync && raop_rtp->ct == 8 && video_arrival_offset) {
|
||||||
uint64_t rtp_time = rtp64_time(raop_rtp, &rtp_timestamp);
|
/* estimate a fake initial remote timestamp for video synchronization with AAC audio before the first rtp sync */
|
||||||
uint64_t ntp_time = 0;
|
uint64_t ts = raop_ntp_get_local_time() - video_arrival_offset;
|
||||||
|
double delay = DELAY_AAC;
|
||||||
|
ts += (uint64_t) (delay * SEC);
|
||||||
|
raop_rtp->client_ntp_sync = ts;
|
||||||
|
raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
|
||||||
|
raop_rtp->initial_sync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) {
|
||||||
|
/* this is a "no data" packet */
|
||||||
|
/* the first such packet could be used to provide the initial rtptime and seqnum formerly given in the RECORD request */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */
|
if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */
|
||||||
|
|
||||||
if (have_synced) {
|
int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, 1);
|
||||||
ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time));
|
|
||||||
} else if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) {
|
|
||||||
/* use the special "no_data" packet to help determine an initial offset before the first rtp sync.
|
|
||||||
* until the first rtp sync occurs, we don't know the exact client ntp timestamp that matches the client rtp timestamp */
|
|
||||||
if (no_data_yet) {
|
|
||||||
int64_t sync_ntp = ((int64_t) raop_ntp_get_local_time(raop_rtp->ntp)) - ((int64_t) raop_rtp->ntp_start_time) ;
|
|
||||||
int64_t sync_rtp = ((int64_t) rtp_time) - ((int64_t) raop_rtp->rtp_start_time);
|
|
||||||
unsigned short seqnum = byteutils_get_short_be(packet, 2);
|
|
||||||
if (rtp_count == 0) {
|
|
||||||
sync_adjustment = ((double) sync_ntp);
|
|
||||||
rtp_count = 1;
|
|
||||||
seqnum1 = seqnum;
|
|
||||||
seqnum2 = seqnum;
|
|
||||||
}
|
|
||||||
if (seqnum2 != seqnum) { /* for AAC-ELD only use copy 1 of the 3 copies of each frame */
|
|
||||||
rtp_count++;
|
|
||||||
sync_adjustment += (((double) sync_ntp) - raop_rtp->rtp_clock_rate * sync_rtp - sync_adjustment) / rtp_count;
|
|
||||||
}
|
|
||||||
seqnum2 = seqnum1;
|
|
||||||
seqnum1 = seqnum;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
no_data_yet = false;
|
|
||||||
}
|
|
||||||
int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, &ntp_time, &rtp_time, 1);
|
|
||||||
assert(result >= 0);
|
assert(result >= 0);
|
||||||
|
|
||||||
if (raop_rtp->ct == 2 && !have_synced) {
|
if (!raop_rtp->initial_sync) {
|
||||||
/* in ALAC Audio-only mode wait until the first sync before dequeing */
|
/* wait until the first sync before dequeing ALAC */
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// Render continuous buffer entries
|
// Render continuous buffer entries
|
||||||
void *payload = NULL;
|
void *payload = NULL;
|
||||||
unsigned int payload_size;
|
unsigned int payload_size;
|
||||||
unsigned short seqnum;
|
unsigned short seqnum;
|
||||||
uint64_t rtp64_timestamp;
|
uint32_t rtp_timestamp;
|
||||||
uint64_t ntp_timestamp;
|
|
||||||
|
|
||||||
while ((payload = raop_buffer_dequeue(raop_rtp->buffer, &payload_size, &ntp_timestamp, &rtp64_timestamp, &seqnum, no_resend))) {
|
while ((payload = raop_buffer_dequeue(raop_rtp->buffer, &payload_size, &rtp_timestamp, &seqnum, no_resend))) {
|
||||||
audio_decode_struct audio_data;
|
audio_decode_struct audio_data;
|
||||||
audio_data.rtp_time = rtp64_timestamp;
|
audio_data.rtp_time = rtp_timestamp;
|
||||||
audio_data.seqnum = seqnum;
|
audio_data.seqnum = seqnum;
|
||||||
audio_data.data_len = payload_size;
|
audio_data.data_len = payload_size;
|
||||||
audio_data.data = payload;
|
audio_data.data = payload;
|
||||||
audio_data.ct = raop_rtp->ct;
|
audio_data.ct = raop_rtp->ct;
|
||||||
if (have_synced) {
|
audio_data.ntp_time_remote = rtp_time_to_client_ntp(raop_rtp, &rtp_timestamp);
|
||||||
if (ntp_timestamp == 0) {
|
audio_data.ntp_time_local = raop_ntp_convert_remote_time(raop_rtp->ntp, audio_data.ntp_time_remote);
|
||||||
ntp_timestamp = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp64_timestamp));
|
|
||||||
}
|
if (logger_debug) {
|
||||||
audio_data.ntp_time_remote = ntp_timestamp;
|
uint64_t ntp_now = raop_ntp_get_local_time();
|
||||||
audio_data.ntp_time_local = raop_ntp_convert_remote_time(raop_rtp->ntp, audio_data.ntp_time_remote);
|
int64_t latency = (audio_data.ntp_time_local ? ((int64_t) ntp_now) - ((int64_t) audio_data.ntp_time_local) : 0);
|
||||||
audio_data.sync_status = 1;
|
logger_log(raop_rtp->logger, LOGGER_DEBUG,
|
||||||
} else {
|
"raop_rtp audio: now = %8.6f, ntp = %8.6f, latency = %9.6f, ts = %8.6f, rtp_time=%u seqnum = %u",
|
||||||
double elapsed_time = raop_rtp->rtp_clock_rate * (rtp64_timestamp - raop_rtp->rtp_start_time) + sync_adjustment
|
(double) ntp_now / SEC, (double) audio_data.ntp_time_local / SEC, (double) latency / SEC,
|
||||||
+ DELAY_AAC * SECOND_IN_NSECS;
|
(double) audio_data.ntp_time_remote /SEC, rtp_timestamp, seqnum);
|
||||||
audio_data.ntp_time_local = raop_rtp->ntp_start_time + (uint64_t) elapsed_time;
|
|
||||||
audio_data.ntp_time_remote = raop_ntp_convert_local_time(raop_rtp->ntp, audio_data.ntp_time_local);
|
|
||||||
audio_data.sync_status = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raop_rtp->callbacks.audio_process(raop_rtp->callbacks.cls, raop_rtp->ntp, &audio_data);
|
raop_rtp->callbacks.audio_process(raop_rtp->callbacks.cls, raop_rtp->ntp, &audio_data);
|
||||||
free(payload);
|
free(payload);
|
||||||
if (logger_debug) {
|
|
||||||
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_local);
|
|
||||||
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_local / SEC, (double) latency / SEC,
|
|
||||||
(uint32_t) rtp64_timestamp, seqnum);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle possible resend requests */
|
/* Handle possible resend requests */
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ raop_rtp_mirror_thread(void *arg)
|
|||||||
const char h265[] = "h265";
|
const char h265[] = "h265";
|
||||||
bool unsupported_codec = false;
|
bool unsupported_codec = false;
|
||||||
bool video_stream_suspended = false;
|
bool video_stream_suspended = false;
|
||||||
|
bool first_packet = true;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
@@ -327,6 +328,11 @@ raop_rtp_mirror_thread(void *arg)
|
|||||||
}
|
}
|
||||||
ntp_timestamp_raw = byteutils_get_long(packet, 8);
|
ntp_timestamp_raw = byteutils_get_long(packet, 8);
|
||||||
ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
|
ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
|
||||||
|
if (first_packet) {
|
||||||
|
uint64_t offset = raop_ntp_get_local_time() - ntp_timestamp_remote;
|
||||||
|
raop_ntp_set_video_arrival_offset(raop_rtp_mirror->ntp, &offset);
|
||||||
|
first_packet = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* packet[4] + packet[5] identify the payload type: values seen are: *
|
/* packet[4] + packet[5] identify the payload type: values seen are: *
|
||||||
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
|
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
|
||||||
@@ -389,10 +395,10 @@ raop_rtp_mirror_thread(void *arg)
|
|||||||
|
|
||||||
ntp_timestamp_local = raop_ntp_convert_remote_time(raop_rtp_mirror->ntp, ntp_timestamp_remote);
|
ntp_timestamp_local = raop_ntp_convert_remote_time(raop_rtp_mirror->ntp, ntp_timestamp_remote);
|
||||||
if (logger_debug) {
|
if (logger_debug) {
|
||||||
uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp_mirror->ntp);
|
uint64_t ntp_now = raop_ntp_get_local_time();
|
||||||
int64_t latency = ((int64_t) ntp_now) - ((int64_t) ntp_timestamp_local);
|
int64_t latency = (ntp_timestamp_local ? ((int64_t) ntp_now) - ((int64_t) ntp_timestamp_local) : 0);
|
||||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||||
"raop_rtp video: now = %8.6f, ntp = %8.6f, latency = %8.6f, ts = %8.6f, %s %s",
|
"raop_rtp video: now = %8.6f, ntp = %8.6f, latency = %9.6f, ts = %8.6f, %s %s",
|
||||||
(double) ntp_now / SEC, (double) ntp_timestamp_local / SEC, (double) latency / SEC,
|
(double) ntp_now / SEC, (double) ntp_timestamp_local / SEC, (double) latency / SEC,
|
||||||
(double) ntp_timestamp_remote / SEC, packet_description, h265_video ? h265 : h264);
|
(double) ntp_timestamp_remote / SEC, packet_description, h265_video ? h265 : h264);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1658,7 +1658,8 @@ extern "C" void audio_process (void *cls, raop_ntp_t *ntp, audio_decode_struct *
|
|||||||
}
|
}
|
||||||
if (use_audio) {
|
if (use_audio) {
|
||||||
if (!remote_clock_offset) {
|
if (!remote_clock_offset) {
|
||||||
remote_clock_offset = data->ntp_time_local - data->ntp_time_remote;
|
uint64_t local_time = (data->ntp_time_local ? data->ntp_time_local : get_local_time());
|
||||||
|
remote_clock_offset = local_time - data->ntp_time_remote;
|
||||||
}
|
}
|
||||||
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
|
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
|
||||||
switch (data->ct) {
|
switch (data->ct) {
|
||||||
@@ -1686,7 +1687,8 @@ extern "C" void video_process (void *cls, raop_ntp_t *ntp, video_decode_struct *
|
|||||||
}
|
}
|
||||||
if (use_video) {
|
if (use_video) {
|
||||||
if (!remote_clock_offset) {
|
if (!remote_clock_offset) {
|
||||||
remote_clock_offset = data->ntp_time_local - data->ntp_time_remote;
|
uint64_t local_time = (data->ntp_time_local ? data->ntp_time_local : get_local_time());
|
||||||
|
remote_clock_offset = local_time - data->ntp_time_remote;
|
||||||
}
|
}
|
||||||
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
|
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
|
||||||
video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote));
|
video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote));
|
||||||
|
|||||||
Reference in New Issue
Block a user