From 3d5e10ab7c39610c078efe310991e4ae1bd328f5 Mon Sep 17 00:00:00 2001 From: George Verhaegen Date: Mon, 21 Jul 2025 16:18:56 +0100 Subject: [PATCH 1/4] sound: update header to v0.4.0 Kernel has upgraded compress headers and bumped version to 0.4.0, so update this header as well. --- include/sound/compress_offload.h | 53 ++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/include/sound/compress_offload.h b/include/sound/compress_offload.h index 54e08a2..65e2310 100644 --- a/include/sound/compress_offload.h +++ b/include/sound/compress_offload.h @@ -21,7 +21,7 @@ #include #include #include -#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 2, 0) +#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 4, 0) struct snd_compressed_buffer { __u32 fragment_size; @@ -42,14 +42,28 @@ struct snd_compr_tstamp { __u32 sampling_rate; }__attribute__((packed, aligned(4))); +struct snd_compr_tstamp64 { + __u32 byte_offset; + __u64 copied_total; + __u64 pcm_frames; + __u64 pcm_io_frames; + __u32 sampling_rate; +} __attribute__((packed, aligned(4))); + struct snd_compr_avail { __u64 avail; struct snd_compr_tstamp tstamp; }__attribute__((packed, aligned(4))); +struct snd_compr_avail64 { + __u64 avail; + struct snd_compr_tstamp64 tstamp; +} __attribute__((packed, aligned(4))); + enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, - SND_COMPRESS_CAPTURE + SND_COMPRESS_CAPTURE, + SND_COMPRESS_ACCEL }; struct snd_compr_caps { @@ -79,6 +93,32 @@ struct snd_compr_metadata { __u32 value[8]; }__attribute__((packed, aligned(4))); +#define SND_COMPRESS_TFLG_NEW_STREAM (1<<0) +struct snd_compr_task { + __u64 seqno; + __u64 origin_seqno; + int input_fd; + int output_fd; + __u64 input_size; + __u32 flags; + __u8 reserved[16]; +} __attribute__((packed, aligned(4))); + +enum snd_compr_state { + SND_COMPRESS_TASK_STATE_IDLE = 0, + SND_COMPRESS_TASK_STATE_ACTIVE, + SND_COMPRESS_TASK_STATE_FINISHED +}; + +struct snd_compr_task_status { + __u64 seqno; + __u64 input_size; + __u64 output_size; + __u32 output_flags; + __u8 state; + __u8 reserved[15]; +} __attribute__((packed, aligned(4))); + #define SNDRV_COMPRESS_IOCTL_VERSION _IOR('C', 0x00, int) #define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x10, struct snd_compr_caps) #define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x11, struct snd_compr_codec_caps) @@ -88,6 +128,8 @@ struct snd_compr_metadata { #define SNDRV_COMPRESS_GET_METADATA _IOWR('C', 0x15, struct snd_compr_metadata) #define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp) #define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail) +#define SNDRV_COMPRESS_TSTAMP64 _IOR('C', 0x22, struct snd_compr_tstamp64) +#define SNDRV_COMPRESS_AVAIL64 _IOR('C', 0x23, struct snd_compr_avail64) #define SNDRV_COMPRESS_PAUSE _IO('C', 0x30) #define SNDRV_COMPRESS_RESUME _IO('C', 0x31) #define SNDRV_COMPRESS_START _IO('C', 0x32) @@ -95,6 +137,13 @@ struct snd_compr_metadata { #define SNDRV_COMPRESS_DRAIN _IO('C', 0x34) #define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35) #define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36) + +#define SNDRV_COMPRESS_TASK_CREATE _IOWR('C', 0x60, struct snd_compr_task) +#define SNDRV_COMPRESS_TASK_FREE _IOW('C', 0x61, __u64) +#define SNDRV_COMPRESS_TASK_START _IOWR('C', 0x62, struct snd_compr_task) +#define SNDRV_COMPRESS_TASK_STOP _IOW('C', 0x63, __u64) +#define SNDRV_COMPRESS_TASK_STATUS _IOWR('C', 0x68, struct snd_compr_task_status) + #define SND_COMPR_TRIGGER_DRAIN 7 #define SND_COMPR_TRIGGER_NEXT_TRACK 8 #define SND_COMPR_TRIGGER_PARTIAL_DRAIN 9 From a885db35c992668d770d6a77cccf1d1c791aa6c4 Mon Sep 17 00:00:00 2001 From: George Verhaegen Date: Mon, 21 Jul 2025 16:19:16 +0100 Subject: [PATCH 2/4] compress_ops: add get_tstamp64 Add get_tstamp64 using the new ioctl SNDRV_COMPRESS_TSTAMP64. --- include/tinycompress/compress_ops.h | 2 ++ include/tinycompress/tinycompress.h | 11 +++++++++++ src/lib/compress.c | 6 ++++++ src/lib/compress_hw.c | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/include/tinycompress/compress_ops.h b/include/tinycompress/compress_ops.h index 2ee8d15..290a831 100644 --- a/include/tinycompress/compress_ops.h +++ b/include/tinycompress/compress_ops.h @@ -23,6 +23,8 @@ struct compress_ops { 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); int (*start)(void *compress_data); diff --git a/include/tinycompress/tinycompress.h b/include/tinycompress/tinycompress.h index a8b4e58..8d9677b 100644 --- a/include/tinycompress/tinycompress.h +++ b/include/tinycompress/tinycompress.h @@ -150,6 +150,17 @@ int compress_get_hpointer(struct compress *compress, int compress_get_tstamp(struct compress *compress, unsigned int *samples, unsigned int *sampling_rate); +/* + * compress_get_tstamp64: get the raw hw timestamp in 64 bit + * return 0 on success, negative on error + * + * @compress: compress stream on which query is made + * @samples: number of decoded samples played + * @sampling_rate: sampling rate of decoded samples + */ +int compress_get_tstamp64(struct compress *compress, + unsigned long long *samples, unsigned int *sampling_rate); + /* * compress_write: write data to the compress stream * return bytes written on success, negative on error diff --git a/src/lib/compress.c b/src/lib/compress.c index 5a8fd04..cf0b295 100644 --- a/src/lib/compress.c +++ b/src/lib/compress.c @@ -205,6 +205,12 @@ int compress_get_tstamp(struct compress *compress, return compress->ops->get_tstamp(compress->data, samples, sampling_rate); } +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); +} + int compress_write(struct compress *compress, const void *buf, unsigned int size) { return compress->ops->write(compress->data, buf, size); diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index 5aabae0..2773639 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -263,6 +263,23 @@ static int compress_hw_get_tstamp(void *data, return 0; } +static int compress_hw_get_tstamp64(void *data, + 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"); + + *samples = ktstamp.pcm_io_frames; + *sampling_rate = ktstamp.sampling_rate; + return 0; +} + static int compress_hw_write(void *data, const void *buf, size_t size) { struct compress_hw_data *compress = (struct compress_hw_data *)data; @@ -603,6 +620,7 @@ 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 81cbe52d8e6c3714120a551bfaf600c835cf27ad Mon Sep 17 00:00:00 2001 From: George Verhaegen Date: Fri, 1 Aug 2025 11:47:43 +0100 Subject: [PATCH 3/4] compress_hw: cache ioctl version Read the version when opened and cache it to reduce ioctl calls. --- src/lib/compress_hw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index 2773639..a07fa8d 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -36,6 +36,7 @@ struct compress_hw_data { int fd; unsigned int flags; char error[COMPR_ERR_MAX]; + int ioctl_version; struct compr_config *config; int running; int max_poll_wait_ms; @@ -88,13 +89,7 @@ static int is_compress_hw_ready(void *data) static int get_compress_hw_version(struct compress_hw_data *compress) { - int version = 0; - - if (ioctl(compress->fd, SNDRV_COMPRESS_IOCTL_VERSION, &version)) { - oops(compress, errno, "cant read version"); - return -1; - } - return version; + return compress->ioctl_version; } static bool _is_codec_type_supported(int fd, struct snd_codec *codec) @@ -178,6 +173,11 @@ static void *compress_hw_open_by_name(const char *name, goto config_fail; } + if (ioctl(compress->fd, SNDRV_COMPRESS_IOCTL_VERSION, &compress->ioctl_version)) { + oops(&bad_compress, errno, "cannot read version"); + goto codec_fail; + } + if (ioctl(compress->fd, SNDRV_COMPRESS_GET_CAPS, &caps)) { oops(compress, errno, "cannot get device caps"); goto codec_fail; From 8f7cb7c53d2528298dced73e3b73a5b60e36e36b Mon Sep 17 00:00:00 2001 From: George Verhaegen Date: Mon, 21 Jul 2025 16:21:11 +0100 Subject: [PATCH 4/4] compress_hw_get_hpointer: use SNDRV_COMPRESS_AVAIL64 Refactor compress_hw_get_hpointer to use the new SNDRV_COMPRESS_AVAIL64 which benefits from overflow safety. --- src/lib/compress_hw.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/lib/compress_hw.c b/src/lib/compress_hw.c index a07fa8d..02314cd 100644 --- a/src/lib/compress_hw.c +++ b/src/lib/compress_hw.c @@ -224,25 +224,49 @@ static void compress_hw_close(void *data) free(compress); } +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; +} + static int compress_hw_get_hpointer(void *data, unsigned int *avail, struct timespec *tstamp) { struct compress_hw_data *compress = (struct compress_hw_data *)data; - struct snd_compr_avail kavail; + struct snd_compr_avail kavail32; + struct snd_compr_avail64 kavail64; __u64 time; if (!is_compress_hw_ready(compress)) return oops(compress, ENODEV, "device not ready"); - if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &kavail)) - return oops(compress, errno, "cannot get avail"); - if (0 == kavail.tstamp.sampling_rate) + const int version = get_compress_hw_version(compress); + if (version <= 0) + return -1; + + if (version < SNDRV_PROTOCOL_VERSION(0, 4, 0)) { + /* SNDRV_COMPRESS_AVAIL64 not supported, fallback to SNDRV_COMPRESS_AVAIL */ + if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &kavail32)) + return oops(compress, errno, "cannot get avail"); + compress_hw_avail64_from_32(&kavail64, &kavail32); + } else { + if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL64, &kavail64)) + return oops(compress, errno, "cannot get avail64"); + } + + if (0 == kavail64.tstamp.sampling_rate) return oops(compress, ENODATA, "sample rate unknown"); - *avail = (unsigned int)kavail.avail; - time = kavail.tstamp.pcm_io_frames / kavail.tstamp.sampling_rate; + *avail = (unsigned int)kavail64.avail; + time = kavail64.tstamp.pcm_io_frames / kavail64.tstamp.sampling_rate; tstamp->tv_sec = time; - time = kavail.tstamp.pcm_io_frames % kavail.tstamp.sampling_rate; - tstamp->tv_nsec = time * 1000000000 / kavail.tstamp.sampling_rate; + time = kavail64.tstamp.pcm_io_frames % kavail64.tstamp.sampling_rate; + tstamp->tv_nsec = time * 1000000000 / kavail64.tstamp.sampling_rate; return 0; }