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
55enum 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};
96const 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
137int 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
153int 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
166const 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
174const 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
185static int oops(struct pcm *pcm, int e, const char *fmt, ...);
186
187static 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
193static 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
199static 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
204static 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
209void 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
221void 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
229void 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
237void 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
247void 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
268static 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
287void 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
310static 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
325void param_dump(struct snd_pcm_hw_params *p) {}
326static void info_dump(struct snd_pcm_info *info) {}
327#endif
328
329int 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
338int 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
347int 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
356int 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
366int 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
376const char* pcm_error(struct pcm *pcm)
377{
378    return pcm->error;
379}
380
381static 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
397long 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
421int 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
434int 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 */
459u_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
471int 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
492int 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
516int 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
526static 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
576static 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
607int 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
615int 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
658static struct pcm bad_pcm = {
659    .fd = -1,
660};
661
662static 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
714static 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
722int 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
756struct 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
853int pcm_ready(struct pcm *pcm)
854{
855    return pcm->fd >= 0;
856}
857