Generate error messages if there is a problem with getting the delay, and pay attention to it in the player thread.
This commit is contained in:
+11
-11
@@ -876,7 +876,8 @@ int delay(long *the_delay) {
|
||||
} else {
|
||||
pthread_cleanup_debug_mutex_lock(&alsa_mutex, 10000, 1);
|
||||
int derr;
|
||||
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING) {
|
||||
snd_pcm_state_t dac_state = snd_pcm_state(alsa_handle);
|
||||
if (dac_state == SND_PCM_STATE_RUNNING) {
|
||||
*the_delay = 0; // just to see what happens
|
||||
reply = snd_pcm_delay(alsa_handle, the_delay);
|
||||
if (reply != 0) {
|
||||
@@ -893,19 +894,18 @@ int delay(long *the_delay) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reply = -EIO; // shomething is wrong
|
||||
frame_index = 0; // we'll be starting over...
|
||||
measurement_data_is_valid = 0;
|
||||
|
||||
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) {
|
||||
*the_delay = 0;
|
||||
reply = 0; // no error
|
||||
if (dac_state == SND_PCM_STATE_PREPARED) {
|
||||
debug(1,"delay not available -- state is SND_PCM_STATE_PREPARED");
|
||||
} else {
|
||||
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) {
|
||||
*the_delay = 0;
|
||||
reply = 0; // no error
|
||||
if (dac_state == SND_PCM_STATE_XRUN) {
|
||||
debug(1,"delay not available -- state is SND_PCM_STATE_XRUN");
|
||||
} else {
|
||||
reply = -EIO;
|
||||
debug(1, "Error -- ALSA delay(): bad state: %d.", snd_pcm_state(alsa_handle));
|
||||
|
||||
debug(1, "Error -- ALSA delay(): bad state: %d.", dac_state);
|
||||
}
|
||||
if ((derr = snd_pcm_prepare(alsa_handle))) {
|
||||
snd_pcm_recover(alsa_handle, derr, 1);
|
||||
@@ -917,7 +917,7 @@ int delay(long *the_delay) {
|
||||
pthread_cleanup_pop(0);
|
||||
// here, occasionally pretend there's a problem with pcm_get_delay()
|
||||
// if ((random() % 100000) < 3) // keep it pretty rare
|
||||
// reply = -EPERM; // pretend something bad has happened
|
||||
// reply = -EIO; // pretend something bad has happened
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
@@ -1005,7 +1005,7 @@ static int play(void *buf, int samples) {
|
||||
measurement_time = get_absolute_time_in_fp();
|
||||
frames_played_at_measurement_time = frames_sent_for_playing - fl;
|
||||
if (frame_index == start_measurement_from_this_frame) {
|
||||
debug(1, "Start frame counting");
|
||||
// debug(1, "Start frame counting");
|
||||
frames_played_at_measurement_start_time = frames_played_at_measurement_time;
|
||||
measurement_start_time = measurement_time;
|
||||
measurement_data_is_valid = 1;
|
||||
|
||||
@@ -1000,9 +1000,9 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
|
||||
int64_t max_dac_delay = config.output_rate / 10; // so the lead-in time must be greater
|
||||
// than this, say 0.2 sec, to allow for
|
||||
// dynamic adjustment
|
||||
int64_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC
|
||||
|
||||
// dynamic adjustment
|
||||
int64_t filler_size = max_dac_delay;
|
||||
|
||||
if (local_time_now >= conn->first_packet_time_to_play) {
|
||||
// debug(1,"Gone past starting time");
|
||||
have_sent_prefiller_silence = 1;
|
||||
@@ -1025,87 +1025,90 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
} else {
|
||||
// do some calculations
|
||||
int64_t lead_time = conn->first_packet_time_to_play - local_time_now;
|
||||
int64_t lead_in_time =
|
||||
// an audio_backend_silent_lead_in_time of less than zero means start filling ASAP
|
||||
int64_t lead_in_time = -1;
|
||||
if (config.audio_backend_silent_lead_in_time>=0)
|
||||
lead_in_time =
|
||||
(int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)0x100000000);
|
||||
// debug(1,"Lead time is %llx at fpttp
|
||||
// %llx.",lead_time,conn->first_packet_time_to_play);
|
||||
// an audio_backend_silent_lead_in_time of less than zero means start filling ASAP
|
||||
if ((lead_in_time < 0) || (lead_time <= lead_in_time)) {
|
||||
// debug(1,"Lead time is %" PRIx64 ", lead-in time is %" PRIx64 " at fpttp %llx.",lead_time,conn->first_packet_time_to_play);
|
||||
|
||||
// debug(1,"Checking");
|
||||
if (config.output->delay) {
|
||||
// conn->first_packet_time_to_play is definitely later than local_time_now
|
||||
if (have_sent_prefiller_silence != 0) {
|
||||
int resp = config.output->delay(&dac_delay);
|
||||
|
||||
if (resp != 0) {
|
||||
debug(1, "Error %d getting dac_delay in buffer_get_frame.", resp);
|
||||
dac_delay = 0;
|
||||
}
|
||||
} else {
|
||||
dac_delay = 0;
|
||||
}
|
||||
int64_t gross_frame_gap =
|
||||
((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 past 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,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read,
|
||||
// ab_write));
|
||||
if (config.output->flush)
|
||||
config.output->flush();
|
||||
ab_resync(conn);
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
} else {
|
||||
int64_t fs = filler_size;
|
||||
if (fs > (max_dac_delay - dac_delay))
|
||||
fs = max_dac_delay - dac_delay;
|
||||
if (fs < 0) {
|
||||
debug(2,
|
||||
"frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld",
|
||||
max_dac_delay, dac_delay);
|
||||
fs = 0;
|
||||
}
|
||||
if ((exact_frame_gap <= fs) ||
|
||||
(exact_frame_gap <= conn->max_frames_per_packet * 2)) {
|
||||
fs = exact_frame_gap;
|
||||
// debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is
|
||||
// %d,
|
||||
// with %d packets, ab_read is %04x, ab_write is
|
||||
// %04x.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read,
|
||||
// ab_write),ab_read,ab_write);
|
||||
conn->ab_buffering = 0;
|
||||
}
|
||||
void *silence;
|
||||
// if (fs==0)
|
||||
// debug(2,"Zero length silence buffer needed with gross_frame_gap of %lld and
|
||||
// dac_delay of %lld.",gross_frame_gap,dac_delay);
|
||||
// the fs (number of frames of silence to play) can be zero in the DAC doesn't
|
||||
// start
|
||||
// outputting frames for a while -- it could get loaded up but not start
|
||||
// responding
|
||||
// for many milliseconds.
|
||||
if (fs > 0) {
|
||||
silence = malloc(conn->output_bytes_per_frame * fs);
|
||||
if (silence == NULL)
|
||||
debug(1, "Failed to allocate %d byte silence buffer.", fs);
|
||||
else {
|
||||
memset(silence, 0, conn->output_bytes_per_frame * fs);
|
||||
// debug(1,"Frames to start: %llu, DAC delay %d, buffer: %d
|
||||
// packets.",exact_frame_gap,dac_delay,seq_diff(conn->ab_read,
|
||||
// conn->ab_write, conn->ab_read));
|
||||
|
||||
//debug (1,"Play %" PRId64 " frames of silence.")
|
||||
config.output->play(silence, fs);
|
||||
free(silence);
|
||||
int resp = 0;
|
||||
dac_delay = 0;
|
||||
if (have_sent_prefiller_silence != 0)
|
||||
resp = config.output->delay(&dac_delay);
|
||||
if (resp == 0) {
|
||||
int64_t gross_frame_gap =
|
||||
((conn->first_packet_time_to_play - local_time_now) * config.output_rate) >>
|
||||
32;
|
||||
int64_t exact_frame_gap = gross_frame_gap - dac_delay;
|
||||
// debug(1,"Exact and gross frame gaps are %" PRId64 " and %" PRId64 " frames, and the dac delay is %ld.", exact_frame_gap, gross_frame_gap, dac_delay);
|
||||
if (exact_frame_gap < 0) {
|
||||
// we've gone past the time...
|
||||
// debug(1,"Run past time.");
|
||||
|
||||
// this might happen if a big clock adjustment was made at just the wrong time.
|
||||
|
||||
debug(1,"Run a bit past the exact start time by %" PRId64 " frames.",-exact_frame_gap);
|
||||
if (config.output->flush)
|
||||
config.output->flush();
|
||||
ab_resync(conn);
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->first_packet_time_to_play = 0;
|
||||
} else {
|
||||
int64_t fs = filler_size;
|
||||
if (fs > (max_dac_delay - dac_delay))
|
||||
fs = max_dac_delay - dac_delay;
|
||||
if (fs < 0) {
|
||||
// this could happen if the dac delay mysteriously grows between samples, which could happen in a transition between having no interpolation and having interpolated buffer numbers.
|
||||
debug(2,
|
||||
"frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld",
|
||||
max_dac_delay, dac_delay);
|
||||
fs = 0;
|
||||
}
|
||||
if ((exact_frame_gap <= fs) ||
|
||||
(exact_frame_gap <= conn->max_frames_per_packet * 2)) {
|
||||
fs = exact_frame_gap;
|
||||
// debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is
|
||||
// %d,
|
||||
// with %d packets, ab_read is %04x, ab_write is
|
||||
// %04x.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read,
|
||||
// ab_write),ab_read,ab_write);
|
||||
conn->ab_buffering = 0;
|
||||
}
|
||||
void *silence;
|
||||
// if (fs==0)
|
||||
// debug(2,"Zero length silence buffer needed with gross_frame_gap of %lld and
|
||||
// dac_delay of %lld.",gross_frame_gap,dac_delay);
|
||||
// the fs (number of frames of silence to play) can be zero in the DAC doesn't
|
||||
// start
|
||||
// outputting frames for a while -- it could get loaded up but not start
|
||||
// responding
|
||||
// for many milliseconds.
|
||||
if (fs > 0) {
|
||||
silence = malloc(conn->output_bytes_per_frame * fs);
|
||||
if (silence == NULL)
|
||||
debug(1, "Failed to allocate %d byte silence buffer.", fs);
|
||||
else {
|
||||
memset(silence, 0, conn->output_bytes_per_frame * fs);
|
||||
// debug(1,"Frames to start: %llu, DAC delay %d, buffer: %d
|
||||
// packets.",exact_frame_gap,dac_delay,seq_diff(conn->ab_read,
|
||||
// conn->ab_write, conn->ab_read));
|
||||
config.output->play(silence, fs);
|
||||
debug(1,"Sent %" PRId64 " frames of silence",fs);
|
||||
free(silence);
|
||||
}
|
||||
}
|
||||
have_sent_prefiller_silence =
|
||||
1; // even if we haven't sent silence because it's zero frames long...
|
||||
}
|
||||
have_sent_prefiller_silence =
|
||||
1; // even if we haven't sent silence because it's zero frames long...
|
||||
} else {
|
||||
// debug(1, "Unable to get dac delay.");
|
||||
}
|
||||
} else {
|
||||
// no delay function on back end -- just send the prefiller silence
|
||||
|
||||
Reference in New Issue
Block a user