Home | History | Annotate | Download | only in libaudio2
      1 /*
      2 ** Copyright 2010, The Android Open-Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 #define LOG_TAG "alsa_pcm"
     18 //#define LOG_NDEBUG 0
     19 #include <cutils/log.h>
     20 #include <cutils/config_utils.h>
     21 
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <fcntl.h>
     25 #include <stdarg.h>
     26 #include <string.h>
     27 #include <errno.h>
     28 #include <unistd.h>
     29 
     30 #include <sys/ioctl.h>
     31 #include <sys/mman.h>
     32 #include <sys/time.h>
     33 
     34 #include <linux/ioctl.h>
     35 
     36 #include "alsa_audio.h"
     37 
     38 #define __force
     39 #define __bitwise
     40 #define __user
     41 #include "asound.h"
     42 
     43 #define DEBUG 0
     44 
     45 /* alsa parameter manipulation cruft */
     46 
     47 #define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
     48 
     49 static inline int param_is_mask(int p)
     50 {
     51     return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
     52         (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
     53 }
     54 
     55 static inline int param_is_interval(int p)
     56 {
     57     return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
     58         (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
     59 }
     60 
     61 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
     62 {
     63     return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
     64 }
     65 
     66 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
     67 {
     68     return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
     69 }
     70 
     71 static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
     72 {
     73     if (bit >= SNDRV_MASK_MAX)
     74         return;
     75     if (param_is_mask(n)) {
     76         struct snd_mask *m = param_to_mask(p, n);
     77         m->bits[0] = 0;
     78         m->bits[1] = 0;
     79         m->bits[bit >> 5] |= (1 << (bit & 31));
     80     }
     81 }
     82 
     83 static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
     84 {
     85     if (param_is_interval(n)) {
     86         struct snd_interval *i = param_to_interval(p, n);
     87         i->min = val;
     88     }
     89 }
     90 
     91 static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
     92 {
     93     if (param_is_interval(n)) {
     94         struct snd_interval *i = param_to_interval(p, n);
     95         i->max = val;
     96     }
     97 }
     98 
     99 static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
    100 {
    101     if (param_is_interval(n)) {
    102         struct snd_interval *i = param_to_interval(p, n);
    103         i->min = val;
    104         i->max = val;
    105         i->integer = 1;
    106     }
    107 }
    108 
    109 static void param_init(struct snd_pcm_hw_params *p)
    110 {
    111     int n;
    112     memset(p, 0, sizeof(*p));
    113     for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
    114          n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
    115             struct snd_mask *m = param_to_mask(p, n);
    116             m->bits[0] = ~0;
    117             m->bits[1] = ~0;
    118     }
    119     for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
    120          n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
    121             struct snd_interval *i = param_to_interval(p, n);
    122             i->min = 0;
    123             i->max = ~0;
    124     }
    125 }
    126 
    127 /* debugging gunk */
    128 
    129 #if DEBUG
    130 static const char *param_name[PARAM_MAX+1] = {
    131     [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
    132     [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
    133     [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
    134 
    135     [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
    136     [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
    137     [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
    138     [SNDRV_PCM_HW_PARAM_RATE] = "rate",
    139     [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
    140     [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
    141     [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
    142     [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
    143     [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
    144     [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
    145     [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
    146     [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
    147 };
    148 
    149 static void param_dump(struct snd_pcm_hw_params *p)
    150 {
    151     int n;
    152 
    153     for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
    154          n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
    155             struct snd_mask *m = param_to_mask(p, n);
    156             LOGV("%s = %08x%08x\n", param_name[n],
    157                    m->bits[1], m->bits[0]);
    158     }
    159     for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
    160          n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
    161             struct snd_interval *i = param_to_interval(p, n);
    162             LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
    163                    param_name[n], i->min, i->max, i->openmin,
    164                    i->openmax, i->integer, i->empty);
    165     }
    166     LOGV("info = %08x\n", p->info);
    167     LOGV("msbits = %d\n", p->msbits);
    168     LOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
    169     LOGV("fifo = %d\n", (int) p->fifo_size);
    170 }
    171 
    172 static void info_dump(struct snd_pcm_info *info)
    173 {
    174     LOGV("device = %d\n", info->device);
    175     LOGV("subdevice = %d\n", info->subdevice);
    176     LOGV("stream = %d\n", info->stream);
    177     LOGV("card = %d\n", info->card);
    178     LOGV("id = '%s'\n", info->id);
    179     LOGV("name = '%s'\n", info->name);
    180     LOGV("subname = '%s'\n", info->subname);
    181     LOGV("dev_class = %d\n", info->dev_class);
    182     LOGV("dev_subclass = %d\n", info->dev_subclass);
    183     LOGV("subdevices_count = %d\n", info->subdevices_count);
    184     LOGV("subdevices_avail = %d\n", info->subdevices_avail);
    185 }
    186 #else
    187 static void param_dump(struct snd_pcm_hw_params *p) {}
    188 static void info_dump(struct snd_pcm_info *info) {}
    189 #endif
    190 
    191 #define PCM_ERROR_MAX 128
    192 
    193 struct pcm {
    194     int fd;
    195     unsigned flags;
    196     int running:1;
    197     int underruns;
    198     unsigned buffer_size;
    199     char error[PCM_ERROR_MAX];
    200 };
    201 
    202 unsigned pcm_buffer_size(struct pcm *pcm)
    203 {
    204     return pcm->buffer_size;
    205 }
    206 
    207 const char* pcm_error(struct pcm *pcm)
    208 {
    209     return pcm->error;
    210 }
    211 
    212 static int oops(struct pcm *pcm, int e, const char *fmt, ...)
    213 {
    214     va_list ap;
    215     int sz;
    216 
    217     va_start(ap, fmt);
    218     vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
    219     va_end(ap);
    220     sz = strlen(pcm->error);
    221 
    222     if (errno)
    223         snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
    224                  ": %s", strerror(e));
    225     return -1;
    226 }
    227 
    228 int pcm_write(struct pcm *pcm, void *data, unsigned count)
    229 {
    230     struct snd_xferi x;
    231 
    232     if (pcm->flags & PCM_IN)
    233         return -EINVAL;
    234 
    235     x.buf = data;
    236     x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
    237 
    238     for (;;) {
    239         if (!pcm->running) {
    240             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
    241                 return oops(pcm, errno, "cannot prepare channel");
    242             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
    243                 return oops(pcm, errno, "cannot write initial data");
    244             pcm->running = 1;
    245             return 0;
    246         }
    247         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
    248             pcm->running = 0;
    249             if (errno == EPIPE) {
    250                     /* we failed to make our window -- try to restart */
    251                 pcm->underruns++;
    252                 continue;
    253             }
    254             return oops(pcm, errno, "cannot write stream data");
    255         }
    256         return 0;
    257     }
    258 }
    259 
    260 int pcm_read(struct pcm *pcm, void *data, unsigned count)
    261 {
    262     struct snd_xferi x;
    263 
    264     if (!(pcm->flags & PCM_IN))
    265         return -EINVAL;
    266 
    267     x.buf = data;
    268     x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
    269 
    270 //    LOGV("read() %d frames", x.frames);
    271     for (;;) {
    272         if (!pcm->running) {
    273             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
    274                 return oops(pcm, errno, "cannot prepare channel");
    275             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
    276                 return oops(pcm, errno, "cannot start channel");
    277             pcm->running = 1;
    278         }
    279         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
    280             pcm->running = 0;
    281             if (errno == EPIPE) {
    282                     /* we failed to make our window -- try to restart */
    283                 pcm->underruns++;
    284                 continue;
    285             }
    286             return oops(pcm, errno, "cannot read stream data");
    287         }
    288 //        LOGV("read() got %d frames", x.frames);
    289         return 0;
    290     }
    291 }
    292 
    293 static struct pcm bad_pcm = {
    294     .fd = -1,
    295 };
    296 
    297 int pcm_close(struct pcm *pcm)
    298 {
    299     if (pcm == &bad_pcm)
    300         return 0;
    301 
    302     if (pcm->fd >= 0)
    303         close(pcm->fd);
    304     pcm->running = 0;
    305     pcm->buffer_size = 0;
    306     pcm->fd = -1;
    307     return 0;
    308 }
    309 
    310 struct pcm *pcm_open(unsigned flags)
    311 {
    312     const char *dname;
    313     struct pcm *pcm;
    314     struct snd_pcm_info info;
    315     struct snd_pcm_hw_params params;
    316     struct snd_pcm_sw_params sparams;
    317     unsigned period_sz;
    318     unsigned period_cnt;
    319 
    320     LOGV("pcm_open(0x%08x)",flags);
    321 
    322     pcm = calloc(1, sizeof(struct pcm));
    323     if (!pcm)
    324         return &bad_pcm;
    325 
    326     if (flags & PCM_IN) {
    327         dname = "/dev/snd/pcmC0D0c";
    328     } else {
    329         dname = "/dev/snd/pcmC0D0p";
    330     }
    331 
    332     LOGV("pcm_open() period sz multiplier %d",
    333          ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
    334     period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
    335     LOGV("pcm_open() period cnt %d",
    336          ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN);
    337     period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN;
    338 
    339     pcm->flags = flags;
    340     pcm->fd = open(dname, O_RDWR);
    341     if (pcm->fd < 0) {
    342         oops(pcm, errno, "cannot open device '%s'");
    343         return pcm;
    344     }
    345 
    346     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
    347         oops(pcm, errno, "cannot get info - %s");
    348         goto fail;
    349     }
    350     info_dump(&info);
    351 
    352     LOGV("pcm_open() period_cnt %d period_sz %d channels %d",
    353          period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2);
    354 
    355     param_init(&params);
    356     param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
    357                    SNDRV_PCM_ACCESS_RW_INTERLEAVED);
    358     param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
    359                    SNDRV_PCM_FORMAT_S16_LE);
    360     param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
    361                    SNDRV_PCM_SUBFORMAT_STD);
    362     param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
    363     param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
    364     param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
    365                   (flags & PCM_MONO) ? 16 : 32);
    366     param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
    367                   (flags & PCM_MONO) ? 1 : 2);
    368     param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
    369     param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
    370 
    371     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
    372         oops(pcm, errno, "cannot set hw params");
    373         goto fail;
    374     }
    375     param_dump(&params);
    376 
    377     memset(&sparams, 0, sizeof(sparams));
    378     sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
    379     sparams.period_step = 1;
    380     sparams.avail_min = 1;
    381     sparams.start_threshold = period_cnt * period_sz;
    382     sparams.stop_threshold = period_cnt * period_sz;
    383     sparams.xfer_align = period_sz / 2; /* needed for old kernels */
    384     sparams.silence_size = 0;
    385     sparams.silence_threshold = 0;
    386 
    387     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
    388         oops(pcm, errno, "cannot set sw params");
    389         goto fail;
    390     }
    391 
    392     pcm->buffer_size = period_cnt * period_sz;
    393     pcm->underruns = 0;
    394     return pcm;
    395 
    396 fail:
    397     close(pcm->fd);
    398     pcm->fd = -1;
    399     return pcm;
    400 }
    401 
    402 int pcm_ready(struct pcm *pcm)
    403 {
    404     return pcm->fd >= 0;
    405 }
    406