static snd_pcm_uframes_t period_size_requested, buffer_size_requested;
static int set_period_size_request, set_buffer_size_request;
-static uint64_t time_of_first_frame;
+static uint64_t measurement_start_time;
+static uint64_t frames_played_at_measurement_start_time;
+
+static uint64_t measurement_time;
+static uint64_t frames_played_at_measurement_time;
+
static uint64_t frames_sent_for_playing;
+static uint64_t frame_index;
+static int measurement_data_is_valid;
static void help(void) {
printf(" -d output-device set the output device [default*|...]\n"
else
sample_format = i_sample_format;
- time_of_first_frame = 0;
- frames_sent_for_playing = 0;
+ frame_index = 0;
+ measurement_data_is_valid = 0;
}
int delay(long *the_delay) {
snd_pcm_recover(alsa_handle, reply, 1);
}
} else {
- time_of_first_frame = 0;
+ 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
}
int get_rate_information(uint64_t *elapsed_time, uint64_t *frames_played) {
- long frames_left = 0;
- int result = delay(&frames_left);
- if (result >= 0) {
- *elapsed_time = get_absolute_time_in_fp()-time_of_first_frame;
- *frames_played = frames_sent_for_playing - frames_left;
+ if (measurement_data_is_valid) {
+ *elapsed_time = measurement_time - measurement_start_time;
+ *frames_played = frames_played_at_measurement_time - frames_played_at_measurement_start_time;
+ } else {
+ *elapsed_time = 0;
+ *frames_played = 0;
}
- return result;
+ return 0;
}
static void play(void *buf, int samples) {
if (ret == 0) {
debug_mutex_lock(&alsa_mutex, 10000, 1);
// snd_pcm_sframes_t current_delay = 0;
- int err;
+ int err, err2;
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) {
if ((err = snd_pcm_prepare(alsa_handle))) {
snd_pcm_recover(alsa_handle, err, 1);
debug(1, "Error preparing after underrun: \"%s\".", snd_strerror(err));
}
- time_of_first_frame = 0;
+ frame_index = 0; // we'll be starting over
+ measurement_data_is_valid = 0;
}
if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) ||
(snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) {
debug(1, "empty buffer being passed to pcm_writei -- skipping it");
if ((samples != 0) && (buf != NULL)) {
err = alsa_pcm_write(alsa_handle, buf, samples);
- if (time_of_first_frame == 0) {
- time_of_first_frame = get_absolute_time_in_fp();
- frames_sent_for_playing = 0;
- }
if (err < 0) {
+ frame_index = 0;
+ measurement_data_is_valid = 0;
debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples,
snd_strerror(err));
snd_pcm_recover(alsa_handle, err, 1);
}
- frames_sent_for_playing += samples;
+ if (frame_index==0) {
+ frames_sent_for_playing = samples;
+ } else {
+ frames_sent_for_playing += samples;
+ }
+ const uint64_t start_measurement_from_this_frame = (2*44100)/352; // two seconds of frames…
+ frame_index++;
+ if ((frame_index == start_measurement_from_this_frame) || (frame_index % 32 == 0)) {
+ long fl = 0;
+ err2 = snd_pcm_delay(alsa_handle,&fl);
+ if (err2 != 0) {
+ frame_index = 0;
+ measurement_data_is_valid = 0;
+ debug(1, "Error %d in delay(): \"%s\". Delay reported is %d frames.", err2,
+ snd_strerror(err2), fl);
+ snd_pcm_recover(alsa_handle, err2, 1);
+ }
+ uint64_t tf = get_absolute_time_in_fp();
+ frames_played_at_measurement_time = frames_sent_for_playing - fl;
+ if (frame_index == start_measurement_from_this_frame) {
+ frames_played_at_measurement_start_time = frames_played_at_measurement_time;
+ measurement_start_time = tf;
+ } else {
+ frames_played_at_measurement_time = frames_played_at_measurement_time;
+ measurement_time = tf;
+ measurement_data_is_valid = 1;
+ }
+ }
}
} else {
debug(1, "Error -- ALSA device in incorrect state (%d) for play.",
snd_pcm_recover(alsa_handle, err, 1);
debug(1, "Error preparing after play error: \"%s\".", snd_strerror(err));
}
- time_of_first_frame = 0;
+ frame_index = 0;
+ measurement_data_is_valid = 0;
}
debug_mutex_unlock(&alsa_mutex, 3);
}
// flush also closes the device
if ((derr = snd_pcm_close(alsa_handle)))
debug(1, "Error %d (\"%s\") closing the output device.", derr, snd_strerror(derr));
- time_of_first_frame = 0;
+ frame_index = 0;
+ measurement_data_is_valid = 0;
alsa_handle = NULL;
}
debug_mutex_unlock(&alsa_mutex, 3);