Introduce snd_pcm_lib_frames_to_timespec64() to replace the calculation audio_nsecs = div_u64(audio_frames * 1000000000LL, runtime->rate); which overflows after a playback duration of 4.8 days @ 44100 HZ or 0.56 days @ 384000 Hz. The implementation of snd_pcm_lib_frames_to_timespec64() extends these limits, to 1.5 million years (@ 384000 Hz), or the 68 year limit of struct timespec on 32-bit systems. Fixes: 3179f6200188 ("ALSA: core: add .get_time_info") Fixes: 4eeaaeaea1ce ("ALSA: core: add hooks for audio timestamps") Signed-off-by: consult.awy@xxxxxxxxx Suggested-by: Jaroslav Kysela <perex@xxxxxxxx> Reviewed-by: Jaroslav Kysela <perex@xxxxxxxx> --- sound/core/pcm_lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 943f5396fc60..e0a6556d33ee 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -205,12 +205,19 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return 0; } +static inline void snd_pcm_lib_frames_to_timespec64(u64 frames, unsigned int rate, struct timespec64 *audio_tstamp) +{ + u32 remainder; + audio_tstamp->tv_sec = div_u64_rem(frames, rate, &remainder); + audio_tstamp->tv_nsec = div_u64(mul_u32_u32(remainder, NSEC_PER_SEC), rate); +} + static void update_audio_tstamp(struct snd_pcm_substream *substream, struct timespec64 *curr_tstamp, struct timespec64 *audio_tstamp) { struct snd_pcm_runtime *runtime = substream->runtime; - u64 audio_frames, audio_nsecs; + u64 audio_frames; struct timespec64 driver_tstamp; if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) @@ -233,9 +240,7 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream, else audio_frames += runtime->delay; } - audio_nsecs = div_u64(audio_frames * 1000000000LL, - runtime->rate); - *audio_tstamp = ns_to_timespec64(audio_nsecs); + snd_pcm_lib_frames_to_timespec64(audio_frames, runtime->rate, audio_tstamp); } if (runtime->status->audio_tstamp.tv_sec != audio_tstamp->tv_sec || -- 2.31.1