]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
Merge branch 'master-tx'
[pulseaudio] / src / modules / alsa / alsa-util.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2009 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <sys/types.h>
28 #include <limits.h>
29 #include <asoundlib.h>
30
31 #include <pulse/sample.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
35 #include <pulse/i18n.h>
36 #include <pulse/utf8.h>
37
38 #include <pulsecore/log.h>
39 #include <pulsecore/macro.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/atomic.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/once.h>
44 #include <pulsecore/thread.h>
45 #include <pulsecore/conf-parser.h>
46
47 #include "alsa-util.h"
48 #include "alsa-mixer.h"
49
50 #ifdef HAVE_HAL
51 #include "hal-util.h"
52 #endif
53
54 #ifdef HAVE_UDEV
55 #include "udev-util.h"
56 #endif
57
58 static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
59
60 static const snd_pcm_format_t format_trans[] = {
61 [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8,
62 [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
63 [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
64 [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
65 [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
66 [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
67 [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
68 [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
69 [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
70 [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
71 [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
72 [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
73 [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE,
74 };
75
76 static const pa_sample_format_t try_order[] = {
77 PA_SAMPLE_FLOAT32NE,
78 PA_SAMPLE_FLOAT32RE,
79 PA_SAMPLE_S32NE,
80 PA_SAMPLE_S32RE,
81 PA_SAMPLE_S24_32NE,
82 PA_SAMPLE_S24_32RE,
83 PA_SAMPLE_S24NE,
84 PA_SAMPLE_S24RE,
85 PA_SAMPLE_S16NE,
86 PA_SAMPLE_S16RE,
87 PA_SAMPLE_ALAW,
88 PA_SAMPLE_ULAW,
89 PA_SAMPLE_U8
90 };
91
92 unsigned i;
93 int ret;
94
95 pa_assert(pcm_handle);
96 pa_assert(f);
97
98 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
99 return ret;
100
101 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
102 snd_pcm_format_description(format_trans[*f]),
103 pa_alsa_strerror(ret));
104
105 if (*f == PA_SAMPLE_FLOAT32BE)
106 *f = PA_SAMPLE_FLOAT32LE;
107 else if (*f == PA_SAMPLE_FLOAT32LE)
108 *f = PA_SAMPLE_FLOAT32BE;
109 else if (*f == PA_SAMPLE_S24BE)
110 *f = PA_SAMPLE_S24LE;
111 else if (*f == PA_SAMPLE_S24LE)
112 *f = PA_SAMPLE_S24BE;
113 else if (*f == PA_SAMPLE_S24_32BE)
114 *f = PA_SAMPLE_S24_32LE;
115 else if (*f == PA_SAMPLE_S24_32LE)
116 *f = PA_SAMPLE_S24_32BE;
117 else if (*f == PA_SAMPLE_S16BE)
118 *f = PA_SAMPLE_S16LE;
119 else if (*f == PA_SAMPLE_S16LE)
120 *f = PA_SAMPLE_S16BE;
121 else if (*f == PA_SAMPLE_S32BE)
122 *f = PA_SAMPLE_S32LE;
123 else if (*f == PA_SAMPLE_S32LE)
124 *f = PA_SAMPLE_S32BE;
125 else
126 goto try_auto;
127
128 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
129 return ret;
130
131 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
132 snd_pcm_format_description(format_trans[*f]),
133 pa_alsa_strerror(ret));
134
135 try_auto:
136
137 for (i = 0; i < PA_ELEMENTSOF(try_order); i++) {
138 *f = try_order[i];
139
140 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
141 return ret;
142
143 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
144 snd_pcm_format_description(format_trans[*f]),
145 pa_alsa_strerror(ret));
146 }
147
148 return -1;
149 }
150
151 /* Set the hardware parameters of the given ALSA device. Returns the
152 * selected fragment settings in *period and *period_size */
153 int pa_alsa_set_hw_params(
154 snd_pcm_t *pcm_handle,
155 pa_sample_spec *ss,
156 uint32_t *periods,
157 snd_pcm_uframes_t *period_size,
158 snd_pcm_uframes_t tsched_size,
159 pa_bool_t *use_mmap,
160 pa_bool_t *use_tsched,
161 pa_bool_t require_exact_channel_number) {
162
163 int ret = -1;
164 snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
165 unsigned int _periods = periods ? *periods : 0;
166 unsigned int r = ss->rate;
167 unsigned int c = ss->channels;
168 pa_sample_format_t f = ss->format;
169 snd_pcm_hw_params_t *hwparams;
170 pa_bool_t _use_mmap = use_mmap && *use_mmap;
171 pa_bool_t _use_tsched = use_tsched && *use_tsched;
172 int dir;
173
174 pa_assert(pcm_handle);
175 pa_assert(ss);
176
177 snd_pcm_hw_params_alloca(&hwparams);
178
179 if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
180 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
181 goto finish;
182 }
183
184 if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
185 pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret));
186 goto finish;
187 }
188
189 if (_use_mmap) {
190
191 if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
192
193 /* mmap() didn't work, fall back to interleaved */
194
195 if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
196 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
197 goto finish;
198 }
199
200 _use_mmap = FALSE;
201 }
202
203 } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
204 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
205 goto finish;
206 }
207
208 if (!_use_mmap)
209 _use_tsched = FALSE;
210
211 if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
212 goto finish;
213
214 if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) {
215 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
216 goto finish;
217 }
218
219 if (require_exact_channel_number) {
220 if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) {
221 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", c, pa_alsa_strerror(ret));
222 goto finish;
223 }
224 } else {
225 if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
226 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", c, pa_alsa_strerror(ret));
227 goto finish;
228 }
229 }
230
231 if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0) {
232 pa_log_debug("snd_pcm_hw_params_set_periods_integer() failed: %s", pa_alsa_strerror(ret));
233 goto finish;
234 }
235
236 if (_period_size && tsched_size && _periods) {
237
238 /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
239 _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
240 tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
241
242 if (_use_tsched) {
243 snd_pcm_uframes_t buffer_size = 0;
244
245 if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0)
246 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
247 else
248 pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
249
250 _period_size = tsched_size;
251 _periods = 1;
252 }
253
254 if (_period_size > 0 && _periods > 0) {
255 snd_pcm_uframes_t buffer_size;
256
257 buffer_size = _periods * _period_size;
258
259 if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
260 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
261 }
262
263 if (_periods > 0) {
264
265 /* First we pass 0 as direction to get exactly what we
266 * asked for. That this is necessary is presumably a bug
267 * in ALSA. All in all this is mostly a hint to ALSA, so
268 * we don't care if this fails. */
269
270 dir = 0;
271 if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir) < 0) {
272 dir = 1;
273 if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir) < 0) {
274 dir = -1;
275 if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
276 pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret));
277 }
278 }
279 }
280 }
281
282 if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
283 goto finish;
284
285 if (ss->rate != r)
286 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
287
288 if (ss->channels != c)
289 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
290
291 if (ss->format != f)
292 pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
293
294 if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
295 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
296 goto finish;
297 }
298
299 if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
300 (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0) {
301 pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret));
302 goto finish;
303 }
304
305 /* If the sample rate deviates too much, we need to resample */
306 if (r < ss->rate*.95 || r > ss->rate*1.05)
307 ss->rate = r;
308 ss->channels = (uint8_t) c;
309 ss->format = f;
310
311 pa_assert(_periods > 0);
312 pa_assert(_period_size > 0);
313
314 if (periods)
315 *periods = _periods;
316
317 if (period_size)
318 *period_size = _period_size;
319
320 if (use_mmap)
321 *use_mmap = _use_mmap;
322
323 if (use_tsched)
324 *use_tsched = _use_tsched;
325
326 ret = 0;
327
328 snd_pcm_nonblock(pcm_handle, 1);
329
330 finish:
331
332 return ret;
333 }
334
335 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) {
336 snd_pcm_sw_params_t *swparams;
337 snd_pcm_uframes_t boundary;
338 int err;
339
340 pa_assert(pcm);
341
342 snd_pcm_sw_params_alloca(&swparams);
343
344 if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
345 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err));
346 return err;
347 }
348
349 if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, 0)) < 0) {
350 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err));
351 return err;
352 }
353
354 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
355 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err));
356 return err;
357 }
358
359 if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
360 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err));
361 return err;
362 }
363
364 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
365 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err));
366 return err;
367 }
368
369 if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
370 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err));
371 return err;
372 }
373
374 if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
375 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
376 return err;
377 }
378
379 if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
380 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err));
381 return err;
382 }
383
384 return 0;
385 }
386
387 snd_pcm_t *pa_alsa_open_by_device_id_auto(
388 const char *dev_id,
389 char **dev,
390 pa_sample_spec *ss,
391 pa_channel_map* map,
392 int mode,
393 uint32_t *nfrags,
394 snd_pcm_uframes_t *period_size,
395 snd_pcm_uframes_t tsched_size,
396 pa_bool_t *use_mmap,
397 pa_bool_t *use_tsched,
398 pa_alsa_profile_set *ps,
399 pa_alsa_mapping **mapping) {
400
401 char *d;
402 snd_pcm_t *pcm_handle;
403 void *state;
404 pa_alsa_mapping *m;
405
406 pa_assert(dev_id);
407 pa_assert(dev);
408 pa_assert(ss);
409 pa_assert(map);
410 pa_assert(nfrags);
411 pa_assert(period_size);
412 pa_assert(ps);
413
414 /* First we try to find a device string with a superset of the
415 * requested channel map. We iterate through our device table from
416 * top to bottom and take the first that matches. If we didn't
417 * find a working device that way, we iterate backwards, and check
418 * all devices that do not provide a superset of the requested
419 * channel map.*/
420
421 PA_HASHMAP_FOREACH(m, ps->mappings, state) {
422 if (!pa_channel_map_superset(&m->channel_map, map))
423 continue;
424
425 pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
426
427 pcm_handle = pa_alsa_open_by_device_id_mapping(
428 dev_id,
429 dev,
430 ss,
431 map,
432 mode,
433 nfrags,
434 period_size,
435 tsched_size,
436 use_mmap,
437 use_tsched,
438 m);
439
440 if (pcm_handle) {
441 if (mapping)
442 *mapping = m;
443
444 return pcm_handle;
445 }
446 }
447
448 PA_HASHMAP_FOREACH_BACKWARDS(m, ps->mappings, state) {
449 if (pa_channel_map_superset(&m->channel_map, map))
450 continue;
451
452 pa_log_debug("Checking for subset %s (%s)", m->name, m->device_strings[0]);
453
454 pcm_handle = pa_alsa_open_by_device_id_mapping(
455 dev_id,
456 dev,
457 ss,
458 map,
459 mode,
460 nfrags,
461 period_size,
462 tsched_size,
463 use_mmap,
464 use_tsched,
465 m);
466
467 if (pcm_handle) {
468 if (mapping)
469 *mapping = m;
470
471 return pcm_handle;
472 }
473 }
474
475 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
476 d = pa_sprintf_malloc("hw:%s", dev_id);
477 pa_log_debug("Trying %s as last resort...", d);
478 pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE);
479 pa_xfree(d);
480
481 if (pcm_handle && mapping)
482 *mapping = NULL;
483
484 return pcm_handle;
485 }
486
487 snd_pcm_t *pa_alsa_open_by_device_id_mapping(
488 const char *dev_id,
489 char **dev,
490 pa_sample_spec *ss,
491 pa_channel_map* map,
492 int mode,
493 uint32_t *nfrags,
494 snd_pcm_uframes_t *period_size,
495 snd_pcm_uframes_t tsched_size,
496 pa_bool_t *use_mmap,
497 pa_bool_t *use_tsched,
498 pa_alsa_mapping *m) {
499
500 snd_pcm_t *pcm_handle;
501 pa_sample_spec try_ss;
502 pa_channel_map try_map;
503
504 pa_assert(dev_id);
505 pa_assert(dev);
506 pa_assert(ss);
507 pa_assert(map);
508 pa_assert(nfrags);
509 pa_assert(period_size);
510 pa_assert(m);
511
512 try_ss.channels = m->channel_map.channels;
513 try_ss.rate = ss->rate;
514 try_ss.format = ss->format;
515 try_map = m->channel_map;
516
517 pcm_handle = pa_alsa_open_by_template(
518 m->device_strings,
519 dev_id,
520 dev,
521 &try_ss,
522 &try_map,
523 mode,
524 nfrags,
525 period_size,
526 tsched_size,
527 use_mmap,
528 use_tsched,
529 TRUE);
530
531 if (!pcm_handle)
532 return NULL;
533
534 *ss = try_ss;
535 *map = try_map;
536 pa_assert(map->channels == ss->channels);
537
538 return pcm_handle;
539 }
540
541 snd_pcm_t *pa_alsa_open_by_device_string(
542 const char *device,
543 char **dev,
544 pa_sample_spec *ss,
545 pa_channel_map* map,
546 int mode,
547 uint32_t *nfrags,
548 snd_pcm_uframes_t *period_size,
549 snd_pcm_uframes_t tsched_size,
550 pa_bool_t *use_mmap,
551 pa_bool_t *use_tsched,
552 pa_bool_t require_exact_channel_number) {
553
554 int err;
555 char *d;
556 snd_pcm_t *pcm_handle;
557 pa_bool_t reformat = FALSE;
558
559 pa_assert(device);
560 pa_assert(ss);
561 pa_assert(map);
562
563 d = pa_xstrdup(device);
564
565 for (;;) {
566 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
567
568 if ((err = snd_pcm_open(&pcm_handle, d, mode,
569 SND_PCM_NONBLOCK|
570 SND_PCM_NO_AUTO_RESAMPLE|
571 SND_PCM_NO_AUTO_CHANNELS|
572 (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
573 pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
574 goto fail;
575 }
576
577 pa_log_debug("Managed to open %s", d);
578
579 if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
580
581 if (!reformat) {
582 reformat = TRUE;
583
584 snd_pcm_close(pcm_handle);
585 continue;
586 }
587
588 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
589 if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
590 char *t;
591
592 t = pa_sprintf_malloc("plug:%s", d);
593 pa_xfree(d);
594 d = t;
595
596 reformat = FALSE;
597
598 snd_pcm_close(pcm_handle);
599 continue;
600 }
601
602 pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
603 snd_pcm_close(pcm_handle);
604
605 goto fail;
606 }
607
608 if (dev)
609 *dev = d;
610 else
611 pa_xfree(d);
612
613 if (ss->channels != map->channels)
614 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
615
616 return pcm_handle;
617 }
618
619 fail:
620 pa_xfree(d);
621
622 return NULL;
623 }
624
625 snd_pcm_t *pa_alsa_open_by_template(
626 char **template,
627 const char *dev_id,
628 char **dev,
629 pa_sample_spec *ss,
630 pa_channel_map* map,
631 int mode,
632 uint32_t *nfrags,
633 snd_pcm_uframes_t *period_size,
634 snd_pcm_uframes_t tsched_size,
635 pa_bool_t *use_mmap,
636 pa_bool_t *use_tsched,
637 pa_bool_t require_exact_channel_number) {
638
639 snd_pcm_t *pcm_handle;
640 char **i;
641
642 for (i = template; *i; i++) {
643 char *d;
644
645 d = pa_replace(*i, "%f", dev_id);
646
647 pcm_handle = pa_alsa_open_by_device_string(
648 d,
649 dev,
650 ss,
651 map,
652 mode,
653 nfrags,
654 period_size,
655 tsched_size,
656 use_mmap,
657 use_tsched,
658 require_exact_channel_number);
659
660 pa_xfree(d);
661
662 if (pcm_handle)
663 return pcm_handle;
664 }
665
666 return NULL;
667 }
668
669 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
670 int err;
671 snd_output_t *out;
672
673 pa_assert(pcm);
674
675 pa_assert_se(snd_output_buffer_open(&out) == 0);
676
677 if ((err = snd_pcm_dump(pcm, out)) < 0)
678 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
679 else {
680 char *s = NULL;
681 snd_output_buffer_string(out, &s);
682 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
683 }
684
685 pa_assert_se(snd_output_close(out) == 0);
686 }
687
688 void pa_alsa_dump_status(snd_pcm_t *pcm) {
689 int err;
690 snd_output_t *out;
691 snd_pcm_status_t *status;
692 char *s = NULL;
693
694 pa_assert(pcm);
695
696 snd_pcm_status_alloca(&status);
697
698 if ((err = snd_output_buffer_open(&out)) < 0) {
699 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err));
700 return;
701 }
702
703 if ((err = snd_pcm_status(pcm, status)) < 0) {
704 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err));
705 goto finish;
706 }
707
708 if ((err = snd_pcm_status_dump(status, out)) < 0) {
709 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
710 goto finish;
711 }
712
713 snd_output_buffer_string(out, &s);
714 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
715
716 finish:
717
718 snd_output_close(out);
719 }
720
721 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
722 va_list ap;
723 char *alsa_file;
724
725 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
726
727 va_start(ap, fmt);
728
729 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
730
731 va_end(ap);
732
733 pa_xfree(alsa_file);
734 }
735
736 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
737
738 void pa_alsa_refcnt_inc(void) {
739 /* This is not really thread safe, but we do our best */
740
741 if (pa_atomic_inc(&n_error_handler_installed) == 0)
742 snd_lib_error_set_handler(alsa_error_handler);
743 }
744
745 void pa_alsa_refcnt_dec(void) {
746 int r;
747
748 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
749
750 if (r == 1) {
751 snd_lib_error_set_handler(NULL);
752 snd_config_update_free_global();
753 }
754 }
755
756 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
757 const char *d, *k;
758 pa_assert(p);
759
760 if (pa_device_init_description(p))
761 return TRUE;
762
763 if (!(d = pa_proplist_gets(p, "alsa.card_name")))
764 d = pa_proplist_gets(p, "alsa.name");
765
766 if (!d)
767 return FALSE;
768
769 k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
770
771 if (d && k)
772 pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
773 else if (d)
774 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
775
776 return FALSE;
777 }
778
779 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
780 char *cn, *lcn, *dn;
781
782 pa_assert(p);
783 pa_assert(card >= 0);
784
785 pa_proplist_setf(p, "alsa.card", "%i", card);
786
787 if (snd_card_get_name(card, &cn) >= 0) {
788 pa_proplist_sets(p, "alsa.card_name", cn);
789 free(cn);
790 }
791
792 if (snd_card_get_longname(card, &lcn) >= 0) {
793 pa_proplist_sets(p, "alsa.long_card_name", lcn);
794 free(lcn);
795 }
796
797 if ((dn = pa_alsa_get_driver_name(card))) {
798 pa_proplist_sets(p, "alsa.driver_name", dn);
799 pa_xfree(dn);
800 }
801
802 #ifdef HAVE_UDEV
803 pa_udev_get_info(card, p);
804 #endif
805
806 #ifdef HAVE_HAL
807 pa_hal_get_info(c, p, card);
808 #endif
809 }
810
811 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
812
813 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
814 [SND_PCM_CLASS_GENERIC] = "generic",
815 [SND_PCM_CLASS_MULTI] = "multi",
816 [SND_PCM_CLASS_MODEM] = "modem",
817 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
818 };
819 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
820 [SND_PCM_CLASS_GENERIC] = "sound",
821 [SND_PCM_CLASS_MULTI] = NULL,
822 [SND_PCM_CLASS_MODEM] = "modem",
823 [SND_PCM_CLASS_DIGITIZER] = NULL
824 };
825 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
826 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
827 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
828 };
829
830 snd_pcm_class_t class;
831 snd_pcm_subclass_t subclass;
832 const char *n, *id, *sdn;
833 int card;
834
835 pa_assert(p);
836 pa_assert(pcm_info);
837
838 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
839
840 if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
841 if (class_table[class])
842 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
843 if (alsa_class_table[class])
844 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
845 }
846
847 if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
848 if (alsa_subclass_table[subclass])
849 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
850
851 if ((n = snd_pcm_info_get_name(pcm_info)))
852 pa_proplist_sets(p, "alsa.name", n);
853
854 if ((id = snd_pcm_info_get_id(pcm_info)))
855 pa_proplist_sets(p, "alsa.id", id);
856
857 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
858 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
859 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
860
861 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
862
863 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
864 pa_alsa_init_proplist_card(c, p, card);
865 }
866
867 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
868 snd_pcm_hw_params_t *hwparams;
869 snd_pcm_info_t *info;
870 int bits, err;
871
872 snd_pcm_hw_params_alloca(&hwparams);
873 snd_pcm_info_alloca(&info);
874
875 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
876 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
877 else {
878
879 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
880 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
881 }
882
883 if ((err = snd_pcm_info(pcm, info)) < 0)
884 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
885 else
886 pa_alsa_init_proplist_pcm_info(c, p, info);
887 }
888
889 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
890 int err;
891 snd_ctl_t *ctl;
892 snd_ctl_card_info_t *info;
893 const char *t;
894
895 pa_assert(p);
896
897 snd_ctl_card_info_alloca(&info);
898
899 if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
900 pa_log_warn("Error opening low-level control device '%s'", name);
901 return;
902 }
903
904 if ((err = snd_ctl_card_info(ctl, info)) < 0) {
905 pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
906 snd_ctl_close(ctl);
907 return;
908 }
909
910 if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
911 pa_proplist_sets(p, "alsa.mixer_name", t);
912
913 if ((t = snd_ctl_card_info_get_components(info)) && *t)
914 pa_proplist_sets(p, "alsa.components", t);
915
916 snd_ctl_close(ctl);
917 }
918
919 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
920 snd_pcm_state_t state;
921 int err;
922
923 pa_assert(pcm);
924
925 if (revents & POLLERR)
926 pa_log_debug("Got POLLERR from ALSA");
927 if (revents & POLLNVAL)
928 pa_log_warn("Got POLLNVAL from ALSA");
929 if (revents & POLLHUP)
930 pa_log_warn("Got POLLHUP from ALSA");
931 if (revents & POLLPRI)
932 pa_log_warn("Got POLLPRI from ALSA");
933 if (revents & POLLIN)
934 pa_log_debug("Got POLLIN from ALSA");
935 if (revents & POLLOUT)
936 pa_log_debug("Got POLLOUT from ALSA");
937
938 state = snd_pcm_state(pcm);
939 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
940
941 /* Try to recover from this error */
942
943 switch (state) {
944
945 case SND_PCM_STATE_XRUN:
946 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
947 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
948 return -1;
949 }
950 break;
951
952 case SND_PCM_STATE_SUSPENDED:
953 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
954 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
955 return -1;
956 }
957 break;
958
959 default:
960
961 snd_pcm_drop(pcm);
962
963 if ((err = snd_pcm_prepare(pcm)) < 0) {
964 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
965 return -1;
966 }
967 break;
968 }
969
970 return 0;
971 }
972
973 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
974 int n, err;
975 struct pollfd *pollfd;
976 pa_rtpoll_item *item;
977
978 pa_assert(pcm);
979
980 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
981 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
982 return NULL;
983 }
984
985 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
986 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
987
988 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
989 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
990 pa_rtpoll_item_free(item);
991 return NULL;
992 }
993
994 return item;
995 }
996
997 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
998 snd_pcm_sframes_t n;
999 size_t k;
1000
1001 pa_assert(pcm);
1002 pa_assert(hwbuf_size > 0);
1003 pa_assert(ss);
1004
1005 /* Some ALSA driver expose weird bugs, let's inform the user about
1006 * what is going on */
1007
1008 n = snd_pcm_avail(pcm);
1009
1010 if (n <= 0)
1011 return n;
1012
1013 k = (size_t) n * pa_frame_size(ss);
1014
1015 if (k >= hwbuf_size * 5 ||
1016 k >= pa_bytes_per_second(ss)*10) {
1017
1018 PA_ONCE_BEGIN {
1019 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1020 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1021 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1022 (unsigned long) k,
1023 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1024 pa_strnull(dn));
1025 pa_xfree(dn);
1026 pa_alsa_dump(PA_LOG_ERROR, pcm);
1027 } PA_ONCE_END;
1028
1029 /* Mhmm, let's try not to fail completely */
1030 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1031 }
1032
1033 return n;
1034 }
1035
1036 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) {
1037 ssize_t k;
1038 size_t abs_k;
1039 int r;
1040
1041 pa_assert(pcm);
1042 pa_assert(delay);
1043 pa_assert(hwbuf_size > 0);
1044 pa_assert(ss);
1045
1046 /* Some ALSA driver expose weird bugs, let's inform the user about
1047 * what is going on */
1048
1049 if ((r = snd_pcm_delay(pcm, delay)) < 0)
1050 return r;
1051
1052 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1053
1054 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1055
1056 if (abs_k >= hwbuf_size * 5 ||
1057 abs_k >= pa_bytes_per_second(ss)*10) {
1058
1059 PA_ONCE_BEGIN {
1060 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1061 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1062 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1063 (signed long) k,
1064 k < 0 ? "-" : "",
1065 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1066 pa_strnull(dn));
1067 pa_xfree(dn);
1068 pa_alsa_dump(PA_LOG_ERROR, pcm);
1069 } PA_ONCE_END;
1070
1071 /* Mhmm, let's try not to fail completely */
1072 if (k < 0)
1073 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1074 else
1075 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1076 }
1077
1078 return 0;
1079 }
1080
1081 int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss) {
1082 int r;
1083 snd_pcm_uframes_t before;
1084 size_t k;
1085
1086 pa_assert(pcm);
1087 pa_assert(areas);
1088 pa_assert(offset);
1089 pa_assert(frames);
1090 pa_assert(hwbuf_size > 0);
1091 pa_assert(ss);
1092
1093 before = *frames;
1094
1095 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1096
1097 if (r < 0)
1098 return r;
1099
1100 k = (size_t) *frames * pa_frame_size(ss);
1101
1102 if (*frames > before ||
1103 k >= hwbuf_size * 3 ||
1104 k >= pa_bytes_per_second(ss)*10)
1105
1106 PA_ONCE_BEGIN {
1107 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1108 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1109 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1110 (unsigned long) k,
1111 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1112 pa_strnull(dn));
1113 pa_xfree(dn);
1114 pa_alsa_dump(PA_LOG_ERROR, pcm);
1115 } PA_ONCE_END;
1116
1117 return r;
1118 }
1119
1120 char *pa_alsa_get_driver_name(int card) {
1121 char *t, *m, *n;
1122
1123 pa_assert(card >= 0);
1124
1125 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1126 m = pa_readlink(t);
1127 pa_xfree(t);
1128
1129 if (!m)
1130 return NULL;
1131
1132 n = pa_xstrdup(pa_path_get_filename(m));
1133 pa_xfree(m);
1134
1135 return n;
1136 }
1137
1138 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1139 int card;
1140 snd_pcm_info_t* info;
1141 snd_pcm_info_alloca(&info);
1142
1143 pa_assert(pcm);
1144
1145 if (snd_pcm_info(pcm, info) < 0)
1146 return NULL;
1147
1148 if ((card = snd_pcm_info_get_card(info)) < 0)
1149 return NULL;
1150
1151 return pa_alsa_get_driver_name(card);
1152 }
1153
1154 char *pa_alsa_get_reserve_name(const char *device) {
1155 const char *t;
1156 int i;
1157
1158 pa_assert(device);
1159
1160 if ((t = strchr(device, ':')))
1161 device = t+1;
1162
1163 if ((i = snd_card_get_index(device)) < 0) {
1164 int32_t k;
1165
1166 if (pa_atoi(device, &k) < 0)
1167 return NULL;
1168
1169 i = (int) k;
1170 }
1171
1172 return pa_sprintf_malloc("Audio%i", i);
1173 }
1174
1175 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1176 snd_pcm_info_t* info;
1177 snd_pcm_info_alloca(&info);
1178
1179 pa_assert(pcm);
1180
1181 if (snd_pcm_info(pcm, info) < 0)
1182 return FALSE;
1183
1184 return snd_pcm_info_get_card(info) >= 0;
1185 }
1186
1187 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1188 snd_pcm_info_t* info;
1189 snd_pcm_info_alloca(&info);
1190
1191 pa_assert(pcm);
1192
1193 if (snd_pcm_info(pcm, info) < 0)
1194 return FALSE;
1195
1196 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1197 }
1198
1199 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1200
1201 const char* pa_alsa_strerror(int errnum) {
1202 const char *original = NULL;
1203 char *translated, *t;
1204 char errbuf[128];
1205
1206 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1207 pa_xfree(t);
1208
1209 original = snd_strerror(errnum);
1210
1211 if (!original) {
1212 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1213 original = errbuf;
1214 }
1215
1216 if (!(translated = pa_locale_to_utf8(original))) {
1217 pa_log_warn("Unable to convert error string to locale, filtering.");
1218 translated = pa_utf8_filter(original);
1219 }
1220
1221 PA_STATIC_TLS_SET(cstrerror, translated);
1222
1223 return translated;
1224 }