typedef struct audio_buffer_entry { // decoded audio packets
int ready;
- uint32_t timestamp;
+ int64_t timestamp;
seq_t sequence_number;
signed short *data;
int length; // the length of the decoded data
// mutex-protected variables
static seq_t ab_read, ab_write;
static int ab_buffering = 1, ab_synced = 0;
-static uint32_t first_packet_timestamp = 0;
+static int64_t first_packet_timestamp = 0;
static int flush_requested = 0;
-static uint32_t flush_rtp_timestamp;
+static int64_t flush_rtp_timestamp;
static uint64_t time_of_last_audio_packet;
static int shutdown_requested;
// 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^64 frames
-// which is about 4*10^8 * 1,000 seconds at 384,000 frames per second -- about 4 trillion seconds or over 100,000 years.
+// 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
-uint64_t monotonic_timestamp(uint32_t timestamp) {
- uint64_t previous_value;
- uint64_t return_value;
+int64_t monotonic_timestamp(uint32_t timestamp) {
+ int64_t previous_value;
+ int64_t return_value;
if (timestamp_epoch==0) {
if (timestamp>maximum_timestamp_interval)
timestamp_epoch=1;
if ((return_value-previous_value)>maximum_timestamp_interval)
debug(1,"interval between successive rtptimes greater than allowed!");
}
+ if (return_value<0)
+ debug(1,"monotonic rtptime is negative!");
return return_value;
}
free(audio_buffer[i].data);
}
-void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len) {
+void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) {
// ignore a request to flush that has been made before the first packet...
if (packet_count==0) {
// debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp);
if ((flush_rtp_timestamp != 0) &&
- ((timestamp == flush_rtp_timestamp) || seq32_order(timestamp, flush_rtp_timestamp))) {
- debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to "
- "timestamp: %u.",
+ (timestamp <= flush_rtp_timestamp)) {
+ debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %lld, flushing to "
+ "timestamp: %lld.",
seqno, timestamp, flush_rtp_timestamp);
} else {
if ((flush_rtp_timestamp != 0x0) &&
- (!seq32_order(timestamp,
- flush_rtp_timestamp))) // if we have gone past the flush boundary time
+ (timestamp>flush_rtp_timestamp)) // if we have gone past the flush boundary time
flush_rtp_timestamp = 0x0;
abuf_t *abuf = 0;
}
if ((flush_rtp_timestamp != 0) &&
- ((curframe->timestamp == flush_rtp_timestamp) ||
- seq32_order(curframe->timestamp, flush_rtp_timestamp))) {
- debug(1, "Dropping flushed packet seqno %u, timestamp %u", curframe->sequence_number,
+ (curframe->timestamp <= flush_rtp_timestamp)) {
+ debug(1, "Dropping flushed packet seqno %u, timestamp %lld", curframe->sequence_number,
curframe->timestamp);
curframe->ready = 0;
flush_limit++;
ab_read = SUCCESSOR(ab_read);
}
- if ((flush_rtp_timestamp != 0) &&
- (!seq32_order(curframe->timestamp,
- flush_rtp_timestamp))) // if we have gone past the flush boundary time
+ if (curframe->timestamp>flush_rtp_timestamp)
flush_rtp_timestamp = 0;
}
} while ((flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0));
notified_buffer_empty=0; // at least one buffer now -- diagnostic only.
if (ab_buffering) { // if we are getting packets but not yet forwarding them to the player
int have_sent_prefiller_silence; // set true when we have sent some silent frames to the DAC
- uint32_t reference_timestamp;
+ 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);
if (first_packet_timestamp == 0) { // if this is the very first packet
// if would be in sync. To do this, we would give it a latency offset of -100 ms, i.e.
// -4410 frames.
- int64_t delta = ((int64_t)first_packet_timestamp - (int64_t)reference_timestamp)+config.latency+config.audio_backend_latency_offset; // uint32_t to int64_t is okay and int32t to int64t promotion is okay.
+ int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency+config.audio_backend_latency_offset;
if (delta>=0) {
- uint64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive
+ int64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive
first_packet_time_to_play=reference_timestamp_time+delta_fp_sec;
} else {
int64_t abs_delta = -delta;
- uint64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive
+ int64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive
first_packet_time_to_play=reference_timestamp_time-delta_fp_sec;
}
if (first_packet_time_to_play != 0) {
// recalculate first_packet_time_to_play -- the latency might change
- int64_t delta = ((int64_t)first_packet_timestamp - (int64_t)reference_timestamp)+config.latency+config.audio_backend_latency_offset; // uint32_t to int64_t is okay and int32t to int64t promotion is okay.
+ int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency+config.audio_backend_latency_offset;
if (delta>=0) {
- uint64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive
+ int64_t delta_fp_sec = (delta << 32) / 44100; // int64_t which is positive
first_packet_time_to_play=reference_timestamp_time+delta_fp_sec;
} else {
int64_t abs_delta = -delta;
- uint64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive
+ int64_t delta_fp_sec = (abs_delta << 32) / 44100; // int64_t which is positive
first_packet_time_to_play=reference_timestamp_time-delta_fp_sec;
}
int do_wait = 0; // don't wait unless we can really prove we must
if ((ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) {
do_wait = 1; // if the current frame exists and is ready, then wait unless it's time to let it go...
- uint32_t reference_timestamp;
+ 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); // all types okay
if (reference_timestamp) { // if we have a reference time
- uint32_t packet_timestamp = curframe->timestamp; // types okay
- int64_t delta = (int64_t)packet_timestamp - (int64_t)reference_timestamp; // uint32_t to int64_t is okay.
+ int64_t packet_timestamp = curframe->timestamp; // types okay
+ int64_t delta = packet_timestamp - reference_timestamp;
int64_t offset = config.latency + config.audio_backend_latency_offset -
config.audio_backend_buffer_desired_length; // all arguments are int32_t, so expression promotion okay
int64_t net_offset = delta + offset; // okay
#endif
#ifdef COMPILE_FOR_OSX
uint64_t sec = time_to_wait_for_wakeup_fp >> 32;
- ;
uint64_t nsec = ((time_to_wait_for_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
struct timespec time_to_wait;
time_to_wait.tv_sec = sec;
at_least_one_frame_seen = 1;
- uint32_t reference_timestamp;
+ 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); // types okay
#endif
}
-void player_flush(uint32_t timestamp) {
+void player_flush(int64_t timestamp) {
debug(3,"Flush requested up to %u. It seems as if 0 is special.",timestamp);
pthread_mutex_lock(&flush_mutex);
flush_requested = 1;
static int timing_socket; // local timing socket
//static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
-static uint32_t reference_timestamp;
+static int64_t reference_timestamp;
static uint64_t reference_timestamp_time;
static uint64_t remote_reference_timestamp_time;
// debug(3, "RTP: Packets out of sequence: expected: %d, got %d.", last_seqno, seqno);
last_seqno = seqno; // reset warning...
}
- uint32_t timestamp = ntohl(*(unsigned long *)(pktp + 4));
+ int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)));
// if (packet[1]&0x10)
// debug(1,"Audio packet Extension bit set.");
uint8_t packet[2048], *pktp;
struct timespec tn;
uint64_t remote_time_of_sync, local_time_now, remote_time_now;
- uint32_t sync_rtp_timestamp, rtp_timestamp_less_latency;
+ int64_t sync_rtp_timestamp, rtp_timestamp_less_latency;
ssize_t nread;
while (itr->please_stop==0) {
nread = recv(control_socket, packet, sizeof(packet), 0);
// debug(1,"Remote Sync Time: %0llx.",remote_time_of_sync);
- rtp_timestamp_less_latency = ntohl(*((uint32_t *)&packet[4]));
- sync_rtp_timestamp = ntohl(*((uint32_t *)&packet[16]));
+ rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])));
+ sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])));
if (config.use_negotiated_latencies) {
- uint32_t la = sync_rtp_timestamp-rtp_timestamp_less_latency+11025;
+ int64_t la = sync_rtp_timestamp-rtp_timestamp_less_latency+11025;
if (la!=config.latency) {
config.latency = la;
// debug(1,"Using negotiated latency of %u frames.",config.latency);
plen -= 4;
seq_t seqno = ntohs(*(unsigned short *)(pktp + 2));
- uint32_t timestamp = ntohl(*(unsigned long *)(pktp + 4));
+ int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)));
pktp += 12;
plen -= 12;
int64_t source_drift_usec;
if (play_segment_reference_frame!=0) {
- uint32_t reference_timestamp;
+ 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);
uint64_t frame_difference = 0;
request_sent = 0;
}
-void get_reference_timestamp_stuff(uint32_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time) {
+void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time) {
// types okay
pthread_mutex_lock(&reference_time_mutex);
*timestamp = reference_timestamp;