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