From 7e53d57e63aae80ed6b7237d519ead1bd7574cdb Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Jan 2026 11:19:04 +0100 Subject: [PATCH 1/4] compress_hw: fix formatting (compress_hw_avail64_from_32) Link: https://github.com/alsa-project/tinycompress/pull/30 Fixes: 72dd4bb ("compress_hw_get_hpointer: use SNDRV_COMPRESS_AVAIL64") Signed-off-by: Jaroslav Kysela --- src/lib/compress_hw.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index 02314cd..52550ef 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -225,14 +225,15 @@ static void compress_hw_close(void *data) } static void compress_hw_avail64_from_32(struct snd_compr_avail64 *avail64, - const struct snd_compr_avail *avail32) { - avail64->avail = avail32->avail; - - avail64->tstamp.byte_offset = avail32->tstamp.byte_offset; - avail64->tstamp.copied_total = avail32->tstamp.copied_total; - avail64->tstamp.pcm_frames = avail32->tstamp.pcm_frames; - avail64->tstamp.pcm_io_frames = avail32->tstamp.pcm_io_frames; - avail64->tstamp.sampling_rate = avail32->tstamp.sampling_rate; + const struct snd_compr_avail *avail32) +{ + avail64->avail = avail32->avail; + + avail64->tstamp.byte_offset = avail32->tstamp.byte_offset; + avail64->tstamp.copied_total = avail32->tstamp.copied_total; + avail64->tstamp.pcm_frames = avail32->tstamp.pcm_frames; + avail64->tstamp.pcm_io_frames = avail32->tstamp.pcm_io_frames; + avail64->tstamp.sampling_rate = avail32->tstamp.sampling_rate; } static int compress_hw_get_hpointer(void *data, From 9f5f8cc5c20694ba4f2d9d947c70c9e78ff6fd55 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Jan 2026 11:31:55 +0100 Subject: [PATCH 2/4] compress_ops: add magic and look for compress_plugin_mops symbol We need more validation of passed ops structure to allow further API changes in future. This change looks for compress_plugin_mops symbol in the dynamic plugin library to make sure that the new magic and new get_tstamp64 members are handled correctly. Link: https://github.com/alsa-project/tinycompress/pull/29 Link: https://github.com/alsa-project/tinycompress/pull/30 Fixes: 0bd5530 ("compress_ops: add get_tstamp64") Signed-off-by: Jaroslav Kysela --- include/tinycompress/compress_ops.h | 3 +++ src/lib/compress.c | 9 ++++++++- src/lib/compress_hw.c | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/tinycompress/compress_ops.h b/include/tinycompress/compress_ops.h index 290a831..e816632 100644 --- a/include/tinycompress/compress_ops.h +++ b/include/tinycompress/compress_ops.h @@ -8,6 +8,8 @@ #include "sound/compress_offload.h" #include "tinycompress.h" +#define COMPRESS_OPS_V2 0xadcc0002 /* version 2 magic */ + /* * struct compress_ops: * ops structure containing ops corresponding to exposed @@ -16,6 +18,7 @@ * done in compress_hw.c */ struct compress_ops { + unsigned int magic; /* version of this structure */ void *(*open_by_name)(const char *name, unsigned int flags, struct compr_config *config); void (*close)(void *compress_data); diff --git a/src/lib/compress.c b/src/lib/compress.c index cf0b295..1ff3dfe 100644 --- a/src/lib/compress.c +++ b/src/lib/compress.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include "tinycompress/tinycompress.h" #include "tinycompress/compress_ops.h" @@ -136,7 +137,7 @@ static int populate_compress_plugin_ops(struct compress *compress, const char *n return ret; } - compress->ops = dlsym(dl_hdl, "compress_plugin_ops"); + compress->ops = dlsym(dl_hdl, "compress_plugin_mops"); err = dlerror(); if (err) { fprintf(stderr, "%s: dlsym to ops failed, err = '%s'\n", @@ -144,6 +145,12 @@ static int populate_compress_plugin_ops(struct compress *compress, const char *n dlclose(dl_hdl); return ret; } + if (compress->ops->magic != COMPRESS_OPS_V2) { + fprintf(stderr, "%s: dlsym to ops failed, bad magic (%08x)\n", + __func__, compress->ops->magic); + dlclose(dl_hdl); + return -ENXIO; + } compress->dl_hdl = dl_hdl; return 0; } diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index 52550ef..f576d04 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -641,6 +641,7 @@ static int compress_hw_set_codec_params(void *data, struct snd_codec *codec) } struct compress_ops compress_hw_ops = { + .magic = COMPRESS_OPS_V2, .open_by_name = compress_hw_open_by_name, .close = compress_hw_close, .get_hpointer = compress_hw_get_hpointer, From c7b9f06861a285a0d171c5d5bbe910d0c6fa8115 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Jan 2026 11:53:46 +0100 Subject: [PATCH 3/4] compress_ops: remove get_tstamp64 callback It is not required to polute ops with two versions of similar callbacks when we introduced V2 ops. Handle the wrapping in the top level (compress_get_tstamp function). Signed-off-by: Jaroslav Kysela --- include/tinycompress/compress_ops.h | 2 -- src/lib/compress.c | 10 ++++++++-- src/lib/compress_hw.c | 29 +++++++++++++++++------------ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/tinycompress/compress_ops.h b/include/tinycompress/compress_ops.h index e816632..7eabeb3 100644 --- a/include/tinycompress/compress_ops.h +++ b/include/tinycompress/compress_ops.h @@ -25,8 +25,6 @@ struct compress_ops { int (*get_hpointer)(void *compress_data, unsigned int *avail, struct timespec *tstamp); int (*get_tstamp)(void *compress_data, - unsigned int *samples, unsigned int *sampling_rate); - int (*get_tstamp64)(void *compress_data, unsigned long long *samples, unsigned int *sampling_rate); int (*write)(void *compress_data, const void *buf, size_t size); int (*read)(void *compress_data, void *buf, size_t size); diff --git a/src/lib/compress.c b/src/lib/compress.c index 1ff3dfe..0c537ac 100644 --- a/src/lib/compress.c +++ b/src/lib/compress.c @@ -209,13 +209,19 @@ int compress_get_hpointer(struct compress *compress, int compress_get_tstamp(struct compress *compress, unsigned int *samples, unsigned int *sampling_rate) { - return compress->ops->get_tstamp(compress->data, samples, sampling_rate); + unsigned long long _samples; + int ret; + + ret = compress->ops->get_tstamp(compress->data, &_samples, sampling_rate); + if (ret >= 0) + *samples = (unsigned int)_samples; + return ret; } int compress_get_tstamp64(struct compress *compress, unsigned long long *samples, unsigned int *sampling_rate) { - return compress->ops->get_tstamp64(compress->data, samples, sampling_rate); + return compress->ops->get_tstamp(compress->data, samples, sampling_rate); } int compress_write(struct compress *compress, const void *buf, unsigned int size) diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index f576d04..6e372c5 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -271,15 +271,11 @@ static int compress_hw_get_hpointer(void *data, return 0; } -static int compress_hw_get_tstamp(void *data, - unsigned int *samples, unsigned int *sampling_rate) +static int compress_hw_get_tstamp_32(struct compress_hw_data *compress, + unsigned long long *samples, unsigned int *sampling_rate) { - struct compress_hw_data *compress = (struct compress_hw_data *)data; struct snd_compr_tstamp ktstamp; - if (!is_compress_hw_ready(compress)) - return oops(compress, ENODEV, "device not ready"); - if (ioctl(compress->fd, SNDRV_COMPRESS_TSTAMP, &ktstamp)) return oops(compress, errno, "cannot get tstamp"); @@ -288,15 +284,11 @@ static int compress_hw_get_tstamp(void *data, return 0; } -static int compress_hw_get_tstamp64(void *data, +static int compress_hw_get_tstamp_64(struct compress_hw_data *compress, unsigned long long *samples, unsigned int *sampling_rate) { - struct compress_hw_data *compress = (struct compress_hw_data *)data; struct snd_compr_tstamp64 ktstamp; - if (!is_compress_hw_ready(compress)) - return oops(compress, ENODEV, "device not ready"); - if (ioctl(compress->fd, SNDRV_COMPRESS_TSTAMP64, &ktstamp)) return oops(compress, errno, "cannot get tstamp64"); @@ -305,6 +297,20 @@ static int compress_hw_get_tstamp64(void *data, return 0; } +static int compress_hw_get_tstamp(void *data, + unsigned long long *samples, unsigned int *sampling_rate) +{ + struct compress_hw_data *compress = (struct compress_hw_data *)data; + + if (!is_compress_hw_ready(compress)) + return oops(compress, ENODEV, "device not ready"); + + if (get_compress_hw_version(compress) >= SNDRV_PROTOCOL_VERSION(0, 4, 0)) + return compress_hw_get_tstamp_64(compress, samples, sampling_rate); + else + return compress_hw_get_tstamp_32(compress, samples, sampling_rate); +} + static int compress_hw_write(void *data, const void *buf, size_t size) { struct compress_hw_data *compress = (struct compress_hw_data *)data; @@ -646,7 +652,6 @@ struct compress_ops compress_hw_ops = { .close = compress_hw_close, .get_hpointer = compress_hw_get_hpointer, .get_tstamp = compress_hw_get_tstamp, - .get_tstamp64 = compress_hw_get_tstamp64, .write = compress_hw_write, .read = compress_hw_read, .start = compress_hw_start, From e2ff8ac6c84f02d3261df093fff8f04a82a740eb Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Jan 2026 11:58:43 +0100 Subject: [PATCH 4/4] lib: introduce compress_get_hpointer64 Allow to pass unwrapped avail value to applications. Introduce new compress_get_hpointer64() function and change callback in ops. Use UINT_MAX limiting rather than blind wrap like in the previous code in compress_get_hpointer(). Signed-off-by: Jaroslav Kysela --- include/tinycompress/compress_ops.h | 2 +- include/tinycompress/tinycompress.h | 12 ++++++++++++ src/lib/compress.c | 16 ++++++++++++++++ src/lib/compress_hw.c | 4 ++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/tinycompress/compress_ops.h b/include/tinycompress/compress_ops.h index 7eabeb3..7a4ffc9 100644 --- a/include/tinycompress/compress_ops.h +++ b/include/tinycompress/compress_ops.h @@ -23,7 +23,7 @@ struct compress_ops { unsigned int flags, struct compr_config *config); void (*close)(void *compress_data); int (*get_hpointer)(void *compress_data, - unsigned int *avail, struct timespec *tstamp); + unsigned long long *avail, struct timespec *tstamp); int (*get_tstamp)(void *compress_data, unsigned long long *samples, unsigned int *sampling_rate); int (*write)(void *compress_data, const void *buf, size_t size); diff --git a/include/tinycompress/tinycompress.h b/include/tinycompress/tinycompress.h index 8d9677b..f954f25 100644 --- a/include/tinycompress/tinycompress.h +++ b/include/tinycompress/tinycompress.h @@ -139,6 +139,18 @@ int compress_get_hpointer(struct compress *compress, unsigned int *avail, struct timespec *tstamp); +/* + * compress_get_hpointe64r: get the hw timestamp + * return 0 on success, negative on error + * + * @compress: compress stream on which query is made + * @avail: buffer availble for write/read, in bytes + * @tstamp: hw time + */ +int compress_get_hpointer64(struct compress *compress, + unsigned long long *avail, struct timespec *tstamp); + + /* * compress_get_tstamp: get the raw hw timestamp * return 0 on success, negative on error diff --git a/src/lib/compress.c b/src/lib/compress.c index 0c537ac..d9ec77a 100644 --- a/src/lib/compress.c +++ b/src/lib/compress.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include "tinycompress/tinycompress.h" @@ -202,6 +203,21 @@ void compress_close(struct compress *compress) int compress_get_hpointer(struct compress *compress, unsigned int *avail, struct timespec *tstamp) +{ + unsigned long long _avail; + int ret; + + ret = compress->ops->get_hpointer(compress->data, &_avail, tstamp); + if (ret >= 0) { + if (_avail > UINT_MAX) + _avail = UINT_MAX; + *avail = (unsigned int)_avail; + } + return ret; +} + +int compress_get_hpointer64(struct compress *compress, + unsigned long long *avail, struct timespec *tstamp) { return compress->ops->get_hpointer(compress->data, avail, tstamp); } diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index 6e372c5..1519d71 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -237,7 +237,7 @@ static void compress_hw_avail64_from_32(struct snd_compr_avail64 *avail64, } static int compress_hw_get_hpointer(void *data, - unsigned int *avail, struct timespec *tstamp) + unsigned long long *avail, struct timespec *tstamp) { struct compress_hw_data *compress = (struct compress_hw_data *)data; struct snd_compr_avail kavail32; @@ -263,7 +263,7 @@ static int compress_hw_get_hpointer(void *data, if (0 == kavail64.tstamp.sampling_rate) return oops(compress, ENODATA, "sample rate unknown"); - *avail = (unsigned int)kavail64.avail; + *avail = kavail64.avail; time = kavail64.tstamp.pcm_io_frames / kavail64.tstamp.sampling_rate; tstamp->tv_sec = time; time = kavail64.tstamp.pcm_io_frames % kavail64.tstamp.sampling_rate;