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
diff --git a/compress.c b/compress.c
index 5845cae..7422c4b 100644
--- a/compress.c
+++ b/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 @@
 	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 @@
 
 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;
 	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 @@
 	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 @@
 		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 @@
 	memcpy(compress->config, config, sizeof(*compress->config));
 	fill_compress_params(config, &params);
 
-	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_PARAMS, &params)) {
+	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, &params)) {
 		oops(&bad_compress, errno, "cannot set device");
 		goto codec_fail;
 	}
@@ -289,7 +259,8 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 			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 @@
 			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 @@
 		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 @@
 			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 @@
 			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 @@
 {
 	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 @@
 {
 	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 @@
 {
 	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 @@
 {
 	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 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 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 @@
 	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!");