• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * BSD LICENSE
3  *
4  * tinycompress library for compress audio offload in alsa
5  * Copyright (c) 2011-2012, Intel Corporation
6  * All rights reserved.
7  *
8  * Author: Vinod Koul <vinod.koul@linux.intel.com>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * Neither the name of Intel Corporation nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * LGPL LICENSE
35  *
36  * tinycompress library for compress audio offload in alsa
37  * Copyright (c) 2011-2012, Intel Corporation.
38  *
39  *
40  * This program is free software; you can redistribute it and/or modify it
41  * under the terms and conditions of the GNU Lesser General Public License,
42  * version 2.1, as published by the Free Software Foundation.
43  *
44  * This program is distributed in the hope it will be useful, but WITHOUT
45  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
47  * License for more details.
48  *
49  * You should have received a copy of the GNU Lesser General Public License
50  * along with this program; if not, write to
51  * the Free Software Foundation, Inc.,
52  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
53  */
54 
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <fcntl.h>
58 #include <stdarg.h>
59 #include <string.h>
60 #include <errno.h>
61 #include <unistd.h>
62 #include <poll.h>
63 #include <stdbool.h>
64 #include <sys/ioctl.h>
65 #include <sys/mman.h>
66 #include <sys/time.h>
67 #include <limits.h>
68 
69 #include <linux/types.h>
70 #include <linux/ioctl.h>
71 #define __force
72 #define __bitwise
73 #define __user
74 #include <sound/asound.h>
75 #include "sound/compress_params.h"
76 #include "sound/compress_offload.h"
77 #include "tinycompress/tinycompress.h"
78 
79 #define COMPR_ERR_MAX 128
80 
81 /* Default maximum time we will wait in a poll() - 20 seconds */
82 #define DEFAULT_MAX_POLL_WAIT_MS    20000
83 
84 struct compress {
85 	int fd;
86 	unsigned int flags;
87 	char error[COMPR_ERR_MAX];
88 	struct compr_config *config;
89 	int running;
90 	int max_poll_wait_ms;
91 	int nonblocking;
92 	unsigned int gapless_metadata;
93 	unsigned int next_track;
94 };
95 
oops(struct compress * compress,int e,const char * fmt,...)96 static int oops(struct compress *compress, int e, const char *fmt, ...)
97 {
98 	va_list ap;
99 	int sz;
100 
101 	va_start(ap, fmt);
102 	vsnprintf(compress->error, COMPR_ERR_MAX, fmt, ap);
103 	va_end(ap);
104 	sz = strlen(compress->error);
105 
106 	snprintf(compress->error + sz, COMPR_ERR_MAX - sz,
107 		": %s", strerror(e));
108 	errno = e;
109 
110 	return -1;
111 }
112 
compress_get_error(struct compress * compress)113 const char *compress_get_error(struct compress *compress)
114 {
115 	return compress->error;
116 }
117 static struct compress bad_compress = {
118 	.fd = -1,
119 };
120 
is_compress_running(struct compress * compress)121 int is_compress_running(struct compress *compress)
122 {
123 	return ((compress->fd > 0) && compress->running) ? 1 : 0;
124 }
125 
is_compress_ready(struct compress * compress)126 int is_compress_ready(struct compress *compress)
127 {
128 	return (compress->fd > 0) ? 1 : 0;
129 }
130 
get_compress_version(struct compress * compress)131 static int get_compress_version(struct compress *compress)
132 {
133 	int version = 0;
134 
135 	if (ioctl(compress->fd, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
136 		oops(compress, errno, "cant read version");
137 		return -1;
138 	}
139 	return version;
140 }
141 
_is_codec_supported(struct compress * compress,struct compr_config * config,const struct snd_compr_caps * caps)142 static bool _is_codec_supported(struct compress *compress, struct compr_config *config,
143 				const struct snd_compr_caps *caps)
144 {
145 	bool codec = false;
146 	unsigned int i;
147 
148 	for (i = 0; i < caps->num_codecs; i++) {
149 		if (caps->codecs[i] == config->codec->id) {
150 			/* found the codec */
151 			codec = true;
152 			break;
153 		}
154 	}
155 	if (codec == false) {
156 		oops(compress, ENXIO, "this codec is not supported");
157 		return false;
158 	}
159 
160 	if (config->fragment_size < caps->min_fragment_size) {
161 		oops(compress, EINVAL, "requested fragment size %d is below min supported %d",
162 			config->fragment_size, caps->min_fragment_size);
163 		return false;
164 	}
165 	if (config->fragment_size > caps->max_fragment_size) {
166 		oops(compress, EINVAL, "requested fragment size %d is above max supported %d",
167 			config->fragment_size, caps->max_fragment_size);
168 		return false;
169 	}
170 	if (config->fragments < caps->min_fragments) {
171 		oops(compress, EINVAL, "requested fragments %d are below min supported %d",
172 			config->fragments, caps->min_fragments);
173 		return false;
174 	}
175 	if (config->fragments > caps->max_fragments) {
176 		oops(compress, EINVAL, "requested fragments %d are above max supported %d",
177 			config->fragments, caps->max_fragments);
178 		return false;
179 	}
180 
181 	/* TODO: match the codec properties */
182 	return true;
183 }
184 
_is_codec_type_supported(int fd,struct snd_codec * codec)185 static bool _is_codec_type_supported(int fd, struct snd_codec *codec)
186 {
187 	struct snd_compr_caps caps;
188 	bool found = false;
189 	unsigned int i;
190 
191 	if (ioctl(fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
192 		oops(&bad_compress, errno, "cannot get device caps");
193 		return false;
194 	}
195 
196 	for (i = 0; i < caps.num_codecs; i++) {
197 		if (caps.codecs[i] == codec->id) {
198 			/* found the codec */
199 			found = true;
200 			break;
201 		}
202 	}
203 	/* TODO: match the codec properties */
204 	return found;
205 }
206 
207 static inline void
fill_compress_params(struct compr_config * config,struct snd_compr_params * params)208 fill_compress_params(struct compr_config *config, struct snd_compr_params *params)
209 {
210 	params->buffer.fragment_size = config->fragment_size;
211 	params->buffer.fragments = config->fragments;
212 	memcpy(&params->codec, config->codec, sizeof(params->codec));
213 }
214 
compress_open(unsigned int card,unsigned int device,unsigned int flags,struct compr_config * config)215 struct compress *compress_open(unsigned int card, unsigned int device,
216 		unsigned int flags, struct compr_config *config)
217 {
218 	struct compress *compress;
219 	struct snd_compr_params params;
220 	struct snd_compr_caps caps;
221 	char fn[256];
222 
223 	if (!config) {
224 		oops(&bad_compress, EINVAL, "passed bad config");
225 		return &bad_compress;
226 	}
227 
228 	compress = calloc(1, sizeof(struct compress));
229 	if (!compress) {
230 		oops(&bad_compress, errno, "cannot allocate compress object");
231 		return &bad_compress;
232 	}
233 
234 	compress->next_track = 0;
235 	compress->gapless_metadata = 0;
236 	compress->config = calloc(1, sizeof(*config));
237 	if (!compress->config)
238 		goto input_fail;
239 
240 	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
241 
242 	compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
243 
244 	compress->flags = flags;
245 	if (!((flags & COMPRESS_OUT) || (flags & COMPRESS_IN))) {
246 		oops(&bad_compress, EINVAL, "can't deduce device direction from given flags");
247 		goto config_fail;
248 	}
249 
250 	if (flags & COMPRESS_OUT) {
251 		compress->fd = open(fn, O_RDONLY);
252 	} else {
253 		compress->fd = open(fn, O_WRONLY);
254 	}
255 	if (compress->fd < 0) {
256 		oops(&bad_compress, errno, "cannot open device '%s'", fn);
257 		goto config_fail;
258 	}
259 
260 	if (ioctl(compress->fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
261 		oops(compress, errno, "cannot get device caps");
262 		goto codec_fail;
263 	}
264 
265 	/* If caller passed "don't care" fill in default values */
266 	if ((config->fragment_size == 0) || (config->fragments == 0)) {
267 		config->fragment_size = caps.min_fragment_size;
268 		config->fragments = caps.max_fragments;
269 	}
270 
271 #if 0
272 	/* FIXME need to turn this On when DSP supports
273 	 * and treat in no support case
274 	 */
275 	if (_is_codec_supported(compress, config, &caps) == false) {
276 		oops(compress, errno, "codec not supported\n");
277 		goto codec_fail;
278 	}
279 #endif
280 
281 	memcpy(compress->config, config, sizeof(*compress->config));
282 	fill_compress_params(config, &params);
283 
284 	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_PARAMS, &params)) {
285 		oops(&bad_compress, errno, "cannot set device");
286 		goto codec_fail;
287 	}
288 
289 	return compress;
290 
291 codec_fail:
292 	close(compress->fd);
293 	compress->fd = -1;
294 config_fail:
295 	free(compress->config);
296 input_fail:
297 	free(compress);
298 	return &bad_compress;
299 }
300 
compress_close(struct compress * compress)301 void compress_close(struct compress *compress)
302 {
303 	if (compress == &bad_compress)
304 		return;
305 
306 	if (compress->fd >= 0)
307 		close(compress->fd);
308 	compress->running = 0;
309 	compress->fd = -1;
310 	free(compress->config);
311 	free(compress);
312 }
313 
compress_get_hpointer(struct compress * compress,unsigned int * avail,struct timespec * tstamp)314 int compress_get_hpointer(struct compress *compress,
315 		unsigned int *avail, struct timespec *tstamp)
316 {
317 	struct snd_compr_avail kavail;
318 	__u64 time;
319 
320 	if (!is_compress_ready(compress))
321 		return oops(compress, ENODEV, "device not ready");
322 
323 	if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &kavail))
324 		return oops(compress, errno, "cannot get avail");
325 	if (0 == kavail.tstamp.sampling_rate)
326 		return oops(compress, ENODATA, "sample rate unknown");
327 	*avail = (unsigned int)kavail.avail;
328 	time = kavail.tstamp.pcm_io_frames / kavail.tstamp.sampling_rate;
329 	tstamp->tv_sec = time;
330 	time = kavail.tstamp.pcm_io_frames % kavail.tstamp.sampling_rate;
331 	tstamp->tv_nsec = time * 1000000000 / kavail.tstamp.sampling_rate;
332 	return 0;
333 }
334 
compress_get_tstamp(struct compress * compress,unsigned long * samples,unsigned int * sampling_rate)335 int compress_get_tstamp(struct compress *compress,
336 			unsigned long *samples, unsigned int *sampling_rate)
337 {
338 	struct snd_compr_tstamp ktstamp;
339 
340 	if (!is_compress_ready(compress))
341 		return oops(compress, ENODEV, "device not ready");
342 
343 	if (ioctl(compress->fd, SNDRV_COMPRESS_TSTAMP, &ktstamp))
344 		return oops(compress, errno, "cannot get tstamp");
345 
346 	*samples = ktstamp.pcm_io_frames;
347 	*sampling_rate = ktstamp.sampling_rate;
348 	return 0;
349 }
350 
compress_write(struct compress * compress,const void * buf,unsigned int size)351 int compress_write(struct compress *compress, const void *buf, unsigned int size)
352 {
353 	struct snd_compr_avail avail;
354 	struct pollfd fds;
355 	int to_write = 0;	/* zero indicates we haven't written yet */
356 	int written, total = 0, ret;
357 	const char* cbuf = buf;
358 	const unsigned int frag_size = compress->config->fragment_size;
359 
360 	if (!(compress->flags & COMPRESS_IN))
361 		return oops(compress, EINVAL, "Invalid flag set");
362 	if (!is_compress_ready(compress))
363 		return oops(compress, ENODEV, "device not ready");
364 	fds.fd = compress->fd;
365 	fds.events = POLLOUT;
366 
367 	/*TODO: treat auto start here first */
368 	while (size) {
369 		if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
370 			return oops(compress, errno, "cannot get avail");
371 
372 		/* We can write if we have at least one fragment available
373 		 * or there is enough space for all remaining data
374 		 */
375 		if ((avail.avail < frag_size) && (avail.avail < size)) {
376 
377 			if (compress->nonblocking)
378 				return total;
379 
380 			ret = poll(&fds, 1, compress->max_poll_wait_ms);
381 			if (fds.revents & POLLERR) {
382 				return oops(compress, EIO, "poll returned error!");
383 			}
384 			/* A pause will cause -EBADFD or zero.
385 			 * This is not an error, just stop writing */
386 			if ((ret == 0) || (ret == -EBADFD))
387 				break;
388 			if (ret < 0)
389 				return oops(compress, errno, "poll error");
390 			if (fds.revents & POLLOUT) {
391 				continue;
392 			}
393 		}
394 		/* write avail bytes */
395 		if (size > avail.avail)
396 			to_write =  avail.avail;
397 		else
398 			to_write = size;
399 		written = write(compress->fd, cbuf, to_write);
400 		/* If play was paused the write returns -EBADFD */
401 		if (written == -EBADFD)
402 			break;
403 		if (written < 0)
404 			return oops(compress, errno, "write failed!");
405 
406 		size -= written;
407 		cbuf += written;
408 		total += written;
409 	}
410 	return total;
411 }
412 
compress_read(struct compress * compress,void * buf,unsigned int size)413 int compress_read(struct compress *compress, void *buf, unsigned int size)
414 {
415 	struct snd_compr_avail avail;
416 	struct pollfd fds;
417 	int to_read = 0;
418 	int num_read, total = 0, ret;
419 	char* cbuf = buf;
420 	const unsigned int frag_size = compress->config->fragment_size;
421 
422 	if (!(compress->flags & COMPRESS_OUT))
423 		return oops(compress, EINVAL, "Invalid flag set");
424 	if (!is_compress_ready(compress))
425 		return oops(compress, ENODEV, "device not ready");
426 	fds.fd = compress->fd;
427 	fds.events = POLLIN;
428 
429 	while (size) {
430 		if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
431 			return oops(compress, errno, "cannot get avail");
432 
433 		if ( (avail.avail < frag_size) && (avail.avail < size) ) {
434 			/* Less than one fragment available and not at the
435 			 * end of the read, so poll
436 			 */
437 			if (compress->nonblocking)
438 				return total;
439 
440 			ret = poll(&fds, 1, compress->max_poll_wait_ms);
441 			if (fds.revents & POLLERR) {
442 				return oops(compress, EIO, "poll returned error!");
443 			}
444 			/* A pause will cause -EBADFD or zero.
445 			 * This is not an error, just stop reading */
446 			if ((ret == 0) || (ret == -EBADFD))
447 				break;
448 			if (ret < 0)
449 				return oops(compress, errno, "poll error");
450 			if (fds.revents & POLLIN) {
451 				continue;
452 			}
453 		}
454 		/* read avail bytes */
455 		if (size > avail.avail)
456 			to_read = avail.avail;
457 		else
458 			to_read = size;
459 		num_read = read(compress->fd, cbuf, to_read);
460 		/* If play was paused the read returns -EBADFD */
461 		if (num_read == -EBADFD)
462 			break;
463 		if (num_read < 0)
464 			return oops(compress, errno, "read failed!");
465 
466 		size -= num_read;
467 		cbuf += num_read;
468 		total += num_read;
469 	}
470 
471 	return total;
472 }
473 
compress_start(struct compress * compress)474 int compress_start(struct compress *compress)
475 {
476 	if (!is_compress_ready(compress))
477 		return oops(compress, ENODEV, "device not ready");
478 	if (ioctl(compress->fd, SNDRV_COMPRESS_START))
479 		return oops(compress, errno, "cannot start the stream");
480 	compress->running = 1;
481 	return 0;
482 
483 }
484 
compress_stop(struct compress * compress)485 int compress_stop(struct compress *compress)
486 {
487 	if (!is_compress_running(compress))
488 		return oops(compress, ENODEV, "device not ready");
489 	if (ioctl(compress->fd, SNDRV_COMPRESS_STOP))
490 		return oops(compress, errno, "cannot stop the stream");
491 	return 0;
492 }
493 
compress_pause(struct compress * compress)494 int compress_pause(struct compress *compress)
495 {
496 	if (!is_compress_running(compress))
497 		return oops(compress, ENODEV, "device not ready");
498 	if (ioctl(compress->fd, SNDRV_COMPRESS_PAUSE))
499 		return oops(compress, errno, "cannot pause the stream");
500 	return 0;
501 }
502 
compress_resume(struct compress * compress)503 int compress_resume(struct compress *compress)
504 {
505 	if (ioctl(compress->fd, SNDRV_COMPRESS_RESUME))
506 		return oops(compress, errno, "cannot resume the stream");
507 	return 0;
508 }
509 
compress_drain(struct compress * compress)510 int compress_drain(struct compress *compress)
511 {
512 	if (!is_compress_running(compress))
513 		return oops(compress, ENODEV, "device not ready");
514 	if (ioctl(compress->fd, SNDRV_COMPRESS_DRAIN))
515 		return oops(compress, errno, "cannot drain the stream");
516 	return 0;
517 }
518 
compress_partial_drain(struct compress * compress)519 int compress_partial_drain(struct compress *compress)
520 {
521 	if (!is_compress_running(compress))
522 		return oops(compress, ENODEV, "device not ready");
523 
524 	if (!compress->next_track)
525 		return oops(compress, EPERM, "next track not signalled");
526 	if (ioctl(compress->fd, SNDRV_COMPRESS_PARTIAL_DRAIN))
527 		return oops(compress, errno, "cannot drain the stream\n");
528 	compress->next_track = 0;
529 	return 0;
530 }
531 
compress_next_track(struct compress * compress)532 int compress_next_track(struct compress *compress)
533 {
534 	if (!is_compress_running(compress))
535 		return oops(compress, ENODEV, "device not ready");
536 
537 	if (!compress->gapless_metadata)
538 		return oops(compress, EPERM, "metadata not set");
539 	if (ioctl(compress->fd, SNDRV_COMPRESS_NEXT_TRACK))
540 		return oops(compress, errno, "cannot set next track\n");
541 	compress->next_track = 1;
542 	compress->gapless_metadata = 0;
543 	return 0;
544 }
545 
compress_set_gapless_metadata(struct compress * compress,struct compr_gapless_mdata * mdata)546 int compress_set_gapless_metadata(struct compress *compress,
547 	struct compr_gapless_mdata *mdata)
548 {
549 	struct snd_compr_metadata metadata;
550 	int version;
551 
552 	if (!is_compress_ready(compress))
553 		return oops(compress, ENODEV, "device not ready");
554 
555 	version = get_compress_version(compress);
556 	if (version <= 0)
557 		return -1;
558 
559 	if (version < SNDRV_PROTOCOL_VERSION(0, 1, 1))
560 		return oops(compress, ENXIO, "gapless apis not supported in kernel");
561 
562 	metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
563 	metadata.value[0] = mdata->encoder_padding;
564 	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
565 		return oops(compress, errno, "can't set metadata for stream\n");
566 
567 	metadata.key = SNDRV_COMPRESS_ENCODER_DELAY;
568 	metadata.value[0] = mdata->encoder_delay;
569 	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
570 		return oops(compress, errno, "can't set metadata for stream\n");
571 	compress->gapless_metadata = 1;
572 	return 0;
573 }
574 
is_codec_supported(unsigned int card,unsigned int device,unsigned int flags,struct snd_codec * codec)575 bool is_codec_supported(unsigned int card, unsigned int device,
576 		unsigned int flags, struct snd_codec *codec)
577 {
578 	unsigned int dev_flag;
579 	bool ret;
580 	int fd;
581 	char fn[256];
582 
583 	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
584 
585 	if (flags & COMPRESS_OUT)
586 		dev_flag = O_RDONLY;
587 	else
588 		dev_flag = O_WRONLY;
589 
590 	fd = open(fn, dev_flag);
591 	if (fd < 0)
592 		return oops(&bad_compress, errno, "cannot open device '%s'", fn);
593 
594 	ret = _is_codec_type_supported(fd, codec);
595 
596 	close(fd);
597 	return ret;
598 }
599 
compress_set_max_poll_wait(struct compress * compress,int milliseconds)600 void compress_set_max_poll_wait(struct compress *compress, int milliseconds)
601 {
602 	compress->max_poll_wait_ms = milliseconds;
603 }
604 
compress_nonblock(struct compress * compress,int nonblock)605 void compress_nonblock(struct compress *compress, int nonblock)
606 {
607 	compress->nonblocking = !!nonblock;
608 }
609 
compress_wait(struct compress * compress,int timeout_ms)610 int compress_wait(struct compress *compress, int timeout_ms)
611 {
612 	struct pollfd fds;
613 	int ret;
614 
615 	fds.fd = compress->fd;
616 	fds.events = POLLOUT | POLLIN;
617 
618 	ret = poll(&fds, 1, timeout_ms);
619 	if (ret > 0) {
620 		if (fds.revents & POLLERR)
621 			return oops(compress, EIO, "poll returned error!");
622 		if (fds.revents & (POLLOUT | POLLIN))
623 			return 0;
624 	}
625 	if (ret == 0)
626 		return oops(compress, ETIME, "poll timed out");
627 	if (ret < 0)
628 		return oops(compress, errno, "poll error");
629 
630 	return oops(compress, EIO, "poll signalled unhandled event");
631 }
632 
633