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 #include "compress_ops.h"
79 #include "snd_utils.h"
80
81 #define COMPR_ERR_MAX 128
82
83 /* Default maximum time we will wait in a poll() - 20 seconds */
84 #define DEFAULT_MAX_POLL_WAIT_MS 20000
85
86 struct compress {
87 int fd;
88 unsigned int flags;
89 char error[COMPR_ERR_MAX];
90 struct compr_config *config;
91 int running;
92 int max_poll_wait_ms;
93 int nonblocking;
94 unsigned int gapless_metadata;
95 unsigned int next_track;
96
97 struct compress_ops *ops;
98 void *data;
99 void *snd_node;
100 };
101
102 extern struct compress_ops compr_hw_ops;
103 extern struct compress_ops compr_plug_ops;
104
oops(struct compress * compress,int e,const char * fmt,...)105 static int oops(struct compress *compress, int e, const char *fmt, ...)
106 {
107 va_list ap;
108 int sz;
109
110 va_start(ap, fmt);
111 vsnprintf(compress->error, COMPR_ERR_MAX, fmt, ap);
112 va_end(ap);
113 sz = strlen(compress->error);
114
115 snprintf(compress->error + sz, COMPR_ERR_MAX - sz,
116 ": %s", strerror(e));
117 errno = e;
118
119 return -1;
120 }
121
compress_get_error(struct compress * compress)122 const char *compress_get_error(struct compress *compress)
123 {
124 return compress->error;
125 }
126 static struct compress bad_compress = {
127 .fd = -1,
128 };
129
is_compress_running(struct compress * compress)130 int is_compress_running(struct compress *compress)
131 {
132 return ((compress->fd >= 0) && compress->running) ? 1 : 0;
133 }
134
is_compress_ready(struct compress * compress)135 int is_compress_ready(struct compress *compress)
136 {
137 return (compress->fd >= 0) ? 1 : 0;
138 }
139
get_compress_version(struct compress * compress)140 static int get_compress_version(struct compress *compress)
141 {
142 int version = 0;
143
144 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
145 oops(compress, errno, "cant read version");
146 return -1;
147 }
148 return version;
149 }
150
_is_codec_type_supported(struct compress_ops * ops,void * data,struct snd_codec * codec)151 static bool _is_codec_type_supported(struct compress_ops *ops, void *data,
152 struct snd_codec *codec)
153 {
154 struct snd_compr_caps caps;
155 bool found = false;
156 unsigned int i;
157
158 if (ops->ioctl(data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
159 oops(&bad_compress, errno, "cannot get device caps");
160 return false;
161 }
162
163 for (i = 0; i < caps.num_codecs; i++) {
164 if (caps.codecs[i] == codec->id) {
165 /* found the codec */
166 found = true;
167 break;
168 }
169 }
170 /* TODO: match the codec properties */
171 return found;
172 }
173
174 static inline void
fill_compress_params(struct compr_config * config,struct snd_compr_params * params)175 fill_compress_params(struct compr_config *config, struct snd_compr_params *params)
176 {
177 params->buffer.fragment_size = config->fragment_size;
178 params->buffer.fragments = config->fragments;
179 memcpy(¶ms->codec, config->codec, sizeof(params->codec));
180 }
181
compress_open(unsigned int card,unsigned int device,unsigned int flags,struct compr_config * config)182 struct compress *compress_open(unsigned int card, unsigned int device,
183 unsigned int flags, struct compr_config *config)
184 {
185 struct compress *compress;
186 struct snd_compr_params params;
187 struct snd_compr_caps caps;
188 int compress_type;
189
190 if (!config) {
191 oops(&bad_compress, EINVAL, "passed bad config");
192 return &bad_compress;
193 }
194
195 compress = calloc(1, sizeof(struct compress));
196 if (!compress) {
197 oops(&bad_compress, errno, "cannot allocate compress object");
198 return &bad_compress;
199 }
200
201 compress->next_track = 0;
202 compress->gapless_metadata = 0;
203 compress->config = calloc(1, sizeof(*config));
204 if (!compress->config)
205 goto input_fail;
206
207 compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
208
209 compress->flags = flags;
210 if (!((flags & COMPRESS_OUT) || (flags & COMPRESS_IN))) {
211 oops(&bad_compress, EINVAL, "can't deduce device direction from given flags");
212 goto config_fail;
213 }
214
215 compress->snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
216 compress_type = snd_utils_get_node_type(compress->snd_node);
217 if (compress_type == SND_NODE_TYPE_PLUGIN)
218 compress->ops = &compr_plug_ops;
219 else
220 compress->ops = &compr_hw_ops;
221
222 compress->fd = compress->ops->open(card, device, flags,
223 &compress->data, compress->snd_node);
224 if (compress->fd < 0) {
225 oops(&bad_compress, errno, "cannot open card(%u) device(%u)",
226 card, device);
227 goto config_fail;
228 }
229
230 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
231 oops(compress, errno, "cannot get device caps");
232 goto codec_fail;
233 }
234
235 /* If caller passed "don't care" fill in default values */
236 if ((config->fragment_size == 0) || (config->fragments == 0)) {
237 config->fragment_size = caps.min_fragment_size;
238 config->fragments = caps.max_fragments;
239 }
240
241 #if 0
242 /* FIXME need to turn this On when DSP supports
243 * and treat in no support case
244 */
245 if (_is_codec_supported(compress, config, &caps) == false) {
246 oops(compress, errno, "codec not supported\n");
247 goto codec_fail;
248 }
249 #endif
250
251 memcpy(compress->config, config, sizeof(*compress->config));
252 fill_compress_params(config, ¶ms);
253
254 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, ¶ms)) {
255 oops(&bad_compress, errno, "cannot set device");
256 goto codec_fail;
257 }
258
259 return compress;
260
261 codec_fail:
262 snd_utils_put_dev_node(compress->snd_node);
263 compress->ops->close(compress->data);
264 compress->fd = -1;
265 config_fail:
266 free(compress->config);
267 input_fail:
268 free(compress);
269 return &bad_compress;
270 }
271
compress_close(struct compress * compress)272 void compress_close(struct compress *compress)
273 {
274 if (compress == &bad_compress)
275 return;
276
277 snd_utils_put_dev_node(compress->snd_node);
278 compress->ops->close(compress->data);
279 compress->running = 0;
280 compress->fd = -1;
281 free(compress->config);
282 free(compress);
283 }
284
compress_get_hpointer(struct compress * compress,unsigned int * avail,struct timespec * tstamp)285 int compress_get_hpointer(struct compress *compress,
286 unsigned int *avail, struct timespec *tstamp)
287 {
288 struct snd_compr_avail kavail;
289 __u64 time;
290
291 if (!is_compress_ready(compress))
292 return oops(compress, ENODEV, "device not ready");
293
294 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &kavail))
295 return oops(compress, errno, "cannot get avail");
296 if (0 == kavail.tstamp.sampling_rate)
297 return oops(compress, ENODATA, "sample rate unknown");
298 *avail = (unsigned int)kavail.avail;
299 time = kavail.tstamp.pcm_io_frames / kavail.tstamp.sampling_rate;
300 tstamp->tv_sec = time;
301 time = kavail.tstamp.pcm_io_frames % kavail.tstamp.sampling_rate;
302 tstamp->tv_nsec = time * 1000000000 / kavail.tstamp.sampling_rate;
303 return 0;
304 }
305
compress_get_tstamp(struct compress * compress,unsigned long * samples,unsigned int * sampling_rate)306 int compress_get_tstamp(struct compress *compress,
307 unsigned long *samples, unsigned int *sampling_rate)
308 {
309 struct snd_compr_tstamp ktstamp;
310
311 if (!is_compress_ready(compress))
312 return oops(compress, ENODEV, "device not ready");
313
314 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_TSTAMP, &ktstamp))
315 return oops(compress, errno, "cannot get tstamp");
316
317 *samples = ktstamp.pcm_io_frames;
318 *sampling_rate = ktstamp.sampling_rate;
319 return 0;
320 }
321
compress_write(struct compress * compress,const void * buf,unsigned int size)322 int compress_write(struct compress *compress, const void *buf, unsigned int size)
323 {
324 struct snd_compr_avail avail;
325 struct pollfd fds;
326 int to_write = 0; /* zero indicates we haven't written yet */
327 int written, total = 0, ret;
328 const char* cbuf = buf;
329 const unsigned int frag_size = compress->config->fragment_size;
330
331 if (!(compress->flags & COMPRESS_IN))
332 return oops(compress, EINVAL, "Invalid flag set");
333 if (!is_compress_ready(compress))
334 return oops(compress, ENODEV, "device not ready");
335 fds.events = POLLOUT;
336
337 /*TODO: treat auto start here first */
338 while (size) {
339 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
340 return oops(compress, errno, "cannot get avail");
341
342 /* We can write if we have at least one fragment available
343 * or there is enough space for all remaining data
344 */
345 if ((avail.avail < frag_size) && (avail.avail < size)) {
346
347 if (compress->nonblocking)
348 return total;
349
350 ret = compress->ops->poll(compress->data, &fds, 1,
351 compress->max_poll_wait_ms);
352 if (fds.revents & POLLERR) {
353 return oops(compress, EIO, "poll returned error!");
354 }
355 /* A pause will cause -EBADFD or zero.
356 * This is not an error, just stop writing */
357 if ((ret == 0) || (ret < 0 && errno == EBADFD))
358 break;
359 if (ret < 0)
360 return oops(compress, errno, "poll error");
361 if (fds.revents & POLLOUT) {
362 continue;
363 }
364 }
365 /* write avail bytes */
366 if (size > avail.avail)
367 to_write = avail.avail;
368 else
369 to_write = size;
370 written = compress->ops->write(compress->data, cbuf, to_write);
371 if (written < 0) {
372 /* If play was paused the write returns -EBADFD */
373 if (errno == EBADFD)
374 break;
375 return oops(compress, errno, "write failed!");
376 }
377
378 size -= written;
379 cbuf += written;
380 total += written;
381 }
382 return total;
383 }
384
compress_read(struct compress * compress,void * buf,unsigned int size)385 int compress_read(struct compress *compress, void *buf, unsigned int size)
386 {
387 struct snd_compr_avail avail;
388 struct pollfd fds;
389 int to_read = 0;
390 int num_read, total = 0, ret;
391 char* cbuf = buf;
392 const unsigned int frag_size = compress->config->fragment_size;
393
394 if (!(compress->flags & COMPRESS_OUT))
395 return oops(compress, EINVAL, "Invalid flag set");
396 if (!is_compress_ready(compress))
397 return oops(compress, ENODEV, "device not ready");
398 fds.events = POLLIN;
399
400 while (size) {
401 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
402 return oops(compress, errno, "cannot get avail");
403
404 if ( (avail.avail < frag_size) && (avail.avail < size) ) {
405 /* Less than one fragment available and not at the
406 * end of the read, so poll
407 */
408 if (compress->nonblocking)
409 return total;
410
411 ret = compress->ops->poll(compress->data, &fds, 1,
412 compress->max_poll_wait_ms);
413 if (fds.revents & POLLERR) {
414 return oops(compress, EIO, "poll returned error!");
415 }
416 /* A pause will cause -EBADFD or zero.
417 * This is not an error, just stop reading */
418 if ((ret == 0) || (ret < 0 && errno == EBADFD))
419 break;
420 if (ret < 0)
421 return oops(compress, errno, "poll error");
422 if (fds.revents & POLLIN) {
423 continue;
424 }
425 }
426 /* read avail bytes */
427 if (size > avail.avail)
428 to_read = avail.avail;
429 else
430 to_read = size;
431 num_read = compress->ops->read(compress->data, cbuf, to_read);
432 if (num_read < 0) {
433 /* If play was paused the read returns -EBADFD */
434 if (errno == EBADFD)
435 break;
436 return oops(compress, errno, "read failed!");
437 }
438
439 size -= num_read;
440 cbuf += num_read;
441 total += num_read;
442 }
443
444 return total;
445 }
446
compress_start(struct compress * compress)447 int compress_start(struct compress *compress)
448 {
449 if (!is_compress_ready(compress))
450 return oops(compress, ENODEV, "device not ready");
451 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_START))
452 return oops(compress, errno, "cannot start the stream");
453 compress->running = 1;
454 return 0;
455
456 }
457
compress_stop(struct compress * compress)458 int compress_stop(struct compress *compress)
459 {
460 if (!is_compress_running(compress))
461 return oops(compress, ENODEV, "device not ready");
462 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_STOP))
463 return oops(compress, errno, "cannot stop the stream");
464 return 0;
465 }
466
compress_pause(struct compress * compress)467 int compress_pause(struct compress *compress)
468 {
469 if (!is_compress_running(compress))
470 return oops(compress, ENODEV, "device not ready");
471 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PAUSE))
472 return oops(compress, errno, "cannot pause the stream");
473 return 0;
474 }
475
compress_resume(struct compress * compress)476 int compress_resume(struct compress *compress)
477 {
478 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_RESUME))
479 return oops(compress, errno, "cannot resume the stream");
480 return 0;
481 }
482
compress_drain(struct compress * compress)483 int compress_drain(struct compress *compress)
484 {
485 if (!is_compress_running(compress))
486 return oops(compress, ENODEV, "device not ready");
487 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_DRAIN))
488 return oops(compress, errno, "cannot drain the stream");
489 return 0;
490 }
491
compress_partial_drain(struct compress * compress)492 int compress_partial_drain(struct compress *compress)
493 {
494 if (!is_compress_running(compress))
495 return oops(compress, ENODEV, "device not ready");
496
497 if (!compress->next_track)
498 return oops(compress, EPERM, "next track not signalled");
499 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PARTIAL_DRAIN))
500 return oops(compress, errno, "cannot drain the stream\n");
501 compress->next_track = 0;
502 return 0;
503 }
504
compress_next_track(struct compress * compress)505 int compress_next_track(struct compress *compress)
506 {
507 if (!is_compress_running(compress))
508 return oops(compress, ENODEV, "device not ready");
509
510 if (!compress->gapless_metadata)
511 return oops(compress, EPERM, "metadata not set");
512 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_NEXT_TRACK))
513 return oops(compress, errno, "cannot set next track\n");
514 compress->next_track = 1;
515 compress->gapless_metadata = 0;
516 return 0;
517 }
518
compress_set_gapless_metadata(struct compress * compress,struct compr_gapless_mdata * mdata)519 int compress_set_gapless_metadata(struct compress *compress,
520 struct compr_gapless_mdata *mdata)
521 {
522 struct snd_compr_metadata metadata;
523 int version;
524
525 if (!is_compress_ready(compress))
526 return oops(compress, ENODEV, "device not ready");
527
528 version = get_compress_version(compress);
529 if (version <= 0)
530 return -1;
531
532 if (version < SNDRV_PROTOCOL_VERSION(0, 1, 1))
533 return oops(compress, ENXIO, "gapless apis not supported in kernel");
534
535 metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
536 metadata.value[0] = mdata->encoder_padding;
537 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
538 return oops(compress, errno, "can't set metadata for stream\n");
539
540 metadata.key = SNDRV_COMPRESS_ENCODER_DELAY;
541 metadata.value[0] = mdata->encoder_delay;
542 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
543 return oops(compress, errno, "can't set metadata for stream\n");
544 compress->gapless_metadata = 1;
545 return 0;
546 }
547
548 #ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
compress_set_next_track_param(struct compress * compress,union snd_codec_options * codec_options)549 int compress_set_next_track_param(struct compress *compress,
550 union snd_codec_options *codec_options)
551 {
552 if (!is_compress_running(compress))
553 return oops(compress, ENODEV, "device not ready");
554
555 if (ioctl(compress->fd, SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM, codec_options))
556 return oops(compress, errno, "cannot set next track params\n");
557 return 0;
558 }
559 #endif
560
is_codec_supported(unsigned int card,unsigned int device,unsigned int flags,struct snd_codec * codec)561 bool is_codec_supported(unsigned int card, unsigned int device,
562 unsigned int flags, struct snd_codec *codec)
563 {
564 struct compress_ops *ops;
565 void *snd_node, *data;
566 bool ret;
567 int compress_type, fd;
568
569 snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
570 compress_type = snd_utils_get_node_type(snd_node);
571 if (compress_type == SND_NODE_TYPE_PLUGIN)
572 ops = &compr_plug_ops;
573 else
574 ops = &compr_hw_ops;
575
576 fd = ops->open(card, device, flags, &data, NULL);
577 if (fd < 0)
578 return oops(&bad_compress, errno, "cannot open card %u, device %u",
579 card, device);
580
581 ret = _is_codec_type_supported(ops, data, codec);
582
583 snd_utils_put_dev_node(snd_node);
584 ops->close(data);
585 return ret;
586 }
587
compress_set_max_poll_wait(struct compress * compress,int milliseconds)588 void compress_set_max_poll_wait(struct compress *compress, int milliseconds)
589 {
590 compress->max_poll_wait_ms = milliseconds;
591 }
592
compress_nonblock(struct compress * compress,int nonblock)593 void compress_nonblock(struct compress *compress, int nonblock)
594 {
595 compress->nonblocking = !!nonblock;
596 }
597
compress_wait(struct compress * compress,int timeout_ms)598 int compress_wait(struct compress *compress, int timeout_ms)
599 {
600 struct pollfd fds;
601 int ret;
602
603 fds.events = POLLOUT | POLLIN;
604
605 ret = compress->ops->poll(compress->data, &fds, 1, timeout_ms);
606 if (ret > 0) {
607 if (fds.revents & POLLERR)
608 return oops(compress, EIO, "poll returned error!");
609 if (fds.revents & (POLLOUT | POLLIN))
610 return 0;
611 }
612 if (ret == 0)
613 return oops(compress, ETIME, "poll timed out");
614 if (ret < 0)
615 return oops(compress, errno, "poll error");
616
617 return oops(compress, EIO, "poll signalled unhandled event");
618 }
619
620 #ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
compress_get_metadata(struct compress * compress,struct snd_compr_metadata * mdata)621 int compress_get_metadata(struct compress *compress,
622 struct snd_compr_metadata *mdata) {
623 int version;
624 if (!is_compress_ready(compress))
625 return oops(compress, ENODEV, "device not ready");
626
627 version = get_compress_version(compress);
628 if (version <= 0)
629 return -1;
630
631 if (ioctl(compress->fd, SNDRV_COMPRESS_GET_METADATA, mdata)) {
632 return oops(compress, errno, "can't get metadata for stream\n");
633 }
634 return 0;
635 }
636
compress_set_metadata(struct compress * compress,struct snd_compr_metadata * mdata)637 int compress_set_metadata(struct compress *compress,
638 struct snd_compr_metadata *mdata) {
639
640 int version;
641 if (!is_compress_ready(compress))
642 return oops(compress, ENODEV, "device not ready");
643
644 version = get_compress_version(compress);
645 if (version <= 0)
646 return -1;
647
648 if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, mdata)) {
649 return oops(compress, errno, "can't set metadata for stream\n");
650 }
651 return 0;
652 }
653 #endif
654