diff mbox series

[2/2] ALSA: Change calculation of audio time from frames

Message ID 20230216135806.1973959-1-consult.awy@gmail.com
State New
Headers show
Series [1/2] ALSA: pcm: generate default audio timestamp | expand

Commit Message

Alan Young Feb. 16, 2023, 1:58 p.m. UTC
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@gmail.com
---
 sound/core/pcm_lib.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
diff mbox series

Patch

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 ||