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>
47 #include "alsa-util.h"
48 #include "alsa-mixer.h"
55 #include "udev-util.h"
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
[] = {
95 pa_assert(pcm_handle
);
98 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
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
));
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
;
128 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
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
));
137 for (i
= 0; i
< PA_ELEMENTSOF(try_order
); i
++) {
140 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
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
));
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
,
157 snd_pcm_uframes_t
*period_size
,
158 snd_pcm_uframes_t tsched_size
,
160 pa_bool_t
*use_tsched
,
161 pa_bool_t require_exact_channel_number
) {
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
;
174 pa_assert(pcm_handle
);
177 snd_pcm_hw_params_alloca(&hwparams
);
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
));
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
));
191 if (snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_MMAP_INTERLEAVED
) < 0) {
193 /* mmap() didn't work, fall back to interleaved */
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
));
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
));
211 if ((ret
= set_format(pcm_handle
, hwparams
, &f
)) < 0)
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
));
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
));
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
));
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
));
236 if (_period_size
&& tsched_size
&& _periods
) {
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
);
243 snd_pcm_uframes_t buffer_size
= 0;
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
));
248 pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size
* 1000 / r
);
250 _period_size
= tsched_size
;
254 if (_period_size
> 0 && _periods
> 0) {
255 snd_pcm_uframes_t buffer_size
;
257 buffer_size
= _periods
* _period_size
;
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
));
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. */
271 if (snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &_periods
, &dir
) < 0) {
273 if (snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &_periods
, &dir
) < 0) {
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
));
282 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0)
286 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, r
);
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
);
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
));
294 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0) {
295 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret
));
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
));
305 /* If the sample rate deviates too much, we need to resample */
306 if (r
< ss
->rate
*.95 || r
> ss
->rate
*1.05)
308 ss
->channels
= (uint8_t) c
;
311 pa_assert(_periods
> 0);
312 pa_assert(_period_size
> 0);
318 *period_size
= _period_size
;
321 *use_mmap
= _use_mmap
;
324 *use_tsched
= _use_tsched
;
328 snd_pcm_nonblock(pcm_handle
, 1);
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
;
342 snd_pcm_sw_params_alloca(&swparams
);
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
387 snd_pcm_t
*pa_alsa_open_by_device_id_auto(
394 snd_pcm_uframes_t
*period_size
,
395 snd_pcm_uframes_t tsched_size
,
397 pa_bool_t
*use_tsched
,
398 pa_alsa_profile_set
*ps
,
399 pa_alsa_mapping
**mapping
) {
402 snd_pcm_t
*pcm_handle
;
411 pa_assert(period_size
);
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
421 PA_HASHMAP_FOREACH(m
, ps
->mappings
, state
) {
422 if (!pa_channel_map_superset(&m
->channel_map
, map
))
425 pa_log_debug("Checking for superset %s (%s)", m
->name
, m
->device_strings
[0]);
427 pcm_handle
= pa_alsa_open_by_device_id_mapping(
448 PA_HASHMAP_FOREACH_BACKWARDS(m
, ps
->mappings
, state
) {
449 if (pa_channel_map_superset(&m
->channel_map
, map
))
452 pa_log_debug("Checking for subset %s (%s)", m
->name
, m
->device_strings
[0]);
454 pcm_handle
= pa_alsa_open_by_device_id_mapping(
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
);
481 if (pcm_handle
&& mapping
)
487 snd_pcm_t
*pa_alsa_open_by_device_id_mapping(
494 snd_pcm_uframes_t
*period_size
,
495 snd_pcm_uframes_t tsched_size
,
497 pa_bool_t
*use_tsched
,
498 pa_alsa_mapping
*m
) {
500 snd_pcm_t
*pcm_handle
;
501 pa_sample_spec try_ss
;
502 pa_channel_map try_map
;
509 pa_assert(period_size
);
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
;
517 pcm_handle
= pa_alsa_open_by_template(
536 pa_assert(map
->channels
== ss
->channels
);
541 snd_pcm_t
*pa_alsa_open_by_device_string(
548 snd_pcm_uframes_t
*period_size
,
549 snd_pcm_uframes_t tsched_size
,
551 pa_bool_t
*use_tsched
,
552 pa_bool_t require_exact_channel_number
) {
556 snd_pcm_t
*pcm_handle
;
557 pa_bool_t reformat
= FALSE
;
563 d
= pa_xstrdup(device
);
566 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d
, reformat
? "without" : "with");
568 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
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
));
577 pa_log_debug("Managed to open %s", d
);
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) {
584 snd_pcm_close(pcm_handle
);
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:")) {
592 t
= pa_sprintf_malloc("plug:%s", d
);
598 snd_pcm_close(pcm_handle
);
602 pa_log_info("Failed to set hardware parameters on %s: %s", d
, pa_alsa_strerror(err
));
603 snd_pcm_close(pcm_handle
);
613 if (ss
->channels
!= map
->channels
)
614 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
625 snd_pcm_t
*pa_alsa_open_by_template(
633 snd_pcm_uframes_t
*period_size
,
634 snd_pcm_uframes_t tsched_size
,
636 pa_bool_t
*use_tsched
,
637 pa_bool_t require_exact_channel_number
) {
639 snd_pcm_t
*pcm_handle
;
642 for (i
= template; *i
; i
++) {
645 d
= pa_replace(*i
, "%f", dev_id
);
647 pcm_handle
= pa_alsa_open_by_device_string(
658 require_exact_channel_number
);
669 void pa_alsa_dump(pa_log_level_t level
, snd_pcm_t
*pcm
) {
675 pa_assert_se(snd_output_buffer_open(&out
) == 0);
677 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
678 pa_logl(level
, "snd_pcm_dump(): %s", pa_alsa_strerror(err
));
681 snd_output_buffer_string(out
, &s
);
682 pa_logl(level
, "snd_pcm_dump():\n%s", pa_strnull(s
));
685 pa_assert_se(snd_output_close(out
) == 0);
688 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
691 snd_pcm_status_t
*status
;
696 snd_pcm_status_alloca(&status
);
698 if ((err
= snd_output_buffer_open(&out
)) < 0) {
699 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err
));
703 if ((err
= snd_pcm_status(pcm
, status
)) < 0) {
704 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err
));
708 if ((err
= snd_pcm_status_dump(status
, out
)) < 0) {
709 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err
));
713 snd_output_buffer_string(out
, &s
);
714 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s
));
718 snd_output_close(out
);
721 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
725 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
729 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
736 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
738 void pa_alsa_refcnt_inc(void) {
739 /* This is not really thread safe, but we do our best */
741 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
742 snd_lib_error_set_handler(alsa_error_handler
);
745 void pa_alsa_refcnt_dec(void) {
748 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
751 snd_lib_error_set_handler(NULL
);
752 snd_config_update_free_global();
756 pa_bool_t
pa_alsa_init_description(pa_proplist
*p
) {
760 if (pa_device_init_description(p
))
763 if (!(d
= pa_proplist_gets(p
, "alsa.card_name")))
764 d
= pa_proplist_gets(p
, "alsa.name");
769 k
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
772 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, _("%s %s"), d
, k
);
774 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, d
);
779 void pa_alsa_init_proplist_card(pa_core
*c
, pa_proplist
*p
, int card
) {
783 pa_assert(card
>= 0);
785 pa_proplist_setf(p
, "alsa.card", "%i", card
);
787 if (snd_card_get_name(card
, &cn
) >= 0) {
788 pa_proplist_sets(p
, "alsa.card_name", cn
);
792 if (snd_card_get_longname(card
, &lcn
) >= 0) {
793 pa_proplist_sets(p
, "alsa.long_card_name", lcn
);
797 if ((dn
= pa_alsa_get_driver_name(card
))) {
798 pa_proplist_sets(p
, "alsa.driver_name", dn
);
803 pa_udev_get_info(card
, p
);
807 pa_hal_get_info(c
, p
, card
);
811 void pa_alsa_init_proplist_pcm_info(pa_core
*c
, pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
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"
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
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"
830 snd_pcm_class_t
class;
831 snd_pcm_subclass_t subclass
;
832 const char *n
, *id
, *sdn
;
838 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
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]);
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
]);
851 if ((n
= snd_pcm_info_get_name(pcm_info
)))
852 pa_proplist_sets(p
, "alsa.name", n
);
854 if ((id
= snd_pcm_info_get_id(pcm_info
)))
855 pa_proplist_sets(p
, "alsa.id", id
);
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
);
861 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
863 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0)
864 pa_alsa_init_proplist_card(c
, p
, card
);
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
;
872 snd_pcm_hw_params_alloca(&hwparams
);
873 snd_pcm_info_alloca(&info
);
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
));
879 if ((bits
= snd_pcm_hw_params_get_sbits(hwparams
)) >= 0)
880 pa_proplist_setf(p
, "alsa.resolution_bits", "%i", bits
);
883 if ((err
= snd_pcm_info(pcm
, info
)) < 0)
884 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err
));
886 pa_alsa_init_proplist_pcm_info(c
, p
, info
);
889 void pa_alsa_init_proplist_ctl(pa_proplist
*p
, const char *name
) {
892 snd_ctl_card_info_t
*info
;
897 snd_ctl_card_info_alloca(&info
);
899 if ((err
= snd_ctl_open(&ctl
, name
, 0)) < 0) {
900 pa_log_warn("Error opening low-level control device '%s'", name
);
904 if ((err
= snd_ctl_card_info(ctl
, info
)) < 0) {
905 pa_log_warn("Control device %s card info: %s", name
, snd_strerror(err
));
910 if ((t
= snd_ctl_card_info_get_mixername(info
)) && *t
)
911 pa_proplist_sets(p
, "alsa.mixer_name", t
);
913 if ((t
= snd_ctl_card_info_get_components(info
)) && *t
)
914 pa_proplist_sets(p
, "alsa.components", t
);
919 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
920 snd_pcm_state_t state
;
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");
938 state
= snd_pcm_state(pcm
);
939 pa_log_debug("PCM state is %s", snd_pcm_state_name(state
));
941 /* Try to recover from this error */
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
));
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
));
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
));
973 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
975 struct pollfd
*pollfd
;
976 pa_rtpoll_item
*item
;
980 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
981 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n
));
985 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
986 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
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
);
997 snd_pcm_sframes_t
pa_alsa_safe_avail(snd_pcm_t
*pcm
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1002 pa_assert(hwbuf_size
> 0);
1005 /* Some ALSA driver expose weird bugs, let's inform the user about
1006 * what is going on */
1008 n
= snd_pcm_avail(pcm
);
1013 k
= (size_t) n
* pa_frame_size(ss
);
1015 if (k
>= hwbuf_size
* 5 ||
1016 k
>= pa_bytes_per_second(ss
)*10) {
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."),
1023 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1026 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1029 /* Mhmm, let's try not to fail completely */
1030 n
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1036 int pa_alsa_safe_delay(snd_pcm_t
*pcm
, snd_pcm_sframes_t
*delay
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1043 pa_assert(hwbuf_size
> 0);
1046 /* Some ALSA driver expose weird bugs, let's inform the user about
1047 * what is going on */
1049 if ((r
= snd_pcm_delay(pcm
, delay
)) < 0)
1052 k
= (ssize_t
) *delay
* (ssize_t
) pa_frame_size(ss
);
1054 abs_k
= k
>= 0 ? (size_t) k
: (size_t) -k
;
1056 if (abs_k
>= hwbuf_size
* 5 ||
1057 abs_k
>= pa_bytes_per_second(ss
)*10) {
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."),
1065 (unsigned long) (pa_bytes_to_usec(abs_k
, ss
) / PA_USEC_PER_MSEC
),
1068 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1071 /* Mhmm, let's try not to fail completely */
1073 *delay
= -(snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1075 *delay
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
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
) {
1083 snd_pcm_uframes_t before
;
1090 pa_assert(hwbuf_size
> 0);
1095 r
= snd_pcm_mmap_begin(pcm
, areas
, offset
, frames
);
1100 k
= (size_t) *frames
* pa_frame_size(ss
);
1102 if (*frames
> before
||
1103 k
>= hwbuf_size
* 3 ||
1104 k
>= pa_bytes_per_second(ss
)*10)
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."),
1111 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1114 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1120 char *pa_alsa_get_driver_name(int card
) {
1123 pa_assert(card
>= 0);
1125 t
= pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card
);
1132 n
= pa_xstrdup(pa_path_get_filename(m
));
1138 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t
*pcm
) {
1140 snd_pcm_info_t
* info
;
1141 snd_pcm_info_alloca(&info
);
1145 if (snd_pcm_info(pcm
, info
) < 0)
1148 if ((card
= snd_pcm_info_get_card(info
)) < 0)
1151 return pa_alsa_get_driver_name(card
);
1154 char *pa_alsa_get_reserve_name(const char *device
) {
1160 if ((t
= strchr(device
, ':')))
1163 if ((i
= snd_card_get_index(device
)) < 0) {
1166 if (pa_atoi(device
, &k
) < 0)
1172 return pa_sprintf_malloc("Audio%i", i
);
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
);
1181 if (snd_pcm_info(pcm
, info
) < 0)
1184 return snd_pcm_info_get_card(info
) >= 0;
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
);
1193 if (snd_pcm_info(pcm
, info
) < 0)
1196 return snd_pcm_info_get_class(info
) == SND_PCM_CLASS_MODEM
;
1199 PA_STATIC_TLS_DECLARE(cstrerror
, pa_xfree
);
1201 const char* pa_alsa_strerror(int errnum
) {
1202 const char *original
= NULL
;
1203 char *translated
, *t
;
1206 if ((t
= PA_STATIC_TLS_GET(cstrerror
)))
1209 original
= snd_strerror(errnum
);
1212 pa_snprintf(errbuf
, sizeof(errbuf
), "Unknown error %i", errnum
);
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
);
1221 PA_STATIC_TLS_SET(cstrerror
, translated
);