1 /* pcm.c 2 ** 3 ** Copyright 2011, The Android Open Source Project 4 ** 5 ** Redistribution and use in source and binary forms, with or without 6 ** modification, are permitted provided that the following conditions are met: 7 ** * Redistributions of source code must retain the above copyright 8 ** notice, this list of conditions and the following disclaimer. 9 ** * Redistributions in binary form must reproduce the above copyright 10 ** notice, this list of conditions and the following disclaimer in the 11 ** documentation and/or other materials provided with the distribution. 12 ** * Neither the name of The Android Open Source Project nor the names of 13 ** its contributors may be used to endorse or promote products derived 14 ** from this software without specific prior written permission. 15 ** 16 ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND 17 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE 20 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 ** DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <fcntl.h> 32 #include <stdarg.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <poll.h> 37 38 #include <sys/ioctl.h> 39 #include <sys/mman.h> 40 #include <sys/time.h> 41 #include <limits.h> 42 43 #include <linux/ioctl.h> 44 #define __force 45 #define __bitwise 46 #define __user 47 #include <sound/asound.h> 48 49 #include <tinyalsa/asoundlib.h> 50 51 #define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL 52 #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) 53 54 static inline int param_is_mask(int p) 55 { 56 return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && 57 (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); 58 } 59 60 static inline int param_is_interval(int p) 61 { 62 return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) && 63 (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL); 64 } 65 66 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n) 67 { 68 return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]); 69 } 70 71 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) 72 { 73 return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); 74 } 75 76 static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit) 77 { 78 if (bit >= SNDRV_MASK_MAX) 79 return; 80 if (param_is_mask(n)) { 81 struct snd_mask *m = param_to_mask(p, n); 82 m->bits[0] = 0; 83 m->bits[1] = 0; 84 m->bits[bit >> 5] |= (1 << (bit & 31)); 85 } 86 } 87 88 static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val) 89 { 90 if (param_is_interval(n)) { 91 struct snd_interval *i = param_to_interval(p, n); 92 i->min = val; 93 } 94 } 95 96 static unsigned int param_get_min(struct snd_pcm_hw_params *p, int n) 97 { 98 if (param_is_interval(n)) { 99 struct snd_interval *i = param_to_interval(p, n); 100 return i->min; 101 } 102 return 0; 103 } 104 105 static unsigned int param_get_max(struct snd_pcm_hw_params *p, int n) 106 { 107 if (param_is_interval(n)) { 108 struct snd_interval *i = param_to_interval(p, n); 109 return i->max; 110 } 111 return 0; 112 } 113 114 static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val) 115 { 116 if (param_is_interval(n)) { 117 struct snd_interval *i = param_to_interval(p, n); 118 i->min = val; 119 i->max = val; 120 i->integer = 1; 121 } 122 } 123 124 static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n) 125 { 126 if (param_is_interval(n)) { 127 struct snd_interval *i = param_to_interval(p, n); 128 if (i->integer) 129 return i->max; 130 } 131 return 0; 132 } 133 134 static void param_init(struct snd_pcm_hw_params *p) 135 { 136 int n; 137 138 memset(p, 0, sizeof(*p)); 139 for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; 140 n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { 141 struct snd_mask *m = param_to_mask(p, n); 142 m->bits[0] = ~0; 143 m->bits[1] = ~0; 144 } 145 for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; 146 n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { 147 struct snd_interval *i = param_to_interval(p, n); 148 i->min = 0; 149 i->max = ~0; 150 } 151 p->rmask = ~0U; 152 p->cmask = 0; 153 p->info = ~0U; 154 } 155 156 #define PCM_ERROR_MAX 128 157 158 struct pcm { 159 int fd; 160 unsigned int flags; 161 int running:1; 162 int underruns; 163 unsigned int buffer_size; 164 unsigned int boundary; 165 char error[PCM_ERROR_MAX]; 166 struct pcm_config config; 167 struct snd_pcm_mmap_status *mmap_status; 168 struct snd_pcm_mmap_control *mmap_control; 169 struct snd_pcm_sync_ptr *sync_ptr; 170 void *mmap_buffer; 171 unsigned int noirq_frames_per_msec; 172 int wait_for_avail_min; 173 }; 174 175 unsigned int pcm_get_buffer_size(struct pcm *pcm) 176 { 177 return pcm->buffer_size; 178 } 179 180 const char* pcm_get_error(struct pcm *pcm) 181 { 182 return pcm->error; 183 } 184 185 static int oops(struct pcm *pcm, int e, const char *fmt, ...) 186 { 187 va_list ap; 188 int sz; 189 190 va_start(ap, fmt); 191 vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); 192 va_end(ap); 193 sz = strlen(pcm->error); 194 195 if (errno) 196 snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, 197 ": %s", strerror(e)); 198 return -1; 199 } 200 201 static unsigned int pcm_format_to_alsa(enum pcm_format format) 202 { 203 switch (format) { 204 case PCM_FORMAT_S32_LE: 205 return SNDRV_PCM_FORMAT_S32_LE; 206 case PCM_FORMAT_S8: 207 return SNDRV_PCM_FORMAT_S8; 208 case PCM_FORMAT_S24_LE: 209 return SNDRV_PCM_FORMAT_S24_LE; 210 default: 211 case PCM_FORMAT_S16_LE: 212 return SNDRV_PCM_FORMAT_S16_LE; 213 }; 214 } 215 216 unsigned int pcm_format_to_bits(enum pcm_format format) 217 { 218 switch (format) { 219 case PCM_FORMAT_S32_LE: 220 case PCM_FORMAT_S24_LE: 221 return 32; 222 default: 223 case PCM_FORMAT_S16_LE: 224 return 16; 225 }; 226 } 227 228 unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) 229 { 230 return bytes / (pcm->config.channels * 231 (pcm_format_to_bits(pcm->config.format) >> 3)); 232 } 233 234 unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) 235 { 236 return frames * pcm->config.channels * 237 (pcm_format_to_bits(pcm->config.format) >> 3); 238 } 239 240 static int pcm_sync_ptr(struct pcm *pcm, int flags) { 241 if (pcm->sync_ptr) { 242 pcm->sync_ptr->flags = flags; 243 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) 244 return -1; 245 } 246 return 0; 247 } 248 249 static int pcm_hw_mmap_status(struct pcm *pcm) { 250 251 if (pcm->sync_ptr) 252 return 0; 253 254 int page_size = sysconf(_SC_PAGE_SIZE); 255 pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, 256 pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); 257 if (pcm->mmap_status == MAP_FAILED) 258 pcm->mmap_status = NULL; 259 if (!pcm->mmap_status) 260 goto mmap_error; 261 262 pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 263 MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); 264 if (pcm->mmap_control == MAP_FAILED) 265 pcm->mmap_control = NULL; 266 if (!pcm->mmap_control) { 267 munmap(pcm->mmap_status, page_size); 268 pcm->mmap_status = NULL; 269 goto mmap_error; 270 } 271 if (pcm->flags & PCM_MMAP) 272 pcm->mmap_control->avail_min = pcm->config.avail_min; 273 else 274 pcm->mmap_control->avail_min = 1; 275 276 return 0; 277 278 mmap_error: 279 280 pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); 281 if (!pcm->sync_ptr) 282 return -ENOMEM; 283 pcm->mmap_status = &pcm->sync_ptr->s.status; 284 pcm->mmap_control = &pcm->sync_ptr->c.control; 285 if (pcm->flags & PCM_MMAP) 286 pcm->mmap_control->avail_min = pcm->config.avail_min; 287 else 288 pcm->mmap_control->avail_min = 1; 289 290 pcm_sync_ptr(pcm, 0); 291 292 return 0; 293 } 294 295 static void pcm_hw_munmap_status(struct pcm *pcm) { 296 if (pcm->sync_ptr) { 297 free(pcm->sync_ptr); 298 pcm->sync_ptr = NULL; 299 } else { 300 int page_size = sysconf(_SC_PAGE_SIZE); 301 if (pcm->mmap_status) 302 munmap(pcm->mmap_status, page_size); 303 if (pcm->mmap_control) 304 munmap(pcm->mmap_control, page_size); 305 } 306 pcm->mmap_status = NULL; 307 pcm->mmap_control = NULL; 308 } 309 310 static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, 311 char *buf, unsigned int src_offset, 312 unsigned int frames) 313 { 314 int size_bytes = pcm_frames_to_bytes(pcm, frames); 315 int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); 316 int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); 317 318 /* interleaved only atm */ 319 if (pcm->flags & PCM_IN) 320 memcpy(buf + src_offset_bytes, 321 (char*)pcm->mmap_buffer + pcm_offset_bytes, 322 size_bytes); 323 else 324 memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, 325 buf + src_offset_bytes, 326 size_bytes); 327 return 0; 328 } 329 330 static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf, 331 unsigned int offset, unsigned int size) 332 { 333 void *pcm_areas; 334 int commit; 335 unsigned int pcm_offset, frames, count = 0; 336 337 while (size > 0) { 338 frames = size; 339 pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); 340 pcm_areas_copy(pcm, pcm_offset, buf, offset, frames); 341 commit = pcm_mmap_commit(pcm, pcm_offset, frames); 342 if (commit < 0) { 343 oops(pcm, commit, "failed to commit %d frames\n", frames); 344 return commit; 345 } 346 347 offset += commit; 348 count += commit; 349 size -= commit; 350 } 351 return count; 352 } 353 354 int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, 355 struct timespec *tstamp) 356 { 357 int frames; 358 int rc; 359 snd_pcm_uframes_t hw_ptr; 360 361 if (!pcm_is_ready(pcm)) 362 return -1; 363 364 rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); 365 if (rc < 0) 366 return -1; 367 368 if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && 369 (pcm->mmap_status->state != PCM_STATE_DRAINING)) 370 return -1; 371 372 *tstamp = pcm->mmap_status->tstamp; 373 if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0) 374 return -1; 375 376 hw_ptr = pcm->mmap_status->hw_ptr; 377 if (pcm->flags & PCM_IN) 378 frames = hw_ptr - pcm->mmap_control->appl_ptr; 379 else 380 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; 381 382 if (frames < 0) 383 frames += pcm->boundary; 384 else if (frames > (int)pcm->boundary) 385 frames -= pcm->boundary; 386 387 *avail = (unsigned int)frames; 388 389 return 0; 390 } 391 392 int pcm_write(struct pcm *pcm, const void *data, unsigned int count) 393 { 394 struct snd_xferi x; 395 396 if (pcm->flags & PCM_IN) 397 return -EINVAL; 398 399 x.buf = (void*)data; 400 x.frames = count / (pcm->config.channels * 401 pcm_format_to_bits(pcm->config.format) / 8); 402 403 for (;;) { 404 if (!pcm->running) { 405 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) 406 return oops(pcm, errno, "cannot prepare channel"); 407 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) 408 return oops(pcm, errno, "cannot write initial data"); 409 pcm->running = 1; 410 return 0; 411 } 412 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { 413 pcm->running = 0; 414 if (errno == EPIPE) { 415 /* we failed to make our window -- try to restart if we are 416 * allowed to do so. Otherwise, simply allow the EPIPE error to 417 * propagate up to the app level */ 418 pcm->underruns++; 419 if (pcm->flags & PCM_NORESTART) 420 return -EPIPE; 421 continue; 422 } 423 return oops(pcm, errno, "cannot write stream data"); 424 } 425 return 0; 426 } 427 } 428 429 int pcm_read(struct pcm *pcm, void *data, unsigned int count) 430 { 431 struct snd_xferi x; 432 433 if (!(pcm->flags & PCM_IN)) 434 return -EINVAL; 435 436 x.buf = data; 437 x.frames = count / (pcm->config.channels * 438 pcm_format_to_bits(pcm->config.format) / 8); 439 440 for (;;) { 441 if (!pcm->running) { 442 if (pcm_start(pcm) < 0) { 443 fprintf(stderr, "start error"); 444 return -errno; 445 } 446 } 447 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { 448 pcm->running = 0; 449 if (errno == EPIPE) { 450 /* we failed to make our window -- try to restart */ 451 pcm->underruns++; 452 continue; 453 } 454 return oops(pcm, errno, "cannot read stream data"); 455 } 456 return 0; 457 } 458 } 459 460 static struct pcm bad_pcm = { 461 .fd = -1, 462 }; 463 464 struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, 465 unsigned int flags) 466 { 467 struct snd_pcm_hw_params *params; 468 char fn[256]; 469 int fd; 470 471 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, 472 flags & PCM_IN ? 'c' : 'p'); 473 474 fd = open(fn, O_RDWR); 475 if (fd < 0) { 476 fprintf(stderr, "cannot open device '%s'\n", fn); 477 goto err_open; 478 } 479 480 params = calloc(1, sizeof(struct snd_pcm_hw_params)); 481 if (!params) 482 goto err_calloc; 483 484 param_init(params); 485 if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { 486 fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); 487 goto err_hw_refine; 488 } 489 490 close(fd); 491 492 return (struct pcm_params *)params; 493 494 err_hw_refine: 495 free(params); 496 err_calloc: 497 close(fd); 498 err_open: 499 return NULL; 500 } 501 502 void pcm_params_free(struct pcm_params *pcm_params) 503 { 504 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 505 506 if (params) 507 free(params); 508 } 509 510 static int pcm_param_to_alsa(enum pcm_param param) 511 { 512 switch (param) { 513 case PCM_PARAM_SAMPLE_BITS: 514 return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; 515 break; 516 case PCM_PARAM_FRAME_BITS: 517 return SNDRV_PCM_HW_PARAM_FRAME_BITS; 518 break; 519 case PCM_PARAM_CHANNELS: 520 return SNDRV_PCM_HW_PARAM_CHANNELS; 521 break; 522 case PCM_PARAM_RATE: 523 return SNDRV_PCM_HW_PARAM_RATE; 524 break; 525 case PCM_PARAM_PERIOD_TIME: 526 return SNDRV_PCM_HW_PARAM_PERIOD_TIME; 527 break; 528 case PCM_PARAM_PERIOD_SIZE: 529 return SNDRV_PCM_HW_PARAM_PERIOD_SIZE; 530 break; 531 case PCM_PARAM_PERIOD_BYTES: 532 return SNDRV_PCM_HW_PARAM_PERIOD_BYTES; 533 break; 534 case PCM_PARAM_PERIODS: 535 return SNDRV_PCM_HW_PARAM_PERIODS; 536 break; 537 case PCM_PARAM_BUFFER_TIME: 538 return SNDRV_PCM_HW_PARAM_BUFFER_TIME; 539 break; 540 case PCM_PARAM_BUFFER_SIZE: 541 return SNDRV_PCM_HW_PARAM_BUFFER_SIZE; 542 break; 543 case PCM_PARAM_BUFFER_BYTES: 544 return SNDRV_PCM_HW_PARAM_BUFFER_BYTES; 545 break; 546 case PCM_PARAM_TICK_TIME: 547 return SNDRV_PCM_HW_PARAM_TICK_TIME; 548 break; 549 550 default: 551 return -1; 552 } 553 } 554 555 unsigned int pcm_params_get_min(struct pcm_params *pcm_params, 556 enum pcm_param param) 557 { 558 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 559 int p; 560 561 if (!params) 562 return 0; 563 564 p = pcm_param_to_alsa(param); 565 if (p < 0) 566 return 0; 567 568 return param_get_min(params, p); 569 } 570 571 unsigned int pcm_params_get_max(struct pcm_params *pcm_params, 572 enum pcm_param param) 573 { 574 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 575 int p; 576 577 if (!params) 578 return 0; 579 580 p = pcm_param_to_alsa(param); 581 if (p < 0) 582 return 0; 583 584 return param_get_max(params, p); 585 } 586 587 int pcm_close(struct pcm *pcm) 588 { 589 if (pcm == &bad_pcm) 590 return 0; 591 592 pcm_hw_munmap_status(pcm); 593 594 if (pcm->flags & PCM_MMAP) { 595 pcm_stop(pcm); 596 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); 597 } 598 599 if (pcm->fd >= 0) 600 close(pcm->fd); 601 pcm->running = 0; 602 pcm->buffer_size = 0; 603 pcm->fd = -1; 604 free(pcm); 605 return 0; 606 } 607 608 struct pcm *pcm_open(unsigned int card, unsigned int device, 609 unsigned int flags, struct pcm_config *config) 610 { 611 struct pcm *pcm; 612 struct snd_pcm_info info; 613 struct snd_pcm_hw_params params; 614 struct snd_pcm_sw_params sparams; 615 char fn[256]; 616 int rc; 617 618 pcm = calloc(1, sizeof(struct pcm)); 619 if (!pcm || !config) 620 return &bad_pcm; /* TODO: could support default config here */ 621 622 pcm->config = *config; 623 624 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, 625 flags & PCM_IN ? 'c' : 'p'); 626 627 pcm->flags = flags; 628 pcm->fd = open(fn, O_RDWR); 629 if (pcm->fd < 0) { 630 oops(pcm, errno, "cannot open device '%s'", fn); 631 return pcm; 632 } 633 634 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { 635 oops(pcm, errno, "cannot get info"); 636 goto fail_close; 637 } 638 639 param_init(¶ms); 640 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, 641 pcm_format_to_alsa(config->format)); 642 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, 643 SNDRV_PCM_SUBFORMAT_STD); 644 param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); 645 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 646 pcm_format_to_bits(config->format)); 647 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, 648 pcm_format_to_bits(config->format) * config->channels); 649 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, 650 config->channels); 651 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); 652 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); 653 654 if (flags & PCM_NOIRQ) { 655 656 if (!(flags & PCM_MMAP)) { 657 oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); 658 goto fail; 659 } 660 661 params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; 662 pcm->noirq_frames_per_msec = config->rate / 1000; 663 } 664 665 if (flags & PCM_MMAP) 666 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, 667 SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); 668 else 669 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, 670 SNDRV_PCM_ACCESS_RW_INTERLEAVED); 671 672 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { 673 oops(pcm, errno, "cannot set hw params"); 674 goto fail_close; 675 } 676 677 /* get our refined hw_params */ 678 config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 679 config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); 680 pcm->buffer_size = config->period_count * config->period_size; 681 682 if (flags & PCM_MMAP) { 683 pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), 684 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); 685 if (pcm->mmap_buffer == MAP_FAILED) { 686 oops(pcm, -errno, "failed to mmap buffer %d bytes\n", 687 pcm_frames_to_bytes(pcm, pcm->buffer_size)); 688 goto fail_close; 689 } 690 } 691 692 693 memset(&sparams, 0, sizeof(sparams)); 694 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; 695 sparams.period_step = 1; 696 697 if (!config->start_threshold) { 698 if (pcm->flags & PCM_IN) 699 pcm->config.start_threshold = sparams.start_threshold = 1; 700 else 701 pcm->config.start_threshold = sparams.start_threshold = 702 config->period_count * config->period_size / 2; 703 } else 704 sparams.start_threshold = config->start_threshold; 705 706 /* pick a high stop threshold - todo: does this need further tuning */ 707 if (!config->stop_threshold) { 708 if (pcm->flags & PCM_IN) 709 pcm->config.stop_threshold = sparams.stop_threshold = 710 config->period_count * config->period_size * 10; 711 else 712 pcm->config.stop_threshold = sparams.stop_threshold = 713 config->period_count * config->period_size; 714 } 715 else 716 sparams.stop_threshold = config->stop_threshold; 717 718 if (!pcm->config.avail_min) { 719 if (pcm->flags & PCM_MMAP) 720 pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; 721 else 722 pcm->config.avail_min = sparams.avail_min = 1; 723 } else 724 sparams.avail_min = config->avail_min; 725 726 sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ 727 sparams.silence_size = 0; 728 sparams.silence_threshold = config->silence_threshold; 729 pcm->boundary = sparams.boundary = pcm->buffer_size; 730 731 while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) 732 pcm->boundary *= 2; 733 734 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { 735 oops(pcm, errno, "cannot set sw params"); 736 goto fail; 737 } 738 739 rc = pcm_hw_mmap_status(pcm); 740 if (rc < 0) { 741 oops(pcm, rc, "mmap status failed"); 742 goto fail; 743 } 744 745 #ifdef SNDRV_PCM_IOCTL_TTSTAMP 746 if (pcm->flags & PCM_MONOTONIC) { 747 int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; 748 rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); 749 if (rc < 0) { 750 oops(pcm, rc, "cannot set timestamp type"); 751 goto fail; 752 } 753 } 754 #endif 755 756 pcm->underruns = 0; 757 return pcm; 758 759 fail: 760 if (flags & PCM_MMAP) 761 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); 762 fail_close: 763 close(pcm->fd); 764 pcm->fd = -1; 765 return pcm; 766 } 767 768 int pcm_is_ready(struct pcm *pcm) 769 { 770 return pcm->fd >= 0; 771 } 772 773 int pcm_start(struct pcm *pcm) 774 { 775 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) 776 return oops(pcm, errno, "cannot prepare channel"); 777 778 if (pcm->flags & PCM_MMAP) 779 pcm_sync_ptr(pcm, 0); 780 781 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) 782 return oops(pcm, errno, "cannot start channel"); 783 784 pcm->running = 1; 785 return 0; 786 } 787 788 int pcm_stop(struct pcm *pcm) 789 { 790 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) 791 return oops(pcm, errno, "cannot stop channel"); 792 793 pcm->running = 0; 794 return 0; 795 } 796 797 static inline int pcm_mmap_playback_avail(struct pcm *pcm) 798 { 799 int avail; 800 801 avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; 802 803 if (avail < 0) 804 avail += pcm->boundary; 805 else if (avail > (int)pcm->boundary) 806 avail -= pcm->boundary; 807 808 return avail; 809 } 810 811 static inline int pcm_mmap_capture_avail(struct pcm *pcm) 812 { 813 int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; 814 if (avail < 0) 815 avail += pcm->boundary; 816 return avail; 817 } 818 819 static inline int pcm_mmap_avail(struct pcm *pcm) 820 { 821 pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); 822 if (pcm->flags & PCM_IN) 823 return pcm_mmap_capture_avail(pcm); 824 else 825 return pcm_mmap_playback_avail(pcm); 826 } 827 828 static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) 829 { 830 unsigned int appl_ptr = pcm->mmap_control->appl_ptr; 831 appl_ptr += frames; 832 833 /* check for boundary wrap */ 834 if (appl_ptr > pcm->boundary) 835 appl_ptr -= pcm->boundary; 836 pcm->mmap_control->appl_ptr = appl_ptr; 837 } 838 839 int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, 840 unsigned int *frames) 841 { 842 unsigned int continuous, copy_frames, avail; 843 844 /* return the mmap buffer */ 845 *areas = pcm->mmap_buffer; 846 847 /* and the application offset in frames */ 848 *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; 849 850 avail = pcm_mmap_avail(pcm); 851 if (avail > pcm->buffer_size) 852 avail = pcm->buffer_size; 853 continuous = pcm->buffer_size - *offset; 854 855 /* we can only copy frames if the are availabale and continuos */ 856 copy_frames = *frames; 857 if (copy_frames > avail) 858 copy_frames = avail; 859 if (copy_frames > continuous) 860 copy_frames = continuous; 861 *frames = copy_frames; 862 863 return 0; 864 } 865 866 int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) 867 { 868 /* update the application pointer in userspace and kernel */ 869 pcm_mmap_appl_forward(pcm, frames); 870 pcm_sync_ptr(pcm, 0); 871 872 return frames; 873 } 874 875 int pcm_avail_update(struct pcm *pcm) 876 { 877 pcm_sync_ptr(pcm, 0); 878 return pcm_mmap_avail(pcm); 879 } 880 881 int pcm_state(struct pcm *pcm) 882 { 883 int err = pcm_sync_ptr(pcm, 0); 884 if (err < 0) 885 return err; 886 887 return pcm->mmap_status->state; 888 } 889 890 int pcm_set_avail_min(struct pcm *pcm, int avail_min) 891 { 892 if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ)) 893 return -ENOSYS; 894 895 pcm->config.avail_min = avail_min; 896 return 0; 897 } 898 899 int pcm_wait(struct pcm *pcm, int timeout) 900 { 901 struct pollfd pfd; 902 int err; 903 904 pfd.fd = pcm->fd; 905 pfd.events = POLLOUT | POLLERR | POLLNVAL; 906 907 do { 908 /* let's wait for avail or timeout */ 909 err = poll(&pfd, 1, timeout); 910 if (err < 0) 911 return -errno; 912 913 /* timeout ? */ 914 if (err == 0) 915 return 0; 916 917 /* have we been interrupted ? */ 918 if (errno == -EINTR) 919 continue; 920 921 /* check for any errors */ 922 if (pfd.revents & (POLLERR | POLLNVAL)) { 923 switch (pcm_state(pcm)) { 924 case PCM_STATE_XRUN: 925 return -EPIPE; 926 case PCM_STATE_SUSPENDED: 927 return -ESTRPIPE; 928 case PCM_STATE_DISCONNECTED: 929 return -ENODEV; 930 default: 931 return -EIO; 932 } 933 } 934 /* poll again if fd not ready for IO */ 935 } while (!(pfd.revents & (POLLIN | POLLOUT))); 936 937 return 1; 938 } 939 940 int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes) 941 { 942 int err = 0, frames, avail; 943 unsigned int offset = 0, count; 944 945 if (bytes == 0) 946 return 0; 947 948 count = pcm_bytes_to_frames(pcm, bytes); 949 950 while (count > 0) { 951 952 /* get the available space for writing new frames */ 953 avail = pcm_avail_update(pcm); 954 if (avail < 0) { 955 fprintf(stderr, "cannot determine available mmap frames"); 956 return err; 957 } 958 959 /* start the audio if we reach the threshold */ 960 if (!pcm->running && 961 (pcm->buffer_size - avail) >= pcm->config.start_threshold) { 962 if (pcm_start(pcm) < 0) { 963 fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", 964 (unsigned int)pcm->mmap_status->hw_ptr, 965 (unsigned int)pcm->mmap_control->appl_ptr, 966 avail); 967 return -errno; 968 } 969 pcm->wait_for_avail_min = 0; 970 } 971 972 /* sleep until we have space to write new frames */ 973 if (pcm->running) { 974 /* enable waiting for avail_min threshold when less frames than we have to write 975 * are available. */ 976 if (!pcm->wait_for_avail_min && (count > (unsigned int)avail)) 977 pcm->wait_for_avail_min = 1; 978 979 if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) { 980 int time = -1; 981 982 /* disable waiting for avail_min threshold to allow small amounts of data to be 983 * written without waiting as long as there is enough room in buffer. */ 984 pcm->wait_for_avail_min = 0; 985 986 if (pcm->flags & PCM_NOIRQ) 987 time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec; 988 989 err = pcm_wait(pcm, time); 990 if (err < 0) { 991 pcm->running = 0; 992 oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n", 993 (unsigned int)pcm->mmap_status->hw_ptr, 994 (unsigned int)pcm->mmap_control->appl_ptr, 995 avail); 996 pcm->mmap_control->appl_ptr = 0; 997 return err; 998 } 999 continue; 1000 } 1001 } 1002 1003 frames = count; 1004 if (frames > avail) 1005 frames = avail; 1006 1007 if (!frames) 1008 break; 1009 1010 /* copy frames from buffer */ 1011 frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames); 1012 if (frames < 0) { 1013 fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", 1014 (unsigned int)pcm->mmap_status->hw_ptr, 1015 (unsigned int)pcm->mmap_control->appl_ptr, 1016 avail); 1017 return frames; 1018 } 1019 1020 offset += frames; 1021 count -= frames; 1022 } 1023 1024 return 0; 1025 } 1026 1027 int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count) 1028 { 1029 if ((~pcm->flags) & (PCM_OUT | PCM_MMAP)) 1030 return -ENOSYS; 1031 1032 return pcm_mmap_transfer(pcm, (void *)data, count); 1033 } 1034 1035 int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count) 1036 { 1037 if ((~pcm->flags) & (PCM_IN | PCM_MMAP)) 1038 return -ENOSYS; 1039 1040 return pcm_mmap_transfer(pcm, data, count); 1041 } 1042