Skip to content

Commit

Permalink
tinycompress: Add support for getting list of supported codecs
Browse files Browse the repository at this point in the history
Right now, there is no way to expose a list of codecs from tinycompress. While
one could theoretically call is_codec_supported multiple times in an application
to check against a list of codecs, an API would make it easy to enumerate supported
codecs. The IOCTL SNDRV_COMPRESS_GET_CAPS after all already exists.

The use case is Pipewire where we would like the compressed sink Pipewire node to
advertise only codecs supported by the underlying hardware.

Signed-off-by: Sanchayan Maity <sanchayan@asymptotic.io>
  • Loading branch information
SanchayanMaity committed Oct 6, 2022
1 parent 7dc18a7 commit e21d175
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/tinycompress/compress_ops.h
Expand Up @@ -42,6 +42,7 @@ struct compress_ops {
int (*is_compress_running)(void *compress_data);
int (*is_compress_ready)(void *compress_data);
const char *(*get_error)(void *compress_data);
int (*get_supported_codecs_by_name)(const char *name, unsigned int flags, void *codecs, int size);
};

#endif /* end of __COMPRESS_OPS_H__ */
31 changes: 31 additions & 0 deletions include/tinycompress/tinycompress.h
Expand Up @@ -307,6 +307,37 @@ int is_compress_ready(struct compress *compress);
/* Returns a human readable reason for the last error */
const char *compress_get_error(struct compress *compress);

/*
* compress_get_supported_codecs: gets the list of supported codecs
*
* returns number of codecs on success, negative on error
*
* @card: sound card number
* @device: device number
* @flags: stream flags
* @codecs: Pointer to an array which will hold the list of codecs
* @size: Size of the codecs array. Must be sized to hold 32 integers.
*/
int compress_get_supported_codecs(unsigned int card, unsigned int device,
unsigned int flags, int *codecs, int size);

/*
* compress_get_supported_codecs_by_name: gets the list of supported codecs
*
* returns number of codecs on success, negative on error
*
* format of name is :
* hw:<card>,<device> for real hw compress node
* <plugin_libname>:<custom string> for virtual compress node
*
* @name: name of the compress node
* @flags: stream flags
* @codecs: Pointer to an array which will hold the list of codecs
* @size: Size of the codecs array. Must be sized to hold 32 integers.
*/
int compress_get_supported_codecs_by_name(const char *name, unsigned int flags,
int *codecs, int size);

#if defined(__cplusplus)
} // extern "C"
#endif
Expand Down
37 changes: 37 additions & 0 deletions src/lib/compress.c
Expand Up @@ -310,3 +310,40 @@ int compress_wait(struct compress *compress, int timeout_ms)
return compress->ops->wait(compress->data, timeout_ms);
}

int compress_get_supported_codecs(unsigned int card, unsigned int device,
unsigned int flags, int *codecs, int size)
{
struct compress_ops *ops = &compress_hw_ops;
char name[128];

snprintf(name, sizeof(name), "hw:%u,%u", card, device);

return ops->get_supported_codecs_by_name(name, flags, codecs, size);
}

int compress_get_supported_codecs_by_name(const char *name, unsigned int flags, int *codecs, int size)
{
struct compress *compress;
int ret = -1;

compress = calloc(1, sizeof(struct compress));
if (!compress)
return ret;

if ((name[0] == 'h') || (name[1] == 'w') || (name[2] == ':')) {
compress->ops = &compress_hw_ops;
} else {
if (populate_compress_plugin_ops(compress, name)) {
free(compress);
return ret;
}
}

ret = compress->ops->get_supported_codecs_by_name(name, flags, codecs, size);

if (compress->dl_hdl)
dlclose(compress->dl_hdl);
free(compress);

return ret;
}
43 changes: 43 additions & 0 deletions src/lib/compress_hw.c
Expand Up @@ -119,6 +119,48 @@ static bool _is_codec_type_supported(int fd, struct snd_codec *codec)
return found;
}

static int compress_hw_get_supported_codecs_by_name(const char *name, unsigned int flags, void *codecs, int size)
{
struct snd_compr_caps caps;
unsigned int *codecs_buf = (unsigned int *)codecs;
unsigned int card, device;
unsigned int dev_flag;
unsigned int num_codecs, i;
int fd, ret;
char fn[256];

if (size < MAX_NUM_CODECS)
return oops(&bad_compress, EINVAL, "Input not big enough to hold list of available codecs");

if (sscanf(&name[3], "%u,%u", &card, &device) != 2)
return -EINVAL;

snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);

if (flags & COMPRESS_OUT)
dev_flag = O_RDONLY;
else
dev_flag = O_WRONLY;

fd = open(fn, dev_flag);
if (fd < 0)
return oops(&bad_compress, errno, "cannot open device '%s'", fn);

if (ioctl(fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
close(fd);
return oops(&bad_compress, errno, "cannot get device caps");
}

close(fd);

num_codecs = caps.num_codecs;
for (i = 0; i < num_codecs; i++) {
codecs_buf[i] = caps.codecs[i];
}

return num_codecs;
}

static inline void
fill_compress_hw_params(struct compr_config *config, struct snd_compr_params *params)
{
Expand Down Expand Up @@ -595,5 +637,6 @@ struct compress_ops compress_hw_ops = {
.is_compress_running = is_compress_hw_running,
.is_compress_ready = is_compress_hw_ready,
.get_error = compress_hw_get_error,
.get_supported_codecs_by_name = compress_hw_get_supported_codecs_by_name,
};

0 comments on commit e21d175

Please sign in to comment.