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 54static 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 60static 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 66static 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 71static 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 76static 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 88static 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 96static 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 105static 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 114static 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 124static 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 134static 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 158struct 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 175unsigned int pcm_get_buffer_size(struct pcm *pcm) 176{ 177 return pcm->buffer_size; 178} 179 180const char* pcm_get_error(struct pcm *pcm) 181{ 182 return pcm->error; 183} 184 185static 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 201static 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 216static unsigned int pcm_format_to_bits(enum pcm_format format) 217{ 218 switch (format) { 219 case PCM_FORMAT_S32_LE: 220 return 32; 221 default: 222 case PCM_FORMAT_S16_LE: 223 return 16; 224 }; 225} 226 227unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) 228{ 229 return bytes / (pcm->config.channels * 230 (pcm_format_to_bits(pcm->config.format) >> 3)); 231} 232 233unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) 234{ 235 return frames * pcm->config.channels * 236 (pcm_format_to_bits(pcm->config.format) >> 3); 237} 238 239static int pcm_sync_ptr(struct pcm *pcm, int flags) { 240 if (pcm->sync_ptr) { 241 pcm->sync_ptr->flags = flags; 242 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) 243 return -1; 244 } 245 return 0; 246} 247 248static int pcm_hw_mmap_status(struct pcm *pcm) { 249 250 if (pcm->sync_ptr) 251 return 0; 252 253 int page_size = sysconf(_SC_PAGE_SIZE); 254 pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, 255 pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); 256 if (pcm->mmap_status == MAP_FAILED) 257 pcm->mmap_status = NULL; 258 if (!pcm->mmap_status) 259 goto mmap_error; 260 261 pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 262 MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); 263 if (pcm->mmap_control == MAP_FAILED) 264 pcm->mmap_control = NULL; 265 if (!pcm->mmap_control) { 266 munmap(pcm->mmap_status, page_size); 267 pcm->mmap_status = NULL; 268 goto mmap_error; 269 } 270 if (pcm->flags & PCM_MMAP) 271 pcm->mmap_control->avail_min = pcm->config.avail_min; 272 else 273 pcm->mmap_control->avail_min = 1; 274 275 return 0; 276 277mmap_error: 278 279 pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); 280 if (!pcm->sync_ptr) 281 return -ENOMEM; 282 pcm->mmap_status = &pcm->sync_ptr->s.status; 283 pcm->mmap_control = &pcm->sync_ptr->c.control; 284 if (pcm->flags & PCM_MMAP) 285 pcm->mmap_control->avail_min = pcm->config.avail_min; 286 else 287 pcm->mmap_control->avail_min = 1; 288 289 pcm_sync_ptr(pcm, 0); 290 291 return 0; 292} 293 294static void pcm_hw_munmap_status(struct pcm *pcm) { 295 if (pcm->sync_ptr) { 296 free(pcm->sync_ptr); 297 pcm->sync_ptr = NULL; 298 } else { 299 int page_size = sysconf(_SC_PAGE_SIZE); 300 if (pcm->mmap_status) 301 munmap(pcm->mmap_status, page_size); 302 if (pcm->mmap_control) 303 munmap(pcm->mmap_control, page_size); 304 } 305 pcm->mmap_status = NULL; 306 pcm->mmap_control = NULL; 307} 308 309static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, 310 const char *src, unsigned int src_offset, 311 unsigned int frames) 312{ 313 int size_bytes = pcm_frames_to_bytes(pcm, frames); 314 int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); 315 int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); 316 317 /* interleaved only atm */ 318 memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, 319 src + src_offset_bytes, size_bytes); 320 return 0; 321} 322 323static int pcm_mmap_write_areas(struct pcm *pcm, const char *src, 324 unsigned int offset, unsigned int size) 325{ 326 void *pcm_areas; 327 int commit; 328 unsigned int pcm_offset, frames, count = 0; 329 330 while (size > 0) { 331 frames = size; 332 pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); 333 pcm_areas_copy(pcm, pcm_offset, src, offset, frames); 334 commit = pcm_mmap_commit(pcm, pcm_offset, frames); 335 if (commit < 0) { 336 oops(pcm, commit, "failed to commit %d frames\n", frames); 337 return commit; 338 } 339 340 offset += commit; 341 count += commit; 342 size -= commit; 343 } 344 return count; 345} 346 347int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, 348 struct timespec *tstamp) 349{ 350 int frames; 351 int rc; 352 snd_pcm_uframes_t hw_ptr; 353 354 if (!pcm_is_ready(pcm)) 355 return -1; 356 357 rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); 358 if (rc < 0) 359 return -1; 360 361 if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && 362 (pcm->mmap_status->state != PCM_STATE_DRAINING)) 363 return -1; 364 365 *tstamp = pcm->mmap_status->tstamp; 366 if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0) 367 return -1; 368 369 hw_ptr = pcm->mmap_status->hw_ptr; 370 if (pcm->flags & PCM_IN) 371 frames = hw_ptr - pcm->mmap_control->appl_ptr; 372 else 373 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; 374 375 if (frames < 0) 376 frames += pcm->boundary; 377 else if (frames > (int)pcm->boundary) 378 frames -= pcm->boundary; 379 380 *avail = (unsigned int)frames; 381 382 return 0; 383} 384 385int pcm_write(struct pcm *pcm, const void *data, unsigned int count) 386{ 387 struct snd_xferi x; 388 389 if (pcm->flags & PCM_IN) 390 return -EINVAL; 391 392 x.buf = (void*)data; 393 x.frames = count / (pcm->config.channels * 394 pcm_format_to_bits(pcm->config.format) / 8); 395 396 for (;;) { 397 if (!pcm->running) { 398 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) 399 return oops(pcm, errno, "cannot prepare channel"); 400 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) 401 return oops(pcm, errno, "cannot write initial data"); 402 pcm->running = 1; 403 return 0; 404 } 405 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { 406 pcm->running = 0; 407 if (errno == EPIPE) { 408 /* we failed to make our window -- try to restart if we are 409 * allowed to do so. Otherwise, simply allow the EPIPE error to 410 * propagate up to the app level */ 411 pcm->underruns++; 412 if (pcm->flags & PCM_NORESTART) 413 return -EPIPE; 414 continue; 415 } 416 return oops(pcm, errno, "cannot write stream data"); 417 } 418 return 0; 419 } 420} 421 422int pcm_read(struct pcm *pcm, void *data, unsigned int count) 423{ 424 struct snd_xferi x; 425 426 if (!(pcm->flags & PCM_IN)) 427 return -EINVAL; 428 429 x.buf = data; 430 x.frames = count / (pcm->config.channels * 431 pcm_format_to_bits(pcm->config.format) / 8); 432 433 for (;;) { 434 if (!pcm->running) { 435 if (pcm_start(pcm) < 0) { 436 fprintf(stderr, "start error"); 437 return -errno; 438 } 439 } 440 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { 441 pcm->running = 0; 442 if (errno == EPIPE) { 443 /* we failed to make our window -- try to restart */ 444 pcm->underruns++; 445 continue; 446 } 447 return oops(pcm, errno, "cannot read stream data"); 448 } 449 return 0; 450 } 451} 452 453static struct pcm bad_pcm = { 454 .fd = -1, 455}; 456 457struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, 458 unsigned int flags) 459{ 460 struct snd_pcm_hw_params *params; 461 char fn[256]; 462 int fd; 463 464 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, 465 flags & PCM_IN ? 'c' : 'p'); 466 467 fd = open(fn, O_RDWR); 468 if (fd < 0) { 469 fprintf(stderr, "cannot open device '%s'\n", fn); 470 goto err_open; 471 } 472 473 params = calloc(1, sizeof(struct snd_pcm_hw_params)); 474 if (!params) 475 goto err_calloc; 476 477 param_init(params); 478 if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { 479 fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); 480 goto err_hw_refine; 481 } 482 483 close(fd); 484 485 return (struct pcm_params *)params; 486 487err_hw_refine: 488 free(params); 489err_calloc: 490 close(fd); 491err_open: 492 return NULL; 493} 494 495void pcm_params_free(struct pcm_params *pcm_params) 496{ 497 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 498 499 if (params) 500 free(params); 501} 502 503static int pcm_param_to_alsa(enum pcm_param param) 504{ 505 switch (param) { 506 case PCM_PARAM_SAMPLE_BITS: 507 return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; 508 break; 509 case PCM_PARAM_FRAME_BITS: 510 return SNDRV_PCM_HW_PARAM_FRAME_BITS; 511 break; 512 case PCM_PARAM_CHANNELS: 513 return SNDRV_PCM_HW_PARAM_CHANNELS; 514 break; 515 case PCM_PARAM_RATE: 516 return SNDRV_PCM_HW_PARAM_RATE; 517 break; 518 case PCM_PARAM_PERIOD_TIME: 519 return SNDRV_PCM_HW_PARAM_PERIOD_TIME; 520 break; 521 case PCM_PARAM_PERIOD_SIZE: 522 return SNDRV_PCM_HW_PARAM_PERIOD_SIZE; 523 break; 524 case PCM_PARAM_PERIOD_BYTES: 525 return SNDRV_PCM_HW_PARAM_PERIOD_BYTES; 526 break; 527 case PCM_PARAM_PERIODS: 528 return SNDRV_PCM_HW_PARAM_PERIODS; 529 break; 530 case PCM_PARAM_BUFFER_TIME: 531 return SNDRV_PCM_HW_PARAM_BUFFER_TIME; 532 break; 533 case PCM_PARAM_BUFFER_SIZE: 534 return SNDRV_PCM_HW_PARAM_BUFFER_SIZE; 535 break; 536 case PCM_PARAM_BUFFER_BYTES: 537 return SNDRV_PCM_HW_PARAM_BUFFER_BYTES; 538 break; 539 case PCM_PARAM_TICK_TIME: 540 return SNDRV_PCM_HW_PARAM_TICK_TIME; 541 break; 542 543 default: 544 return -1; 545 } 546} 547 548unsigned int pcm_params_get_min(struct pcm_params *pcm_params, 549 enum pcm_param param) 550{ 551 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 552 int p; 553 554 if (!params) 555 return 0; 556 557 p = pcm_param_to_alsa(param); 558 if (p < 0) 559 return 0; 560 561 return param_get_min(params, p); 562} 563 564unsigned int pcm_params_get_max(struct pcm_params *pcm_params, 565 enum pcm_param param) 566{ 567 struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; 568 int p; 569 570 if (!params) 571 return 0; 572 573 p = pcm_param_to_alsa(param); 574 if (p < 0) 575 return 0; 576 577 return param_get_max(params, p); 578} 579 580int pcm_close(struct pcm *pcm) 581{ 582 if (pcm == &bad_pcm) 583 return 0; 584 585 pcm_hw_munmap_status(pcm); 586 587 if (pcm->flags & PCM_MMAP) { 588 pcm_stop(pcm); 589 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); 590 } 591 592 if (pcm->fd >= 0) 593 close(pcm->fd); 594 pcm->running = 0; 595 pcm->buffer_size = 0; 596 pcm->fd = -1; 597 free(pcm); 598 return 0; 599} 600 601struct pcm *pcm_open(unsigned int card, unsigned int device, 602 unsigned int flags, struct pcm_config *config) 603{ 604 struct pcm *pcm; 605 struct snd_pcm_info info; 606 struct snd_pcm_hw_params params; 607 struct snd_pcm_sw_params sparams; 608 char fn[256]; 609 int rc; 610 611 pcm = calloc(1, sizeof(struct pcm)); 612 if (!pcm || !config) 613 return &bad_pcm; /* TODO: could support default config here */ 614 615 pcm->config = *config; 616 617 snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, 618 flags & PCM_IN ? 'c' : 'p'); 619 620 pcm->flags = flags; 621 pcm->fd = open(fn, O_RDWR); 622 if (pcm->fd < 0) { 623 oops(pcm, errno, "cannot open device '%s'", fn); 624 return pcm; 625 } 626 627 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { 628 oops(pcm, errno, "cannot get info"); 629 goto fail_close; 630 } 631 632 param_init(¶ms); 633 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, 634 pcm_format_to_alsa(config->format)); 635 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, 636 SNDRV_PCM_SUBFORMAT_STD); 637 param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); 638 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 639 pcm_format_to_bits(config->format)); 640 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, 641 pcm_format_to_bits(config->format) * config->channels); 642 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, 643 config->channels); 644 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); 645 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); 646 647 if (flags & PCM_NOIRQ) { 648 649 if (!(flags & PCM_MMAP)) { 650 oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); 651 goto fail; 652 } 653 654 params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; 655 pcm->noirq_frames_per_msec = config->rate / 1000; 656 } 657 658 if (flags & PCM_MMAP) 659 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, 660 SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); 661 else 662 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, 663 SNDRV_PCM_ACCESS_RW_INTERLEAVED); 664 665 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { 666 oops(pcm, errno, "cannot set hw params"); 667 goto fail_close; 668 } 669 670 /* get our refined hw_params */ 671 config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 672 config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); 673 pcm->buffer_size = config->period_count * config->period_size; 674 675 if (flags & PCM_MMAP) { 676 pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), 677 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); 678 if (pcm->mmap_buffer == MAP_FAILED) { 679 oops(pcm, -errno, "failed to mmap buffer %d bytes\n", 680 pcm_frames_to_bytes(pcm, pcm->buffer_size)); 681 goto fail_close; 682 } 683 } 684 685 686 memset(&sparams, 0, sizeof(sparams)); 687 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; 688 sparams.period_step = 1; 689 690 if (!config->start_threshold) { 691 if (pcm->flags & PCM_IN) 692 pcm->config.start_threshold = sparams.start_threshold = 1; 693 else 694 pcm->config.start_threshold = sparams.start_threshold = 695 config->period_count * config->period_size / 2; 696 } else 697 sparams.start_threshold = config->start_threshold; 698 699 /* pick a high stop threshold - todo: does this need further tuning */ 700 if (!config->stop_threshold) { 701 if (pcm->flags & PCM_IN) 702 pcm->config.stop_threshold = sparams.stop_threshold = 703 config->period_count * config->period_size * 10; 704 else 705 pcm->config.stop_threshold = sparams.stop_threshold = 706 config->period_count * config->period_size; 707 } 708 else 709 sparams.stop_threshold = config->stop_threshold; 710 711 if (!pcm->config.avail_min) { 712 if (pcm->flags & PCM_MMAP) 713 pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; 714 else 715 pcm->config.avail_min = sparams.avail_min = 1; 716 } else 717 sparams.avail_min = config->avail_min; 718 719 sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ 720 sparams.silence_size = 0; 721 sparams.silence_threshold = config->silence_threshold; 722 pcm->boundary = sparams.boundary = pcm->buffer_size; 723 724 while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) 725 pcm->boundary *= 2; 726 727 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { 728 oops(pcm, errno, "cannot set sw params"); 729 goto fail; 730 } 731 732 rc = pcm_hw_mmap_status(pcm); 733 if (rc < 0) { 734 oops(pcm, rc, "mmap status failed"); 735 goto fail; 736 } 737 738 pcm->underruns = 0; 739 return pcm; 740 741fail: 742 if (flags & PCM_MMAP) 743 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); 744fail_close: 745 close(pcm->fd); 746 pcm->fd = -1; 747 return pcm; 748} 749 750int pcm_is_ready(struct pcm *pcm) 751{ 752 return pcm->fd >= 0; 753} 754 755int pcm_start(struct pcm *pcm) 756{ 757 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) 758 return oops(pcm, errno, "cannot prepare channel"); 759 760 if (pcm->flags & PCM_MMAP) 761 pcm_sync_ptr(pcm, 0); 762 763 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) 764 return oops(pcm, errno, "cannot start channel"); 765 766 pcm->running = 1; 767 return 0; 768} 769 770int pcm_stop(struct pcm *pcm) 771{ 772 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) 773 return oops(pcm, errno, "cannot stop channel"); 774 775 pcm->running = 0; 776 return 0; 777} 778 779static inline int pcm_mmap_playback_avail(struct pcm *pcm) 780{ 781 int avail; 782 783 avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; 784 785 if (avail < 0) 786 avail += pcm->boundary; 787 else if (avail > (int)pcm->boundary) 788 avail -= pcm->boundary; 789 790 return avail; 791} 792 793static inline int pcm_mmap_capture_avail(struct pcm *pcm) 794{ 795 int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; 796 if (avail < 0) 797 avail += pcm->boundary; 798 return avail; 799} 800 801static inline int pcm_mmap_avail(struct pcm *pcm) 802{ 803 pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); 804 if (pcm->flags & PCM_IN) 805 return pcm_mmap_capture_avail(pcm); 806 else 807 return pcm_mmap_playback_avail(pcm); 808} 809 810static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) 811{ 812 unsigned int appl_ptr = pcm->mmap_control->appl_ptr; 813 appl_ptr += frames; 814 815 /* check for boundary wrap */ 816 if (appl_ptr > pcm->boundary) 817 appl_ptr -= pcm->boundary; 818 pcm->mmap_control->appl_ptr = appl_ptr; 819} 820 821int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, 822 unsigned int *frames) 823{ 824 unsigned int continuous, copy_frames, avail; 825 826 /* return the mmap buffer */ 827 *areas = pcm->mmap_buffer; 828 829 /* and the application offset in frames */ 830 *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; 831 832 avail = pcm_mmap_avail(pcm); 833 if (avail > pcm->buffer_size) 834 avail = pcm->buffer_size; 835 continuous = pcm->buffer_size - *offset; 836 837 /* we can only copy frames if the are availabale and continuos */ 838 copy_frames = *frames; 839 if (copy_frames > avail) 840 copy_frames = avail; 841 if (copy_frames > continuous) 842 copy_frames = continuous; 843 *frames = copy_frames; 844 845 return 0; 846} 847 848int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) 849{ 850 /* update the application pointer in userspace and kernel */ 851 pcm_mmap_appl_forward(pcm, frames); 852 pcm_sync_ptr(pcm, 0); 853 854 return frames; 855} 856 857int pcm_avail_update(struct pcm *pcm) 858{ 859 pcm_sync_ptr(pcm, 0); 860 return pcm_mmap_avail(pcm); 861} 862 863int pcm_state(struct pcm *pcm) 864{ 865 int err = pcm_sync_ptr(pcm, 0); 866 if (err < 0) 867 return err; 868 869 return pcm->mmap_status->state; 870} 871 872int pcm_set_avail_min(struct pcm *pcm, int avail_min) 873{ 874 if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ)) 875 return -ENOSYS; 876 877 pcm->config.avail_min = avail_min; 878 return 0; 879} 880 881int pcm_wait(struct pcm *pcm, int timeout) 882{ 883 struct pollfd pfd; 884 int err; 885 886 pfd.fd = pcm->fd; 887 pfd.events = POLLOUT | POLLERR | POLLNVAL; 888 889 do { 890 /* let's wait for avail or timeout */ 891 err = poll(&pfd, 1, timeout); 892 if (err < 0) 893 return -errno; 894 895 /* timeout ? */ 896 if (err == 0) 897 return 0; 898 899 /* have we been interrupted ? */ 900 if (errno == -EINTR) 901 continue; 902 903 /* check for any errors */ 904 if (pfd.revents & (POLLERR | POLLNVAL)) { 905 switch (pcm_state(pcm)) { 906 case PCM_STATE_XRUN: 907 return -EPIPE; 908 case PCM_STATE_SUSPENDED: 909 return -ESTRPIPE; 910 case PCM_STATE_DISCONNECTED: 911 return -ENODEV; 912 default: 913 return -EIO; 914 } 915 } 916 /* poll again if fd not ready for IO */ 917 } while (!(pfd.revents & (POLLIN | POLLOUT))); 918 919 return 1; 920} 921 922int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) 923{ 924 int err = 0, frames, avail; 925 unsigned int offset = 0, count; 926 927 if (bytes == 0) 928 return 0; 929 930 count = pcm_bytes_to_frames(pcm, bytes); 931 932 while (count > 0) { 933 934 /* get the available space for writing new frames */ 935 avail = pcm_avail_update(pcm); 936 if (avail < 0) { 937 fprintf(stderr, "cannot determine available mmap frames"); 938 return err; 939 } 940 941 /* start the audio if we reach the threshold */ 942 if (!pcm->running && 943 (pcm->buffer_size - avail) >= pcm->config.start_threshold) { 944 if (pcm_start(pcm) < 0) { 945 fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", 946 (unsigned int)pcm->mmap_status->hw_ptr, 947 (unsigned int)pcm->mmap_control->appl_ptr, 948 avail); 949 return -errno; 950 } 951 pcm->wait_for_avail_min = 0; 952 } 953 954 /* sleep until we have space to write new frames */ 955 if (pcm->running) { 956 /* enable waiting for avail_min threshold when less frames than we have to write 957 * are available. */ 958 if (!pcm->wait_for_avail_min && (count > (unsigned int)avail)) 959 pcm->wait_for_avail_min = 1; 960 961 if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) { 962 int time = -1; 963 964 /* disable waiting for avail_min threshold to allow small amounts of data to be 965 * written without waiting as long as there is enough room in buffer. */ 966 pcm->wait_for_avail_min = 0; 967 968 if (pcm->flags & PCM_NOIRQ) 969 time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec; 970 971 err = pcm_wait(pcm, time); 972 if (err < 0) { 973 pcm->running = 0; 974 oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n", 975 (unsigned int)pcm->mmap_status->hw_ptr, 976 (unsigned int)pcm->mmap_control->appl_ptr, 977 avail); 978 pcm->mmap_control->appl_ptr = 0; 979 return err; 980 } 981 continue; 982 } 983 } 984 985 frames = count; 986 if (frames > avail) 987 frames = avail; 988 989 if (!frames) 990 break; 991 992 /* copy frames from buffer */ 993 frames = pcm_mmap_write_areas(pcm, buffer, offset, frames); 994 if (frames < 0) { 995 fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", 996 (unsigned int)pcm->mmap_status->hw_ptr, 997 (unsigned int)pcm->mmap_control->appl_ptr, 998 avail); 999 return frames; 1000 } 1001 1002 offset += frames; 1003 count -= frames; 1004 } 1005 1006 return 0; 1007} 1008