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
27 #include <sys/types.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>
46 #include <pulsecore/core-rtclock.h>
48 #include "alsa-util.h"
49 #include "alsa-mixer.h"
56 #include "udev-util.h"
59 static int set_format(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, pa_sample_format_t
*f
) {
61 static const snd_pcm_format_t format_trans
[] = {
62 [PA_SAMPLE_U8
] = SND_PCM_FORMAT_U8
,
63 [PA_SAMPLE_ALAW
] = SND_PCM_FORMAT_A_LAW
,
64 [PA_SAMPLE_ULAW
] = SND_PCM_FORMAT_MU_LAW
,
65 [PA_SAMPLE_S16LE
] = SND_PCM_FORMAT_S16_LE
,
66 [PA_SAMPLE_S16BE
] = SND_PCM_FORMAT_S16_BE
,
67 [PA_SAMPLE_FLOAT32LE
] = SND_PCM_FORMAT_FLOAT_LE
,
68 [PA_SAMPLE_FLOAT32BE
] = SND_PCM_FORMAT_FLOAT_BE
,
69 [PA_SAMPLE_S32LE
] = SND_PCM_FORMAT_S32_LE
,
70 [PA_SAMPLE_S32BE
] = SND_PCM_FORMAT_S32_BE
,
71 [PA_SAMPLE_S24LE
] = SND_PCM_FORMAT_S24_3LE
,
72 [PA_SAMPLE_S24BE
] = SND_PCM_FORMAT_S24_3BE
,
73 [PA_SAMPLE_S24_32LE
] = SND_PCM_FORMAT_S24_LE
,
74 [PA_SAMPLE_S24_32BE
] = SND_PCM_FORMAT_S24_BE
,
77 static const pa_sample_format_t try_order
[] = {
96 pa_assert(pcm_handle
);
100 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
103 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
104 snd_pcm_format_description(format_trans
[*f
]),
105 pa_alsa_strerror(ret
));
107 if (*f
== PA_SAMPLE_FLOAT32BE
)
108 *f
= PA_SAMPLE_FLOAT32LE
;
109 else if (*f
== PA_SAMPLE_FLOAT32LE
)
110 *f
= PA_SAMPLE_FLOAT32BE
;
111 else if (*f
== PA_SAMPLE_S24BE
)
112 *f
= PA_SAMPLE_S24LE
;
113 else if (*f
== PA_SAMPLE_S24LE
)
114 *f
= PA_SAMPLE_S24BE
;
115 else if (*f
== PA_SAMPLE_S24_32BE
)
116 *f
= PA_SAMPLE_S24_32LE
;
117 else if (*f
== PA_SAMPLE_S24_32LE
)
118 *f
= PA_SAMPLE_S24_32BE
;
119 else if (*f
== PA_SAMPLE_S16BE
)
120 *f
= PA_SAMPLE_S16LE
;
121 else if (*f
== PA_SAMPLE_S16LE
)
122 *f
= PA_SAMPLE_S16BE
;
123 else if (*f
== PA_SAMPLE_S32BE
)
124 *f
= PA_SAMPLE_S32LE
;
125 else if (*f
== PA_SAMPLE_S32LE
)
126 *f
= PA_SAMPLE_S32BE
;
130 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
133 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
134 snd_pcm_format_description(format_trans
[*f
]),
135 pa_alsa_strerror(ret
));
139 for (i
= 0; i
< PA_ELEMENTSOF(try_order
); i
++) {
142 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
145 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
146 snd_pcm_format_description(format_trans
[*f
]),
147 pa_alsa_strerror(ret
));
153 static int set_period_size(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, snd_pcm_uframes_t size
) {
157 pa_assert(pcm_handle
);
162 if (snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
) < 0) {
165 if (snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
) < 0) {
168 if ((ret
= snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
)) < 0) {
169 pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret
));
178 static int set_buffer_size(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, snd_pcm_uframes_t size
) {
181 pa_assert(pcm_handle
);
184 if ((ret
= snd_pcm_hw_params_set_buffer_size_near(pcm_handle
, hwparams
, &size
)) < 0) {
185 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret
));
192 /* Set the hardware parameters of the given ALSA device. Returns the
193 * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */
194 int pa_alsa_set_hw_params(
195 snd_pcm_t
*pcm_handle
,
197 snd_pcm_uframes_t
*period_size
,
198 snd_pcm_uframes_t
*buffer_size
,
199 snd_pcm_uframes_t tsched_size
,
201 pa_bool_t
*use_tsched
,
202 pa_bool_t require_exact_channel_number
) {
205 snd_pcm_hw_params_t
*hwparams
, *hwparams_copy
;
207 snd_pcm_uframes_t _period_size
= period_size
? *period_size
: 0;
208 snd_pcm_uframes_t _buffer_size
= buffer_size
? *buffer_size
: 0;
209 pa_bool_t _use_mmap
= use_mmap
&& *use_mmap
;
210 pa_bool_t _use_tsched
= use_tsched
&& *use_tsched
;
211 pa_sample_spec _ss
= *ss
;
213 pa_assert(pcm_handle
);
216 snd_pcm_hw_params_alloca(&hwparams
);
217 snd_pcm_hw_params_alloca(&hwparams_copy
);
219 if ((ret
= snd_pcm_hw_params_any(pcm_handle
, hwparams
)) < 0) {
220 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret
));
224 if ((ret
= snd_pcm_hw_params_set_rate_resample(pcm_handle
, hwparams
, 0)) < 0) {
225 pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret
));
231 if (snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_MMAP_INTERLEAVED
) < 0) {
233 /* mmap() didn't work, fall back to interleaved */
235 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0) {
236 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret
));
243 } else if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0) {
244 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret
));
251 if (!pa_alsa_pcm_is_hw(pcm_handle
))
254 if ((ret
= set_format(pcm_handle
, hwparams
, &_ss
.format
)) < 0)
257 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm_handle
, hwparams
, &_ss
.rate
, NULL
)) < 0) {
258 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret
));
262 /* We ignore very small sampling rate deviations */
263 if (_ss
.rate
>= ss
->rate
*.95 && _ss
.rate
<= ss
->rate
*1.05)
266 if (require_exact_channel_number
) {
267 if ((ret
= snd_pcm_hw_params_set_channels(pcm_handle
, hwparams
, _ss
.channels
)) < 0) {
268 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
272 unsigned int c
= _ss
.channels
;
274 if ((ret
= snd_pcm_hw_params_set_channels_near(pcm_handle
, hwparams
, &c
)) < 0) {
275 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
282 if (_use_tsched
&& tsched_size
> 0) {
283 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) tsched_size
* _ss
.rate
) / ss
->rate
);
284 _period_size
= _buffer_size
;
286 _period_size
= (snd_pcm_uframes_t
) (((uint64_t) _period_size
* _ss
.rate
) / ss
->rate
);
287 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) _buffer_size
* _ss
.rate
) / ss
->rate
);
290 if (_buffer_size
> 0 || _period_size
> 0) {
291 snd_pcm_uframes_t max_frames
= 0;
293 if ((ret
= snd_pcm_hw_params_get_buffer_size_max(hwparams
, &max_frames
)) < 0)
294 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret
));
296 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames
* PA_MSEC_PER_SEC
/ _ss
.rate
));
298 /* Some ALSA drivers really don't like if we set the buffer
299 * size first and the number of periods second. (which would
300 * make a lot more sense to me) So, try a few combinations
301 * before we give up. */
303 if (_buffer_size
> 0 && _period_size
> 0) {
304 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
306 /* First try: set buffer size first, followed by period size */
307 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
308 set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
309 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
310 pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size
, (unsigned long) _period_size
);
314 /* Second try: set period size first, followed by buffer size */
315 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
316 set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
317 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
318 pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size
, (unsigned long) _buffer_size
);
323 if (_buffer_size
> 0) {
324 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
326 /* Third try: set only buffer size */
327 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
328 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
329 pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size
);
334 if (_period_size
> 0) {
335 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
337 /* Fourth try: set only period size */
338 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
339 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
340 pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size
);
346 pa_log_debug("Set neither period nor buffer size.");
348 /* Last chance, set nothing */
349 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0) {
350 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret
));
356 if (ss
->rate
!= _ss
.rate
)
357 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, _ss
.rate
);
359 if (ss
->channels
!= _ss
.channels
)
360 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, _ss
.channels
);
362 if (ss
->format
!= _ss
.format
)
363 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
));
365 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0) {
366 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret
));
370 if ((ret
= snd_pcm_hw_params_current(pcm_handle
, hwparams
)) < 0) {
371 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret
));
375 if ((ret
= snd_pcm_hw_params_get_period_size(hwparams
, &_period_size
, &dir
)) < 0 ||
376 (ret
= snd_pcm_hw_params_get_buffer_size(hwparams
, &_buffer_size
)) < 0) {
377 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret
));
382 ss
->channels
= _ss
.channels
;
383 ss
->format
= _ss
.format
;
385 pa_assert(_period_size
> 0);
386 pa_assert(_buffer_size
> 0);
389 *buffer_size
= _buffer_size
;
392 *period_size
= _period_size
;
395 *use_mmap
= _use_mmap
;
398 *use_tsched
= _use_tsched
;
402 snd_pcm_nonblock(pcm_handle
, 1);
409 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
, snd_pcm_uframes_t avail_min
, pa_bool_t period_event
) {
410 snd_pcm_sw_params_t
*swparams
;
411 snd_pcm_uframes_t boundary
;
416 snd_pcm_sw_params_alloca(&swparams
);
418 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
419 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err
));
423 if ((err
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, period_event
)) < 0) {
424 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err
));
428 if ((err
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
)) < 0) {
429 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err
));
433 if ((err
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
)) < 0) {
434 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err
));
438 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
)) < 0) {
439 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err
));
443 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
444 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err
));
448 if ((err
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, avail_min
)) < 0) {
449 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err
));
453 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
454 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err
));
461 snd_pcm_t
*pa_alsa_open_by_device_id_auto(
467 snd_pcm_uframes_t
*period_size
,
468 snd_pcm_uframes_t
*buffer_size
,
469 snd_pcm_uframes_t tsched_size
,
471 pa_bool_t
*use_tsched
,
472 pa_alsa_profile_set
*ps
,
473 pa_alsa_mapping
**mapping
) {
476 snd_pcm_t
*pcm_handle
;
486 /* First we try to find a device string with a superset of the
487 * requested channel map. We iterate through our device table from
488 * top to bottom and take the first that matches. If we didn't
489 * find a working device that way, we iterate backwards, and check
490 * all devices that do not provide a superset of the requested
493 PA_HASHMAP_FOREACH(m
, ps
->mappings
, state
) {
494 if (!pa_channel_map_superset(&m
->channel_map
, map
))
497 pa_log_debug("Checking for superset %s (%s)", m
->name
, m
->device_strings
[0]);
499 pcm_handle
= pa_alsa_open_by_device_id_mapping(
520 PA_HASHMAP_FOREACH_BACKWARDS(m
, ps
->mappings
, state
) {
521 if (pa_channel_map_superset(&m
->channel_map
, map
))
524 pa_log_debug("Checking for subset %s (%s)", m
->name
, m
->device_strings
[0]);
526 pcm_handle
= pa_alsa_open_by_device_id_mapping(
547 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
548 d
= pa_sprintf_malloc("hw:%s", dev_id
);
549 pa_log_debug("Trying %s as last resort...", d
);
550 pcm_handle
= pa_alsa_open_by_device_string(
564 if (pcm_handle
&& mapping
)
570 snd_pcm_t
*pa_alsa_open_by_device_id_mapping(
576 snd_pcm_uframes_t
*period_size
,
577 snd_pcm_uframes_t
*buffer_size
,
578 snd_pcm_uframes_t tsched_size
,
580 pa_bool_t
*use_tsched
,
581 pa_alsa_mapping
*m
) {
583 snd_pcm_t
*pcm_handle
;
584 pa_sample_spec try_ss
;
585 pa_channel_map try_map
;
593 try_ss
.channels
= m
->channel_map
.channels
;
594 try_ss
.rate
= ss
->rate
;
595 try_ss
.format
= ss
->format
;
596 try_map
= m
->channel_map
;
598 pcm_handle
= pa_alsa_open_by_template(
617 pa_assert(map
->channels
== ss
->channels
);
622 snd_pcm_t
*pa_alsa_open_by_device_string(
628 snd_pcm_uframes_t
*period_size
,
629 snd_pcm_uframes_t
*buffer_size
,
630 snd_pcm_uframes_t tsched_size
,
632 pa_bool_t
*use_tsched
,
633 pa_bool_t require_exact_channel_number
) {
637 snd_pcm_t
*pcm_handle
;
638 pa_bool_t reformat
= FALSE
;
644 d
= pa_xstrdup(device
);
647 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d
, reformat
? "without" : "with");
649 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
651 SND_PCM_NO_AUTO_RESAMPLE
|
652 SND_PCM_NO_AUTO_CHANNELS
|
653 (reformat
? 0 : SND_PCM_NO_AUTO_FORMAT
))) < 0) {
654 pa_log_info("Error opening PCM device %s: %s", d
, pa_alsa_strerror(err
));
658 pa_log_debug("Managed to open %s", d
);
660 if ((err
= pa_alsa_set_hw_params(
668 require_exact_channel_number
)) < 0) {
673 snd_pcm_close(pcm_handle
);
677 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
678 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
681 t
= pa_sprintf_malloc("plug:%s", d
);
687 snd_pcm_close(pcm_handle
);
691 pa_log_info("Failed to set hardware parameters on %s: %s", d
, pa_alsa_strerror(err
));
692 snd_pcm_close(pcm_handle
);
702 if (ss
->channels
!= map
->channels
)
703 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
714 snd_pcm_t
*pa_alsa_open_by_template(
721 snd_pcm_uframes_t
*period_size
,
722 snd_pcm_uframes_t
*buffer_size
,
723 snd_pcm_uframes_t tsched_size
,
725 pa_bool_t
*use_tsched
,
726 pa_bool_t require_exact_channel_number
) {
728 snd_pcm_t
*pcm_handle
;
731 for (i
= template; *i
; i
++) {
734 d
= pa_replace(*i
, "%f", dev_id
);
736 pcm_handle
= pa_alsa_open_by_device_string(
747 require_exact_channel_number
);
758 void pa_alsa_dump(pa_log_level_t level
, snd_pcm_t
*pcm
) {
764 pa_assert_se(snd_output_buffer_open(&out
) == 0);
766 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
767 pa_logl(level
, "snd_pcm_dump(): %s", pa_alsa_strerror(err
));
770 snd_output_buffer_string(out
, &s
);
771 pa_logl(level
, "snd_pcm_dump():\n%s", pa_strnull(s
));
774 pa_assert_se(snd_output_close(out
) == 0);
777 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
780 snd_pcm_status_t
*status
;
785 snd_pcm_status_alloca(&status
);
787 if ((err
= snd_output_buffer_open(&out
)) < 0) {
788 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err
));
792 if ((err
= snd_pcm_status(pcm
, status
)) < 0) {
793 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err
));
797 if ((err
= snd_pcm_status_dump(status
, out
)) < 0) {
798 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err
));
802 snd_output_buffer_string(out
, &s
);
803 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s
));
807 snd_output_close(out
);
810 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
814 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
818 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
825 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
827 void pa_alsa_refcnt_inc(void) {
828 /* This is not really thread safe, but we do our best */
830 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
831 snd_lib_error_set_handler(alsa_error_handler
);
834 void pa_alsa_refcnt_dec(void) {
837 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
840 snd_lib_error_set_handler(NULL
);
841 snd_config_update_free_global();
845 pa_bool_t
pa_alsa_init_description(pa_proplist
*p
) {
849 if (pa_device_init_description(p
))
852 if (!(d
= pa_proplist_gets(p
, "alsa.card_name")))
853 d
= pa_proplist_gets(p
, "alsa.name");
858 k
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
861 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, _("%s %s"), d
, k
);
863 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, d
);
868 void pa_alsa_init_proplist_card(pa_core
*c
, pa_proplist
*p
, int card
) {
872 pa_assert(card
>= 0);
874 pa_proplist_setf(p
, "alsa.card", "%i", card
);
876 if (snd_card_get_name(card
, &cn
) >= 0) {
877 pa_proplist_sets(p
, "alsa.card_name", pa_strip(cn
));
881 if (snd_card_get_longname(card
, &lcn
) >= 0) {
882 pa_proplist_sets(p
, "alsa.long_card_name", pa_strip(lcn
));
886 if ((dn
= pa_alsa_get_driver_name(card
))) {
887 pa_proplist_sets(p
, "alsa.driver_name", dn
);
892 pa_udev_get_info(card
, p
);
896 pa_hal_get_info(c
, p
, card
);
900 void pa_alsa_init_proplist_pcm_info(pa_core
*c
, pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
902 static const char * const alsa_class_table
[SND_PCM_CLASS_LAST
+1] = {
903 [SND_PCM_CLASS_GENERIC
] = "generic",
904 [SND_PCM_CLASS_MULTI
] = "multi",
905 [SND_PCM_CLASS_MODEM
] = "modem",
906 [SND_PCM_CLASS_DIGITIZER
] = "digitizer"
908 static const char * const class_table
[SND_PCM_CLASS_LAST
+1] = {
909 [SND_PCM_CLASS_GENERIC
] = "sound",
910 [SND_PCM_CLASS_MULTI
] = NULL
,
911 [SND_PCM_CLASS_MODEM
] = "modem",
912 [SND_PCM_CLASS_DIGITIZER
] = NULL
914 static const char * const alsa_subclass_table
[SND_PCM_SUBCLASS_LAST
+1] = {
915 [SND_PCM_SUBCLASS_GENERIC_MIX
] = "generic-mix",
916 [SND_PCM_SUBCLASS_MULTI_MIX
] = "multi-mix"
919 snd_pcm_class_t
class;
920 snd_pcm_subclass_t subclass
;
921 const char *n
, *id
, *sdn
;
927 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
929 if ((class = snd_pcm_info_get_class(pcm_info
)) <= SND_PCM_CLASS_LAST
) {
930 if (class_table
[class])
931 pa_proplist_sets(p
, PA_PROP_DEVICE_CLASS
, class_table
[class]);
932 if (alsa_class_table
[class])
933 pa_proplist_sets(p
, "alsa.class", alsa_class_table
[class]);
936 if ((subclass
= snd_pcm_info_get_subclass(pcm_info
)) <= SND_PCM_SUBCLASS_LAST
)
937 if (alsa_subclass_table
[subclass
])
938 pa_proplist_sets(p
, "alsa.subclass", alsa_subclass_table
[subclass
]);
940 if ((n
= snd_pcm_info_get_name(pcm_info
))) {
941 char *t
= pa_xstrdup(n
);
942 pa_proplist_sets(p
, "alsa.name", pa_strip(t
));
946 if ((id
= snd_pcm_info_get_id(pcm_info
)))
947 pa_proplist_sets(p
, "alsa.id", id
);
949 pa_proplist_setf(p
, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info
));
950 if ((sdn
= snd_pcm_info_get_subdevice_name(pcm_info
)))
951 pa_proplist_sets(p
, "alsa.subdevice_name", sdn
);
953 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
955 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0)
956 pa_alsa_init_proplist_card(c
, p
, card
);
959 void pa_alsa_init_proplist_pcm(pa_core
*c
, pa_proplist
*p
, snd_pcm_t
*pcm
) {
960 snd_pcm_hw_params_t
*hwparams
;
961 snd_pcm_info_t
*info
;
964 snd_pcm_hw_params_alloca(&hwparams
);
965 snd_pcm_info_alloca(&info
);
967 if ((err
= snd_pcm_hw_params_current(pcm
, hwparams
)) < 0)
968 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err
));
971 if ((bits
= snd_pcm_hw_params_get_sbits(hwparams
)) >= 0)
972 pa_proplist_setf(p
, "alsa.resolution_bits", "%i", bits
);
975 if ((err
= snd_pcm_info(pcm
, info
)) < 0)
976 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err
));
978 pa_alsa_init_proplist_pcm_info(c
, p
, info
);
981 void pa_alsa_init_proplist_ctl(pa_proplist
*p
, const char *name
) {
984 snd_ctl_card_info_t
*info
;
989 snd_ctl_card_info_alloca(&info
);
991 if ((err
= snd_ctl_open(&ctl
, name
, 0)) < 0) {
992 pa_log_warn("Error opening low-level control device '%s': %s", name
, snd_strerror(err
));
996 if ((err
= snd_ctl_card_info(ctl
, info
)) < 0) {
997 pa_log_warn("Control device %s card info: %s", name
, snd_strerror(err
));
1002 if ((t
= snd_ctl_card_info_get_mixername(info
)) && *t
)
1003 pa_proplist_sets(p
, "alsa.mixer_name", t
);
1005 if ((t
= snd_ctl_card_info_get_components(info
)) && *t
)
1006 pa_proplist_sets(p
, "alsa.components", t
);
1011 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
1012 snd_pcm_state_t state
;
1017 if (revents
& POLLERR
)
1018 pa_log_debug("Got POLLERR from ALSA");
1019 if (revents
& POLLNVAL
)
1020 pa_log_warn("Got POLLNVAL from ALSA");
1021 if (revents
& POLLHUP
)
1022 pa_log_warn("Got POLLHUP from ALSA");
1023 if (revents
& POLLPRI
)
1024 pa_log_warn("Got POLLPRI from ALSA");
1025 if (revents
& POLLIN
)
1026 pa_log_debug("Got POLLIN from ALSA");
1027 if (revents
& POLLOUT
)
1028 pa_log_debug("Got POLLOUT from ALSA");
1030 state
= snd_pcm_state(pcm
);
1031 pa_log_debug("PCM state is %s", snd_pcm_state_name(state
));
1033 /* Try to recover from this error */
1037 case SND_PCM_STATE_XRUN
:
1038 if ((err
= snd_pcm_recover(pcm
, -EPIPE
, 1)) != 0) {
1039 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err
));
1044 case SND_PCM_STATE_SUSPENDED
:
1045 if ((err
= snd_pcm_recover(pcm
, -ESTRPIPE
, 1)) != 0) {
1046 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err
));
1055 if ((err
= snd_pcm_prepare(pcm
)) < 0) {
1056 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err
));
1065 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
1067 struct pollfd
*pollfd
;
1068 pa_rtpoll_item
*item
;
1072 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
1073 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n
));
1077 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
1078 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
1080 if ((err
= snd_pcm_poll_descriptors(pcm
, pollfd
, (unsigned) n
)) < 0) {
1081 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err
));
1082 pa_rtpoll_item_free(item
);
1089 snd_pcm_sframes_t
pa_alsa_safe_avail(snd_pcm_t
*pcm
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1090 snd_pcm_sframes_t n
;
1094 pa_assert(hwbuf_size
> 0);
1097 /* Some ALSA driver expose weird bugs, let's inform the user about
1098 * what is going on */
1100 n
= snd_pcm_avail(pcm
);
1105 k
= (size_t) n
* pa_frame_size(ss
);
1107 if (k
>= hwbuf_size
* 5 ||
1108 k
>= pa_bytes_per_second(ss
)*10) {
1111 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1112 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1113 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1115 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1118 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1121 /* Mhmm, let's try not to fail completely */
1122 n
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1128 int pa_alsa_safe_delay(snd_pcm_t
*pcm
, snd_pcm_sframes_t
*delay
, size_t hwbuf_size
, const pa_sample_spec
*ss
, pa_bool_t capture
) {
1132 snd_pcm_sframes_t avail
= 0;
1136 pa_assert(hwbuf_size
> 0);
1139 /* Some ALSA driver expose weird bugs, let's inform the user about
1140 * what is going on. We're going to get both the avail and delay values so
1141 * that we can compare and check them for capture */
1143 if ((r
= snd_pcm_avail_delay(pcm
, &avail
, delay
)) < 0)
1146 k
= (ssize_t
) *delay
* (ssize_t
) pa_frame_size(ss
);
1148 abs_k
= k
>= 0 ? (size_t) k
: (size_t) -k
;
1150 if (abs_k
>= hwbuf_size
* 5 ||
1151 abs_k
>= pa_bytes_per_second(ss
)*10) {
1154 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1155 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1156 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1159 (unsigned long) (pa_bytes_to_usec(abs_k
, ss
) / PA_USEC_PER_MSEC
),
1162 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1165 /* Mhmm, let's try not to fail completely */
1167 *delay
= -(snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1169 *delay
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1173 abs_k
= (size_t) avail
* pa_frame_size(ss
);
1175 if (abs_k
>= hwbuf_size
* 5 ||
1176 abs_k
>= pa_bytes_per_second(ss
)*10) {
1179 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1180 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1181 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1183 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1186 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1189 /* Mhmm, let's try not to fail completely */
1190 avail
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1193 if (*delay
< avail
) {
1195 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1196 pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
1197 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1198 (unsigned long) *delay
,
1199 (unsigned long) avail
,
1202 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1213 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
) {
1215 snd_pcm_uframes_t before
;
1222 pa_assert(hwbuf_size
> 0);
1227 r
= snd_pcm_mmap_begin(pcm
, areas
, offset
, frames
);
1232 k
= (size_t) *frames
* pa_frame_size(ss
);
1234 if (*frames
> before
||
1235 k
>= hwbuf_size
* 3 ||
1236 k
>= pa_bytes_per_second(ss
)*10)
1239 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1240 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1241 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1243 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1246 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1252 char *pa_alsa_get_driver_name(int card
) {
1255 pa_assert(card
>= 0);
1257 t
= pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card
);
1264 n
= pa_xstrdup(pa_path_get_filename(m
));
1270 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t
*pcm
) {
1272 snd_pcm_info_t
* info
;
1273 snd_pcm_info_alloca(&info
);
1277 if (snd_pcm_info(pcm
, info
) < 0)
1280 if ((card
= snd_pcm_info_get_card(info
)) < 0)
1283 return pa_alsa_get_driver_name(card
);
1286 char *pa_alsa_get_reserve_name(const char *device
) {
1292 if ((t
= strchr(device
, ':')))
1295 if ((i
= snd_card_get_index(device
)) < 0) {
1298 if (pa_atoi(device
, &k
) < 0)
1304 return pa_sprintf_malloc("Audio%i", i
);
1307 pa_bool_t
pa_alsa_pcm_is_hw(snd_pcm_t
*pcm
) {
1308 snd_pcm_info_t
* info
;
1309 snd_pcm_info_alloca(&info
);
1313 if (snd_pcm_info(pcm
, info
) < 0)
1316 return snd_pcm_info_get_card(info
) >= 0;
1319 pa_bool_t
pa_alsa_pcm_is_modem(snd_pcm_t
*pcm
) {
1320 snd_pcm_info_t
* info
;
1321 snd_pcm_info_alloca(&info
);
1325 if (snd_pcm_info(pcm
, info
) < 0)
1328 return snd_pcm_info_get_class(info
) == SND_PCM_CLASS_MODEM
;
1331 PA_STATIC_TLS_DECLARE(cstrerror
, pa_xfree
);
1333 const char* pa_alsa_strerror(int errnum
) {
1334 const char *original
= NULL
;
1335 char *translated
, *t
;
1338 if ((t
= PA_STATIC_TLS_GET(cstrerror
)))
1341 original
= snd_strerror(errnum
);
1344 pa_snprintf(errbuf
, sizeof(errbuf
), "Unknown error %i", errnum
);
1348 if (!(translated
= pa_locale_to_utf8(original
))) {
1349 pa_log_warn("Unable to convert error string to locale, filtering.");
1350 translated
= pa_utf8_filter(original
);
1353 PA_STATIC_TLS_SET(cstrerror
, translated
);
1358 pa_bool_t
pa_alsa_may_tsched(pa_bool_t want
) {
1363 if (!pa_rtclock_hrtimer()) {
1364 /* We cannot depend on being woken up in time when the timers
1365 are inaccurate, so let's fallback to classic IO based playback
1367 pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1370 if (pa_running_in_vm()) {
1371 /* We cannot depend on being woken up when we ask for in a VM,
1372 * so let's fallback to classic IO based playback then. */
1373 pa_log_notice("Disabling timer-based scheduling because running inside a VM.");