1 /*
2 ** Copyright 2010, The Android Open-Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define LOG_TAG "alsa_pcm"
18 //#define LOG_NDEBUG 0
19 #include <cutils/log.h>
20 #include <cutils/config_utils.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <sys/time.h>
33
34 #include <linux/ioctl.h>
35
36 #include "alsa_audio.h"
37
38 #define __force
39 #define __bitwise
40 #define __user
41 #include "asound.h"
42
43 #define DEBUG 0
44
45 /* alsa parameter manipulation cruft */
46
47 #define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
48
param_is_mask(int p)49 static inline int param_is_mask(int p)
50 {
51 return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
52 (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
53 }
54
param_is_interval(int p)55 static inline int param_is_interval(int p)
56 {
57 return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
58 (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
59 }
60
param_to_interval(struct snd_pcm_hw_params * p,int n)61 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
62 {
63 return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
64 }
65
param_to_mask(struct snd_pcm_hw_params * p,int n)66 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
67 {
68 return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
69 }
70
param_set_mask(struct snd_pcm_hw_params * p,int n,unsigned bit)71 static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
72 {
73 if (bit >= SNDRV_MASK_MAX)
74 return;
75 if (param_is_mask(n)) {
76 struct snd_mask *m = param_to_mask(p, n);
77 m->bits[0] = 0;
78 m->bits[1] = 0;
79 m->bits[bit >> 5] |= (1 << (bit & 31));
80 }
81 }
82
param_set_min(struct snd_pcm_hw_params * p,int n,unsigned val)83 static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
84 {
85 if (param_is_interval(n)) {
86 struct snd_interval *i = param_to_interval(p, n);
87 i->min = val;
88 }
89 }
90
param_set_max(struct snd_pcm_hw_params * p,int n,unsigned val)91 static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
92 {
93 if (param_is_interval(n)) {
94 struct snd_interval *i = param_to_interval(p, n);
95 i->max = val;
96 }
97 }
98
param_set_int(struct snd_pcm_hw_params * p,int n,unsigned val)99 static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
100 {
101 if (param_is_interval(n)) {
102 struct snd_interval *i = param_to_interval(p, n);
103 i->min = val;
104 i->max = val;
105 i->integer = 1;
106 }
107 }
108
param_init(struct snd_pcm_hw_params * p)109 static void param_init(struct snd_pcm_hw_params *p)
110 {
111 int n;
112 memset(p, 0, sizeof(*p));
113 for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
114 n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
115 struct snd_mask *m = param_to_mask(p, n);
116 m->bits[0] = ~0;
117 m->bits[1] = ~0;
118 }
119 for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
120 n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
121 struct snd_interval *i = param_to_interval(p, n);
122 i->min = 0;
123 i->max = ~0;
124 }
125 }
126
127 /* debugging gunk */
128
129 #if DEBUG
130 static const char *param_name[PARAM_MAX+1] = {
131 [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
132 [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
133 [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
134
135 [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
136 [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
137 [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
138 [SNDRV_PCM_HW_PARAM_RATE] = "rate",
139 [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
140 [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
141 [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
142 [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
143 [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
144 [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
145 [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
146 [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
147 };
148
param_dump(struct snd_pcm_hw_params * p)149 static void param_dump(struct snd_pcm_hw_params *p)
150 {
151 int n;
152
153 for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
154 n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
155 struct snd_mask *m = param_to_mask(p, n);
156 LOGV("%s = %08x%08x\n", param_name[n],
157 m->bits[1], m->bits[0]);
158 }
159 for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
160 n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
161 struct snd_interval *i = param_to_interval(p, n);
162 LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
163 param_name[n], i->min, i->max, i->openmin,
164 i->openmax, i->integer, i->empty);
165 }
166 LOGV("info = %08x\n", p->info);
167 LOGV("msbits = %d\n", p->msbits);
168 LOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
169 LOGV("fifo = %d\n", (int) p->fifo_size);
170 }
171
info_dump(struct snd_pcm_info * info)172 static void info_dump(struct snd_pcm_info *info)
173 {
174 LOGV("device = %d\n", info->device);
175 LOGV("subdevice = %d\n", info->subdevice);
176 LOGV("stream = %d\n", info->stream);
177 LOGV("card = %d\n", info->card);
178 LOGV("id = '%s'\n", info->id);
179 LOGV("name = '%s'\n", info->name);
180 LOGV("subname = '%s'\n", info->subname);
181 LOGV("dev_class = %d\n", info->dev_class);
182 LOGV("dev_subclass = %d\n", info->dev_subclass);
183 LOGV("subdevices_count = %d\n", info->subdevices_count);
184 LOGV("subdevices_avail = %d\n", info->subdevices_avail);
185 }
186 #else
param_dump(struct snd_pcm_hw_params * p)187 static void param_dump(struct snd_pcm_hw_params *p) {}
info_dump(struct snd_pcm_info * info)188 static void info_dump(struct snd_pcm_info *info) {}
189 #endif
190
191 #define PCM_ERROR_MAX 128
192
193 struct pcm {
194 int fd;
195 unsigned flags;
196 int running:1;
197 int underruns;
198 unsigned buffer_size;
199 char error[PCM_ERROR_MAX];
200 };
201
pcm_buffer_size(struct pcm * pcm)202 unsigned pcm_buffer_size(struct pcm *pcm)
203 {
204 return pcm->buffer_size;
205 }
206
pcm_error(struct pcm * pcm)207 const char* pcm_error(struct pcm *pcm)
208 {
209 return pcm->error;
210 }
211
oops(struct pcm * pcm,int e,const char * fmt,...)212 static int oops(struct pcm *pcm, int e, const char *fmt, ...)
213 {
214 va_list ap;
215 int sz;
216
217 va_start(ap, fmt);
218 vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
219 va_end(ap);
220 sz = strlen(pcm->error);
221
222 if (errno)
223 snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
224 ": %s", strerror(e));
225 return -1;
226 }
227
pcm_write(struct pcm * pcm,void * data,unsigned count)228 int pcm_write(struct pcm *pcm, void *data, unsigned count)
229 {
230 struct snd_xferi x;
231
232 if (pcm->flags & PCM_IN)
233 return -EINVAL;
234
235 x.buf = data;
236 x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
237
238 for (;;) {
239 if (!pcm->running) {
240 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
241 return oops(pcm, errno, "cannot prepare channel");
242 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
243 return oops(pcm, errno, "cannot write initial data");
244 pcm->running = 1;
245 return 0;
246 }
247 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
248 pcm->running = 0;
249 if (errno == EPIPE) {
250 /* we failed to make our window -- try to restart */
251 pcm->underruns++;
252 continue;
253 }
254 return oops(pcm, errno, "cannot write stream data");
255 }
256 return 0;
257 }
258 }
259
pcm_read(struct pcm * pcm,void * data,unsigned count)260 int pcm_read(struct pcm *pcm, void *data, unsigned count)
261 {
262 struct snd_xferi x;
263
264 if (!(pcm->flags & PCM_IN))
265 return -EINVAL;
266
267 x.buf = data;
268 x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
269
270 // LOGV("read() %d frames", x.frames);
271 for (;;) {
272 if (!pcm->running) {
273 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
274 return oops(pcm, errno, "cannot prepare channel");
275 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
276 return oops(pcm, errno, "cannot start channel");
277 pcm->running = 1;
278 }
279 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
280 pcm->running = 0;
281 if (errno == EPIPE) {
282 /* we failed to make our window -- try to restart */
283 pcm->underruns++;
284 continue;
285 }
286 return oops(pcm, errno, "cannot read stream data");
287 }
288 // LOGV("read() got %d frames", x.frames);
289 return 0;
290 }
291 }
292
293 static struct pcm bad_pcm = {
294 .fd = -1,
295 };
296
pcm_close(struct pcm * pcm)297 int pcm_close(struct pcm *pcm)
298 {
299 if (pcm == &bad_pcm)
300 return 0;
301
302 if (pcm->fd >= 0)
303 close(pcm->fd);
304 pcm->running = 0;
305 pcm->buffer_size = 0;
306 pcm->fd = -1;
307 return 0;
308 }
309
pcm_open(unsigned flags)310 struct pcm *pcm_open(unsigned flags)
311 {
312 const char *dname;
313 struct pcm *pcm;
314 struct snd_pcm_info info;
315 struct snd_pcm_hw_params params;
316 struct snd_pcm_sw_params sparams;
317 unsigned period_sz;
318 unsigned period_cnt;
319
320 LOGV("pcm_open(0x%08x)",flags);
321
322 pcm = calloc(1, sizeof(struct pcm));
323 if (!pcm)
324 return &bad_pcm;
325
326 if (flags & PCM_IN) {
327 dname = "/dev/snd/pcmC0D0c";
328 } else {
329 dname = "/dev/snd/pcmC0D0p";
330 }
331
332 LOGV("pcm_open() period sz multiplier %d",
333 ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
334 period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
335 LOGV("pcm_open() period cnt %d",
336 ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN);
337 period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN;
338
339 pcm->flags = flags;
340 pcm->fd = open(dname, O_RDWR);
341 if (pcm->fd < 0) {
342 oops(pcm, errno, "cannot open device '%s'");
343 return pcm;
344 }
345
346 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
347 oops(pcm, errno, "cannot get info - %s");
348 goto fail;
349 }
350 info_dump(&info);
351
352 LOGV("pcm_open() period_cnt %d period_sz %d channels %d",
353 period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2);
354
355 param_init(¶ms);
356 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS,
357 SNDRV_PCM_ACCESS_RW_INTERLEAVED);
358 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT,
359 SNDRV_PCM_FORMAT_S16_LE);
360 param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT,
361 SNDRV_PCM_SUBFORMAT_STD);
362 param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
363 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
364 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS,
365 (flags & PCM_MONO) ? 16 : 32);
366 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS,
367 (flags & PCM_MONO) ? 1 : 2);
368 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
369 param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, 44100);
370
371 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) {
372 oops(pcm, errno, "cannot set hw params");
373 goto fail;
374 }
375 param_dump(¶ms);
376
377 memset(&sparams, 0, sizeof(sparams));
378 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
379 sparams.period_step = 1;
380 sparams.avail_min = 1;
381 sparams.start_threshold = period_cnt * period_sz;
382 sparams.stop_threshold = period_cnt * period_sz;
383 sparams.xfer_align = period_sz / 2; /* needed for old kernels */
384 sparams.silence_size = 0;
385 sparams.silence_threshold = 0;
386
387 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
388 oops(pcm, errno, "cannot set sw params");
389 goto fail;
390 }
391
392 pcm->buffer_size = period_cnt * period_sz;
393 pcm->underruns = 0;
394 return pcm;
395
396 fail:
397 close(pcm->fd);
398 pcm->fd = -1;
399 return pcm;
400 }
401
pcm_ready(struct pcm * pcm)402 int pcm_ready(struct pcm *pcm)
403 {
404 return pcm->fd >= 0;
405 }
406