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