• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_compressed_format(const char * format)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 
get_format(const char * name)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 
get_format_name(int format)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 
get_format_desc(int format)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 
param_is_mask(int p)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 
param_is_interval(int p)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 
param_to_interval(struct snd_pcm_hw_params * p,int n)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 
param_to_mask(struct snd_pcm_hw_params * p,int n)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 
param_set_mask(struct snd_pcm_hw_params * p,int n,unsigned bit)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 
param_set_min(struct snd_pcm_hw_params * p,int n,unsigned val)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 
param_set_max(struct snd_pcm_hw_params * p,int n,unsigned val)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 
param_set_int(struct snd_pcm_hw_params * p,int n,unsigned val)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 
param_init(struct snd_pcm_hw_params * p)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 
param_dump(struct snd_pcm_hw_params * p)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 
info_dump(struct snd_pcm_info * info)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
param_dump(struct snd_pcm_hw_params * p)321 void param_dump(struct snd_pcm_hw_params *p) {}
info_dump(struct snd_pcm_info * info)322 static void info_dump(struct snd_pcm_info *info) {}
323 #endif
324 
param_set_hw_refine(struct pcm * pcm,struct snd_pcm_hw_params * params)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 
param_set_hw_params(struct pcm * pcm,struct snd_pcm_hw_params * params)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 
param_set_sw_params(struct pcm * pcm,struct snd_pcm_sw_params * sparams)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 
pcm_buffer_size(struct snd_pcm_hw_params * params)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 
pcm_period_size(struct snd_pcm_hw_params * params)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 
pcm_error(struct pcm * pcm)372 const char* pcm_error(struct pcm *pcm)
373 {
374     return pcm->error;
375 }
376 
oops(struct pcm * pcm,int e,const char * fmt,...)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 
pcm_avail(struct pcm * pcm)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 
sync_ptr(struct pcm * pcm)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 
mmap_buffer(struct pcm * pcm)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  */
dst_address(struct pcm * pcm)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 
mmap_transfer(struct pcm * pcm,void * data,unsigned offset,long frames)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 
mmap_transfer_capture(struct pcm * pcm,void * data,unsigned offset,long frames)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 
pcm_prepare(struct pcm * pcm)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 
pcm_write_mmap(struct pcm * pcm,void * data,unsigned count)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 
pcm_write_nmmap(struct pcm * pcm,void * data,unsigned count)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 
pcm_write(struct pcm * pcm,void * data,unsigned count)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 
pcm_read(struct pcm * pcm,void * data,unsigned count)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 
enable_timer(struct pcm * pcm)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 
disable_timer(struct pcm * pcm)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 
pcm_close(struct pcm * pcm)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 
pcm_open(unsigned flags,char * device)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 
pcm_ready(struct pcm * pcm)849 int pcm_ready(struct pcm *pcm)
850 {
851     return pcm->fd >= 0;
852 }
853