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