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