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