• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params);
356     param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
357                    SNDRV_PCM_ACCESS_RW_INTERLEAVED);
358     param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
359                    SNDRV_PCM_FORMAT_S16_LE);
360     param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
361                    SNDRV_PCM_SUBFORMAT_STD);
362     param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
363     param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
364     param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
365                   (flags & PCM_MONO) ? 16 : 32);
366     param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
367                   (flags & PCM_MONO) ? 1 : 2);
368     param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
369     param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
370 
371     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
372         oops(pcm, errno, "cannot set hw params");
373         goto fail;
374     }
375     param_dump(&params);
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