de-globalise flowcontrol ab_mutex,flush_mutex, first_packet_time_to_play, time_since_play_started
This commit is contained in:
@@ -79,16 +79,7 @@
|
||||
static uint32_t timestamp_epoch, last_timestamp,
|
||||
maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2
|
||||
// or 1.
|
||||
|
||||
// #define FRAME_BYTES(max_frames_per_packet) (4 * max_frames_per_packet)
|
||||
// maximal resampling shift - conservative
|
||||
//#define OUTFRAME_BYTES(max_frames_per_packet) (4 * (max_frames_per_packet + 3))
|
||||
|
||||
// static pthread_t player_thread = NULL;
|
||||
|
||||
// debug variables
|
||||
static int32_t last_seqno_read;
|
||||
|
||||
|
||||
// interthread variables
|
||||
static int fix_volume = 0x10000;
|
||||
static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
@@ -112,13 +103,6 @@ static int flush_requested = 0;
|
||||
static int64_t flush_rtp_timestamp;
|
||||
static uint64_t time_of_last_audio_packet;
|
||||
|
||||
// mutexes and condition variables
|
||||
static pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t flush_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t flowcontrol;
|
||||
|
||||
static int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds
|
||||
|
||||
// make timestamps and seqnos definitely monotonic
|
||||
|
||||
// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33
|
||||
@@ -181,7 +165,7 @@ static void ab_resync(rtsp_conn_info* conn) {
|
||||
conn->audio_buffer[i].sequence_number = 0;
|
||||
}
|
||||
ab_synced = 0;
|
||||
last_seqno_read = -1;
|
||||
conn->last_seqno_read = -1;
|
||||
ab_buffering = 1;
|
||||
}
|
||||
|
||||
@@ -486,13 +470,13 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r
|
||||
|
||||
// ignore a request to flush that has been made before the first packet...
|
||||
if (conn->packet_count == 0) {
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
flush_requested = 0;
|
||||
flush_rtp_timestamp = 0;
|
||||
pthread_mutex_unlock(&flush_mutex);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ab_mutex);
|
||||
pthread_mutex_lock(&conn->ab_mutex);
|
||||
conn->packet_count++;
|
||||
time_of_last_audio_packet = get_absolute_time_in_fp();
|
||||
if (conn->connection_state_to_output) { // if we are supposed to be processing these packets
|
||||
@@ -565,11 +549,11 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r
|
||||
|
||||
// pthread_mutex_lock(&ab_mutex);
|
||||
}
|
||||
int rc = pthread_cond_signal(&flowcontrol);
|
||||
int rc = pthread_cond_signal(&conn->flowcontrol);
|
||||
if (rc)
|
||||
debug(1, "Error signalling flowcontrol.");
|
||||
}
|
||||
pthread_mutex_unlock(&ab_mutex);
|
||||
pthread_mutex_unlock(&conn->ab_mutex);
|
||||
}
|
||||
|
||||
int32_t rand_in_range(int32_t exclusive_range_limit) {
|
||||
@@ -712,7 +696,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
abuf_t *curframe;
|
||||
int notified_buffer_empty = 0; // diagnostic only
|
||||
|
||||
pthread_mutex_lock(&ab_mutex);
|
||||
pthread_mutex_lock(&conn->ab_mutex);
|
||||
int wait;
|
||||
long dac_delay = 0; // long because alsa returns a long
|
||||
do {
|
||||
@@ -740,23 +724,23 @@ 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
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
flush_requested = 1;
|
||||
pthread_mutex_unlock(&flush_mutex);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
if (flush_requested == 1) {
|
||||
if (config.output->flush)
|
||||
config.output->flush();
|
||||
ab_resync(conn);
|
||||
first_packet_timestamp = 0;
|
||||
first_packet_time_to_play = 0;
|
||||
time_since_play_started = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
conn->time_since_play_started = 0;
|
||||
flush_requested = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&flush_mutex);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
|
||||
uint32_t flush_limit = 0;
|
||||
if (ab_synced) {
|
||||
@@ -849,25 +833,25 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
if (delta >= 0) {
|
||||
int64_t delta_fp_sec =
|
||||
(delta << 32) / config.output_rate; // int64_t which is positive
|
||||
first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
|
||||
conn->first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
|
||||
} else {
|
||||
int64_t abs_delta = -delta;
|
||||
int64_t delta_fp_sec =
|
||||
(abs_delta << 32) / config.output_rate; // int64_t which is positive
|
||||
first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
|
||||
conn->first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
|
||||
}
|
||||
|
||||
if (local_time_now >= first_packet_time_to_play) {
|
||||
if (local_time_now >= conn->first_packet_time_to_play) {
|
||||
debug(
|
||||
1,
|
||||
"First packet is late! It should have played before now. Flushing 0.1 seconds");
|
||||
player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio);
|
||||
player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio,conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first_packet_time_to_play != 0) {
|
||||
// recalculate first_packet_time_to_play -- the latency might change
|
||||
if (conn->first_packet_time_to_play != 0) {
|
||||
// recalculate conn->first_packet_time_to_play -- the latency might change
|
||||
int64_t delta = (first_packet_timestamp - reference_timestamp) +
|
||||
config.latency * conn->output_sample_ratio +
|
||||
config.audio_backend_latency_offset * config.output_rate;
|
||||
@@ -875,32 +859,32 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
if (delta >= 0) {
|
||||
int64_t delta_fp_sec =
|
||||
(delta << 32) / config.output_rate; // int64_t which is positive
|
||||
first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
|
||||
conn->first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
|
||||
} else {
|
||||
int64_t abs_delta = -delta;
|
||||
int64_t delta_fp_sec =
|
||||
(abs_delta << 32) / config.output_rate; // int64_t which is positive
|
||||
first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
|
||||
conn->first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
|
||||
}
|
||||
|
||||
int64_t max_dac_delay = config.output_rate / 10;
|
||||
int64_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC
|
||||
|
||||
if (local_time_now >= first_packet_time_to_play) {
|
||||
if (local_time_now >= conn->first_packet_time_to_play) {
|
||||
// we've gone past the time...
|
||||
// debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp
|
||||
// of %llx and dac_delay of %d and %d packets;
|
||||
// flush.",(((tn-first_packet_time_to_play)*config.output_rate)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read,
|
||||
// flush.",(((tn-conn->first_packet_time_to_play)*config.output_rate)>>32)+dac_delay,tn,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read,
|
||||
// ab_write));
|
||||
|
||||
if (config.output->flush)
|
||||
config.output->flush();
|
||||
ab_resync(conn);
|
||||
first_packet_timestamp = 0;
|
||||
first_packet_time_to_play = 0;
|
||||
time_since_play_started = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
conn->time_since_play_started = 0;
|
||||
} else {
|
||||
// first_packet_time_to_play is definitely later than local_time_now
|
||||
// conn->first_packet_time_to_play is definitely later than local_time_now
|
||||
if ((config.output->delay) && (have_sent_prefiller_silence != 0)) {
|
||||
int resp = config.output->delay(&dac_delay);
|
||||
if (resp != 0) {
|
||||
@@ -910,19 +894,19 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
} else
|
||||
dac_delay = 0;
|
||||
int64_t gross_frame_gap =
|
||||
((first_packet_time_to_play - local_time_now) * config.output_rate) >> 32;
|
||||
((conn->first_packet_time_to_play - local_time_now) * config.output_rate) >> 32;
|
||||
int64_t exact_frame_gap = gross_frame_gap - dac_delay;
|
||||
if (exact_frame_gap < 0) {
|
||||
// we've gone past the time...
|
||||
// debug(1,"Run a bit past the exact start time by %lld frames, with time now of
|
||||
// %llx, fpttp of %llx and dac_delay of %d and %d packets;
|
||||
// flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read,
|
||||
// flush.",-exact_frame_gap,tn,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read,
|
||||
// ab_write));
|
||||
if (config.output->flush)
|
||||
config.output->flush();
|
||||
ab_resync(conn);
|
||||
first_packet_timestamp = 0;
|
||||
first_packet_time_to_play = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
} else {
|
||||
int64_t fs = filler_size;
|
||||
if (fs > (max_dac_delay - dac_delay))
|
||||
@@ -1052,7 +1036,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
time_of_wakeup.tv_sec = sec;
|
||||
time_of_wakeup.tv_nsec = nsec;
|
||||
|
||||
pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup);
|
||||
pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup);
|
||||
// int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup);
|
||||
// if (rc!=0)
|
||||
// debug(1,"pthread_cond_timedwait returned error code %d.",rc);
|
||||
@@ -1063,13 +1047,13 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
struct timespec time_to_wait;
|
||||
time_to_wait.tv_sec = sec;
|
||||
time_to_wait.tv_nsec = nsec;
|
||||
pthread_cond_timedwait_relative_np(&flowcontrol, &ab_mutex, &time_to_wait);
|
||||
pthread_cond_timedwait_relative_np(&conn->flowcontrol, &conn->ab_mutex, &time_to_wait);
|
||||
#endif
|
||||
}
|
||||
} while (wait);
|
||||
|
||||
if (conn->player_thread_please_stop) {
|
||||
pthread_mutex_unlock(&ab_mutex);
|
||||
pthread_mutex_unlock(&conn->ab_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1097,7 +1081,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) {
|
||||
}
|
||||
curframe->ready = 0;
|
||||
ab_read = SUCCESSOR(ab_read);
|
||||
pthread_mutex_unlock(&ab_mutex);
|
||||
pthread_mutex_unlock(&conn->ab_mutex);
|
||||
return curframe;
|
||||
}
|
||||
|
||||
@@ -1500,8 +1484,8 @@ static void *player_thread_func(void *arg) {
|
||||
play_number++;
|
||||
if (inframe->timestamp == 0) {
|
||||
// debug(1,"Player has a supplied silent frame.");
|
||||
last_seqno_read =
|
||||
(SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder
|
||||
conn->last_seqno_read =
|
||||
(SUCCESSOR(conn->last_seqno_read) & 0xffff); // manage the packet out of sequence minder
|
||||
config.output->play(silence, conn->max_frames_per_packet * conn->output_sample_ratio);
|
||||
} else {
|
||||
|
||||
@@ -1641,18 +1625,18 @@ static void *player_thread_func(void *arg) {
|
||||
int amount_to_stuff = 0;
|
||||
|
||||
// check sequencing
|
||||
if (last_seqno_read == -1)
|
||||
last_seqno_read =
|
||||
if (conn->last_seqno_read == -1)
|
||||
conn->last_seqno_read =
|
||||
inframe->sequence_number; // int32_t from seq_t, i.e. uint16_t, so okay.
|
||||
else {
|
||||
last_seqno_read =
|
||||
SUCCESSOR(last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
|
||||
conn->last_seqno_read =
|
||||
SUCCESSOR(conn->last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
|
||||
if (inframe->sequence_number !=
|
||||
last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay
|
||||
conn->last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay
|
||||
debug(1, "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u "
|
||||
"and ab_write: %u.",
|
||||
last_seqno_read, inframe->sequence_number, ab_read, ab_write);
|
||||
last_seqno_read = inframe->sequence_number; // reset warning...
|
||||
conn->last_seqno_read, inframe->sequence_number, ab_read, ab_write);
|
||||
conn->last_seqno_read = inframe->sequence_number; // reset warning...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1725,10 +1709,10 @@ static void *player_thread_func(void *arg) {
|
||||
// calculate the time elapsed since the play session started.
|
||||
|
||||
if (amount_to_stuff) {
|
||||
if ((local_time_now) && (first_packet_time_to_play) &&
|
||||
(local_time_now >= first_packet_time_to_play)) {
|
||||
if ((local_time_now) && (conn->first_packet_time_to_play) &&
|
||||
(local_time_now >= conn->first_packet_time_to_play)) {
|
||||
|
||||
int64_t tp = (local_time_now - first_packet_time_to_play) >>
|
||||
int64_t tp = (local_time_now - conn->first_packet_time_to_play) >>
|
||||
32; // seconds int64_t from uint64_t which is always positive, so ok
|
||||
|
||||
if (tp < 5)
|
||||
@@ -1810,7 +1794,7 @@ static void *player_thread_func(void *arg) {
|
||||
"resyncing. Error: %lld.",
|
||||
sync_error_out_of_bounds, sync_error);
|
||||
sync_error_out_of_bounds = 0;
|
||||
player_flush(nt);
|
||||
player_flush(nt,conn);
|
||||
}
|
||||
} else {
|
||||
sync_error_out_of_bounds = 0;
|
||||
@@ -2011,7 +1995,7 @@ static void *player_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
// takes the volume as specified by the airplay protocol
|
||||
void player_volume(double airplay_volume) {
|
||||
void player_volume(double airplay_volume, rtsp_conn_info* conn) {
|
||||
|
||||
// The volume ranges -144.0 (mute) or -30 -- 0. See
|
||||
// http://git.zx2c4.com/Airtunes2/about/#setting-volume
|
||||
@@ -2203,13 +2187,13 @@ void player_volume(double airplay_volume) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void player_flush(int64_t timestamp) {
|
||||
void player_flush(int64_t timestamp, rtsp_conn_info* conn) {
|
||||
debug(3, "Flush requested up to %u. It seems as if 0 is special.", timestamp);
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
pthread_mutex_lock(&conn->flush_mutex);
|
||||
flush_requested = 1;
|
||||
// if (timestamp!=0)
|
||||
flush_rtp_timestamp = timestamp; // flush all packets up to (and including?) this
|
||||
pthread_mutex_unlock(&flush_mutex);
|
||||
pthread_mutex_unlock(&conn->flush_mutex);
|
||||
play_segment_reference_frame = 0;
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('pfls', NULL, 0, 1);
|
||||
@@ -2229,18 +2213,25 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) {
|
||||
send_ssnc_metadata('pbeg', NULL, 0, 1);
|
||||
#endif
|
||||
|
||||
|
||||
int rc = pthread_mutex_init(&conn->ab_mutex, NULL);
|
||||
if (rc)
|
||||
debug(1, "Error initialising ab_mutex.");
|
||||
rc = pthread_mutex_init(&conn->flush_mutex, NULL);
|
||||
if (rc)
|
||||
debug(1, "Error initialising flush_mutex.");
|
||||
// set the flowcontrol condition variable to wait on a monotonic clock
|
||||
#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
|
||||
pthread_condattr_t attr;
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it.
|
||||
int rc = pthread_cond_init(&flowcontrol, &attr);
|
||||
rc = pthread_cond_init(&conn->flowcontrol, &attr);
|
||||
#endif
|
||||
#ifdef COMPILE_FOR_OSX
|
||||
int rc = pthread_cond_init(&flowcontrol, NULL);
|
||||
rc = pthread_cond_init(&conn->flowcontrol, NULL);
|
||||
#endif
|
||||
if (rc)
|
||||
debug(1, "Error initialising condition variable.");
|
||||
debug(1, "Error initialising flowcontrol condition variable.");
|
||||
config.output->start(config.output_rate, config.output_format);
|
||||
size_t size = (PTHREAD_STACK_MIN + 256 * 1024);
|
||||
pthread_attr_t tattr;
|
||||
@@ -2258,14 +2249,20 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) {
|
||||
// debug(1,"Trying to stop a non-existent player thread");
|
||||
// else {
|
||||
conn->player_thread_please_stop = 1;
|
||||
pthread_cond_signal(&flowcontrol); // tell it to give up
|
||||
pthread_cond_signal(&conn->flowcontrol); // tell it to give up
|
||||
pthread_join(*player_thread, NULL);
|
||||
#ifdef CONFIG_METADATA
|
||||
send_ssnc_metadata('pend', NULL, 0, 1);
|
||||
#endif
|
||||
command_stop();
|
||||
int rc = pthread_cond_destroy(&flowcontrol);
|
||||
int rc = pthread_cond_destroy(&conn->flowcontrol);
|
||||
if (rc)
|
||||
debug(1, "Error destroying condition variable.");
|
||||
debug(1, "Error destroying flowcontrol condition variable.");
|
||||
rc = pthread_mutex_destroy(&conn->flush_mutex);
|
||||
if (rc)
|
||||
debug(1, "Error destroying flush_mutex variable.");
|
||||
rc = pthread_mutex_destroy(&conn->ab_mutex);
|
||||
if (rc)
|
||||
debug(1, "Error destroying ab_mutex variable.");
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -61,11 +61,15 @@ typedef struct {
|
||||
int shutdown_requested;
|
||||
int connection_state_to_output;
|
||||
int player_thread_please_stop;
|
||||
int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds
|
||||
// stats
|
||||
uint64_t missing_packets, late_packets, too_late_packets, resend_requests;
|
||||
int decoder_in_use;
|
||||
// debug variables
|
||||
int32_t last_seqno_read;
|
||||
// mutexes and condition variables
|
||||
pthread_cond_t flowcontrol;
|
||||
pthread_mutex_t ab_mutex,flush_mutex;
|
||||
|
||||
#ifdef HAVE_LIBMBEDTLS
|
||||
mbedtls_aes_context dctx;
|
||||
@@ -86,8 +90,8 @@ int32_t seq_diff(seq_t a, seq_t b);
|
||||
int player_play(pthread_t *thread, rtsp_conn_info* conn);
|
||||
void player_stop(pthread_t *thread, rtsp_conn_info* conn);
|
||||
|
||||
void player_volume(double f);
|
||||
void player_flush(int64_t timestamp);
|
||||
void player_volume(double f, rtsp_conn_info* conn);
|
||||
void player_flush(int64_t timestamp, rtsp_conn_info* conn);
|
||||
void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info* conn);
|
||||
|
||||
int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic
|
||||
|
||||
@@ -643,7 +643,7 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
|
||||
rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1
|
||||
rtptime--;
|
||||
// debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime);
|
||||
player_flush(rtptime);
|
||||
player_flush(rtptime,conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -684,7 +684,7 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
|
||||
}
|
||||
}
|
||||
// debug(1,"RTSP Flush Requested: %u.",rtptime);
|
||||
player_flush(rtptime);
|
||||
player_flush(rtptime,conn);
|
||||
resp->respcode = 200;
|
||||
}
|
||||
|
||||
@@ -848,7 +848,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
|
||||
float volume = atof(cp + 8);
|
||||
if (config.ignore_volume_control == 0) {
|
||||
debug(2, "volume: %f\n", volume);
|
||||
player_volume(volume);
|
||||
player_volume(volume,conn);
|
||||
}
|
||||
#ifdef CONFIG_METADATA
|
||||
else { // if ignore volume is on...
|
||||
|
||||
Reference in New Issue
Block a user