• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_OPEN)
88 		return -EBADFD;
89 
90 	if (params->buffer.fragment_size == 0 ||
91 	   params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
92 	   params->buffer.fragments == 0)
93 		return -EINVAL;
94 
95 	rc = plugin->ops->set_params(plugin, params);
96 	if (!rc)
97 		plugin->state = COMPRESS_PLUG_STATE_SETUP;
98 
99 	return rc;
100 }
101 
compress_plug_avail(struct compress_plug_data * plug_data,struct snd_compr_avail * avail)102 static int compress_plug_avail(struct compress_plug_data *plug_data,
103 		struct snd_compr_avail *avail)
104 {
105 	struct compress_plugin *plugin = plug_data->plugin;
106 
107 	return plugin->ops->avail(plugin, avail);
108 }
109 
compress_plug_tstamp(struct compress_plug_data * plug_data,struct snd_compr_tstamp * tstamp)110 static int compress_plug_tstamp(struct compress_plug_data *plug_data,
111 		struct snd_compr_tstamp *tstamp)
112 {
113 	struct compress_plugin *plugin = plug_data->plugin;
114 
115 	if (plugin->state != COMPRESS_PLUG_STATE_SETUP)
116 		return -EBADFD;
117 
118 	return plugin->ops->tstamp(plugin, tstamp);
119 }
120 
compress_plug_start(struct compress_plug_data * plug_data)121 static int compress_plug_start(struct compress_plug_data *plug_data)
122 {
123 	struct compress_plugin *plugin = plug_data->plugin;
124 	int rc;
125 
126 	/* for playback moved to prepare in first write */
127 	/* for capture: move to prepare state set params */
128 	 /* TODO: add direction in set params */
129 	if (plugin->state != COMPRESS_PLUG_STATE_PREPARED)
130 		return -EBADFD;
131 
132 	rc = plugin->ops->start(plugin);
133 	if (!rc)
134 		plugin->state = COMPRESS_PLUG_STATE_RUNNING;
135 
136 	return rc;
137 }
138 
compress_plug_stop(struct compress_plug_data * plug_data)139 static int compress_plug_stop(struct compress_plug_data *plug_data)
140 {
141 	struct compress_plugin *plugin = plug_data->plugin;
142 	int rc;
143 
144 	if (plugin->state == COMPRESS_PLUG_STATE_PREPARED ||
145 		plugin->state == COMPRESS_PLUG_STATE_SETUP)
146 		return -EBADFD;
147 
148 	rc = plugin->ops->stop(plugin);
149 	if (!rc)
150 		plugin->state = COMPRESS_PLUG_STATE_SETUP;
151 
152 	return rc;
153 }
154 
compress_plug_pause(struct compress_plug_data * plug_data)155 static int compress_plug_pause(struct compress_plug_data *plug_data)
156 {
157 	struct compress_plugin *plugin = plug_data->plugin;
158 	int rc;
159 
160 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
161 		return -EBADFD;
162 
163 	rc = plugin->ops->pause(plugin);
164 	if (!rc)
165 		plugin->state = COMPRESS_PLUG_STATE_PAUSE;
166 
167 	return rc;
168 }
169 
compress_plug_resume(struct compress_plug_data * plug_data)170 static int compress_plug_resume(struct compress_plug_data *plug_data)
171 {
172 	struct compress_plugin *plugin = plug_data->plugin;
173 	int rc;
174 
175 	if (plugin->state != COMPRESS_PLUG_STATE_PAUSE)
176 		return -EBADFD;
177 
178 	rc = plugin->ops->resume(plugin);
179 	if (!rc)
180 		plugin->state = COMPRESS_PLUG_STATE_RUNNING;
181 
182 	return rc;
183 }
184 
compress_plug_drain(struct compress_plug_data * plug_data)185 static int compress_plug_drain(struct compress_plug_data *plug_data)
186 {
187 	struct compress_plugin *plugin = plug_data->plugin;
188 
189 	/* check if we will allow in pause */
190 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
191 		return -EBADFD;
192 
193 	return plugin->ops->drain(plugin);
194 }
195 
compress_plug_partial_drain(struct compress_plug_data * plug_data)196 static int compress_plug_partial_drain(struct compress_plug_data *plug_data)
197 {
198 	struct compress_plugin *plugin = plug_data->plugin;
199 
200 	 /* check if we will allow in pause */
201 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
202 		return -EBADFD;
203 
204 	return plugin->ops->partial_drain(plugin);
205 }
206 
compress_plug_next_track(struct compress_plug_data * plug_data)207 static int compress_plug_next_track(struct compress_plug_data *plug_data)
208 {
209 	struct compress_plugin *plugin = plug_data->plugin;
210 
211 	/* transion to next track applied to running stream only */
212 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
213 		return -EBADFD;
214 
215 	return plugin->ops->next_track(plugin);
216 }
217 
compress_plug_ioctl(void * data,unsigned int cmd,...)218 static int compress_plug_ioctl(void *data, unsigned int cmd, ...)
219 {
220 	struct compress_plug_data *plug_data = data;
221 	struct compress_plugin *plugin = plug_data->plugin;
222 	int ret = 0;
223 	va_list ap;
224 	void *arg;
225 
226 	va_start(ap, cmd);
227 	arg = va_arg(ap, void *);
228 	va_end(ap);
229 
230 	switch (cmd) {
231 	case SNDRV_COMPRESS_IOCTL_VERSION:
232 		*((int*)arg) = SNDRV_COMPRESS_VERSION;
233 		break;
234 	case SNDRV_COMPRESS_GET_CAPS:
235 		ret = compress_plug_get_caps(plug_data, arg);
236 		break;
237 	case SNDRV_COMPRESS_SET_PARAMS:
238 		ret = compress_plug_set_params(plug_data, arg);
239 		break;
240 	case SNDRV_COMPRESS_AVAIL:
241 		ret = compress_plug_avail(plug_data, arg);
242 		break;
243 	case SNDRV_COMPRESS_TSTAMP:
244 		ret = compress_plug_tstamp(plug_data, arg);
245 		break;
246 	case SNDRV_COMPRESS_START:
247 		ret = compress_plug_start(plug_data);
248 		break;
249 	case SNDRV_COMPRESS_STOP:
250 		ret = compress_plug_stop(plug_data);
251 		break;
252 	case SNDRV_COMPRESS_PAUSE:
253 		ret = compress_plug_pause(plug_data);
254 		break;
255 	case SNDRV_COMPRESS_RESUME:
256 		ret = compress_plug_resume(plug_data);
257 		break;
258 	case SNDRV_COMPRESS_DRAIN:
259 		ret = compress_plug_drain(plug_data);
260 		break;
261 	case SNDRV_COMPRESS_PARTIAL_DRAIN:
262 		ret = compress_plug_partial_drain(plug_data);
263 		break;
264 	case SNDRV_COMPRESS_NEXT_TRACK:
265 		ret = compress_plug_next_track(plug_data);
266 		break;
267 	default:
268 		if (plugin->ops->ioctl)
269 			ret = plugin->ops->ioctl(plugin, cmd, arg);
270 		else
271 			ret = -EINVAL;
272 		break;
273 	}
274 
275 	return ret;
276 }
277 
compress_plug_poll(void * data,struct pollfd * fds,nfds_t nfds,int timeout)278 static int compress_plug_poll(void *data, struct pollfd *fds,
279 				nfds_t nfds, int timeout)
280 {
281 	struct compress_plug_data *plug_data = data;
282 	struct compress_plugin *plugin = plug_data->plugin;
283 
284 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING)
285 		return -EBADFD;
286 
287 	return plugin->ops->poll(plugin, fds, nfds, timeout);
288 }
289 
290 
compress_plug_read(void * data,void * buf,size_t size)291 static int compress_plug_read(void *data, void *buf, size_t size)
292 {
293 	struct compress_plug_data *plug_data = data;
294 	struct compress_plugin *plugin = plug_data->plugin;
295 
296 	if (plugin->state != COMPRESS_PLUG_STATE_RUNNING &&
297 		plugin->state != COMPRESS_PLUG_STATE_SETUP)
298 		return -EBADFD;
299 
300 	return plugin->ops->read(plugin, buf, size);
301 }
302 
compress_plug_write(void * data,const void * buf,size_t size)303 static int compress_plug_write(void *data, const void *buf, size_t size)
304 {
305 	struct compress_plug_data *plug_data = data;
306 	struct compress_plugin *plugin = plug_data->plugin;
307 	int rc;
308 
309 	if (plugin->state != COMPRESS_PLUG_STATE_SETUP &&
310 	    plugin->state != COMPRESS_PLUG_STATE_PREPARED &&
311 	    plugin->state != COMPRESS_PLUG_STATE_RUNNING)
312 		return -EBADFD;
313 
314 	rc = plugin->ops->write(plugin, buf, size);
315 	if ((rc > 0) && (plugin->state == COMPRESS_PLUG_STATE_SETUP))
316 		plugin->state = COMPRESS_PLUG_STATE_PREPARED;
317 
318 	return rc;
319 }
320 
compress_plug_close(void * data)321 static void compress_plug_close(void *data)
322 {
323 	struct compress_plug_data *plug_data = data;
324 	struct compress_plugin *plugin = plug_data->plugin;
325 
326 	plugin->ops->close(plugin);
327 	dlclose(plug_data->dl_hdl);
328 
329 	free(plug_data);
330 }
331 
compress_plug_open(unsigned int card,unsigned int device,unsigned int flags,void ** data,void * node)332 static int compress_plug_open(unsigned int card, unsigned int device,
333 			unsigned int flags, void **data, void *node)
334 {
335 	struct compress_plug_data *plug_data;
336 	void *dl_hdl;
337 	int rc = 0;
338 	char *so_name, *open_fn, token[80], *name, *token_saveptr;
339 
340 	plug_data = calloc(1, sizeof(*plug_data));
341 	if (!plug_data) {
342 		return -ENOMEM;
343 	}
344 
345 	rc = snd_utils_get_str(node, "so-name", &so_name);
346 	if (rc) {
347 		fprintf(stderr, "%s: failed to get plugin lib name\n",
348 				__func__);
349 		goto err_get_lib;
350 	}
351 
352 	dl_hdl = dlopen(so_name, RTLD_NOW);
353 	if (!dl_hdl) {
354 		fprintf(stderr, "%s: unable to open %s, error: %s\n",
355 					__func__, so_name, dlerror());
356 		goto err_dl_open;
357 	} else {
358 		fprintf(stderr, "%s: dlopen successful for %s\n",
359 					__func__, so_name);
360 	}
361 
362 	sscanf(so_name, "lib%s", token);
363 	token_saveptr = token;
364 	name = strtok_r(token, ".", &token_saveptr);
365 	if (!name) {
366 		fprintf(stderr, "%s: invalid library name\n", __func__);
367 		goto err_open_fn;
368 	}
369 	const size_t open_fn_size = strlen(name) + strlen("_open") + 1;
370 	open_fn = calloc(1, open_fn_size);
371 	if (!open_fn) {
372 		rc = -ENOMEM;
373 		goto err_open_fn;
374 	}
375 
376 	strlcpy(open_fn, name, open_fn_size);
377 	strlcat(open_fn, "_open", open_fn_size);
378 
379 	plug_data->plugin_open_fn = dlsym(dl_hdl, open_fn);
380 	if (!plug_data->plugin_open_fn) {
381 		fprintf(stderr, "%s: dlsym to open fn failed, err = '%s'\n",
382 				__func__, dlerror());
383 		goto err_dlsym;
384 	}
385 
386 	rc = plug_data->plugin_open_fn(&plug_data->plugin,
387 					card, device, flags);
388 	if (rc) {
389 		fprintf(stderr, "%s: failed to open plugin\n", __func__);
390 		goto err_dlsym;
391 	}
392 
393 	/* Call snd-card-def to get card and compress nodes */
394 	/* Check how to manage fd for plugin */
395 
396 	plug_data->dl_hdl = dl_hdl;
397 	plug_data->card = card;
398 	plug_data->device = device;
399 	plug_data->dev_node = node;
400 	plug_data->flags = flags;
401 
402 	*data = plug_data;
403 
404 	plug_data->plugin->state = COMPRESS_PLUG_STATE_OPEN;
405 
406 	return 0;
407 
408 err_dlsym:
409 	free(open_fn);
410 err_open_fn:
411 	dlclose(dl_hdl);
412 err_get_lib:
413 err_dl_open:
414 	free(plug_data);
415 
416 	return rc;
417 }
418 
419 struct compress_ops compr_plug_ops = {
420 	.open = compress_plug_open,
421 	.close = compress_plug_close,
422 	.ioctl = compress_plug_ioctl,
423 	.read = compress_plug_read,
424 	.write = compress_plug_write,
425 	.poll = compress_plug_poll,
426 };
427