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 (at) 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 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 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 121 int is_compress_running(struct compress *compress) 122 { 123 return ((compress->fd > 0) && compress->running) ? 1 : 0; 124 } 125 126 int is_compress_ready(struct compress *compress) 127 { 128 return (compress->fd > 0) ? 1 : 0; 129 } 130 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 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 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 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(¶ms->codec, config->codec, sizeof(params->codec)); 213 } 214 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, ¶ms); 283 284 if (ioctl(compress->fd, SNDRV_COMPRESS_SET_PARAMS, ¶ms)) { 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 600 void compress_set_max_poll_wait(struct compress *compress, int milliseconds) 601 { 602 compress->max_poll_wait_ms = milliseconds; 603 } 604 605 void compress_nonblock(struct compress *compress, int nonblock) 606 { 607 compress->nonblocking = !!nonblock; 608 } 609 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