external: tinycompress: add support for compress plugins
Add plugin support to use vendor specific compress implementation Bug: 166667071 Test: manual offload playback test Test: cts AudioTrackOffloadTest CRs-Fixed: 2563258 Change-Id: I71f588b9ed84b62d3b1b08dae7ce65f8fa649e6a
This commit is contained in:
parent
86c50cec6d
commit
931e7cf24b
8 changed files with 1003 additions and 105 deletions
|
@ -12,6 +12,9 @@ cc_library_shared {
|
|||
srcs: [
|
||||
"compress.c",
|
||||
"utils.c",
|
||||
"compress_hw.c",
|
||||
"compress_plugin.c",
|
||||
"snd_utils.c",
|
||||
],
|
||||
shared_libs: [
|
||||
"libcutils",
|
||||
|
|
184
compress.c
184
compress.c
|
@ -75,6 +75,8 @@
|
|||
#include "sound/compress_params.h"
|
||||
#include "sound/compress_offload.h"
|
||||
#include "tinycompress/tinycompress.h"
|
||||
#include "compress_ops.h"
|
||||
#include "snd_utils.h"
|
||||
|
||||
#define COMPR_ERR_MAX 128
|
||||
|
||||
|
@ -91,8 +93,15 @@ struct compress {
|
|||
int nonblocking;
|
||||
unsigned int gapless_metadata;
|
||||
unsigned int next_track;
|
||||
|
||||
struct compress_ops *ops;
|
||||
void *data;
|
||||
void *snd_node;
|
||||
};
|
||||
|
||||
extern struct compress_ops compr_hw_ops;
|
||||
extern struct compress_ops compr_plug_ops;
|
||||
|
||||
static int oops(struct compress *compress, int e, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -120,75 +129,33 @@ static struct compress bad_compress = {
|
|||
|
||||
int is_compress_running(struct compress *compress)
|
||||
{
|
||||
return ((compress->fd > 0) && compress->running) ? 1 : 0;
|
||||
return ((compress->fd >= 0) && compress->running) ? 1 : 0;
|
||||
}
|
||||
|
||||
int is_compress_ready(struct compress *compress)
|
||||
{
|
||||
return (compress->fd > 0) ? 1 : 0;
|
||||
return (compress->fd >= 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int get_compress_version(struct compress *compress)
|
||||
{
|
||||
int version = 0;
|
||||
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
|
||||
oops(compress, errno, "cant read version");
|
||||
return -1;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
static bool _is_codec_supported(struct compress *compress, struct compr_config *config,
|
||||
const struct snd_compr_caps *caps)
|
||||
{
|
||||
bool codec = false;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < caps->num_codecs; i++) {
|
||||
if (caps->codecs[i] == config->codec->id) {
|
||||
/* found the codec */
|
||||
codec = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (codec == false) {
|
||||
oops(compress, ENXIO, "this codec is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config->fragment_size < caps->min_fragment_size) {
|
||||
oops(compress, EINVAL, "requested fragment size %d is below min supported %d",
|
||||
config->fragment_size, caps->min_fragment_size);
|
||||
return false;
|
||||
}
|
||||
if (config->fragment_size > caps->max_fragment_size) {
|
||||
oops(compress, EINVAL, "requested fragment size %d is above max supported %d",
|
||||
config->fragment_size, caps->max_fragment_size);
|
||||
return false;
|
||||
}
|
||||
if (config->fragments < caps->min_fragments) {
|
||||
oops(compress, EINVAL, "requested fragments %d are below min supported %d",
|
||||
config->fragments, caps->min_fragments);
|
||||
return false;
|
||||
}
|
||||
if (config->fragments > caps->max_fragments) {
|
||||
oops(compress, EINVAL, "requested fragments %d are above max supported %d",
|
||||
config->fragments, caps->max_fragments);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: match the codec properties */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _is_codec_type_supported(int fd, struct snd_codec *codec)
|
||||
static bool _is_codec_type_supported(struct compress_ops *ops, void *data,
|
||||
struct snd_codec *codec)
|
||||
{
|
||||
struct snd_compr_caps caps;
|
||||
bool found = false;
|
||||
unsigned int i;
|
||||
|
||||
if (ioctl(fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
|
||||
if (ops->ioctl(data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
|
||||
oops(&bad_compress, errno, "cannot get device caps");
|
||||
return false;
|
||||
}
|
||||
|
@ -218,7 +185,7 @@ struct compress *compress_open(unsigned int card, unsigned int device,
|
|||
struct compress *compress;
|
||||
struct snd_compr_params params;
|
||||
struct snd_compr_caps caps;
|
||||
char fn[256];
|
||||
int compress_type;
|
||||
|
||||
if (!config) {
|
||||
oops(&bad_compress, EINVAL, "passed bad config");
|
||||
|
@ -237,8 +204,6 @@ struct compress *compress_open(unsigned int card, unsigned int device,
|
|||
if (!compress->config)
|
||||
goto input_fail;
|
||||
|
||||
snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
|
||||
|
||||
compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
|
||||
|
||||
compress->flags = flags;
|
||||
|
@ -247,17 +212,22 @@ struct compress *compress_open(unsigned int card, unsigned int device,
|
|||
goto config_fail;
|
||||
}
|
||||
|
||||
if (flags & COMPRESS_OUT) {
|
||||
compress->fd = open(fn, O_RDONLY);
|
||||
} else {
|
||||
compress->fd = open(fn, O_WRONLY);
|
||||
}
|
||||
compress->snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
|
||||
compress_type = snd_utils_get_node_type(compress->snd_node);
|
||||
if (compress_type == SND_NODE_TYPE_PLUGIN)
|
||||
compress->ops = &compr_plug_ops;
|
||||
else
|
||||
compress->ops = &compr_hw_ops;
|
||||
|
||||
compress->fd = compress->ops->open(card, device, flags,
|
||||
&compress->data, compress->snd_node);
|
||||
if (compress->fd < 0) {
|
||||
oops(&bad_compress, errno, "cannot open device '%s'", fn);
|
||||
oops(&bad_compress, errno, "cannot open card(%u) device(%u)",
|
||||
card, device);
|
||||
goto config_fail;
|
||||
}
|
||||
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
|
||||
oops(compress, errno, "cannot get device caps");
|
||||
goto codec_fail;
|
||||
}
|
||||
|
@ -281,7 +251,7 @@ struct compress *compress_open(unsigned int card, unsigned int device,
|
|||
memcpy(compress->config, config, sizeof(*compress->config));
|
||||
fill_compress_params(config, ¶ms);
|
||||
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_SET_PARAMS, ¶ms)) {
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, ¶ms)) {
|
||||
oops(&bad_compress, errno, "cannot set device");
|
||||
goto codec_fail;
|
||||
}
|
||||
|
@ -289,7 +259,8 @@ struct compress *compress_open(unsigned int card, unsigned int device,
|
|||
return compress;
|
||||
|
||||
codec_fail:
|
||||
close(compress->fd);
|
||||
snd_utils_put_dev_node(compress->snd_node);
|
||||
compress->ops->close(compress->data);
|
||||
compress->fd = -1;
|
||||
config_fail:
|
||||
free(compress->config);
|
||||
|
@ -303,8 +274,8 @@ void compress_close(struct compress *compress)
|
|||
if (compress == &bad_compress)
|
||||
return;
|
||||
|
||||
if (compress->fd >= 0)
|
||||
close(compress->fd);
|
||||
snd_utils_put_dev_node(compress->snd_node);
|
||||
compress->ops->close(compress->data);
|
||||
compress->running = 0;
|
||||
compress->fd = -1;
|
||||
free(compress->config);
|
||||
|
@ -320,7 +291,7 @@ int compress_get_hpointer(struct compress *compress,
|
|||
if (!is_compress_ready(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &kavail))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &kavail))
|
||||
return oops(compress, errno, "cannot get avail");
|
||||
if (0 == kavail.tstamp.sampling_rate)
|
||||
return oops(compress, ENODATA, "sample rate unknown");
|
||||
|
@ -340,7 +311,7 @@ int compress_get_tstamp(struct compress *compress,
|
|||
if (!is_compress_ready(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_TSTAMP, &ktstamp))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_TSTAMP, &ktstamp))
|
||||
return oops(compress, errno, "cannot get tstamp");
|
||||
|
||||
*samples = ktstamp.pcm_io_frames;
|
||||
|
@ -361,12 +332,11 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
|
|||
return oops(compress, EINVAL, "Invalid flag set");
|
||||
if (!is_compress_ready(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
fds.fd = compress->fd;
|
||||
fds.events = POLLOUT;
|
||||
|
||||
/*TODO: treat auto start here first */
|
||||
while (size) {
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
|
||||
return oops(compress, errno, "cannot get avail");
|
||||
|
||||
/* We can write if we have at least one fragment available
|
||||
|
@ -377,13 +347,14 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
|
|||
if (compress->nonblocking)
|
||||
return total;
|
||||
|
||||
ret = poll(&fds, 1, compress->max_poll_wait_ms);
|
||||
ret = compress->ops->poll(compress->data, &fds, 1,
|
||||
compress->max_poll_wait_ms);
|
||||
if (fds.revents & POLLERR) {
|
||||
return oops(compress, EIO, "poll returned error!");
|
||||
}
|
||||
/* A pause will cause -EBADFD or zero.
|
||||
* This is not an error, just stop writing */
|
||||
if ((ret == 0) || (ret == -EBADFD))
|
||||
if ((ret == 0) || (ret < 0 && errno == EBADFD))
|
||||
break;
|
||||
if (ret < 0)
|
||||
return oops(compress, errno, "poll error");
|
||||
|
@ -396,12 +367,13 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
|
|||
to_write = avail.avail;
|
||||
else
|
||||
to_write = size;
|
||||
written = write(compress->fd, cbuf, to_write);
|
||||
/* If play was paused the write returns -EBADFD */
|
||||
if (written == -EBADFD)
|
||||
break;
|
||||
if (written < 0)
|
||||
written = compress->ops->write(compress->data, cbuf, to_write);
|
||||
if (written < 0) {
|
||||
/* If play was paused the write returns -EBADFD */
|
||||
if (errno == EBADFD)
|
||||
break;
|
||||
return oops(compress, errno, "write failed!");
|
||||
}
|
||||
|
||||
size -= written;
|
||||
cbuf += written;
|
||||
|
@ -423,11 +395,10 @@ int compress_read(struct compress *compress, void *buf, unsigned int size)
|
|||
return oops(compress, EINVAL, "Invalid flag set");
|
||||
if (!is_compress_ready(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
fds.fd = compress->fd;
|
||||
fds.events = POLLIN;
|
||||
|
||||
while (size) {
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
|
||||
return oops(compress, errno, "cannot get avail");
|
||||
|
||||
if ( (avail.avail < frag_size) && (avail.avail < size) ) {
|
||||
|
@ -437,13 +408,14 @@ int compress_read(struct compress *compress, void *buf, unsigned int size)
|
|||
if (compress->nonblocking)
|
||||
return total;
|
||||
|
||||
ret = poll(&fds, 1, compress->max_poll_wait_ms);
|
||||
ret = compress->ops->poll(compress->data, &fds, 1,
|
||||
compress->max_poll_wait_ms);
|
||||
if (fds.revents & POLLERR) {
|
||||
return oops(compress, EIO, "poll returned error!");
|
||||
}
|
||||
/* A pause will cause -EBADFD or zero.
|
||||
* This is not an error, just stop reading */
|
||||
if ((ret == 0) || (ret == -EBADFD))
|
||||
if ((ret == 0) || (ret < 0 && errno == EBADFD))
|
||||
break;
|
||||
if (ret < 0)
|
||||
return oops(compress, errno, "poll error");
|
||||
|
@ -456,12 +428,13 @@ int compress_read(struct compress *compress, void *buf, unsigned int size)
|
|||
to_read = avail.avail;
|
||||
else
|
||||
to_read = size;
|
||||
num_read = read(compress->fd, cbuf, to_read);
|
||||
/* If play was paused the read returns -EBADFD */
|
||||
if (num_read == -EBADFD)
|
||||
break;
|
||||
if (num_read < 0)
|
||||
num_read = compress->ops->read(compress->data, cbuf, to_read);
|
||||
if (num_read < 0) {
|
||||
/* If play was paused the read returns -EBADFD */
|
||||
if (errno == EBADFD)
|
||||
break;
|
||||
return oops(compress, errno, "read failed!");
|
||||
}
|
||||
|
||||
size -= num_read;
|
||||
cbuf += num_read;
|
||||
|
@ -475,7 +448,7 @@ int compress_start(struct compress *compress)
|
|||
{
|
||||
if (!is_compress_ready(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_START))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_START))
|
||||
return oops(compress, errno, "cannot start the stream");
|
||||
compress->running = 1;
|
||||
return 0;
|
||||
|
@ -486,7 +459,7 @@ int compress_stop(struct compress *compress)
|
|||
{
|
||||
if (!is_compress_running(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_STOP))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_STOP))
|
||||
return oops(compress, errno, "cannot stop the stream");
|
||||
return 0;
|
||||
}
|
||||
|
@ -495,14 +468,14 @@ int compress_pause(struct compress *compress)
|
|||
{
|
||||
if (!is_compress_running(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_PAUSE))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PAUSE))
|
||||
return oops(compress, errno, "cannot pause the stream");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int compress_resume(struct compress *compress)
|
||||
{
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_RESUME))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_RESUME))
|
||||
return oops(compress, errno, "cannot resume the stream");
|
||||
return 0;
|
||||
}
|
||||
|
@ -511,7 +484,7 @@ int compress_drain(struct compress *compress)
|
|||
{
|
||||
if (!is_compress_running(compress))
|
||||
return oops(compress, ENODEV, "device not ready");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_DRAIN))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_DRAIN))
|
||||
return oops(compress, errno, "cannot drain the stream");
|
||||
return 0;
|
||||
}
|
||||
|
@ -523,7 +496,7 @@ int compress_partial_drain(struct compress *compress)
|
|||
|
||||
if (!compress->next_track)
|
||||
return oops(compress, EPERM, "next track not signalled");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_PARTIAL_DRAIN))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PARTIAL_DRAIN))
|
||||
return oops(compress, errno, "cannot drain the stream\n");
|
||||
compress->next_track = 0;
|
||||
return 0;
|
||||
|
@ -536,7 +509,7 @@ int compress_next_track(struct compress *compress)
|
|||
|
||||
if (!compress->gapless_metadata)
|
||||
return oops(compress, EPERM, "metadata not set");
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_NEXT_TRACK))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_NEXT_TRACK))
|
||||
return oops(compress, errno, "cannot set next track\n");
|
||||
compress->next_track = 1;
|
||||
compress->gapless_metadata = 0;
|
||||
|
@ -561,12 +534,12 @@ int compress_set_gapless_metadata(struct compress *compress,
|
|||
|
||||
metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
|
||||
metadata.value[0] = mdata->encoder_padding;
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
|
||||
return oops(compress, errno, "can't set metadata for stream\n");
|
||||
|
||||
metadata.key = SNDRV_COMPRESS_ENCODER_DELAY;
|
||||
metadata.value[0] = mdata->encoder_delay;
|
||||
if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
|
||||
if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
|
||||
return oops(compress, errno, "can't set metadata for stream\n");
|
||||
compress->gapless_metadata = 1;
|
||||
return 0;
|
||||
|
@ -588,25 +561,27 @@ int compress_set_next_track_param(struct compress *compress,
|
|||
bool is_codec_supported(unsigned int card, unsigned int device,
|
||||
unsigned int flags, struct snd_codec *codec)
|
||||
{
|
||||
unsigned int dev_flag;
|
||||
struct compress_ops *ops;
|
||||
void *snd_node, *data;
|
||||
bool ret;
|
||||
int fd;
|
||||
char fn[256];
|
||||
int compress_type, fd;
|
||||
|
||||
snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
|
||||
|
||||
if (flags & COMPRESS_OUT)
|
||||
dev_flag = O_RDONLY;
|
||||
snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
|
||||
compress_type = snd_utils_get_node_type(snd_node);
|
||||
if (compress_type == SND_NODE_TYPE_PLUGIN)
|
||||
ops = &compr_plug_ops;
|
||||
else
|
||||
dev_flag = O_WRONLY;
|
||||
ops = &compr_hw_ops;
|
||||
|
||||
fd = open(fn, dev_flag);
|
||||
fd = ops->open(card, device, flags, &data, NULL);
|
||||
if (fd < 0)
|
||||
return oops(&bad_compress, errno, "cannot open device '%s'", fn);
|
||||
return oops(&bad_compress, errno, "cannot open card %u, device %u",
|
||||
card, device);
|
||||
|
||||
ret = _is_codec_type_supported(fd, codec);
|
||||
ret = _is_codec_type_supported(ops, data, codec);
|
||||
|
||||
close(fd);
|
||||
snd_utils_put_dev_node(snd_node);
|
||||
ops->close(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -625,10 +600,9 @@ int compress_wait(struct compress *compress, int timeout_ms)
|
|||
struct pollfd fds;
|
||||
int ret;
|
||||
|
||||
fds.fd = compress->fd;
|
||||
fds.events = POLLOUT | POLLIN;
|
||||
|
||||
ret = poll(&fds, 1, timeout_ms);
|
||||
ret = compress->ops->poll(compress->data, &fds, 1, timeout_ms);
|
||||
if (ret > 0) {
|
||||
if (fds.revents & POLLERR)
|
||||
return oops(compress, EIO, "poll returned error!");
|
||||
|
|
138
compress_hw.c
Normal file
138
compress_hw.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* compress_hw.c
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <sound/asound.h>
|
||||
#include "tinycompress/tinycompress.h"
|
||||
#include "compress_ops.h"
|
||||
|
||||
struct compress_hw_data {
|
||||
unsigned int card;
|
||||
unsigned int device;
|
||||
unsigned int fd;
|
||||
};
|
||||
|
||||
static int compress_hw_poll(void *data, struct pollfd *fds,
|
||||
nfds_t nfds, int timeout)
|
||||
{
|
||||
struct compress_hw_data *hw_data = data;
|
||||
|
||||
fds->fd = hw_data->fd;
|
||||
return poll(fds, nfds, timeout);
|
||||
}
|
||||
|
||||
static int compress_hw_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
struct compress_hw_data *hw_data = data;
|
||||
|
||||
return write(hw_data->fd, buf, size);
|
||||
}
|
||||
|
||||
static int compress_hw_read(void *data, void *buf, size_t size)
|
||||
{
|
||||
struct compress_hw_data *hw_data = data;
|
||||
|
||||
return read(hw_data->fd, buf, size);
|
||||
}
|
||||
|
||||
static int compress_hw_ioctl(void *data, unsigned int cmd, ...)
|
||||
{
|
||||
struct compress_hw_data *hw_data = data;
|
||||
va_list ap;
|
||||
void *arg;
|
||||
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
return ioctl(hw_data->fd, cmd, arg);
|
||||
}
|
||||
|
||||
static void compress_hw_close(void *data)
|
||||
{
|
||||
struct compress_hw_data *hw_data = data;
|
||||
|
||||
if (hw_data->fd > 0)
|
||||
close(hw_data->fd);
|
||||
|
||||
free(hw_data);
|
||||
}
|
||||
|
||||
static int compress_hw_open(unsigned int card, unsigned int device,
|
||||
unsigned int flags, void **data, __unused void *node)
|
||||
{
|
||||
struct compress_hw_data *hw_data;
|
||||
char fn[256];
|
||||
int fd;
|
||||
|
||||
hw_data = calloc(1, sizeof(*hw_data));
|
||||
if (!hw_data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
|
||||
|
||||
if (flags & COMPRESS_OUT)
|
||||
fd = open(fn, O_RDONLY);
|
||||
else
|
||||
fd = open(fn, O_WRONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
hw_data->card = card;
|
||||
hw_data->device = device;
|
||||
hw_data->fd = fd;
|
||||
|
||||
*data = hw_data;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct compress_ops compr_hw_ops = {
|
||||
.open = compress_hw_open,
|
||||
.close = compress_hw_close,
|
||||
.ioctl = compress_hw_ioctl,
|
||||
.read = compress_hw_read,
|
||||
.write = compress_hw_write,
|
||||
.poll = compress_hw_poll,
|
||||
};
|
50
compress_ops.h
Normal file
50
compress_ops.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* compress.h
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#ifndef __COMPRESS_H__
|
||||
#define __COMPRESS_H__
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "sound/compress_params.h"
|
||||
#include "sound/compress_offload.h"
|
||||
|
||||
struct compress_ops {
|
||||
int (*open) (unsigned int card, unsigned int device,
|
||||
unsigned int flags, void **data, void *node);
|
||||
void (*close) (void *data);
|
||||
int (*ioctl) (void *data, unsigned int cmd, ...);
|
||||
int (*read) (void *data, void *buf, size_t size);
|
||||
int (*write) (void *data, const void *buf, size_t size);
|
||||
int (*poll) (void *data, struct pollfd *fds, nfds_t nfds,
|
||||
int timeout);
|
||||
};
|
||||
|
||||
#endif /* end of __PCM_H__ */
|
423
compress_plugin.c
Normal file
423
compress_plugin.c
Normal file
|
@ -0,0 +1,423 @@
|
|||
/* compress_plugin.c
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <sound/asound.h>
|
||||
#include "tinycompress/compress_plugin.h"
|
||||
#include "sound/compress_offload.h"
|
||||
#include "compress_ops.h"
|
||||
#include "snd_utils.h"
|
||||
|
||||
#define U32_MAX ((uint32_t)~0U)
|
||||
|
||||
enum {
|
||||
COMPRESS_PLUG_STATE_OPEN,
|
||||
COMPRESS_PLUG_STATE_SETUP,
|
||||
COMPRESS_PLUG_STATE_PREPARED,
|
||||
COMPRESS_PLUG_STATE_PAUSE,
|
||||
COMPRESS_PLUG_STATE_RUNNING,
|
||||
};
|
||||
|
||||
struct compress_plug_data {
|
||||
unsigned int card;
|
||||
unsigned int device;
|
||||
unsigned int fd;
|
||||
unsigned int flags;
|
||||
|
||||
void *dl_hdl;
|
||||
COMPRESS_PLUGIN_OPEN_FN_PTR();
|
||||
|
||||
struct compress_plugin *plugin;
|
||||
void *dev_node;
|
||||
};
|
||||
|
||||
static int compress_plug_get_caps(struct compress_plug_data *plug_data,
|
||||
struct snd_compr_caps *caps)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
return plugin->ops->get_caps(plugin, caps);
|
||||
}
|
||||
|
||||
static int compress_plug_set_params(struct compress_plug_data *plug_data,
|
||||
struct snd_compr_params *params)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_OPEN)
|
||||
return -EBADFD;
|
||||
|
||||
if (params->buffer.fragment_size == 0 ||
|
||||
params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
|
||||
params->buffer.fragments == 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc = plugin->ops->set_params(plugin, params);
|
||||
if (!rc)
|
||||
plugin->state = COMPRESS_PLUG_STATE_SETUP;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compress_plug_avail(struct compress_plug_data *plug_data,
|
||||
struct snd_compr_avail *avail)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
return plugin->ops->avail(plugin, avail);
|
||||
}
|
||||
|
||||
static int compress_plug_tstamp(struct compress_plug_data *plug_data,
|
||||
struct snd_compr_tstamp *tstamp)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_SETUP)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->tstamp(plugin, tstamp);
|
||||
}
|
||||
|
||||
static int compress_plug_start(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
/* for playback moved to prepare in first write */
|
||||
/* for capture: move to prepare state set params */
|
||||
/* TODO: add direction in set params */
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_PREPARED)
|
||||
return -EBADFD;
|
||||
|
||||
rc = plugin->ops->start(plugin);
|
||||
if (!rc)
|
||||
plugin->state = COMPRESS_PLUG_STATE_RUNNING;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compress_plug_stop(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
if (plugin->state == COMPRESS_PLUG_STATE_PREPARED ||
|
||||
plugin->state == COMPRESS_PLUG_STATE_SETUP)
|
||||
return -EBADFD;
|
||||
|
||||
rc = plugin->ops->stop(plugin);
|
||||
if (!rc)
|
||||
plugin->state = COMPRESS_PLUG_STATE_SETUP;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compress_plug_pause(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
rc = plugin->ops->pause(plugin);
|
||||
if (!rc)
|
||||
plugin->state = COMPRESS_PLUG_STATE_PAUSE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compress_plug_resume(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_PAUSE)
|
||||
return -EBADFD;
|
||||
|
||||
rc = plugin->ops->resume(plugin);
|
||||
if (!rc)
|
||||
plugin->state = COMPRESS_PLUG_STATE_RUNNING;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compress_plug_drain(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
/* check if we will allow in pause */
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->drain(plugin);
|
||||
}
|
||||
|
||||
static int compress_plug_partial_drain(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
/* check if we will allow in pause */
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->partial_drain(plugin);
|
||||
}
|
||||
|
||||
static int compress_plug_next_track(struct compress_plug_data *plug_data)
|
||||
{
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
/* transion to next track applied to running stream only */
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->next_track(plugin);
|
||||
}
|
||||
|
||||
static int compress_plug_ioctl(void *data, unsigned int cmd, ...)
|
||||
{
|
||||
struct compress_plug_data *plug_data = data;
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int ret = 0;
|
||||
va_list ap;
|
||||
void *arg;
|
||||
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_COMPRESS_IOCTL_VERSION:
|
||||
*((int*)arg) = SNDRV_COMPRESS_VERSION;
|
||||
break;
|
||||
case SNDRV_COMPRESS_GET_CAPS:
|
||||
ret = compress_plug_get_caps(plug_data, arg);
|
||||
break;
|
||||
case SNDRV_COMPRESS_SET_PARAMS:
|
||||
ret = compress_plug_set_params(plug_data, arg);
|
||||
break;
|
||||
case SNDRV_COMPRESS_AVAIL:
|
||||
ret = compress_plug_avail(plug_data, arg);
|
||||
break;
|
||||
case SNDRV_COMPRESS_TSTAMP:
|
||||
ret = compress_plug_tstamp(plug_data, arg);
|
||||
break;
|
||||
case SNDRV_COMPRESS_START:
|
||||
ret = compress_plug_start(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_STOP:
|
||||
ret = compress_plug_stop(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_PAUSE:
|
||||
ret = compress_plug_pause(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_RESUME:
|
||||
ret = compress_plug_resume(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_DRAIN:
|
||||
ret = compress_plug_drain(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_PARTIAL_DRAIN:
|
||||
ret = compress_plug_partial_drain(plug_data);
|
||||
break;
|
||||
case SNDRV_COMPRESS_NEXT_TRACK:
|
||||
ret = compress_plug_next_track(plug_data);
|
||||
break;
|
||||
default:
|
||||
if (plugin->ops->ioctl)
|
||||
ret = plugin->ops->ioctl(plugin, cmd, arg);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compress_plug_poll(void *data, struct pollfd *fds,
|
||||
nfds_t nfds, int timeout)
|
||||
{
|
||||
struct compress_plug_data *plug_data = data;
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->poll(plugin, fds, nfds, timeout);
|
||||
}
|
||||
|
||||
|
||||
static int compress_plug_read(void *data, void *buf, size_t size)
|
||||
{
|
||||
struct compress_plug_data *plug_data = data;
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_RUNNING &&
|
||||
plugin->state != COMPRESS_PLUG_STATE_SETUP)
|
||||
return -EBADFD;
|
||||
|
||||
return plugin->ops->read(plugin, buf, size);
|
||||
}
|
||||
|
||||
static int compress_plug_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
struct compress_plug_data *plug_data = data;
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
int rc;
|
||||
|
||||
if (plugin->state != COMPRESS_PLUG_STATE_SETUP &&
|
||||
plugin->state != COMPRESS_PLUG_STATE_PREPARED &&
|
||||
plugin->state != COMPRESS_PLUG_STATE_RUNNING)
|
||||
return -EBADFD;
|
||||
|
||||
rc = plugin->ops->write(plugin, buf, size);
|
||||
if ((rc > 0) && (plugin->state == COMPRESS_PLUG_STATE_SETUP))
|
||||
plugin->state = COMPRESS_PLUG_STATE_PREPARED;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void compress_plug_close(void *data)
|
||||
{
|
||||
struct compress_plug_data *plug_data = data;
|
||||
struct compress_plugin *plugin = plug_data->plugin;
|
||||
|
||||
plugin->ops->close(plugin);
|
||||
dlclose(plug_data->dl_hdl);
|
||||
|
||||
free(plug_data);
|
||||
}
|
||||
|
||||
static int compress_plug_open(unsigned int card, unsigned int device,
|
||||
unsigned int flags, void **data, void *node)
|
||||
{
|
||||
struct compress_plug_data *plug_data;
|
||||
const char *err = NULL;
|
||||
void *dl_hdl;
|
||||
int rc = 0;
|
||||
char *so_name, *open_fn, token[80], *name;
|
||||
|
||||
plug_data = calloc(1, sizeof(*plug_data));
|
||||
if (!plug_data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = snd_utils_get_str(node, "so-name", &so_name);
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s: failed to get plugin lib name\n",
|
||||
__func__);
|
||||
goto err_get_lib;
|
||||
}
|
||||
|
||||
dl_hdl = dlopen(so_name, RTLD_NOW);
|
||||
if (!dl_hdl) {
|
||||
fprintf(stderr, "%s: unable to open %s, error: %s\n",
|
||||
__func__, so_name, dlerror());
|
||||
goto err_dl_open;
|
||||
} else {
|
||||
fprintf(stderr, "%s: dlopen successful for %s\n",
|
||||
__func__, so_name);
|
||||
}
|
||||
|
||||
sscanf(so_name, "lib%s", token);
|
||||
name = strtok(token, ".");
|
||||
open_fn = calloc(1, strlen(name) + strlen("_open") + 1);
|
||||
if (!open_fn) {
|
||||
rc = -ENOMEM;
|
||||
goto err_open_fn;
|
||||
}
|
||||
|
||||
strncpy(open_fn, name, strlen(name) + 1);
|
||||
strcat(open_fn, "_open");
|
||||
|
||||
plug_data->plugin_open_fn = dlsym(dl_hdl, open_fn);
|
||||
err = dlerror();
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: dlsym to open fn failed, err = '%s'\n",
|
||||
__func__, err);
|
||||
goto err_dlsym;
|
||||
}
|
||||
|
||||
rc = plug_data->plugin_open_fn(&plug_data->plugin,
|
||||
card, device, flags);
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s: failed to open plugin\n", __func__);
|
||||
goto err_dlsym;
|
||||
}
|
||||
|
||||
/* Call snd-card-def to get card and compress nodes */
|
||||
/* Check how to manage fd for plugin */
|
||||
|
||||
plug_data->dl_hdl = dl_hdl;
|
||||
plug_data->card = card;
|
||||
plug_data->device = device;
|
||||
plug_data->dev_node = node;
|
||||
plug_data->flags = flags;
|
||||
|
||||
*data = plug_data;
|
||||
|
||||
plug_data->plugin->state = COMPRESS_PLUG_STATE_OPEN;
|
||||
|
||||
return 0;
|
||||
|
||||
err_dlsym:
|
||||
free(open_fn);
|
||||
err_open_fn:
|
||||
dlclose(dl_hdl);
|
||||
err_get_lib:
|
||||
err_dl_open:
|
||||
free(plug_data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct compress_ops compr_plug_ops = {
|
||||
.open = compress_plug_open,
|
||||
.close = compress_plug_close,
|
||||
.ioctl = compress_plug_ioctl,
|
||||
.read = compress_plug_read,
|
||||
.write = compress_plug_write,
|
||||
.poll = compress_plug_poll,
|
||||
};
|
89
include/tinycompress/compress_plugin.h
Normal file
89
include/tinycompress/compress_plugin.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* compress_plugin.h
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#ifndef __COMPRESS_PLUGIN_H__
|
||||
#define __COMPRESS_PLUGIN_H__
|
||||
|
||||
#include "sound/compress_params.h"
|
||||
#include "sound/compress_offload.h"
|
||||
|
||||
#define COMPRESS_PLUGIN_OPEN_FN(name) \
|
||||
int name##_open(struct compress_plugin **plugin, \
|
||||
unsigned int card, \
|
||||
unsigned int device, \
|
||||
unsigned int flags)
|
||||
|
||||
#define COMPRESS_PLUGIN_OPEN_FN_PTR() \
|
||||
int (*plugin_open_fn) (struct compress_plugin **plugin, \
|
||||
unsigned int card, \
|
||||
unsigned int device, \
|
||||
unsigned int flags);
|
||||
|
||||
struct compress_plugin;
|
||||
|
||||
struct compress_plugin_ops {
|
||||
void (*close) (struct compress_plugin *plugin);
|
||||
int (*get_caps) (struct compress_plugin *plugin,
|
||||
struct snd_compr_caps *caps);
|
||||
int (*set_params) (struct compress_plugin *plugin,
|
||||
struct snd_compr_params *params);
|
||||
int (*avail) (struct compress_plugin *plugin,
|
||||
struct snd_compr_avail *avail);
|
||||
int (*tstamp) (struct compress_plugin *plugin,
|
||||
struct snd_compr_tstamp *tstamp);
|
||||
int (*write) (struct compress_plugin *plugin,
|
||||
const void *buf, size_t size);
|
||||
int (*read) (struct compress_plugin *plugin,
|
||||
void *buf, size_t size);
|
||||
int (*start) (struct compress_plugin *plugin);
|
||||
int (*stop) (struct compress_plugin *plugin);
|
||||
int (*pause) (struct compress_plugin *plugin);
|
||||
int (*resume) (struct compress_plugin *plugin);
|
||||
int (*drain) (struct compress_plugin *plugin);
|
||||
int (*partial_drain) (struct compress_plugin *plugin);
|
||||
int (*next_track) (struct compress_plugin *plugin);
|
||||
int (*ioctl) (struct compress_plugin *plugin, int cmd, ...);
|
||||
int (*poll) (struct compress_plugin *plugin,
|
||||
struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
};
|
||||
|
||||
struct compress_plugin {
|
||||
unsigned int card;
|
||||
|
||||
struct compress_plugin_ops *ops;
|
||||
|
||||
void *node;
|
||||
int mode;
|
||||
void *priv;
|
||||
|
||||
unsigned int state;
|
||||
};
|
||||
|
||||
#endif /* end of __COMPRESS_PLUGIN_H__ */
|
149
snd_utils.c
Normal file
149
snd_utils.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* snd_utils.c
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "snd_utils.h"
|
||||
|
||||
#define SND_DLSYM(h, p, s, err) \
|
||||
do { \
|
||||
err = 0; \
|
||||
p = dlsym(h, s); \
|
||||
if (!p) \
|
||||
err = -ENODEV; \
|
||||
} while(0)
|
||||
|
||||
int snd_utils_get_int(struct snd_node *node, const char *prop, int *val)
|
||||
{
|
||||
if (!node || !node->card_node || !node->dev_node)
|
||||
return SND_NODE_TYPE_HW;
|
||||
|
||||
return node->get_int(node->dev_node, prop, val);
|
||||
}
|
||||
|
||||
int snd_utils_get_str(struct snd_node *node, const char *prop, char **val)
|
||||
{
|
||||
if (!node || !node->card_node || !node->dev_node)
|
||||
return SND_NODE_TYPE_HW;
|
||||
|
||||
return node->get_str(node->dev_node, prop, val);
|
||||
}
|
||||
|
||||
void snd_utils_put_dev_node(struct snd_node *node)
|
||||
{
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (node->card_node)
|
||||
node->put_card(node->card_node);
|
||||
|
||||
if (node->dl_hdl)
|
||||
dlclose(node->dl_hdl);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
enum snd_node_type snd_utils_get_node_type(struct snd_node *node)
|
||||
{
|
||||
int val = SND_NODE_TYPE_HW;
|
||||
|
||||
if (!node || !node->card_node || !node->dev_node)
|
||||
return SND_NODE_TYPE_HW;
|
||||
|
||||
node->get_int(node->dev_node, "type", &val);
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
|
||||
static int snd_utils_resolve_symbols(struct snd_node *node)
|
||||
{
|
||||
void *dl = node->dl_hdl;
|
||||
int err;
|
||||
|
||||
SND_DLSYM(dl, node->get_card, "snd_card_def_get_card", err);
|
||||
if (err)
|
||||
goto done;
|
||||
SND_DLSYM(dl, node->put_card, "snd_card_def_put_card", err);
|
||||
if (err)
|
||||
goto done;
|
||||
SND_DLSYM(dl, node->get_node, "snd_card_def_get_node", err);
|
||||
if (err)
|
||||
goto done;
|
||||
SND_DLSYM(dl, node->get_int, "snd_card_def_get_int", err);
|
||||
if (err)
|
||||
goto done;
|
||||
SND_DLSYM(dl, node->get_str, "snd_card_def_get_str", err);
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
struct snd_node *snd_utils_get_dev_node(unsigned int card,
|
||||
unsigned int device, int dev_type)
|
||||
{
|
||||
struct snd_node *node;
|
||||
int rc = 0;
|
||||
|
||||
node = calloc(1, sizeof(*node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
node->dl_hdl = dlopen("libsndcardparser.so", RTLD_NOW);
|
||||
if (!node->dl_hdl) {
|
||||
goto err_dl_open;
|
||||
}
|
||||
|
||||
rc = snd_utils_resolve_symbols(node);
|
||||
if (rc < 0)
|
||||
goto err_resolve_symbols;
|
||||
|
||||
node->card_node = node->get_card(card);
|
||||
if (!node->card_node)
|
||||
goto err_resolve_symbols;
|
||||
|
||||
node->dev_node = node->get_node(node->card_node,
|
||||
device, dev_type);
|
||||
if (!node->dev_node)
|
||||
goto err_get_node;
|
||||
|
||||
return node;
|
||||
|
||||
err_get_node:
|
||||
node->put_card(node->card_node);
|
||||
|
||||
err_resolve_symbols:
|
||||
dlclose(node->dl_hdl);
|
||||
|
||||
err_dl_open:
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
72
snd_utils.h
Normal file
72
snd_utils.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* snd_utils.h
|
||||
**
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#ifndef __SND_CARD_UTILS_H__
|
||||
#define __SND_CARD_UTILS_H__
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
struct snd_node {
|
||||
void *card_node;
|
||||
void *dev_node;
|
||||
void *dl_hdl;
|
||||
|
||||
void* (*get_card) (unsigned int card);
|
||||
void (*put_card) (void *card);
|
||||
void* (*get_node) (void *card, unsigned int id,
|
||||
int type);
|
||||
int (*get_int) (void *node, const char *prop, int *val);
|
||||
int (*get_str) (void *node, const char *prop, char **val);
|
||||
};
|
||||
|
||||
enum {
|
||||
NODE_PCM,
|
||||
NODE_MIXER,
|
||||
NODE_COMPRESS,
|
||||
};
|
||||
|
||||
enum snd_node_type {
|
||||
SND_NODE_TYPE_HW = 0,
|
||||
SND_NODE_TYPE_PLUGIN,
|
||||
SND_NODE_TYPE_INVALID,
|
||||
};
|
||||
|
||||
struct snd_node *snd_utils_get_dev_node(unsigned int card,
|
||||
unsigned int device, int dev_type);
|
||||
|
||||
void snd_utils_put_dev_node(struct snd_node *node);
|
||||
|
||||
enum snd_node_type snd_utils_get_node_type(struct snd_node *node);
|
||||
|
||||
int snd_utils_get_int(struct snd_node *node, const char *prop, int *val);
|
||||
|
||||
int snd_utils_get_str(struct snd_node *node, const char *prop, char **val);
|
||||
|
||||
#endif /* end of __SND_CARD_UTILS_H__ */
|
Loading…
Reference in a new issue