Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions include/sound/compress_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <linux/types.h>
#include <sound/asound.h>
#include <sound/compress_params.h>
#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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -88,13 +128,22 @@ 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)
#define SNDRV_COMPRESS_STOP _IO('C', 0x33)
#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
Expand Down
2 changes: 2 additions & 0 deletions include/tinycompress/compress_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions include/tinycompress/tinycompress.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/lib/compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
72 changes: 57 additions & 15 deletions src/lib/compress_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see compress_hw_get_tstamp() updated. compress_hw_write() uses AVAIL ioctl, that should be updated too...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment!

I dont see compress_hw_get_tstamp() updated

Correct, I added a parallel compress_hw_get_tstamp64 to get the 64 bit struct.
On the other hand, compress_hw_get_tstamp has been unchanged, still returning the 32 bit structure via ioctl SNDRV_COMPRESS_TSTAMP which will stay supported in the kernel forever.

compress_hw_write() uses AVAIL ioctl, that should be updated too...

There is no benefit in using AVAIL64 here since only the avail field of the structure is being used (was already 64 bit). The only difference between AVAIL and AVAIL64 return value is the tstamp field which is unused in compress_hw_write


Expand All @@ -263,6 +287,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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to use forced 64-bit type like __u64 instead long long. But it's probably for the discussion. The other exported functions do not force 32-bit types.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I retained the C standard types for consistency with the existing API as you mentioned. Long long is guaranteed to be at least 64 bits wide so it won't cause any truncation issues.

{
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;
Expand Down Expand Up @@ -603,6 +644,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,
Expand Down