alsa: disable tsched for software devices before we configure the buffer metrics...
[pulseaudio-mirror.git] / src / modules / alsa / alsa-util.c
blobf934285a2b9201ac97ec8b6f117e2ffa67e6be9b
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2009 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <sys/types.h>
28 #include <limits.h>
29 #include <asoundlib.h>
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>
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>
47 #include "alsa-util.h"
48 #include "alsa-mixer.h"
50 #ifdef HAVE_HAL
51 #include "hal-util.h"
52 #endif
54 #ifdef HAVE_UDEV
55 #include "udev-util.h"
56 #endif
58 static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
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,
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
92 unsigned i;
93 int ret;
95 pa_assert(pcm_handle);
96 pa_assert(hwparams);
97 pa_assert(f);
99 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
100 return ret;
102 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
103 snd_pcm_format_description(format_trans[*f]),
104 pa_alsa_strerror(ret));
106 if (*f == PA_SAMPLE_FLOAT32BE)
107 *f = PA_SAMPLE_FLOAT32LE;
108 else if (*f == PA_SAMPLE_FLOAT32LE)
109 *f = PA_SAMPLE_FLOAT32BE;
110 else if (*f == PA_SAMPLE_S24BE)
111 *f = PA_SAMPLE_S24LE;
112 else if (*f == PA_SAMPLE_S24LE)
113 *f = PA_SAMPLE_S24BE;
114 else if (*f == PA_SAMPLE_S24_32BE)
115 *f = PA_SAMPLE_S24_32LE;
116 else if (*f == PA_SAMPLE_S24_32LE)
117 *f = PA_SAMPLE_S24_32BE;
118 else if (*f == PA_SAMPLE_S16BE)
119 *f = PA_SAMPLE_S16LE;
120 else if (*f == PA_SAMPLE_S16LE)
121 *f = PA_SAMPLE_S16BE;
122 else if (*f == PA_SAMPLE_S32BE)
123 *f = PA_SAMPLE_S32LE;
124 else if (*f == PA_SAMPLE_S32LE)
125 *f = PA_SAMPLE_S32BE;
126 else
127 goto try_auto;
129 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
130 return ret;
132 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
133 snd_pcm_format_description(format_trans[*f]),
134 pa_alsa_strerror(ret));
136 try_auto:
138 for (i = 0; i < PA_ELEMENTSOF(try_order); i++) {
139 *f = try_order[i];
141 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
142 return ret;
144 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
145 snd_pcm_format_description(format_trans[*f]),
146 pa_alsa_strerror(ret));
149 return -1;
152 static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
153 snd_pcm_uframes_t s;
154 int d, ret;
156 pa_assert(pcm_handle);
157 pa_assert(hwparams);
159 s = size;
160 d = 0;
161 if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
162 s = size;
163 d = -1;
164 if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
165 s = size;
166 d = 1;
167 if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
168 pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
169 return ret;
174 return 0;
177 static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
178 int ret;
180 pa_assert(pcm_handle);
181 pa_assert(hwparams);
183 if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
184 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
185 return ret;
188 return 0;
191 /* Set the hardware parameters of the given ALSA device. Returns the
192 * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */
193 int pa_alsa_set_hw_params(
194 snd_pcm_t *pcm_handle,
195 pa_sample_spec *ss,
196 snd_pcm_uframes_t *period_size,
197 snd_pcm_uframes_t *buffer_size,
198 snd_pcm_uframes_t tsched_size,
199 pa_bool_t *use_mmap,
200 pa_bool_t *use_tsched,
201 pa_bool_t require_exact_channel_number) {
203 int ret = -1;
204 snd_pcm_hw_params_t *hwparams, *hwparams_copy;
205 int dir;
206 snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
207 snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
208 pa_bool_t _use_mmap = use_mmap && *use_mmap;
209 pa_bool_t _use_tsched = use_tsched && *use_tsched;
210 pa_sample_spec _ss = *ss;
212 pa_assert(pcm_handle);
213 pa_assert(ss);
215 snd_pcm_hw_params_alloca(&hwparams);
216 snd_pcm_hw_params_alloca(&hwparams_copy);
218 if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
219 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
220 goto finish;
223 if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
224 pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret));
225 goto finish;
228 if (_use_mmap) {
230 if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
232 /* mmap() didn't work, fall back to interleaved */
234 if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
235 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
236 goto finish;
239 _use_mmap = FALSE;
242 } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
243 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
244 goto finish;
247 if (!_use_mmap)
248 _use_tsched = FALSE;
250 if (!pa_alsa_pcm_is_hw(pcm_handle))
251 _use_tsched = FALSE;
253 if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
254 goto finish;
256 if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
257 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
258 goto finish;
261 if (require_exact_channel_number) {
262 if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
263 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
264 goto finish;
266 } else {
267 unsigned int c = _ss.channels;
269 if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
270 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
271 goto finish;
274 _ss.channels = c;
277 if (_use_tsched && tsched_size > 0) {
278 _buffer_size = pa_convert_size(tsched_size, ss, &_ss);
279 _period_size = _buffer_size;
280 } else {
281 _period_size = pa_convert_size(_period_size, ss, &_ss);
282 _buffer_size = pa_convert_size(_buffer_size, ss, &_ss);
285 if (_buffer_size > 0 || _period_size > 0) {
286 snd_pcm_uframes_t max_frames = 0;
288 if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
289 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
290 else
291 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) max_frames * PA_MSEC_PER_SEC / _ss.rate);
293 /* Some ALSA drivers really don't like if we set the buffer
294 * size first and the number of periods second. (which would
295 * make a lot more sense to me) So, try a few combinations
296 * before we give up. */
298 if (_buffer_size > 0 && _period_size > 0) {
299 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
301 /* First try: set buffer size first, followed by period size */
302 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
303 set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
304 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
305 pa_log_debug("Set buffer size first, period size second.");
306 goto success;
309 /* Second try: set period size first, followed by buffer size */
310 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
311 set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
312 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
313 pa_log_debug("Set period size first, buffer size second.");
314 goto success;
318 if (_buffer_size > 0) {
319 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
321 /* Third try: set only buffer size */
322 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
323 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
324 pa_log_debug("Set only buffer size second.");
325 goto success;
329 if (_period_size > 0) {
330 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
332 /* Fourth try: set only period size */
333 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
334 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
335 pa_log_debug("Set only period size second.");
336 goto success;
341 pa_log_debug("Set neither period nor buffer size.");
343 /* Last chance, set nothing */
344 if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
345 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
346 goto finish;
349 success:
351 if (ss->rate != _ss.rate)
352 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
354 if (ss->channels != _ss.channels)
355 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
357 if (ss->format != _ss.format)
358 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(_ss.format));
360 if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
361 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
362 goto finish;
365 if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
366 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
367 goto finish;
370 if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
371 (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
372 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
373 goto finish;
376 /* If the sample rate deviates too much, we need to resample */
377 if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05)
378 ss->rate = _ss.rate;
379 ss->channels = _ss.channels;
380 ss->format = _ss.format;
382 pa_assert(_period_size > 0);
383 pa_assert(_buffer_size > 0);
385 if (buffer_size)
386 *buffer_size = _buffer_size;
388 if (period_size)
389 *period_size = _period_size;
391 if (use_mmap)
392 *use_mmap = _use_mmap;
394 if (use_tsched)
395 *use_tsched = _use_tsched;
397 ret = 0;
399 snd_pcm_nonblock(pcm_handle, 1);
401 finish:
403 return ret;
406 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) {
407 snd_pcm_sw_params_t *swparams;
408 snd_pcm_uframes_t boundary;
409 int err;
411 pa_assert(pcm);
413 snd_pcm_sw_params_alloca(&swparams);
415 if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
416 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err));
417 return err;
420 if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, 0)) < 0) {
421 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err));
422 return err;
425 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
426 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err));
427 return err;
430 if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
431 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err));
432 return err;
435 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
436 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err));
437 return err;
440 if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
441 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err));
442 return err;
445 if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
446 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
447 return err;
450 if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
451 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err));
452 return err;
455 return 0;
458 snd_pcm_t *pa_alsa_open_by_device_id_auto(
459 const char *dev_id,
460 char **dev,
461 pa_sample_spec *ss,
462 pa_channel_map* map,
463 int mode,
464 snd_pcm_uframes_t *period_size,
465 snd_pcm_uframes_t *buffer_size,
466 snd_pcm_uframes_t tsched_size,
467 pa_bool_t *use_mmap,
468 pa_bool_t *use_tsched,
469 pa_alsa_profile_set *ps,
470 pa_alsa_mapping **mapping) {
472 char *d;
473 snd_pcm_t *pcm_handle;
474 void *state;
475 pa_alsa_mapping *m;
477 pa_assert(dev_id);
478 pa_assert(dev);
479 pa_assert(ss);
480 pa_assert(map);
481 pa_assert(ps);
483 /* First we try to find a device string with a superset of the
484 * requested channel map. We iterate through our device table from
485 * top to bottom and take the first that matches. If we didn't
486 * find a working device that way, we iterate backwards, and check
487 * all devices that do not provide a superset of the requested
488 * channel map.*/
490 PA_HASHMAP_FOREACH(m, ps->mappings, state) {
491 if (!pa_channel_map_superset(&m->channel_map, map))
492 continue;
494 pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
496 pcm_handle = pa_alsa_open_by_device_id_mapping(
497 dev_id,
498 dev,
500 map,
501 mode,
502 period_size,
503 buffer_size,
504 tsched_size,
505 use_mmap,
506 use_tsched,
509 if (pcm_handle) {
510 if (mapping)
511 *mapping = m;
513 return pcm_handle;
517 PA_HASHMAP_FOREACH_BACKWARDS(m, ps->mappings, state) {
518 if (pa_channel_map_superset(&m->channel_map, map))
519 continue;
521 pa_log_debug("Checking for subset %s (%s)", m->name, m->device_strings[0]);
523 pcm_handle = pa_alsa_open_by_device_id_mapping(
524 dev_id,
525 dev,
527 map,
528 mode,
529 period_size,
530 buffer_size,
531 tsched_size,
532 use_mmap,
533 use_tsched,
536 if (pcm_handle) {
537 if (mapping)
538 *mapping = m;
540 return pcm_handle;
544 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
545 d = pa_sprintf_malloc("hw:%s", dev_id);
546 pa_log_debug("Trying %s as last resort...", d);
547 pcm_handle = pa_alsa_open_by_device_string(
549 dev,
551 map,
552 mode,
553 period_size,
554 buffer_size,
555 tsched_size,
556 use_mmap,
557 use_tsched,
558 FALSE);
559 pa_xfree(d);
561 if (pcm_handle && mapping)
562 *mapping = NULL;
564 return pcm_handle;
567 snd_pcm_t *pa_alsa_open_by_device_id_mapping(
568 const char *dev_id,
569 char **dev,
570 pa_sample_spec *ss,
571 pa_channel_map* map,
572 int mode,
573 snd_pcm_uframes_t *period_size,
574 snd_pcm_uframes_t *buffer_size,
575 snd_pcm_uframes_t tsched_size,
576 pa_bool_t *use_mmap,
577 pa_bool_t *use_tsched,
578 pa_alsa_mapping *m) {
580 snd_pcm_t *pcm_handle;
581 pa_sample_spec try_ss;
582 pa_channel_map try_map;
584 pa_assert(dev_id);
585 pa_assert(dev);
586 pa_assert(ss);
587 pa_assert(map);
588 pa_assert(m);
590 try_ss.channels = m->channel_map.channels;
591 try_ss.rate = ss->rate;
592 try_ss.format = ss->format;
593 try_map = m->channel_map;
595 pcm_handle = pa_alsa_open_by_template(
596 m->device_strings,
597 dev_id,
598 dev,
599 &try_ss,
600 &try_map,
601 mode,
602 period_size,
603 buffer_size,
604 tsched_size,
605 use_mmap,
606 use_tsched,
607 TRUE);
609 if (!pcm_handle)
610 return NULL;
612 *ss = try_ss;
613 *map = try_map;
614 pa_assert(map->channels == ss->channels);
616 return pcm_handle;
619 snd_pcm_t *pa_alsa_open_by_device_string(
620 const char *device,
621 char **dev,
622 pa_sample_spec *ss,
623 pa_channel_map* map,
624 int mode,
625 snd_pcm_uframes_t *period_size,
626 snd_pcm_uframes_t *buffer_size,
627 snd_pcm_uframes_t tsched_size,
628 pa_bool_t *use_mmap,
629 pa_bool_t *use_tsched,
630 pa_bool_t require_exact_channel_number) {
632 int err;
633 char *d;
634 snd_pcm_t *pcm_handle;
635 pa_bool_t reformat = FALSE;
637 pa_assert(device);
638 pa_assert(ss);
639 pa_assert(map);
641 d = pa_xstrdup(device);
643 for (;;) {
644 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
646 if ((err = snd_pcm_open(&pcm_handle, d, mode,
647 SND_PCM_NONBLOCK|
648 SND_PCM_NO_AUTO_RESAMPLE|
649 SND_PCM_NO_AUTO_CHANNELS|
650 (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
651 pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
652 goto fail;
655 pa_log_debug("Managed to open %s", d);
657 if ((err = pa_alsa_set_hw_params(
658 pcm_handle,
660 period_size,
661 buffer_size,
662 tsched_size,
663 use_mmap,
664 use_tsched,
665 require_exact_channel_number)) < 0) {
667 if (!reformat) {
668 reformat = TRUE;
670 snd_pcm_close(pcm_handle);
671 continue;
674 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
675 if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
676 char *t;
678 t = pa_sprintf_malloc("plug:%s", d);
679 pa_xfree(d);
680 d = t;
682 reformat = FALSE;
684 snd_pcm_close(pcm_handle);
685 continue;
688 pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
689 snd_pcm_close(pcm_handle);
691 goto fail;
694 if (dev)
695 *dev = d;
696 else
697 pa_xfree(d);
699 if (ss->channels != map->channels)
700 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
702 return pcm_handle;
705 fail:
706 pa_xfree(d);
708 return NULL;
711 snd_pcm_t *pa_alsa_open_by_template(
712 char **template,
713 const char *dev_id,
714 char **dev,
715 pa_sample_spec *ss,
716 pa_channel_map* map,
717 int mode,
718 snd_pcm_uframes_t *period_size,
719 snd_pcm_uframes_t *buffer_size,
720 snd_pcm_uframes_t tsched_size,
721 pa_bool_t *use_mmap,
722 pa_bool_t *use_tsched,
723 pa_bool_t require_exact_channel_number) {
725 snd_pcm_t *pcm_handle;
726 char **i;
728 for (i = template; *i; i++) {
729 char *d;
731 d = pa_replace(*i, "%f", dev_id);
733 pcm_handle = pa_alsa_open_by_device_string(
735 dev,
737 map,
738 mode,
739 period_size,
740 buffer_size,
741 tsched_size,
742 use_mmap,
743 use_tsched,
744 require_exact_channel_number);
746 pa_xfree(d);
748 if (pcm_handle)
749 return pcm_handle;
752 return NULL;
755 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
756 int err;
757 snd_output_t *out;
759 pa_assert(pcm);
761 pa_assert_se(snd_output_buffer_open(&out) == 0);
763 if ((err = snd_pcm_dump(pcm, out)) < 0)
764 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
765 else {
766 char *s = NULL;
767 snd_output_buffer_string(out, &s);
768 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
771 pa_assert_se(snd_output_close(out) == 0);
774 void pa_alsa_dump_status(snd_pcm_t *pcm) {
775 int err;
776 snd_output_t *out;
777 snd_pcm_status_t *status;
778 char *s = NULL;
780 pa_assert(pcm);
782 snd_pcm_status_alloca(&status);
784 if ((err = snd_output_buffer_open(&out)) < 0) {
785 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err));
786 return;
789 if ((err = snd_pcm_status(pcm, status)) < 0) {
790 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err));
791 goto finish;
794 if ((err = snd_pcm_status_dump(status, out)) < 0) {
795 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
796 goto finish;
799 snd_output_buffer_string(out, &s);
800 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
802 finish:
804 snd_output_close(out);
807 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
808 va_list ap;
809 char *alsa_file;
811 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
813 va_start(ap, fmt);
815 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
817 va_end(ap);
819 pa_xfree(alsa_file);
822 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
824 void pa_alsa_refcnt_inc(void) {
825 /* This is not really thread safe, but we do our best */
827 if (pa_atomic_inc(&n_error_handler_installed) == 0)
828 snd_lib_error_set_handler(alsa_error_handler);
831 void pa_alsa_refcnt_dec(void) {
832 int r;
834 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
836 if (r == 1) {
837 snd_lib_error_set_handler(NULL);
838 snd_config_update_free_global();
842 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
843 const char *d, *k;
844 pa_assert(p);
846 if (pa_device_init_description(p))
847 return TRUE;
849 if (!(d = pa_proplist_gets(p, "alsa.card_name")))
850 d = pa_proplist_gets(p, "alsa.name");
852 if (!d)
853 return FALSE;
855 k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
857 if (d && k)
858 pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
859 else if (d)
860 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
862 return FALSE;
865 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
866 char *cn, *lcn, *dn;
868 pa_assert(p);
869 pa_assert(card >= 0);
871 pa_proplist_setf(p, "alsa.card", "%i", card);
873 if (snd_card_get_name(card, &cn) >= 0) {
874 pa_proplist_sets(p, "alsa.card_name", cn);
875 free(cn);
878 if (snd_card_get_longname(card, &lcn) >= 0) {
879 pa_proplist_sets(p, "alsa.long_card_name", lcn);
880 free(lcn);
883 if ((dn = pa_alsa_get_driver_name(card))) {
884 pa_proplist_sets(p, "alsa.driver_name", dn);
885 pa_xfree(dn);
888 #ifdef HAVE_UDEV
889 pa_udev_get_info(card, p);
890 #endif
892 #ifdef HAVE_HAL
893 pa_hal_get_info(c, p, card);
894 #endif
897 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
899 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
900 [SND_PCM_CLASS_GENERIC] = "generic",
901 [SND_PCM_CLASS_MULTI] = "multi",
902 [SND_PCM_CLASS_MODEM] = "modem",
903 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
905 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
906 [SND_PCM_CLASS_GENERIC] = "sound",
907 [SND_PCM_CLASS_MULTI] = NULL,
908 [SND_PCM_CLASS_MODEM] = "modem",
909 [SND_PCM_CLASS_DIGITIZER] = NULL
911 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
912 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
913 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
916 snd_pcm_class_t class;
917 snd_pcm_subclass_t subclass;
918 const char *n, *id, *sdn;
919 int card;
921 pa_assert(p);
922 pa_assert(pcm_info);
924 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
926 if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
927 if (class_table[class])
928 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
929 if (alsa_class_table[class])
930 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
933 if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
934 if (alsa_subclass_table[subclass])
935 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
937 if ((n = snd_pcm_info_get_name(pcm_info)))
938 pa_proplist_sets(p, "alsa.name", n);
940 if ((id = snd_pcm_info_get_id(pcm_info)))
941 pa_proplist_sets(p, "alsa.id", id);
943 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
944 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
945 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
947 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
949 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
950 pa_alsa_init_proplist_card(c, p, card);
953 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
954 snd_pcm_hw_params_t *hwparams;
955 snd_pcm_info_t *info;
956 int bits, err;
958 snd_pcm_hw_params_alloca(&hwparams);
959 snd_pcm_info_alloca(&info);
961 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
962 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
963 else {
965 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
966 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
969 if ((err = snd_pcm_info(pcm, info)) < 0)
970 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
971 else
972 pa_alsa_init_proplist_pcm_info(c, p, info);
975 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
976 int err;
977 snd_ctl_t *ctl;
978 snd_ctl_card_info_t *info;
979 const char *t;
981 pa_assert(p);
983 snd_ctl_card_info_alloca(&info);
985 if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
986 pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));
987 return;
990 if ((err = snd_ctl_card_info(ctl, info)) < 0) {
991 pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
992 snd_ctl_close(ctl);
993 return;
996 if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
997 pa_proplist_sets(p, "alsa.mixer_name", t);
999 if ((t = snd_ctl_card_info_get_components(info)) && *t)
1000 pa_proplist_sets(p, "alsa.components", t);
1002 snd_ctl_close(ctl);
1005 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1006 snd_pcm_state_t state;
1007 int err;
1009 pa_assert(pcm);
1011 if (revents & POLLERR)
1012 pa_log_debug("Got POLLERR from ALSA");
1013 if (revents & POLLNVAL)
1014 pa_log_warn("Got POLLNVAL from ALSA");
1015 if (revents & POLLHUP)
1016 pa_log_warn("Got POLLHUP from ALSA");
1017 if (revents & POLLPRI)
1018 pa_log_warn("Got POLLPRI from ALSA");
1019 if (revents & POLLIN)
1020 pa_log_debug("Got POLLIN from ALSA");
1021 if (revents & POLLOUT)
1022 pa_log_debug("Got POLLOUT from ALSA");
1024 state = snd_pcm_state(pcm);
1025 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1027 /* Try to recover from this error */
1029 switch (state) {
1031 case SND_PCM_STATE_XRUN:
1032 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1033 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1034 return -1;
1036 break;
1038 case SND_PCM_STATE_SUSPENDED:
1039 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
1040 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
1041 return -1;
1043 break;
1045 default:
1047 snd_pcm_drop(pcm);
1049 if ((err = snd_pcm_prepare(pcm)) < 0) {
1050 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
1051 return -1;
1053 break;
1056 return 0;
1059 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1060 int n, err;
1061 struct pollfd *pollfd;
1062 pa_rtpoll_item *item;
1064 pa_assert(pcm);
1066 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1067 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1068 return NULL;
1071 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1072 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1074 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1075 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1076 pa_rtpoll_item_free(item);
1077 return NULL;
1080 return item;
1083 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1084 snd_pcm_sframes_t n;
1085 size_t k;
1087 pa_assert(pcm);
1088 pa_assert(hwbuf_size > 0);
1089 pa_assert(ss);
1091 /* Some ALSA driver expose weird bugs, let's inform the user about
1092 * what is going on */
1094 n = snd_pcm_avail(pcm);
1096 if (n <= 0)
1097 return n;
1099 k = (size_t) n * pa_frame_size(ss);
1101 if (k >= hwbuf_size * 5 ||
1102 k >= pa_bytes_per_second(ss)*10) {
1104 PA_ONCE_BEGIN {
1105 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1106 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1107 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1108 (unsigned long) k,
1109 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1110 pa_strnull(dn));
1111 pa_xfree(dn);
1112 pa_alsa_dump(PA_LOG_ERROR, pcm);
1113 } PA_ONCE_END;
1115 /* Mhmm, let's try not to fail completely */
1116 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1119 return n;
1122 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) {
1123 ssize_t k;
1124 size_t abs_k;
1125 int r;
1127 pa_assert(pcm);
1128 pa_assert(delay);
1129 pa_assert(hwbuf_size > 0);
1130 pa_assert(ss);
1132 /* Some ALSA driver expose weird bugs, let's inform the user about
1133 * what is going on */
1135 if ((r = snd_pcm_delay(pcm, delay)) < 0)
1136 return r;
1138 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1140 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1142 if (abs_k >= hwbuf_size * 5 ||
1143 abs_k >= pa_bytes_per_second(ss)*10) {
1145 PA_ONCE_BEGIN {
1146 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1147 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1148 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1149 (signed long) k,
1150 k < 0 ? "-" : "",
1151 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1152 pa_strnull(dn));
1153 pa_xfree(dn);
1154 pa_alsa_dump(PA_LOG_ERROR, pcm);
1155 } PA_ONCE_END;
1157 /* Mhmm, let's try not to fail completely */
1158 if (k < 0)
1159 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1160 else
1161 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1164 return 0;
1167 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) {
1168 int r;
1169 snd_pcm_uframes_t before;
1170 size_t k;
1172 pa_assert(pcm);
1173 pa_assert(areas);
1174 pa_assert(offset);
1175 pa_assert(frames);
1176 pa_assert(hwbuf_size > 0);
1177 pa_assert(ss);
1179 before = *frames;
1181 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1183 if (r < 0)
1184 return r;
1186 k = (size_t) *frames * pa_frame_size(ss);
1188 if (*frames > before ||
1189 k >= hwbuf_size * 3 ||
1190 k >= pa_bytes_per_second(ss)*10)
1192 PA_ONCE_BEGIN {
1193 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1194 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1195 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1196 (unsigned long) k,
1197 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1198 pa_strnull(dn));
1199 pa_xfree(dn);
1200 pa_alsa_dump(PA_LOG_ERROR, pcm);
1201 } PA_ONCE_END;
1203 return r;
1206 char *pa_alsa_get_driver_name(int card) {
1207 char *t, *m, *n;
1209 pa_assert(card >= 0);
1211 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1212 m = pa_readlink(t);
1213 pa_xfree(t);
1215 if (!m)
1216 return NULL;
1218 n = pa_xstrdup(pa_path_get_filename(m));
1219 pa_xfree(m);
1221 return n;
1224 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1225 int card;
1226 snd_pcm_info_t* info;
1227 snd_pcm_info_alloca(&info);
1229 pa_assert(pcm);
1231 if (snd_pcm_info(pcm, info) < 0)
1232 return NULL;
1234 if ((card = snd_pcm_info_get_card(info)) < 0)
1235 return NULL;
1237 return pa_alsa_get_driver_name(card);
1240 char *pa_alsa_get_reserve_name(const char *device) {
1241 const char *t;
1242 int i;
1244 pa_assert(device);
1246 if ((t = strchr(device, ':')))
1247 device = t+1;
1249 if ((i = snd_card_get_index(device)) < 0) {
1250 int32_t k;
1252 if (pa_atoi(device, &k) < 0)
1253 return NULL;
1255 i = (int) k;
1258 return pa_sprintf_malloc("Audio%i", i);
1261 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1262 snd_pcm_info_t* info;
1263 snd_pcm_info_alloca(&info);
1265 pa_assert(pcm);
1267 if (snd_pcm_info(pcm, info) < 0)
1268 return FALSE;
1270 return snd_pcm_info_get_card(info) >= 0;
1273 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1274 snd_pcm_info_t* info;
1275 snd_pcm_info_alloca(&info);
1277 pa_assert(pcm);
1279 if (snd_pcm_info(pcm, info) < 0)
1280 return FALSE;
1282 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1285 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1287 const char* pa_alsa_strerror(int errnum) {
1288 const char *original = NULL;
1289 char *translated, *t;
1290 char errbuf[128];
1292 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1293 pa_xfree(t);
1295 original = snd_strerror(errnum);
1297 if (!original) {
1298 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1299 original = errbuf;
1302 if (!(translated = pa_locale_to_utf8(original))) {
1303 pa_log_warn("Unable to convert error string to locale, filtering.");
1304 translated = pa_utf8_filter(original);
1307 PA_STATIC_TLS_SET(cstrerror, translated);
1309 return translated;