Home | History | Annotate | Download | only in libalsa-intf
      1 /*
      2 ** Copyright 2010, The Android Open-Source Project
      3 ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "alsa_pcm"
     19 #define LOG_NDEBUG 1
     20 #ifdef ANDROID
     21 /* definitions for Android logging */
     22 #include <utils/Log.h>
     23 #include <cutils/properties.h>
     24 #else /* ANDROID */
     25 #define strlcat g_strlcat
     26 #define strlcpy g_strlcpy
     27 #define ALOGI(...)      fprintf(stdout, __VA_ARGS__)
     28 #define ALOGE(...)      fprintf(stderr, __VA_ARGS__)
     29 #define ALOGV(...)      fprintf(stderr, __VA_ARGS__)
     30 #endif /* ANDROID */
     31 
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <fcntl.h>
     35 #include <stdarg.h>
     36 #include <string.h>
     37 #include <errno.h>
     38 #include <unistd.h>
     39 #include <stdint.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/mman.h>
     42 #include <sys/time.h>
     43 #include <sys/poll.h>
     44 #include <linux/ioctl.h>
     45 #include <linux/types.h>
     46 
     47 #include "alsa_audio.h"
     48 
     49 #define __force
     50 #define __bitwise
     51 #define __user
     52 
     53 #define DEBUG 1
     54 
     55 enum format_alias {
     56       S8 = 0,
     57       U8,
     58       S16_LE,
     59       S16_BE,
     60       U16_LE,
     61       U16_BE,
     62       S24_LE,
     63       S24_BE,
     64       U24_LE,
     65       U24_BE,
     66       S32_LE,
     67       S32_BE,
     68       U32_LE,
     69       U32_BE,
     70       FLOAT_LE,
     71       FLOAT_BE,
     72       FLOAT64_LE,
     73       FLOAT64_BE,
     74       IEC958_SUBFRAME_LE,
     75       IEC958_SUBFRAME_BE,
     76       MU_LAW,
     77       A_LAW,
     78       IMA_ADPCM,
     79       MPEG,
     80       GSM,
     81       SPECIAL = 31,
     82       S24_3LE,
     83       S24_3BE,
     84       U24_3LE,
     85       U24_3BE,
     86       S20_3LE,
     87       S20_3BE,
     88       U20_3LE,
     89       U20_3BE,
     90       S18_3LE,
     91       S18_3BE,
     92       U18_3LE,
     93       U18_3BE,
     94       FORMAT_LAST,
     95 };
     96 const char *formats_list[][2] = {
     97         {"S8", "Signed 8 bit"},
     98         {"U8", "Unsigned 8 bit"},
     99         {"S16_LE", "Signed 16 bit Little Endian"},
    100         {"S16_BE", "Signed 16 bit Big Endian"},
    101         {"U16_LE", "Unsigned 16 bit Little Endian"},
    102         {"U16_BE", "Unsigned 16 bit Big Endian"},
    103         {"S24_LE", "Signed 24 bit Little Endian"},
    104         {"S24_BE", "Signed 24 bit Big Endian"},
    105         {"U24_LE", "Unsigned 24 bit Little Endian"},
    106         {"U24_BE", "Unsigned 24 bit Big Endian"},
    107         {"S32_LE", "Signed 32 bit Little Endian"},
    108         {"S32_BE", "Signed 32 bit Big Endian"},
    109         {"U32_LE", "Unsigned 32 bit Little Endian"},
    110         {"U32_BE", "Unsigned 32 bit Big Endian"},
    111         {"FLOAT_LE", "Float 32 bit Little Endian"},
    112         {"FLOAT_BE", "Float 32 bit Big Endian"},
    113         {"FLOAT64_LE", "Float 64 bit Little Endian"},
    114         {"FLOAT64_BE", "Float 64 bit Big Endian"},
    115         {"IEC958_SUBFRAME_LE", "IEC-958 Little Endian"},
    116         {"IEC958_SUBFRAME_BE", "IEC-958 Big Endian"},
    117         {"MU_LAW", "Mu-Law"},
    118         {"A_LAW", "A-Law"},
    119         {"IMA_ADPCM", "Ima-ADPCM"},
    120         {"MPEG", "MPEG"},
    121         {"GSM", "GSM"},
    122         [31] = {"SPECIAL", "Special"},
    123         {"S24_3LE", "Signed 24 bit Little Endian in 3bytes"},
    124         {"S24_3BE", "Signed 24 bit Big Endian in 3bytes"},
    125         {"U24_3LE", "Unsigned 24 bit Little Endian in 3bytes"},
    126         {"U24_3BE", "Unsigned 24 bit Big Endian in 3bytes"},
    127         {"S20_3LE", "Signed 20 bit Little Endian in 3bytes"},
    128         {"S20_3BE", "Signed 20 bit Big Endian in 3bytes"},
    129         {"U20_3LE", "Unsigned 20 bit Little Endian in 3bytes"},
    130         {"U20_3BE", "Unsigned 20 bit Big Endian in 3bytes"},
    131         {"S18_3LE", "Signed 18 bit Little Endian in 3bytes"},
    132         {"S18_3BE", "Signed 18 bit Big Endian in 3bytes"},
    133         {"U18_3LE", "Unsigned 18 bit Little Endian in 3bytes"},
    134         {"U18_3BE", "Unsigned 18 bit Big Endian in 3bytes"},
    135 };
    136 
    137 int get_compressed_format(const char *format)
    138 {
    139         const char *ch = format;
    140         if (strcmp(ch, "MP3") == 0) {
    141                 printf("MP3 is selected\n");
    142                 return FORMAT_MP3;
    143         } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) {
    144                 printf("AC3 PASS THROUGH is selected\n");
    145                 return FORMAT_AC3_PASS_THROUGH;
    146         } else {
    147                 printf("invalid format\n");
    148                 return -1;
    149         }
    150         return 0;
    151 }
    152 
    153 int get_format(const char* name)
    154 {
    155         int format;
    156         for (format = 0; format < FORMAT_LAST; format++) {
    157                 if (formats_list[format][0] &&
    158                     strcasecmp(name, formats_list[format][0]) == 0) {
    159                         ALOGV("format_names %s", name);
    160                         return  format;
    161                 }
    162         }
    163         return -EINVAL;
    164 }
    165 
    166 const char *get_format_name(int format)
    167 {
    168         if ((format < FORMAT_LAST) &&
    169              formats_list[format][0])
    170             return formats_list[format][0];
    171         return NULL;
    172 }
    173 
    174 const char *get_format_desc(int format)
    175 {
    176         if ((format < FORMAT_LAST) &&
    177              formats_list[format][1])
    178             return formats_list[format][1];
    179         return NULL;
    180 }
    181 
    182 /* alsa parameter manipulation cruft */
    183 
    184 #define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
    185 static int oops(struct pcm *pcm, int e, const char *fmt, ...);
    186 
    187 static inline int param_is_mask(int p)
    188 {
    189     return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
    190         (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
    191 }
    192 
    193 static inline int param_is_interval(int p)
    194 {
    195     return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
    196         (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
    197 }
    198 
    199 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
    200 {
    201     return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
    202 }
    203 
    204 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
    205 {
    206     return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
    207 }
    208 
    209 void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
    210 {
    211     if (bit >= SNDRV_MASK_MAX)
    212         return;
    213     if (param_is_mask(n)) {
    214         struct snd_mask *m = param_to_mask(p, n);
    215         m->bits[0] = 0;
    216         m->bits[1] = 0;
    217         m->bits[bit >> 5] |= (1 << (bit & 31));
    218     }
    219 }
    220 
    221 void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
    222 {
    223     if (param_is_interval(n)) {
    224         struct snd_interval *i = param_to_interval(p, n);
    225         i->min = val;
    226     }
    227 }
    228 
    229 void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
    230 {
    231     if (param_is_interval(n)) {
    232         struct snd_interval *i = param_to_interval(p, n);
    233         i->max = val;
    234     }
    235 }
    236 
    237 void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
    238 {
    239     if (param_is_interval(n)) {
    240         struct snd_interval *i = param_to_interval(p, n);
    241         i->min = val;
    242         i->max = val;
    243         i->integer = 1;
    244     }
    245 }
    246 
    247 void param_init(struct snd_pcm_hw_params *p)
    248 {
    249     int n;
    250     memset(p, 0, sizeof(*p));
    251     for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
    252          n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
    253             struct snd_mask *m = param_to_mask(p, n);
    254             m->bits[0] = ~0;
    255             m->bits[1] = ~0;
    256     }
    257     for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
    258          n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
    259             struct snd_interval *i = param_to_interval(p, n);
    260             i->min = 0;
    261             i->max = ~0;
    262     }
    263 }
    264 
    265 /* debugging gunk */
    266 
    267 #if DEBUG
    268 static const char *param_name[PARAM_MAX+1] = {
    269     [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
    270     [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
    271     [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
    272 
    273     [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
    274     [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
    275     [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
    276     [SNDRV_PCM_HW_PARAM_RATE] = "rate",
    277     [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
    278     [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
    279     [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
    280     [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
    281     [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
    282     [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
    283     [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
    284     [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
    285 };
    286 
    287 void param_dump(struct snd_pcm_hw_params *p)
    288 {
    289     int n;
    290 
    291     for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
    292          n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
    293             struct snd_mask *m = param_to_mask(p, n);
    294             ALOGV("%s = %08x%08x\n", param_name[n],
    295                    m->bits[1], m->bits[0]);
    296     }
    297     for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
    298          n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
    299             struct snd_interval *i = param_to_interval(p, n);
    300             ALOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
    301                    param_name[n], i->min, i->max, i->openmin,
    302                    i->openmax, i->integer, i->empty);
    303     }
    304     ALOGV("info = %08x\n", p->info);
    305     ALOGV("msbits = %d\n", p->msbits);
    306     ALOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
    307     ALOGV("fifo = %d\n", (int) p->fifo_size);
    308 }
    309 
    310 static void info_dump(struct snd_pcm_info *info)
    311 {
    312     ALOGV("device = %d\n", info->device);
    313     ALOGV("subdevice = %d\n", info->subdevice);
    314     ALOGV("stream = %d\n", info->stream);
    315     ALOGV("card = %d\n", info->card);
    316     ALOGV("id = '%s'\n", info->id);
    317     ALOGV("name = '%s'\n", info->name);
    318     ALOGV("subname = '%s'\n", info->subname);
    319     ALOGV("dev_class = %d\n", info->dev_class);
    320     ALOGV("dev_subclass = %d\n", info->dev_subclass);
    321     ALOGV("subdevices_count = %d\n", info->subdevices_count);
    322     ALOGV("subdevices_avail = %d\n", info->subdevices_avail);
    323 }
    324 #else
    325 void param_dump(struct snd_pcm_hw_params *p) {}
    326 static void info_dump(struct snd_pcm_info *info) {}
    327 #endif
    328 
    329 int param_set_hw_refine(struct pcm *pcm, struct snd_pcm_hw_params *params)
    330 {
    331     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) {
    332         ALOGE("SNDRV_PCM_IOCTL_HW_REFINE failed");
    333         return -EPERM;
    334     }
    335     return 0;
    336 }
    337 
    338 int param_set_hw_params(struct pcm *pcm, struct snd_pcm_hw_params *params)
    339 {
    340     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params)) {
    341         return -EPERM;
    342     }
    343     pcm->hw_p = params;
    344     return 0;
    345 }
    346 
    347 int param_set_sw_params(struct pcm *pcm, struct snd_pcm_sw_params *sparams)
    348 {
    349     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, sparams)) {
    350         return -EPERM;
    351     }
    352     pcm->sw_p = sparams;
    353     return 0;
    354 }
    355 
    356 int pcm_buffer_size(struct snd_pcm_hw_params *params)
    357 {
    358     struct snd_interval *i = param_to_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
    359             ALOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
    360                    param_name[SNDRV_PCM_HW_PARAM_BUFFER_BYTES],
    361                    i->min, i->max, i->openmin,
    362                    i->openmax, i->integer, i->empty);
    363     return i->min;
    364 }
    365 
    366 int pcm_period_size(struct snd_pcm_hw_params *params)
    367 {
    368     struct snd_interval *i = param_to_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
    369             ALOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
    370                    param_name[SNDRV_PCM_HW_PARAM_PERIOD_BYTES],
    371                    i->min, i->max, i->openmin,
    372                    i->openmax, i->integer, i->empty);
    373     return i->min;
    374 }
    375 
    376 const char* pcm_error(struct pcm *pcm)
    377 {
    378     return pcm->error;
    379 }
    380 
    381 static int oops(struct pcm *pcm, int e, const char *fmt, ...)
    382 {
    383     va_list ap;
    384     int sz;
    385 
    386     va_start(ap, fmt);
    387     vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
    388     va_end(ap);
    389     sz = strnlen(pcm->error, PCM_ERROR_MAX);
    390 
    391     if (errno)
    392         snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
    393                  ": %s", strerror(e));
    394     return -1;
    395 }
    396 
    397 long pcm_avail(struct pcm *pcm)
    398 {
    399      struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
    400      if (pcm->flags & DEBUG_ON) {
    401         ALOGV("hw_ptr = %d buf_size = %d appl_ptr = %d\n",
    402                 sync_ptr->s.status.hw_ptr,
    403                 pcm->buffer_size,
    404                 sync_ptr->c.control.appl_ptr);
    405      }
    406      if (pcm->flags & PCM_IN) {
    407           long avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr;
    408         if (avail < 0)
    409                 avail += pcm->sw_p->boundary;
    410         return avail;
    411      } else {
    412          long avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + ((pcm->flags & PCM_MONO) ? pcm->buffer_size/2 : pcm->buffer_size/4);
    413          if (avail < 0)
    414               avail += pcm->sw_p->boundary;
    415          else if ((unsigned long) avail >= pcm->sw_p->boundary)
    416               avail -= pcm->sw_p->boundary;
    417          return avail;
    418      }
    419 }
    420 
    421 int sync_ptr(struct pcm *pcm)
    422 {
    423     int err;
    424     err = ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr);
    425     if (err < 0) {
    426         err = errno;
    427         ALOGE("SNDRV_PCM_IOCTL_SYNC_PTR failed %d \n", err);
    428         return err;
    429     }
    430 
    431     return 0;
    432 }
    433 
    434 int mmap_buffer(struct pcm *pcm)
    435 {
    436     int err, i;
    437     char *ptr;
    438     unsigned size;
    439     struct snd_pcm_channel_info ch;
    440     int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
    441 
    442     size = pcm->buffer_size;
    443     if (pcm->flags & DEBUG_ON)
    444         ALOGV("size = %d\n", size);
    445     pcm->addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
    446                            pcm->fd, 0);
    447     if (pcm->addr)
    448          return 0;
    449     else
    450          return -errno;
    451 }
    452 
    453 /*
    454  * Destination offset would be mod of total data written
    455  * (application pointer) and the buffer size of the driver.
    456  * Hence destination address would be base address(pcm->addr) +
    457  * destination offset.
    458  */
    459 u_int8_t *dst_address(struct pcm *pcm)
    460 {
    461     unsigned long pcm_offset = 0;
    462     struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
    463     unsigned int appl_ptr = 0;
    464 
    465     appl_ptr = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
    466     pcm_offset = (appl_ptr % (unsigned long)pcm->buffer_size);
    467     return pcm->addr + pcm_offset;
    468 
    469 }
    470 
    471 int mmap_transfer(struct pcm *pcm, void *data, unsigned offset,
    472                   long frames)
    473 {
    474     struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
    475     unsigned size;
    476     u_int8_t *dst_addr, *mmaped_addr;
    477     u_int8_t *src_addr = data;
    478     int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
    479 
    480     dst_addr = dst_address(pcm);
    481 
    482     frames = frames * channels *2 ;
    483 
    484     while (frames-- > 0) {
    485         *(u_int8_t*)dst_addr = *(const u_int8_t*)src_addr;
    486          src_addr++;
    487          dst_addr++;
    488     }
    489     return 0;
    490 }
    491 
    492 int mmap_transfer_capture(struct pcm *pcm, void *data, unsigned offset,
    493                           long frames)
    494 {
    495     struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
    496     unsigned long pcm_offset = 0;
    497     unsigned size;
    498     u_int8_t *dst_addr, *mmaped_addr;
    499     u_int8_t *src_addr;
    500     int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
    501     unsigned int tmp = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
    502 
    503     pcm_offset = (tmp % (unsigned long)pcm->buffer_size);
    504     dst_addr = data;
    505     src_addr = pcm->addr + pcm_offset;
    506     frames = frames * channels *2 ;
    507 
    508     while (frames-- > 0) {
    509         *(u_int8_t*)dst_addr = *(const u_int8_t*)src_addr;
    510          src_addr++;
    511          dst_addr++;
    512     }
    513     return 0;
    514 }
    515 
    516 int pcm_prepare(struct pcm *pcm)
    517 {
    518     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) {
    519            ALOGE("cannot prepare channel: errno =%d\n", -errno);
    520            return -errno;
    521     }
    522     pcm->running = 1;
    523     return 0;
    524 }
    525 
    526 static int pcm_write_mmap(struct pcm *pcm, void *data, unsigned count)
    527 {
    528     long frames;
    529     int err;
    530     int bytes_written;
    531 
    532     frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
    533 
    534     pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
    535     err = sync_ptr(pcm);
    536     if (err == EPIPE) {
    537         ALOGE("Failed in sync_ptr\n");
    538         /* we failed to make our window -- try to restart */
    539         pcm->underruns++;
    540         pcm->running = 0;
    541         pcm_prepare(pcm);
    542     }
    543     pcm->sync_ptr->c.control.appl_ptr += frames;
    544     pcm->sync_ptr->flags = 0;
    545 
    546     err = sync_ptr(pcm);
    547     if (err == EPIPE) {
    548         ALOGE("Failed in sync_ptr 2 \n");
    549         /* we failed to make our window -- try to restart */
    550         pcm->underruns++;
    551         pcm->running = 0;
    552         pcm_prepare(pcm);
    553     }
    554     bytes_written = pcm->sync_ptr->c.control.appl_ptr - pcm->sync_ptr->s.status.hw_ptr;
    555     if ((bytes_written >= pcm->sw_p->start_threshold) && (!pcm->start)) {
    556         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
    557             err = -errno;
    558             if (errno == EPIPE) {
    559                 ALOGE("Failed in SNDRV_PCM_IOCTL_START\n");
    560                 /* we failed to make our window -- try to restart */
    561                 pcm->underruns++;
    562                 pcm->running = 0;
    563                 pcm_prepare(pcm);
    564             } else {
    565                 ALOGE("Error no %d \n", errno);
    566                 return -errno;
    567             }
    568         } else {
    569              ALOGD(" start\n");
    570              pcm->start = 1;
    571         }
    572     }
    573     return 0;
    574 }
    575 
    576 static int pcm_write_nmmap(struct pcm *pcm, void *data, unsigned count)
    577 {
    578     struct snd_xferi x;
    579     int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
    580 
    581     if (pcm->flags & PCM_IN)
    582         return -EINVAL;
    583     x.buf = data;
    584     x.frames =  (count / (channels * 2)) ;
    585 
    586     for (;;) {
    587         if (!pcm->running) {
    588             if (pcm_prepare(pcm))
    589                 return -errno;
    590         }
    591         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
    592             if (errno == EPIPE) {
    593                     /* we failed to make our window -- try to restart */
    594                 ALOGE("Underrun Error\n");
    595                 pcm->underruns++;
    596                 pcm->running = 0;
    597                 continue;
    598             }
    599             return -errno;
    600         }
    601         if (pcm->flags & DEBUG_ON)
    602           ALOGV("Sent frame\n");
    603         return 0;
    604     }
    605 }
    606 
    607 int pcm_write(struct pcm *pcm, void *data, unsigned count)
    608 {
    609      if (pcm->flags & PCM_MMAP)
    610          return pcm_write_mmap(pcm, data, count);
    611      else
    612          return pcm_write_nmmap(pcm, data, count);
    613 }
    614 
    615 int pcm_read(struct pcm *pcm, void *data, unsigned count)
    616 {
    617     struct snd_xferi x;
    618 
    619     if (!(pcm->flags & PCM_IN))
    620         return -EINVAL;
    621 
    622     x.buf = data;
    623     if (pcm->flags & PCM_MONO) {
    624         x.frames = (count / 2);
    625     } else if (pcm->flags & PCM_QUAD) {
    626         x.frames = (count / 8);
    627     } else if (pcm->flags & PCM_5POINT1) {
    628         x.frames = (count / 12);
    629     } else {
    630         x.frames = (count / 4);
    631     }
    632 
    633     for (;;) {
    634         if (!pcm->running) {
    635             if (pcm_prepare(pcm))
    636                 return -errno;
    637             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
    638                 ALOGE("Arec:SNDRV_PCM_IOCTL_START failed\n");
    639                 return -errno;
    640             }
    641             pcm->running = 1;
    642         }
    643         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
    644             if (errno == EPIPE) {
    645                 /* we failed to make our window -- try to restart */
    646                 ALOGE("Arec:Overrun Error\n");
    647                 pcm->underruns++;
    648                 pcm->running = 0;
    649                 continue;
    650             }
    651             ALOGE("Arec: error%d\n", errno);
    652             return -errno;
    653         }
    654         return 0;
    655     }
    656 }
    657 
    658 static struct pcm bad_pcm = {
    659     .fd = -1,
    660 };
    661 
    662 static int enable_timer(struct pcm *pcm) {
    663 
    664     pcm->timer_fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK);
    665     if (pcm->timer_fd < 0) {
    666        close(pcm->fd);
    667        ALOGE("cannot open timer device 'timer'");
    668        return &bad_pcm;
    669     }
    670     int arg = 1;
    671     struct snd_timer_params timer_param;
    672     struct snd_timer_select sel;
    673     if (ioctl(pcm->timer_fd, SNDRV_TIMER_IOCTL_TREAD, &arg) < 0) {
    674            ALOGE("extended read is not supported (SNDRV_TIMER_IOCTL_TREAD)\n");
    675     }
    676     memset(&sel, 0, sizeof(sel));
    677     sel.id.dev_class = SNDRV_TIMER_CLASS_PCM;
    678     sel.id.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
    679     sel.id.card = pcm->card_no;
    680     sel.id.device = pcm->device_no;
    681     if (pcm->flags & PCM_IN)
    682         sel.id.subdevice = 1;
    683     else
    684         sel.id.subdevice = 0;
    685 
    686     if (pcm->flags & DEBUG_ON) {
    687         ALOGD("sel.id.dev_class= %d\n", sel.id.dev_class);
    688         ALOGD("sel.id.dev_sclass = %d\n", sel.id.dev_sclass);
    689         ALOGD("sel.id.card = %d\n", sel.id.card);
    690         ALOGD("sel.id.device = %d\n", sel.id.device);
    691         ALOGD("sel.id.subdevice = %d\n", sel.id.subdevice);
    692     }
    693     if (ioctl(pcm->timer_fd, SNDRV_TIMER_IOCTL_SELECT, &sel) < 0) {
    694           ALOGE("SNDRV_TIMER_IOCTL_SELECT failed.\n");
    695           close(pcm->timer_fd);
    696           close(pcm->fd);
    697           return &bad_pcm;
    698     }
    699     memset(&timer_param, 0, sizeof(struct snd_timer_params));
    700     timer_param.flags |= SNDRV_TIMER_PSFLG_AUTO;
    701     timer_param.ticks = 1;
    702     timer_param.filter = (1<<SNDRV_TIMER_EVENT_MSUSPEND) | (1<<SNDRV_TIMER_EVENT_MRESUME) | (1<<SNDRV_TIMER_EVENT_TICK);
    703 
    704     if (ioctl(pcm->timer_fd, SNDRV_TIMER_IOCTL_PARAMS, &timer_param)< 0) {
    705            ALOGE("SNDRV_TIMER_IOCTL_PARAMS failed\n");
    706     }
    707     if (ioctl(pcm->timer_fd, SNDRV_TIMER_IOCTL_START) < 0) {
    708            close(pcm->timer_fd);
    709            ALOGE("SNDRV_TIMER_IOCTL_START failed\n");
    710     }
    711     return 0;
    712 }
    713 
    714 static int disable_timer(struct pcm *pcm) {
    715      if (pcm == &bad_pcm)
    716          return 0;
    717      if (ioctl(pcm->timer_fd, SNDRV_TIMER_IOCTL_STOP) < 0)
    718          ALOGE("SNDRV_TIMER_IOCTL_STOP failed\n");
    719      return close(pcm->timer_fd);
    720 }
    721 
    722 int pcm_close(struct pcm *pcm)
    723 {
    724     if (pcm == &bad_pcm)
    725         return 0;
    726 
    727     if (pcm->flags & PCM_MMAP) {
    728         disable_timer(pcm);
    729         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) {
    730             ALOGE("Reset failed");
    731         }
    732 
    733         if (munmap(pcm->addr, pcm->buffer_size))
    734             ALOGE("munmap failed");
    735 
    736         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) {
    737             ALOGE("HW_FREE failed");
    738         }
    739     }
    740 
    741     if (pcm->fd >= 0)
    742         close(pcm->fd);
    743     pcm->running = 0;
    744     pcm->buffer_size = 0;
    745     pcm->fd = -1;
    746     if (pcm->sw_p)
    747         free(pcm->sw_p);
    748     if (pcm->hw_p)
    749         free(pcm->hw_p);
    750     if (pcm->sync_ptr)
    751         free(pcm->sync_ptr);
    752     free(pcm);
    753     return 0;
    754 }
    755 
    756 struct pcm *pcm_open(unsigned flags, char *device)
    757 {
    758     char dname[19];
    759     struct pcm *pcm;
    760     struct snd_pcm_info info;
    761     struct snd_pcm_hw_params params;
    762     struct snd_pcm_sw_params sparams;
    763     unsigned period_sz;
    764     unsigned period_cnt;
    765     char *tmp;
    766 
    767     if (flags & DEBUG_ON) {
    768         ALOGV("pcm_open(0x%08x)",flags);
    769         ALOGV("device %s\n",device);
    770     }
    771 
    772     pcm = calloc(1, sizeof(struct pcm));
    773     if (!pcm)
    774         return &bad_pcm;
    775 
    776     tmp = device+4;
    777     if ((strncmp(device, "hw:",3) != 0) || (strncmp(tmp, ",",1) != 0)){
    778         ALOGE("Wrong device fromat\n");
    779         free(pcm);
    780         return -EINVAL;
    781     }
    782 
    783     if (flags & PCM_IN) {
    784         strlcpy(dname, "/dev/snd/pcmC", sizeof(dname));
    785         tmp = device+3;
    786         strlcat(dname, tmp, (2+strlen(dname))) ;
    787         pcm->card_no = atoi(tmp);
    788         strlcat(dname, "D", (sizeof("D")+strlen(dname)));
    789         tmp = device+5;
    790         pcm->device_no = atoi(tmp);
    791 	/* should be safe to assume pcm dev ID never exceed 99 */
    792         if (pcm->device_no > 9)
    793             strlcat(dname, tmp, (3+strlen(dname)));
    794         else
    795             strlcat(dname, tmp, (2+strlen(dname)));
    796         strlcat(dname, "c", (sizeof("c")+strlen(dname)));
    797     } else {
    798         strlcpy(dname, "/dev/snd/pcmC", sizeof(dname));
    799         tmp = device+3;
    800         strlcat(dname, tmp, (2+strlen(dname))) ;
    801         pcm->card_no = atoi(tmp);
    802         strlcat(dname, "D", (sizeof("D")+strlen(dname)));
    803         tmp = device+5;
    804         pcm->device_no = atoi(tmp);
    805 	/* should be safe to assume pcm dev ID never exceed 99 */
    806         if (pcm->device_no > 9)
    807             strlcat(dname, tmp, (3+strlen(dname)));
    808         else
    809             strlcat(dname, tmp, (2+strlen(dname)));
    810         strlcat(dname, "p", (sizeof("p")+strlen(dname)));
    811     }
    812     if (pcm->flags & DEBUG_ON)
    813         ALOGV("Device name %s\n", dname);
    814 
    815     pcm->sync_ptr = calloc(1, sizeof(struct snd_pcm_sync_ptr));
    816     if (!pcm->sync_ptr) {
    817          free(pcm);
    818          return &bad_pcm;
    819     }
    820     pcm->flags = flags;
    821 
    822     pcm->fd = open(dname, O_RDWR|O_NONBLOCK);
    823     if (pcm->fd < 0) {
    824         free(pcm->sync_ptr);
    825         free(pcm);
    826         ALOGE("cannot open device '%s', errno %d", dname, errno);
    827         return &bad_pcm;
    828     }
    829 
    830     if (fcntl(pcm->fd, F_SETFL, fcntl(pcm->fd, F_GETFL) &
    831             ~O_NONBLOCK) < 0) {
    832         close(pcm->fd);
    833         free(pcm->sync_ptr);
    834         free(pcm);
    835         ALOGE("failed to change the flag, errno %d", errno);
    836         return &bad_pcm;
    837     }
    838 
    839     if (pcm->flags & PCM_MMAP)
    840         enable_timer(pcm);
    841 
    842     if (pcm->flags & DEBUG_ON)
    843         ALOGV("pcm_open() %s\n", dname);
    844     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
    845         ALOGE("cannot get info - %s", dname);
    846     }
    847     if (pcm->flags & DEBUG_ON)
    848        info_dump(&info);
    849 
    850     return pcm;
    851 }
    852 
    853 int pcm_ready(struct pcm *pcm)
    854 {
    855     return pcm->fd >= 0;
    856 }
    857