xref: /aosp_15_r20/external/tinycompress/compress_plugin.c (revision de0de75214967e333758016dcf6345eb33d24356)
1 /* compress_plugin.c
2 **
3 ** Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions are
7 ** met:
8 **   * Redistributions of source code must retain the above copyright
9 **     notice, this list of conditions and the following disclaimer.
10 **   * Redistributions in binary form must reproduce the above
11 **     copyright notice, this list of conditions and the following
12 **     disclaimer in the documentation and/or other materials provided
13 **     with the distribution.
14 **   * Neither the name of The Linux Foundation nor the names of its
15 **     contributors may be used to endorse or promote products derived
16 **     from this software without specific prior written permission.
17 **
18 ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
19 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
21 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 **/
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <fcntl.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <poll.h>
40 #include <dlfcn.h>
41 
42 #include <sys/ioctl.h>
43 #include <linux/ioctl.h>
44 #include <sound/asound.h>
45 #include "tinycompress/compress_plugin.h"
46 #include "sound/compress_offload.h"
47 #include "compress_ops.h"
48 #include "snd_utils.h"
49 
50 #define U32_MAX	((uint32_t)~0U)
51 
52 enum {
53 	COMPRESS_PLUG_STATE_OPEN,
54 	COMPRESS_PLUG_STATE_SETUP,
55 	COMPRESS_PLUG_STATE_PREPARED,
56 	COMPRESS_PLUG_STATE_PAUSE,
57 	COMPRESS_PLUG_STATE_RUNNING,
58 };
59 
60 struct compress_plug_data {
61 	unsigned int card;
62 	unsigned int device;
63 	unsigned int fd;
64 	unsigned int flags;
65 
66 	void *dl_hdl;
67 	COMPRESS_PLUGIN_OPEN_FN_PTR();
68 
69 	struct compress_plugin *plugin;
70 	void *dev_node;
71 };
72 
compress_plug_get_caps(struct compress_plug_data * plug_data,struct snd_compr_caps * caps)73 static int compress_plug_get_caps(struct compress_plug_data *plug_data,
74 		struct snd_compr_caps *caps)
75 {
76 	struct compress_plugin *plugin = plug_data->plugin;
77 
78 	return plugin->ops->get_caps(plugin, caps);
79 }
80 
compress_plug_set_params(struct compress_plug_data * plug_data,struct snd_compr_params * params)81 static int compress_plug_set_params(struct compress_plug_data *plug_data,
82 		struct snd_compr_params *params)
83 {
84 	struct compress_plugin *plugin = plug_data->plugin;
85 	int rc;
86 
87 	if (plugin->state == COMPRESS_PLUG_STATE_RUNNING)
88 		return plugin->ops->set_params(plugin, params);
89 	else if (plugin->state != COMPRESS_PLUG_STATE_OPEN)
90 		return -EBADFD;
91 
92 	if (params->buffer.fragment_size == 0 ||
93 	   params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
94 	   params->buffer.fragments == 0)
95 		return -EINVAL;
96 
97 	rc = plugin->ops->set_params(plugin, params);
98 	if (!rc)
99 		plugin->state = COMPRESS_PLUG_STATE_SETUP;
100 
101 	return rc;
102 }
103 
compress_plug_avail(struct compress_plug_data * plug_data,struct snd_compr_avail * avail)104 static int compress_plug_avail(struct compress_plug_data *plug_data,
105 		struct snd_compr_avail *avail)
106 {
107 	struct compress_plugin *plugin = plug_data->plugin;
108 
109 	return plugin->ops->avail(plugin, avail);
110 }
111 
compress_plug_tstamp(struct compress_plug_data * plug_data,struct snd_compr_tstamp * tstamp)112 static int compress_plug_tstamp(struct compress_plug_data *plug_data,
113 		struct snd_compr_tstamp *tstamp)
114 {
115 	struct compress_plugin *plugin = plug_data->plugin;
116 
117 	if (plugin->state != COMPRESS_PLUG_STATE_SETUP)
118 		return -EBADFD;
119 
120 	return plugin->ops->tstamp(plugin, tstamp);
121 }
122 
compress_plug_start(struct compress_plug_data * plug_data)123 static int compress_plug_start(struct compress_plug_data *plug_data)
124 {
125 	struct compress_plugin *plugin = plug_data->plugin;
126 	int rc;
127 
128 	/* for playback moved to prepare in first write */
129 	/* for capture: move to prepare state set params */
130 	 /* TODO: add direction in set params */
131 	if (plugin->state != COMPRESS_PLUG_STATE_PREPARED)
132 		return -EBADFD;
133 
134 	rc = plugin->ops->start(plugin);
135 	if (!rc)
136 		plugin->state = COMPRESS_PLUG_STATE_RUNNING;
137 
138 	return rc;
139 }
140 
compress_plug_stop(struct compress_plug_data * plug_data)141 static int compress_plug_stop(struct compress_plug_data *plug_data)
142 {
143 	struct compress_plugin *plugin = plug_data->plugin;
144 	int rc;
145 
146 	if (plugin->state == COMPRESS_PLUG_STATE_PREPARED ||
147 		plugin->state == COMPRESS_PLUG_STATE_SETUP)
148 		return -EBADFD;
149 
150 	rc = plugin->ops->stop(plugin);
151 	if (!rc)
152 		plugin->state = COMPRESS_PLUG_STATE_SETUP;
153 
154 	return rc;
155 }
156 
compress_plug_pause(struct compress_plug_data * plug_data)157 static int compress_plug_pause(struct compress_plug_data *plug_data)
158 {
159 	struct compress_plugin *plugin = plug_data->plugin;
160 	int rc;
161 
162 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
163 		return -EBADFD;
164 
165 	rc = plugin->ops->pause(plugin);
166 	if (!rc)
167 		plugin->state = COMPRESS_PLUG_STATE_PAUSE;
168 
169 	return rc;
170 }
171 
compress_plug_resume(struct compress_plug_data * plug_data)172 static int compress_plug_resume(struct compress_plug_data *plug_data)
173 {
174 	struct compress_plugin *plugin = plug_data->plugin;
175 	int rc;
176 
177 	if (plugin->state != COMPRESS_PLUG_STATE_PAUSE)
178 		return -EBADFD;
179 
180 	rc = plugin->ops->resume(plugin);
181 	if (!rc)
182 		plugin->state = COMPRESS_PLUG_STATE_RUNNING;
183 
184 	return rc;
185 }
186 
compress_plug_drain(struct compress_plug_data * plug_data)187 static int compress_plug_drain(struct compress_plug_data *plug_data)
188 {
189 	struct compress_plugin *plugin = plug_data->plugin;
190 
191 	/* check if we will allow in pause */
192 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
193 		return -EBADFD;
194 
195 	return plugin->ops->drain(plugin);
196 }
197 
compress_plug_partial_drain(struct compress_plug_data * plug_data)198 static int compress_plug_partial_drain(struct compress_plug_data *plug_data)
199 {
200 	struct compress_plugin *plugin = plug_data->plugin;
201 
202 	 /* check if we will allow in pause */
203 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
204 		return -EBADFD;
205 
206 	return plugin->ops->partial_drain(plugin);
207 }
208 
compress_plug_next_track(struct compress_plug_data * plug_data)209 static int compress_plug_next_track(struct compress_plug_data *plug_data)
210 {
211 	struct compress_plugin *plugin = plug_data->plugin;
212 
213 	/* transion to next track applied to running stream only */
214 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
215 		return -EBADFD;
216 
217 	return plugin->ops->next_track(plugin);
218 }
219 
compress_plug_ioctl(void * data,unsigned int cmd,...)220 static int compress_plug_ioctl(void *data, unsigned int cmd, ...)
221 {
222 	struct compress_plug_data *plug_data = data;
223 	struct compress_plugin *plugin = plug_data->plugin;
224 	int ret = 0;
225 	va_list ap;
226 	void *arg;
227 
228 	va_start(ap, cmd);
229 	arg = va_arg(ap, void *);
230 	va_end(ap);
231 
232 	switch (cmd) {
233 	case SNDRV_COMPRESS_IOCTL_VERSION:
234 		*((int*)arg) = SNDRV_COMPRESS_VERSION;
235 		break;
236 	case SNDRV_COMPRESS_GET_CAPS:
237 		ret = compress_plug_get_caps(plug_data, arg);
238 		break;
239 	case SNDRV_COMPRESS_SET_PARAMS:
240 		ret = compress_plug_set_params(plug_data, arg);
241 		break;
242 	case SNDRV_COMPRESS_AVAIL:
243 		ret = compress_plug_avail(plug_data, arg);
244 		break;
245 	case SNDRV_COMPRESS_TSTAMP:
246 		ret = compress_plug_tstamp(plug_data, arg);
247 		break;
248 	case SNDRV_COMPRESS_START:
249 		ret = compress_plug_start(plug_data);
250 		break;
251 	case SNDRV_COMPRESS_STOP:
252 		ret = compress_plug_stop(plug_data);
253 		break;
254 	case SNDRV_COMPRESS_PAUSE:
255 		ret = compress_plug_pause(plug_data);
256 		break;
257 	case SNDRV_COMPRESS_RESUME:
258 		ret = compress_plug_resume(plug_data);
259 		break;
260 	case SNDRV_COMPRESS_DRAIN:
261 		ret = compress_plug_drain(plug_data);
262 		break;
263 	case SNDRV_COMPRESS_PARTIAL_DRAIN:
264 		ret = compress_plug_partial_drain(plug_data);
265 		break;
266 	case SNDRV_COMPRESS_NEXT_TRACK:
267 		ret = compress_plug_next_track(plug_data);
268 		break;
269 	default:
270 		if (plugin->ops->ioctl)
271 			ret = plugin->ops->ioctl(plugin, cmd, arg);
272 		else
273 			ret = -EINVAL;
274 		break;
275 	}
276 
277 	return ret;
278 }
279 
compress_plug_poll(void * data,struct pollfd * fds,nfds_t nfds,int timeout)280 static int compress_plug_poll(void *data, struct pollfd *fds,
281 				nfds_t nfds, int timeout)
282 {
283 	struct compress_plug_data *plug_data = data;
284 	struct compress_plugin *plugin = plug_data->plugin;
285 
286 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
287 		return -EBADFD;
288 
289 	return plugin->ops->poll(plugin, fds, nfds, timeout);
290 }
291 
292 
compress_plug_read(void * data,void * buf,size_t size)293 static int compress_plug_read(void *data, void *buf, size_t size)
294 {
295 	struct compress_plug_data *plug_data = data;
296 	struct compress_plugin *plugin = plug_data->plugin;
297 
298 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING &&
299 		plugin->state != COMPRESS_PLUG_STATE_SETUP)
300 		return -EBADFD;
301 
302 	return plugin->ops->read(plugin, buf, size);
303 }
304 
compress_plug_write(void * data,const void * buf,size_t size)305 static int compress_plug_write(void *data, const void *buf, size_t size)
306 {
307 	struct compress_plug_data *plug_data = data;
308 	struct compress_plugin *plugin = plug_data->plugin;
309 	int rc;
310 
311 	if (plugin->state != COMPRESS_PLUG_STATE_SETUP &&
312 	    plugin->state != COMPRESS_PLUG_STATE_PREPARED &&
313 	    plugin->state != COMPRESS_PLUG_STATE_RUNNING)
314 		return -EBADFD;
315 
316 	rc = plugin->ops->write(plugin, buf, size);
317 	if ((rc > 0) && (plugin->state == COMPRESS_PLUG_STATE_SETUP))
318 		plugin->state = COMPRESS_PLUG_STATE_PREPARED;
319 
320 	return rc;
321 }
322 
compress_plug_close(void * data)323 static void compress_plug_close(void *data)
324 {
325 	struct compress_plug_data *plug_data = data;
326 	struct compress_plugin *plugin = plug_data->plugin;
327 
328 	plugin->ops->close(plugin);
329 	dlclose(plug_data->dl_hdl);
330 
331 	free(plug_data);
332 }
333 
compress_plug_open(unsigned int card,unsigned int device,unsigned int flags,void ** data,void * node)334 static int compress_plug_open(unsigned int card, unsigned int device,
335 			unsigned int flags, void **data, void *node)
336 {
337 	struct compress_plug_data *plug_data;
338 	void *dl_hdl;
339 	int rc = 0;
340 	char *so_name, *open_fn, token[80], *name, *token_saveptr;
341 
342 	plug_data = calloc(1, sizeof(*plug_data));
343 	if (!plug_data) {
344 		return -ENOMEM;
345 	}
346 
347 	rc = snd_utils_get_str(node, "so-name", &so_name);
348 	if (rc) {
349 		fprintf(stderr, "%s: failed to get plugin lib name\n",
350 				__func__);
351 		goto err_get_lib;
352 	}
353 
354 	dl_hdl = dlopen(so_name, RTLD_NOW);
355 	if (!dl_hdl) {
356 		fprintf(stderr, "%s: unable to open %s, error: %s\n",
357 					__func__, so_name, dlerror());
358 		goto err_dl_open;
359 	} else {
360 		fprintf(stderr, "%s: dlopen successful for %s\n",
361 					__func__, so_name);
362 	}
363 
364 	sscanf(so_name, "lib%s", token);
365 	token_saveptr = token;
366 	name = strtok_r(token, ".", &token_saveptr);
367 	if (!name) {
368 		fprintf(stderr, "%s: invalid library name\n", __func__);
369 		goto err_open_fn;
370 	}
371 	const size_t open_fn_size = strlen(name) + strlen("_open") + 1;
372 	open_fn = calloc(1, open_fn_size);
373 	if (!open_fn) {
374 		rc = -ENOMEM;
375 		goto err_open_fn;
376 	}
377 
378 	strlcpy(open_fn, name, open_fn_size);
379 	strlcat(open_fn, "_open", open_fn_size);
380 
381 	plug_data->plugin_open_fn = dlsym(dl_hdl, open_fn);
382 	if (!plug_data->plugin_open_fn) {
383 		fprintf(stderr, "%s: dlsym to open fn failed, err = '%s'\n",
384 				__func__, dlerror());
385 		goto err_dlsym;
386 	}
387 
388 	rc = plug_data->plugin_open_fn(&plug_data->plugin,
389 					card, device, flags);
390 	if (rc) {
391 		fprintf(stderr, "%s: failed to open plugin\n", __func__);
392 		goto err_dlsym;
393 	}
394 
395 	/* Call snd-card-def to get card and compress nodes */
396 	/* Check how to manage fd for plugin */
397 
398 	plug_data->dl_hdl = dl_hdl;
399 	plug_data->card = card;
400 	plug_data->device = device;
401 	plug_data->dev_node = node;
402 	plug_data->flags = flags;
403 
404 	*data = plug_data;
405 
406 	plug_data->plugin->state = COMPRESS_PLUG_STATE_OPEN;
407 
408 	return 0;
409 
410 err_dlsym:
411 	free(open_fn);
412 err_open_fn:
413 	dlclose(dl_hdl);
414 err_get_lib:
415 err_dl_open:
416 	free(plug_data);
417 
418 	return rc;
419 }
420 
421 struct compress_ops compr_plug_ops = {
422 	.open = compress_plug_open,
423 	.close = compress_plug_close,
424 	.ioctl = compress_plug_ioctl,
425 	.read = compress_plug_read,
426 	.write = compress_plug_write,
427 	.poll = compress_plug_poll,
428 };
429