Home | History | Annotate | Download | only in tinyalsa
      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 /* Logs information into a string; follows snprintf() in that
     55  * offset may be greater than size, and though no characters are copied
     56  * into string, characters are still counted into offset. */
     57 #define STRLOG(string, offset, size, ...) \
     58     do { int temp, clipoffset = offset > size ? size : offset; \
     59          temp = snprintf(string + clipoffset, size - clipoffset, __VA_ARGS__); \
     60          if (temp > 0) offset += temp; } while (0)
     61 
     62 #ifndef ARRAY_SIZE
     63 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
     64 #endif
     65 
     66 /* refer to SNDRV_PCM_ACCESS_##index in sound/asound.h. */
     67 static const char * const access_lookup[] = {
     68         "MMAP_INTERLEAVED",
     69         "MMAP_NONINTERLEAVED",
     70         "MMAP_COMPLEX",
     71         "RW_INTERLEAVED",
     72         "RW_NONINTERLEAVED",
     73 };
     74 
     75 /* refer to SNDRV_PCM_FORMAT_##index in sound/asound.h. */
     76 static const char * const format_lookup[] = {
     77         /*[0] =*/ "S8",
     78         "U8",
     79         "S16_LE",
     80         "S16_BE",
     81         "U16_LE",
     82         "U16_BE",
     83         "S24_LE",
     84         "S24_BE",
     85         "U24_LE",
     86         "U24_BE",
     87         "S32_LE",
     88         "S32_BE",
     89         "U32_LE",
     90         "U32_BE",
     91         "FLOAT_LE",
     92         "FLOAT_BE",
     93         "FLOAT64_LE",
     94         "FLOAT64_BE",
     95         "IEC958_SUBFRAME_LE",
     96         "IEC958_SUBFRAME_BE",
     97         "MU_LAW",
     98         "A_LAW",
     99         "IMA_ADPCM",
    100         "MPEG",
    101         /*[24] =*/ "GSM",
    102         /* gap */
    103         [31] = "SPECIAL",
    104         "S24_3LE",
    105         "S24_3BE",
    106         "U24_3LE",
    107         "U24_3BE",
    108         "S20_3LE",
    109         "S20_3BE",
    110         "U20_3LE",
    111         "U20_3BE",
    112         "S18_3LE",
    113         "S18_3BE",
    114         "U18_3LE",
    115         /*[43] =*/ "U18_3BE",
    116 #if 0
    117         /* recent additions, may not be present on local asound.h */
    118         "G723_24",
    119         "G723_24_1B",
    120         "G723_40",
    121         "G723_40_1B",
    122         "DSD_U8",
    123         "DSD_U16_LE",
    124 #endif
    125 };
    126 
    127 /* refer to SNDRV_PCM_SUBFORMAT_##index in sound/asound.h. */
    128 static const char * const subformat_lookup[] = {
    129         "STD",
    130 };
    131 
    132 static inline int param_is_mask(int p)
    133 {
    134     return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
    135         (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
    136 }
    137 
    138 static inline int param_is_interval(int p)
    139 {
    140     return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
    141         (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
    142 }
    143 
    144 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
    145 {
    146     return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
    147 }
    148 
    149 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
    150 {
    151     return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
    152 }
    153 
    154 static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
    155 {
    156     if (bit >= SNDRV_MASK_MAX)
    157         return;
    158     if (param_is_mask(n)) {
    159         struct snd_mask *m = param_to_mask(p, n);
    160         m->bits[0] = 0;
    161         m->bits[1] = 0;
    162         m->bits[bit >> 5] |= (1 << (bit & 31));
    163     }
    164 }
    165 
    166 static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val)
    167 {
    168     if (param_is_interval(n)) {
    169         struct snd_interval *i = param_to_interval(p, n);
    170         i->min = val;
    171     }
    172 }
    173 
    174 static unsigned int param_get_min(struct snd_pcm_hw_params *p, int n)
    175 {
    176     if (param_is_interval(n)) {
    177         struct snd_interval *i = param_to_interval(p, n);
    178         return i->min;
    179     }
    180     return 0;
    181 }
    182 
    183 static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned int val)
    184 {
    185     if (param_is_interval(n)) {
    186         struct snd_interval *i = param_to_interval(p, n);
    187         i->max = val;
    188     }
    189 }
    190 
    191 static unsigned int param_get_max(struct snd_pcm_hw_params *p, int n)
    192 {
    193     if (param_is_interval(n)) {
    194         struct snd_interval *i = param_to_interval(p, n);
    195         return i->max;
    196     }
    197     return 0;
    198 }
    199 
    200 static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val)
    201 {
    202     if (param_is_interval(n)) {
    203         struct snd_interval *i = param_to_interval(p, n);
    204         i->min = val;
    205         i->max = val;
    206         i->integer = 1;
    207     }
    208 }
    209 
    210 static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
    211 {
    212     if (param_is_interval(n)) {
    213         struct snd_interval *i = param_to_interval(p, n);
    214         if (i->integer)
    215             return i->max;
    216     }
    217     return 0;
    218 }
    219 
    220 static void param_init(struct snd_pcm_hw_params *p)
    221 {
    222     int n;
    223 
    224     memset(p, 0, sizeof(*p));
    225     for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
    226          n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
    227             struct snd_mask *m = param_to_mask(p, n);
    228             m->bits[0] = ~0;
    229             m->bits[1] = ~0;
    230     }
    231     for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
    232          n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
    233             struct snd_interval *i = param_to_interval(p, n);
    234             i->min = 0;
    235             i->max = ~0;
    236     }
    237     p->rmask = ~0U;
    238     p->cmask = 0;
    239     p->info = ~0U;
    240 }
    241 
    242 #define PCM_ERROR_MAX 128
    243 
    244 struct pcm {
    245     int fd;
    246     unsigned int flags;
    247     int running:1;
    248     int prepared:1;
    249     int underruns;
    250     unsigned int buffer_size;
    251     unsigned int boundary;
    252     char error[PCM_ERROR_MAX];
    253     struct pcm_config config;
    254     struct snd_pcm_mmap_status *mmap_status;
    255     struct snd_pcm_mmap_control *mmap_control;
    256     struct snd_pcm_sync_ptr *sync_ptr;
    257     void *mmap_buffer;
    258     unsigned int noirq_frames_per_msec;
    259     int wait_for_avail_min;
    260 };
    261 
    262 unsigned int pcm_get_buffer_size(struct pcm *pcm)
    263 {
    264     return pcm->buffer_size;
    265 }
    266 
    267 const char* pcm_get_error(struct pcm *pcm)
    268 {
    269     return pcm->error;
    270 }
    271 
    272 static int oops(struct pcm *pcm, int e, const char *fmt, ...)
    273 {
    274     va_list ap;
    275     int sz;
    276 
    277     va_start(ap, fmt);
    278     vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
    279     va_end(ap);
    280     sz = strlen(pcm->error);
    281 
    282     if (errno)
    283         snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
    284                  ": %s", strerror(e));
    285     return -1;
    286 }
    287 
    288 static unsigned int pcm_format_to_alsa(enum pcm_format format)
    289 {
    290     switch (format) {
    291     case PCM_FORMAT_S32_LE:
    292         return SNDRV_PCM_FORMAT_S32_LE;
    293     case PCM_FORMAT_S8:
    294         return SNDRV_PCM_FORMAT_S8;
    295     case PCM_FORMAT_S24_3LE:
    296         return SNDRV_PCM_FORMAT_S24_3LE;
    297     case PCM_FORMAT_S24_LE:
    298         return SNDRV_PCM_FORMAT_S24_LE;
    299     default:
    300     case PCM_FORMAT_S16_LE:
    301         return SNDRV_PCM_FORMAT_S16_LE;
    302     };
    303 }
    304 
    305 unsigned int pcm_format_to_bits(enum pcm_format format)
    306 {
    307     switch (format) {
    308     case PCM_FORMAT_S32_LE:
    309     case PCM_FORMAT_S24_LE:
    310         return 32;
    311     case PCM_FORMAT_S24_3LE:
    312         return 24;
    313     default:
    314     case PCM_FORMAT_S16_LE:
    315         return 16;
    316     };
    317 }
    318 
    319 unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes)
    320 {
    321     return bytes / (pcm->config.channels *
    322         (pcm_format_to_bits(pcm->config.format) >> 3));
    323 }
    324 
    325 unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames)
    326 {
    327     return frames * pcm->config.channels *
    328         (pcm_format_to_bits(pcm->config.format) >> 3);
    329 }
    330 
    331 static int pcm_sync_ptr(struct pcm *pcm, int flags) {
    332     if (pcm->sync_ptr) {
    333         pcm->sync_ptr->flags = flags;
    334         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0)
    335             return -1;
    336     }
    337     return 0;
    338 }
    339 
    340 static int pcm_hw_mmap_status(struct pcm *pcm) {
    341 
    342     if (pcm->sync_ptr)
    343         return 0;
    344 
    345     int page_size = sysconf(_SC_PAGE_SIZE);
    346     pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED,
    347                             pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
    348     if (pcm->mmap_status == MAP_FAILED)
    349         pcm->mmap_status = NULL;
    350     if (!pcm->mmap_status)
    351         goto mmap_error;
    352 
    353     pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
    354                              MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
    355     if (pcm->mmap_control == MAP_FAILED)
    356         pcm->mmap_control = NULL;
    357     if (!pcm->mmap_control) {
    358         munmap(pcm->mmap_status, page_size);
    359         pcm->mmap_status = NULL;
    360         goto mmap_error;
    361     }
    362     if (pcm->flags & PCM_MMAP)
    363         pcm->mmap_control->avail_min = pcm->config.avail_min;
    364     else
    365         pcm->mmap_control->avail_min = 1;
    366 
    367     return 0;
    368 
    369 mmap_error:
    370 
    371     pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr));
    372     if (!pcm->sync_ptr)
    373         return -ENOMEM;
    374     pcm->mmap_status = &pcm->sync_ptr->s.status;
    375     pcm->mmap_control = &pcm->sync_ptr->c.control;
    376     if (pcm->flags & PCM_MMAP)
    377         pcm->mmap_control->avail_min = pcm->config.avail_min;
    378     else
    379         pcm->mmap_control->avail_min = 1;
    380 
    381     pcm_sync_ptr(pcm, 0);
    382 
    383     return 0;
    384 }
    385 
    386 static void pcm_hw_munmap_status(struct pcm *pcm) {
    387     if (pcm->sync_ptr) {
    388         free(pcm->sync_ptr);
    389         pcm->sync_ptr = NULL;
    390     } else {
    391         int page_size = sysconf(_SC_PAGE_SIZE);
    392         if (pcm->mmap_status)
    393             munmap(pcm->mmap_status, page_size);
    394         if (pcm->mmap_control)
    395             munmap(pcm->mmap_control, page_size);
    396     }
    397     pcm->mmap_status = NULL;
    398     pcm->mmap_control = NULL;
    399 }
    400 
    401 static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset,
    402                           char *buf, unsigned int src_offset,
    403                           unsigned int frames)
    404 {
    405     int size_bytes = pcm_frames_to_bytes(pcm, frames);
    406     int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset);
    407     int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset);
    408 
    409     /* interleaved only atm */
    410     if (pcm->flags & PCM_IN)
    411         memcpy(buf + src_offset_bytes,
    412                (char*)pcm->mmap_buffer + pcm_offset_bytes,
    413                size_bytes);
    414     else
    415         memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes,
    416                buf + src_offset_bytes,
    417                size_bytes);
    418     return 0;
    419 }
    420 
    421 static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf,
    422                                 unsigned int offset, unsigned int size)
    423 {
    424     void *pcm_areas;
    425     int commit;
    426     unsigned int pcm_offset, frames, count = 0;
    427 
    428     while (size > 0) {
    429         frames = size;
    430         pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
    431         pcm_areas_copy(pcm, pcm_offset, buf, offset, frames);
    432         commit = pcm_mmap_commit(pcm, pcm_offset, frames);
    433         if (commit < 0) {
    434             oops(pcm, commit, "failed to commit %d frames\n", frames);
    435             return commit;
    436         }
    437 
    438         offset += commit;
    439         count += commit;
    440         size -= commit;
    441     }
    442     return count;
    443 }
    444 
    445 int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
    446                        struct timespec *tstamp)
    447 {
    448     int frames;
    449     int rc;
    450     snd_pcm_uframes_t hw_ptr;
    451 
    452     if (!pcm_is_ready(pcm))
    453         return -1;
    454 
    455     rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC);
    456     if (rc < 0)
    457         return -1;
    458 
    459     if ((pcm->mmap_status->state != PCM_STATE_RUNNING) &&
    460             (pcm->mmap_status->state != PCM_STATE_DRAINING))
    461         return -1;
    462 
    463     *tstamp = pcm->mmap_status->tstamp;
    464     if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0)
    465         return -1;
    466 
    467     hw_ptr = pcm->mmap_status->hw_ptr;
    468     if (pcm->flags & PCM_IN)
    469         frames = hw_ptr - pcm->mmap_control->appl_ptr;
    470     else
    471         frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
    472 
    473     if (frames < 0)
    474         frames += pcm->boundary;
    475     else if (frames > (int)pcm->boundary)
    476         frames -= pcm->boundary;
    477 
    478     *avail = (unsigned int)frames;
    479 
    480     return 0;
    481 }
    482 
    483 int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
    484 {
    485     struct snd_xferi x;
    486 
    487     if (pcm->flags & PCM_IN)
    488         return -EINVAL;
    489 
    490     x.buf = (void*)data;
    491     x.frames = count / (pcm->config.channels *
    492                         pcm_format_to_bits(pcm->config.format) / 8);
    493 
    494     for (;;) {
    495         if (!pcm->running) {
    496             int prepare_error = pcm_prepare(pcm);
    497             if (prepare_error)
    498                 return prepare_error;
    499             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
    500                 return oops(pcm, errno, "cannot write initial data");
    501             pcm->running = 1;
    502             return 0;
    503         }
    504         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
    505             pcm->prepared = 0;
    506             pcm->running = 0;
    507             if (errno == EPIPE) {
    508                 /* we failed to make our window -- try to restart if we are
    509                  * allowed to do so.  Otherwise, simply allow the EPIPE error to
    510                  * propagate up to the app level */
    511                 pcm->underruns++;
    512                 if (pcm->flags & PCM_NORESTART)
    513                     return -EPIPE;
    514                 continue;
    515             }
    516             return oops(pcm, errno, "cannot write stream data");
    517         }
    518         return 0;
    519     }
    520 }
    521 
    522 int pcm_read(struct pcm *pcm, void *data, unsigned int count)
    523 {
    524     struct snd_xferi x;
    525 
    526     if (!(pcm->flags & PCM_IN))
    527         return -EINVAL;
    528 
    529     x.buf = data;
    530     x.frames = count / (pcm->config.channels *
    531                         pcm_format_to_bits(pcm->config.format) / 8);
    532 
    533     for (;;) {
    534         if (!pcm->running) {
    535             if (pcm_start(pcm) < 0) {
    536                 fprintf(stderr, "start error");
    537                 return -errno;
    538             }
    539         }
    540         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
    541             pcm->prepared = 0;
    542             pcm->running = 0;
    543             if (errno == EPIPE) {
    544                     /* we failed to make our window -- try to restart */
    545                 pcm->underruns++;
    546                 continue;
    547             }
    548             return oops(pcm, errno, "cannot read stream data");
    549         }
    550         return 0;
    551     }
    552 }
    553 
    554 static struct pcm bad_pcm = {
    555     .fd = -1,
    556 };
    557 
    558 struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
    559                                   unsigned int flags)
    560 {
    561     struct snd_pcm_hw_params *params;
    562     char fn[256];
    563     int fd;
    564 
    565     snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
    566              flags & PCM_IN ? 'c' : 'p');
    567 
    568     fd = open(fn, O_RDWR);
    569     if (fd < 0) {
    570         fprintf(stderr, "cannot open device '%s'\n", fn);
    571         goto err_open;
    572     }
    573 
    574     params = calloc(1, sizeof(struct snd_pcm_hw_params));
    575     if (!params)
    576         goto err_calloc;
    577 
    578     param_init(params);
    579     if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) {
    580         fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno);
    581         goto err_hw_refine;
    582     }
    583 
    584     close(fd);
    585 
    586     return (struct pcm_params *)params;
    587 
    588 err_hw_refine:
    589     free(params);
    590 err_calloc:
    591     close(fd);
    592 err_open:
    593     return NULL;
    594 }
    595 
    596 void pcm_params_free(struct pcm_params *pcm_params)
    597 {
    598     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    599 
    600     if (params)
    601         free(params);
    602 }
    603 
    604 static int pcm_param_to_alsa(enum pcm_param param)
    605 {
    606     switch (param) {
    607     case PCM_PARAM_ACCESS:
    608         return SNDRV_PCM_HW_PARAM_ACCESS;
    609     case PCM_PARAM_FORMAT:
    610         return SNDRV_PCM_HW_PARAM_FORMAT;
    611     case PCM_PARAM_SUBFORMAT:
    612         return SNDRV_PCM_HW_PARAM_SUBFORMAT;
    613     case PCM_PARAM_SAMPLE_BITS:
    614         return SNDRV_PCM_HW_PARAM_SAMPLE_BITS;
    615         break;
    616     case PCM_PARAM_FRAME_BITS:
    617         return SNDRV_PCM_HW_PARAM_FRAME_BITS;
    618         break;
    619     case PCM_PARAM_CHANNELS:
    620         return SNDRV_PCM_HW_PARAM_CHANNELS;
    621         break;
    622     case PCM_PARAM_RATE:
    623         return SNDRV_PCM_HW_PARAM_RATE;
    624         break;
    625     case PCM_PARAM_PERIOD_TIME:
    626         return SNDRV_PCM_HW_PARAM_PERIOD_TIME;
    627         break;
    628     case PCM_PARAM_PERIOD_SIZE:
    629         return SNDRV_PCM_HW_PARAM_PERIOD_SIZE;
    630         break;
    631     case PCM_PARAM_PERIOD_BYTES:
    632         return SNDRV_PCM_HW_PARAM_PERIOD_BYTES;
    633         break;
    634     case PCM_PARAM_PERIODS:
    635         return SNDRV_PCM_HW_PARAM_PERIODS;
    636         break;
    637     case PCM_PARAM_BUFFER_TIME:
    638         return SNDRV_PCM_HW_PARAM_BUFFER_TIME;
    639         break;
    640     case PCM_PARAM_BUFFER_SIZE:
    641         return SNDRV_PCM_HW_PARAM_BUFFER_SIZE;
    642         break;
    643     case PCM_PARAM_BUFFER_BYTES:
    644         return SNDRV_PCM_HW_PARAM_BUFFER_BYTES;
    645         break;
    646     case PCM_PARAM_TICK_TIME:
    647         return SNDRV_PCM_HW_PARAM_TICK_TIME;
    648         break;
    649 
    650     default:
    651         return -1;
    652     }
    653 }
    654 
    655 struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
    656                                      enum pcm_param param)
    657 {
    658     int p;
    659     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    660     if (params == NULL) {
    661         return NULL;
    662     }
    663 
    664     p = pcm_param_to_alsa(param);
    665     if (p < 0 || !param_is_mask(p)) {
    666         return NULL;
    667     }
    668 
    669     return (struct pcm_mask *)param_to_mask(params, p);
    670 }
    671 
    672 unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
    673                                 enum pcm_param param)
    674 {
    675     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    676     int p;
    677 
    678     if (!params)
    679         return 0;
    680 
    681     p = pcm_param_to_alsa(param);
    682     if (p < 0)
    683         return 0;
    684 
    685     return param_get_min(params, p);
    686 }
    687 
    688 void pcm_params_set_min(struct pcm_params *pcm_params,
    689                                 enum pcm_param param, unsigned int val)
    690 {
    691     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    692     int p;
    693 
    694     if (!params)
    695         return;
    696 
    697     p = pcm_param_to_alsa(param);
    698     if (p < 0)
    699         return;
    700 
    701     param_set_min(params, p, val);
    702 }
    703 
    704 unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
    705                                 enum pcm_param param)
    706 {
    707     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    708     int p;
    709 
    710     if (!params)
    711         return 0;
    712 
    713     p = pcm_param_to_alsa(param);
    714     if (p < 0)
    715         return 0;
    716 
    717     return param_get_max(params, p);
    718 }
    719 
    720 void pcm_params_set_max(struct pcm_params *pcm_params,
    721                                 enum pcm_param param, unsigned int val)
    722 {
    723     struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
    724     int p;
    725 
    726     if (!params)
    727         return;
    728 
    729     p = pcm_param_to_alsa(param);
    730     if (p < 0)
    731         return;
    732 
    733     param_set_max(params, p, val);
    734 }
    735 
    736 static int pcm_mask_test(struct pcm_mask *m, unsigned int index)
    737 {
    738     const unsigned int bitshift = 5; /* for 32 bit integer */
    739     const unsigned int bitmask = (1 << bitshift) - 1;
    740     unsigned int element;
    741 
    742     element = index >> bitshift;
    743     if (element >= ARRAY_SIZE(m->bits))
    744         return 0; /* for safety, but should never occur */
    745     return (m->bits[element] >> (index & bitmask)) & 1;
    746 }
    747 
    748 static int pcm_mask_to_string(struct pcm_mask *m, char *string, unsigned int size,
    749                               char *mask_name,
    750                               const char * const *bit_array_name, size_t bit_array_size)
    751 {
    752     unsigned int i;
    753     unsigned int offset = 0;
    754 
    755     if (m == NULL)
    756         return 0;
    757     if (bit_array_size < 32) {
    758         STRLOG(string, offset, size, "%12s:\t%#08x\n", mask_name, m->bits[0]);
    759     } else { /* spans two or more bitfields, print with an array index */
    760         for (i = 0; i < (bit_array_size + 31) >> 5; ++i) {
    761             STRLOG(string, offset, size, "%9s[%d]:\t%#08x\n",
    762                    mask_name, i, m->bits[i]);
    763         }
    764     }
    765     for (i = 0; i < bit_array_size; ++i) {
    766         if (pcm_mask_test(m, i)) {
    767             STRLOG(string, offset, size, "%12s \t%s\n", "", bit_array_name[i]);
    768         }
    769     }
    770     return offset;
    771 }
    772 
    773 int pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size)
    774 {
    775     struct pcm_mask *m;
    776     unsigned int min, max;
    777     unsigned int clipoffset, offset;
    778 
    779     m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
    780     offset = pcm_mask_to_string(m, string, size,
    781                                  "Access", access_lookup, ARRAY_SIZE(access_lookup));
    782     m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
    783     clipoffset = offset > size ? size : offset;
    784     offset += pcm_mask_to_string(m, string + clipoffset, size - clipoffset,
    785                                  "Format", format_lookup, ARRAY_SIZE(format_lookup));
    786     m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
    787     clipoffset = offset > size ? size : offset;
    788     offset += pcm_mask_to_string(m, string + clipoffset, size - clipoffset,
    789                                  "Subformat", subformat_lookup, ARRAY_SIZE(subformat_lookup));
    790     min = pcm_params_get_min(params, PCM_PARAM_RATE);
    791     max = pcm_params_get_max(params, PCM_PARAM_RATE);
    792     STRLOG(string, offset, size, "        Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
    793     min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
    794     max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
    795     STRLOG(string, offset, size, "    Channels:\tmin=%u\t\tmax=%u\n", min, max);
    796     min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
    797     max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
    798     STRLOG(string, offset, size, " Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
    799     min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
    800     max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
    801     STRLOG(string, offset, size, " Period size:\tmin=%u\t\tmax=%u\n", min, max);
    802     min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
    803     max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
    804     STRLOG(string, offset, size, "Period count:\tmin=%u\t\tmax=%u\n", min, max);
    805     return offset;
    806 }
    807 
    808 int pcm_params_format_test(struct pcm_params *params, enum pcm_format format)
    809 {
    810     unsigned int alsa_format = pcm_format_to_alsa(format);
    811 
    812     if (alsa_format == SNDRV_PCM_FORMAT_S16_LE && format != PCM_FORMAT_S16_LE)
    813         return 0; /* caution: format not recognized is equivalent to S16_LE */
    814     return pcm_mask_test(pcm_params_get_mask(params, PCM_PARAM_FORMAT), alsa_format);
    815 }
    816 
    817 int pcm_close(struct pcm *pcm)
    818 {
    819     if (pcm == &bad_pcm)
    820         return 0;
    821 
    822     pcm_hw_munmap_status(pcm);
    823 
    824     if (pcm->flags & PCM_MMAP) {
    825         pcm_stop(pcm);
    826         munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
    827     }
    828 
    829     if (pcm->fd >= 0)
    830         close(pcm->fd);
    831     pcm->prepared = 0;
    832     pcm->running = 0;
    833     pcm->buffer_size = 0;
    834     pcm->fd = -1;
    835     free(pcm);
    836     return 0;
    837 }
    838 
    839 struct pcm *pcm_open(unsigned int card, unsigned int device,
    840                      unsigned int flags, struct pcm_config *config)
    841 {
    842     struct pcm *pcm;
    843     struct snd_pcm_info info;
    844     struct snd_pcm_hw_params params;
    845     struct snd_pcm_sw_params sparams;
    846     char fn[256];
    847     int rc;
    848 
    849     pcm = calloc(1, sizeof(struct pcm));
    850     if (!pcm || !config)
    851         return &bad_pcm; /* TODO: could support default config here */
    852 
    853     pcm->config = *config;
    854 
    855     snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
    856              flags & PCM_IN ? 'c' : 'p');
    857 
    858     pcm->flags = flags;
    859     pcm->fd = open(fn, O_RDWR);
    860     if (pcm->fd < 0) {
    861         oops(pcm, errno, "cannot open device '%s'", fn);
    862         return pcm;
    863     }
    864 
    865     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
    866         oops(pcm, errno, "cannot get info");
    867         goto fail_close;
    868     }
    869 
    870     param_init(&params);
    871     param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
    872                    pcm_format_to_alsa(config->format));
    873     param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
    874                    SNDRV_PCM_SUBFORMAT_STD);
    875     param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size);
    876     param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
    877                   pcm_format_to_bits(config->format));
    878     param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
    879                   pcm_format_to_bits(config->format) * config->channels);
    880     param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
    881                   config->channels);
    882     param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count);
    883     param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, config->rate);
    884 
    885     if (flags & PCM_NOIRQ) {
    886         if (!(flags & PCM_MMAP)) {
    887             oops(pcm, -EINVAL, "noirq only currently supported with mmap().");
    888             goto fail;
    889         }
    890 
    891         params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP;
    892         pcm->noirq_frames_per_msec = config->rate / 1000;
    893     }
    894 
    895     if (flags & PCM_MMAP)
    896         param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
    897                        SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
    898     else
    899         param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
    900                        SNDRV_PCM_ACCESS_RW_INTERLEAVED);
    901 
    902     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
    903         oops(pcm, errno, "cannot set hw params");
    904         goto fail_close;
    905     }
    906 
    907     /* get our refined hw_params */
    908     config->period_size = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
    909     config->period_count = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIODS);
    910     pcm->buffer_size = config->period_count * config->period_size;
    911 
    912     if (flags & PCM_MMAP) {
    913         pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size),
    914                                 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0);
    915         if (pcm->mmap_buffer == MAP_FAILED) {
    916             oops(pcm, -errno, "failed to mmap buffer %d bytes\n",
    917                  pcm_frames_to_bytes(pcm, pcm->buffer_size));
    918             goto fail_close;
    919         }
    920     }
    921 
    922     memset(&sparams, 0, sizeof(sparams));
    923     sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
    924     sparams.period_step = 1;
    925 
    926     if (!config->start_threshold) {
    927         if (pcm->flags & PCM_IN)
    928             pcm->config.start_threshold = sparams.start_threshold = 1;
    929         else
    930             pcm->config.start_threshold = sparams.start_threshold =
    931                 config->period_count * config->period_size / 2;
    932     } else
    933         sparams.start_threshold = config->start_threshold;
    934 
    935     /* pick a high stop threshold - todo: does this need further tuning */
    936     if (!config->stop_threshold) {
    937         if (pcm->flags & PCM_IN)
    938             pcm->config.stop_threshold = sparams.stop_threshold =
    939                 config->period_count * config->period_size * 10;
    940         else
    941             pcm->config.stop_threshold = sparams.stop_threshold =
    942                 config->period_count * config->period_size;
    943     }
    944     else
    945         sparams.stop_threshold = config->stop_threshold;
    946 
    947     if (!pcm->config.avail_min) {
    948         if (pcm->flags & PCM_MMAP)
    949             pcm->config.avail_min = sparams.avail_min = pcm->config.period_size;
    950         else
    951             pcm->config.avail_min = sparams.avail_min = 1;
    952     } else
    953         sparams.avail_min = config->avail_min;
    954 
    955     sparams.xfer_align = config->period_size / 2; /* needed for old kernels */
    956     sparams.silence_size = 0;
    957     sparams.silence_threshold = config->silence_threshold;
    958     pcm->boundary = sparams.boundary = pcm->buffer_size;
    959 
    960     while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size)
    961         pcm->boundary *= 2;
    962 
    963     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
    964         oops(pcm, errno, "cannot set sw params");
    965         goto fail;
    966     }
    967 
    968     rc = pcm_hw_mmap_status(pcm);
    969     if (rc < 0) {
    970         oops(pcm, rc, "mmap status failed");
    971         goto fail;
    972     }
    973 
    974 #ifdef SNDRV_PCM_IOCTL_TTSTAMP
    975     if (pcm->flags & PCM_MONOTONIC) {
    976         int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
    977         rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg);
    978         if (rc < 0) {
    979             oops(pcm, rc, "cannot set timestamp type");
    980             goto fail;
    981         }
    982     }
    983 #endif
    984 
    985     pcm->underruns = 0;
    986     return pcm;
    987 
    988 fail:
    989     if (flags & PCM_MMAP)
    990         munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
    991 fail_close:
    992     close(pcm->fd);
    993     pcm->fd = -1;
    994     return pcm;
    995 }
    996 
    997 int pcm_is_ready(struct pcm *pcm)
    998 {
    999     return pcm->fd >= 0;
   1000 }
   1001 
   1002 int pcm_prepare(struct pcm *pcm)
   1003 {
   1004     if (pcm->prepared)
   1005         return 0;
   1006 
   1007     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0)
   1008         return oops(pcm, errno, "cannot prepare channel");
   1009 
   1010     pcm->prepared = 1;
   1011     return 0;
   1012 }
   1013 
   1014 int pcm_start(struct pcm *pcm)
   1015 {
   1016     int prepare_error = pcm_prepare(pcm);
   1017     if (prepare_error)
   1018         return prepare_error;
   1019 
   1020     if (pcm->flags & PCM_MMAP)
   1021 	    pcm_sync_ptr(pcm, 0);
   1022 
   1023     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0)
   1024         return oops(pcm, errno, "cannot start channel");
   1025 
   1026     pcm->running = 1;
   1027     return 0;
   1028 }
   1029 
   1030 int pcm_stop(struct pcm *pcm)
   1031 {
   1032     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0)
   1033         return oops(pcm, errno, "cannot stop channel");
   1034 
   1035     pcm->prepared = 0;
   1036     pcm->running = 0;
   1037     return 0;
   1038 }
   1039 
   1040 static inline int pcm_mmap_playback_avail(struct pcm *pcm)
   1041 {
   1042     int avail;
   1043 
   1044     avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
   1045 
   1046     if (avail < 0)
   1047         avail += pcm->boundary;
   1048     else if (avail > (int)pcm->boundary)
   1049         avail -= pcm->boundary;
   1050 
   1051     return avail;
   1052 }
   1053 
   1054 static inline int pcm_mmap_capture_avail(struct pcm *pcm)
   1055 {
   1056     int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
   1057     if (avail < 0)
   1058         avail += pcm->boundary;
   1059     return avail;
   1060 }
   1061 
   1062 static inline int pcm_mmap_avail(struct pcm *pcm)
   1063 {
   1064     pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC);
   1065     if (pcm->flags & PCM_IN)
   1066         return pcm_mmap_capture_avail(pcm);
   1067     else
   1068         return pcm_mmap_playback_avail(pcm);
   1069 }
   1070 
   1071 static void pcm_mmap_appl_forward(struct pcm *pcm, int frames)
   1072 {
   1073     unsigned int appl_ptr = pcm->mmap_control->appl_ptr;
   1074     appl_ptr += frames;
   1075 
   1076     /* check for boundary wrap */
   1077     if (appl_ptr > pcm->boundary)
   1078          appl_ptr -= pcm->boundary;
   1079     pcm->mmap_control->appl_ptr = appl_ptr;
   1080 }
   1081 
   1082 int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
   1083                    unsigned int *frames)
   1084 {
   1085     unsigned int continuous, copy_frames, avail;
   1086 
   1087     /* return the mmap buffer */
   1088     *areas = pcm->mmap_buffer;
   1089 
   1090     /* and the application offset in frames */
   1091     *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size;
   1092 
   1093     avail = pcm_mmap_avail(pcm);
   1094     if (avail > pcm->buffer_size)
   1095         avail = pcm->buffer_size;
   1096     continuous = pcm->buffer_size - *offset;
   1097 
   1098     /* we can only copy frames if the are availabale and continuos */
   1099     copy_frames = *frames;
   1100     if (copy_frames > avail)
   1101         copy_frames = avail;
   1102     if (copy_frames > continuous)
   1103         copy_frames = continuous;
   1104     *frames = copy_frames;
   1105 
   1106     return 0;
   1107 }
   1108 
   1109 int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames)
   1110 {
   1111     /* update the application pointer in userspace and kernel */
   1112     pcm_mmap_appl_forward(pcm, frames);
   1113     pcm_sync_ptr(pcm, 0);
   1114 
   1115     return frames;
   1116 }
   1117 
   1118 int pcm_avail_update(struct pcm *pcm)
   1119 {
   1120     pcm_sync_ptr(pcm, 0);
   1121     return pcm_mmap_avail(pcm);
   1122 }
   1123 
   1124 int pcm_state(struct pcm *pcm)
   1125 {
   1126     int err = pcm_sync_ptr(pcm, 0);
   1127     if (err < 0)
   1128         return err;
   1129 
   1130     return pcm->mmap_status->state;
   1131 }
   1132 
   1133 int pcm_set_avail_min(struct pcm *pcm, int avail_min)
   1134 {
   1135     if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ))
   1136         return -ENOSYS;
   1137 
   1138     pcm->config.avail_min = avail_min;
   1139     return 0;
   1140 }
   1141 
   1142 int pcm_wait(struct pcm *pcm, int timeout)
   1143 {
   1144     struct pollfd pfd;
   1145     int err;
   1146 
   1147     pfd.fd = pcm->fd;
   1148     pfd.events = POLLOUT | POLLERR | POLLNVAL;
   1149 
   1150     do {
   1151         /* let's wait for avail or timeout */
   1152         err = poll(&pfd, 1, timeout);
   1153         if (err < 0)
   1154             return -errno;
   1155 
   1156         /* timeout ? */
   1157         if (err == 0)
   1158             return 0;
   1159 
   1160         /* have we been interrupted ? */
   1161         if (errno == -EINTR)
   1162             continue;
   1163 
   1164         /* check for any errors */
   1165         if (pfd.revents & (POLLERR | POLLNVAL)) {
   1166             switch (pcm_state(pcm)) {
   1167             case PCM_STATE_XRUN:
   1168                 return -EPIPE;
   1169             case PCM_STATE_SUSPENDED:
   1170                 return -ESTRPIPE;
   1171             case PCM_STATE_DISCONNECTED:
   1172                 return -ENODEV;
   1173             default:
   1174                 return -EIO;
   1175             }
   1176         }
   1177     /* poll again if fd not ready for IO */
   1178     } while (!(pfd.revents & (POLLIN | POLLOUT)));
   1179 
   1180     return 1;
   1181 }
   1182 
   1183 int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes)
   1184 {
   1185     int err = 0, frames, avail;
   1186     unsigned int offset = 0, count;
   1187 
   1188     if (bytes == 0)
   1189         return 0;
   1190 
   1191     count = pcm_bytes_to_frames(pcm, bytes);
   1192 
   1193     while (count > 0) {
   1194 
   1195         /* get the available space for writing new frames */
   1196         avail = pcm_avail_update(pcm);
   1197         if (avail < 0) {
   1198             fprintf(stderr, "cannot determine available mmap frames");
   1199             return err;
   1200         }
   1201 
   1202         /* start the audio if we reach the threshold */
   1203 	    if (!pcm->running &&
   1204             (pcm->buffer_size - avail) >= pcm->config.start_threshold) {
   1205             if (pcm_start(pcm) < 0) {
   1206                fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n",
   1207                     (unsigned int)pcm->mmap_status->hw_ptr,
   1208                     (unsigned int)pcm->mmap_control->appl_ptr,
   1209                     avail);
   1210                 return -errno;
   1211             }
   1212             pcm->wait_for_avail_min = 0;
   1213         }
   1214 
   1215         /* sleep until we have space to write new frames */
   1216         if (pcm->running) {
   1217             /* enable waiting for avail_min threshold when less frames than we have to write
   1218              * are available. */
   1219             if (!pcm->wait_for_avail_min && (count > (unsigned int)avail))
   1220                 pcm->wait_for_avail_min = 1;
   1221 
   1222             if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) {
   1223                 int time = -1;
   1224 
   1225                 /* disable waiting for avail_min threshold to allow small amounts of data to be
   1226                  * written without waiting as long as there is enough room in buffer. */
   1227                 pcm->wait_for_avail_min = 0;
   1228 
   1229                 if (pcm->flags & PCM_NOIRQ)
   1230                     time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec;
   1231 
   1232                 err = pcm_wait(pcm, time);
   1233                 if (err < 0) {
   1234                     pcm->prepared = 0;
   1235                     pcm->running = 0;
   1236                     oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
   1237                         (unsigned int)pcm->mmap_status->hw_ptr,
   1238                         (unsigned int)pcm->mmap_control->appl_ptr,
   1239                         avail);
   1240                     pcm->mmap_control->appl_ptr = 0;
   1241                     return err;
   1242                 }
   1243                 continue;
   1244             }
   1245         }
   1246 
   1247         frames = count;
   1248         if (frames > avail)
   1249             frames = avail;
   1250 
   1251         if (!frames)
   1252             break;
   1253 
   1254         /* copy frames from buffer */
   1255         frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames);
   1256         if (frames < 0) {
   1257             fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n",
   1258                     (unsigned int)pcm->mmap_status->hw_ptr,
   1259                     (unsigned int)pcm->mmap_control->appl_ptr,
   1260                     avail);
   1261             return frames;
   1262         }
   1263 
   1264         offset += frames;
   1265         count -= frames;
   1266     }
   1267 
   1268     return 0;
   1269 }
   1270 
   1271 int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count)
   1272 {
   1273     if ((~pcm->flags) & (PCM_OUT | PCM_MMAP))
   1274         return -ENOSYS;
   1275 
   1276     return pcm_mmap_transfer(pcm, (void *)data, count);
   1277 }
   1278 
   1279 int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count)
   1280 {
   1281     if ((~pcm->flags) & (PCM_IN | PCM_MMAP))
   1282         return -ENOSYS;
   1283 
   1284     return pcm_mmap_transfer(pcm, data, count);
   1285 }
   1286 
   1287 int pcm_ioctl(struct pcm *pcm, int request, ...)
   1288 {
   1289     va_list ap;
   1290     void * arg;
   1291 
   1292     if (!pcm_is_ready(pcm))
   1293         return -1;
   1294 
   1295     va_start(ap, request);
   1296     arg = va_arg(ap, void *);
   1297     va_end(ap);
   1298 
   1299     return ioctl(pcm->fd, request, arg);
   1300 }
   1301