From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sat, 27 Mar 2021 15:37:29 +0000 (+0000) Subject: Be more careful with changing precision. Stop using snd_pcm_status_get_driver_htstamp. X-Git-Tag: 4.0-dev~95 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd4c429b5a8126c0fff276f41a41af771bec247e;p=thirdparty%2Fshairport-sync.git Be more careful with changing precision. Stop using snd_pcm_status_get_driver_htstamp. --- diff --git a/audio_alsa.c b/audio_alsa.c index 69722d12..45a51321 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -1456,18 +1456,23 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, if (ret == 0) { // must be 1.1 or later to use snd_pcm_status_get_driver_htstamp -#if SND_LIB_MINOR == 0 +//#if SND_LIB_MINOR == 0 snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp); -#else - snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &update_timestamp); -#endif +//#else +// snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &update_timestamp); +//#endif *state = snd_pcm_status_get_state(alsa_snd_pcm_status); if ((*state == SND_PCM_STATE_RUNNING) || (*state == SND_PCM_STATE_DRAINING)) { - uint64_t update_timestamp_ns = - update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec; + // uint64_t update_timestamp_ns = + // update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec; + + uint64_t update_timestamp_ns = update_timestamp.tv_sec; + update_timestamp_ns = update_timestamp_ns * 1000000000; + update_timestamp_ns = update_timestamp_ns + update_timestamp.tv_nsec; + // if the update_timestamp is zero, we take this to mean that the device doesn't report // interrupt timings. (It could be that it's not a real hardware device.) @@ -1497,7 +1502,7 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, if (update_timestamp_ns == 0) { ret = snd_pcm_delay(alsa_handle, delay); } else { - *delay = snd_pcm_status_get_delay(alsa_snd_pcm_status); + snd_pcm_sframes_t delay_temp = snd_pcm_status_get_delay(alsa_snd_pcm_status); /* // It seems that the alsa library uses CLOCK_REALTIME before 1.0.28, even though @@ -1514,11 +1519,15 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, else clock_gettime(CLOCK_REALTIME, &tn); - uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec; + // uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec; + uint64_t time_now_ns = tn.tv_sec; + time_now_ns = time_now_ns * 1000000000; + time_now_ns = time_now_ns + tn.tv_nsec; + // see if it's stalled - if ((stall_monitor_start_time != 0) && (stall_monitor_frame_count == *delay)) { + if ((stall_monitor_start_time != 0) && (stall_monitor_frame_count == delay_temp)) { // hasn't outputted anything since the last call to delay() if (((update_timestamp_ns - stall_monitor_start_time) > stall_monitor_error_threshold) || @@ -1539,19 +1548,27 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, } } else { stall_monitor_start_time = update_timestamp_ns; - stall_monitor_frame_count = *delay; + stall_monitor_frame_count = delay_temp; } if (ret == 0) { uint64_t delta = time_now_ns - update_timestamp_ns; - uint64_t frames_played_since_last_interrupt = - ((uint64_t)config.output_rate * delta) / 1000000000; +// uint64_t frames_played_since_last_interrupt = +// ((uint64_t)config.output_rate * delta) / 1000000000; + + uint64_t frames_played_since_last_interrupt = config.output_rate; + frames_played_since_last_interrupt = frames_played_since_last_interrupt * delta; + frames_played_since_last_interrupt = frames_played_since_last_interrupt / 1000000000; + + snd_pcm_sframes_t frames_played_since_last_interrupt_sized = frames_played_since_last_interrupt; - - *delay = *delay - frames_played_since_last_interrupt_sized; + if ((frames_played_since_last_interrupt_sized < 0) || ((uint64_t)frames_played_since_last_interrupt_sized != frames_played_since_last_interrupt)) + debug(1,"overflow resizing frames_played_since_last_interrupt % " PRIx64 " to frames_played_since_last_interrupt %lx.", frames_played_since_last_interrupt, frames_played_since_last_interrupt_sized); + delay_temp = delay_temp - frames_played_since_last_interrupt_sized; } + *delay = delay_temp; } } else { // not running, thus no delay information, thus can't check for // stall