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
> 0 && tsched_size
> 0 && _periods
> 0) {
237 snd_pcm_uframes_t buffer_size
;
240 /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
241 _period_size
= (snd_pcm_uframes_t
) (((uint64_t) _period_size
* r
) / ss
->rate
);
242 tsched_size
= (snd_pcm_uframes_t
) (((uint64_t) tsched_size
* r
) / ss
->rate
);
247 if ((ret
= snd_pcm_hw_params_get_buffer_size_max(hwparams
, &buffer_size
)) < 0)
248 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret
));
250 pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size
* 1000 / r
);
252 _period_size
= tsched_size
;
256 /* Some ALSA drivers really don't like if we set the buffer
257 * size first and the number of periods second. (which would
258 * make a lot more sense to me) So, follow this rule and
259 * adjust the periods first and the buffer size second */
261 /* First we pass 0 as direction to get exactly what we
262 * asked for. That this is necessary is presumably a bug
263 * in ALSA. All in all this is mostly a hint to ALSA, so
264 * we don't care if this fails. */
268 if (snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &p
, &dir
) < 0) {
271 if (snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &p
, &dir
) < 0) {
274 if ((ret
= snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &p
, &dir
)) < 0)
275 pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret
));
279 /* Now set the buffer size */
280 buffer_size
= _periods
* _period_size
;
281 if ((ret
= snd_pcm_hw_params_set_buffer_size_near(pcm_handle
, hwparams
, &buffer_size
)) < 0)
282 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret
));
285 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0)
289 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, r
);
291 if (ss
->channels
!= c
)
292 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, c
);
295 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
));
297 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0) {
298 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret
));
302 if ((ret
= snd_pcm_hw_params_get_period_size(hwparams
, &_period_size
, &dir
)) < 0 ||
303 (ret
= snd_pcm_hw_params_get_periods(hwparams
, &_periods
, &dir
)) < 0) {
304 pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret
));
308 /* If the sample rate deviates too much, we need to resample */
309 if (r
< ss
->rate
*.95 || r
> ss
->rate
*1.05)
311 ss
->channels
= (uint8_t) c
;
314 pa_assert(_periods
> 0);
315 pa_assert(_period_size
> 0);
321 *period_size
= _period_size
;
324 *use_mmap
= _use_mmap
;
327 *use_tsched
= _use_tsched
;
331 snd_pcm_nonblock(pcm_handle
, 1);
338 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
, snd_pcm_uframes_t avail_min
) {
339 snd_pcm_sw_params_t
*swparams
;
340 snd_pcm_uframes_t boundary
;
345 snd_pcm_sw_params_alloca(&swparams
);
347 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
348 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err
));
352 if ((err
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, 0)) < 0) {
353 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err
));
357 if ((err
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
)) < 0) {
358 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err
));
362 if ((err
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
)) < 0) {
363 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err
));
367 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
)) < 0) {
368 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err
));
372 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
373 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err
));
377 if ((err
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, avail_min
)) < 0) {
378 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err
));
382 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
383 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err
));
390 snd_pcm_t
*pa_alsa_open_by_device_id_auto(
397 snd_pcm_uframes_t
*period_size
,
398 snd_pcm_uframes_t tsched_size
,
400 pa_bool_t
*use_tsched
,
401 pa_alsa_profile_set
*ps
,
402 pa_alsa_mapping
**mapping
) {
405 snd_pcm_t
*pcm_handle
;
414 pa_assert(period_size
);
417 /* First we try to find a device string with a superset of the
418 * requested channel map. We iterate through our device table from
419 * top to bottom and take the first that matches. If we didn't
420 * find a working device that way, we iterate backwards, and check
421 * all devices that do not provide a superset of the requested
424 PA_HASHMAP_FOREACH(m
, ps
->mappings
, state
) {
425 if (!pa_channel_map_superset(&m
->channel_map
, map
))
428 pa_log_debug("Checking for superset %s (%s)", m
->name
, m
->device_strings
[0]);
430 pcm_handle
= pa_alsa_open_by_device_id_mapping(
451 PA_HASHMAP_FOREACH_BACKWARDS(m
, ps
->mappings
, state
) {
452 if (pa_channel_map_superset(&m
->channel_map
, map
))
455 pa_log_debug("Checking for subset %s (%s)", m
->name
, m
->device_strings
[0]);
457 pcm_handle
= pa_alsa_open_by_device_id_mapping(
478 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
479 d
= pa_sprintf_malloc("hw:%s", dev_id
);
480 pa_log_debug("Trying %s as last resort...", d
);
481 pcm_handle
= pa_alsa_open_by_device_string(d
, dev
, ss
, map
, mode
, nfrags
, period_size
, tsched_size
, use_mmap
, use_tsched
, FALSE
);
484 if (pcm_handle
&& mapping
)
490 snd_pcm_t
*pa_alsa_open_by_device_id_mapping(
497 snd_pcm_uframes_t
*period_size
,
498 snd_pcm_uframes_t tsched_size
,
500 pa_bool_t
*use_tsched
,
501 pa_alsa_mapping
*m
) {
503 snd_pcm_t
*pcm_handle
;
504 pa_sample_spec try_ss
;
505 pa_channel_map try_map
;
512 pa_assert(period_size
);
515 try_ss
.channels
= m
->channel_map
.channels
;
516 try_ss
.rate
= ss
->rate
;
517 try_ss
.format
= ss
->format
;
518 try_map
= m
->channel_map
;
520 pcm_handle
= pa_alsa_open_by_template(
539 pa_assert(map
->channels
== ss
->channels
);
544 snd_pcm_t
*pa_alsa_open_by_device_string(
551 snd_pcm_uframes_t
*period_size
,
552 snd_pcm_uframes_t tsched_size
,
554 pa_bool_t
*use_tsched
,
555 pa_bool_t require_exact_channel_number
) {
559 snd_pcm_t
*pcm_handle
;
560 pa_bool_t reformat
= FALSE
;
566 d
= pa_xstrdup(device
);
569 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d
, reformat
? "without" : "with");
571 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
573 SND_PCM_NO_AUTO_RESAMPLE
|
574 SND_PCM_NO_AUTO_CHANNELS
|
575 (reformat
? 0 : SND_PCM_NO_AUTO_FORMAT
))) < 0) {
576 pa_log_info("Error opening PCM device %s: %s", d
, pa_alsa_strerror(err
));
580 pa_log_debug("Managed to open %s", d
);
582 if ((err
= pa_alsa_set_hw_params(pcm_handle
, ss
, nfrags
, period_size
, tsched_size
, use_mmap
, use_tsched
, require_exact_channel_number
)) < 0) {
587 snd_pcm_close(pcm_handle
);
591 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
592 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
595 t
= pa_sprintf_malloc("plug:%s", d
);
601 snd_pcm_close(pcm_handle
);
605 pa_log_info("Failed to set hardware parameters on %s: %s", d
, pa_alsa_strerror(err
));
606 snd_pcm_close(pcm_handle
);
616 if (ss
->channels
!= map
->channels
)
617 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
628 snd_pcm_t
*pa_alsa_open_by_template(
636 snd_pcm_uframes_t
*period_size
,
637 snd_pcm_uframes_t tsched_size
,
639 pa_bool_t
*use_tsched
,
640 pa_bool_t require_exact_channel_number
) {
642 snd_pcm_t
*pcm_handle
;
645 for (i
= template; *i
; i
++) {
648 d
= pa_replace(*i
, "%f", dev_id
);
650 pcm_handle
= pa_alsa_open_by_device_string(
661 require_exact_channel_number
);
672 void pa_alsa_dump(pa_log_level_t level
, snd_pcm_t
*pcm
) {
678 pa_assert_se(snd_output_buffer_open(&out
) == 0);
680 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
681 pa_logl(level
, "snd_pcm_dump(): %s", pa_alsa_strerror(err
));
684 snd_output_buffer_string(out
, &s
);
685 pa_logl(level
, "snd_pcm_dump():\n%s", pa_strnull(s
));
688 pa_assert_se(snd_output_close(out
) == 0);
691 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
694 snd_pcm_status_t
*status
;
699 snd_pcm_status_alloca(&status
);
701 if ((err
= snd_output_buffer_open(&out
)) < 0) {
702 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err
));
706 if ((err
= snd_pcm_status(pcm
, status
)) < 0) {
707 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err
));
711 if ((err
= snd_pcm_status_dump(status
, out
)) < 0) {
712 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err
));
716 snd_output_buffer_string(out
, &s
);
717 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s
));
721 snd_output_close(out
);
724 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
728 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
732 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
739 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
741 void pa_alsa_refcnt_inc(void) {
742 /* This is not really thread safe, but we do our best */
744 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
745 snd_lib_error_set_handler(alsa_error_handler
);
748 void pa_alsa_refcnt_dec(void) {
751 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
754 snd_lib_error_set_handler(NULL
);
755 snd_config_update_free_global();
759 pa_bool_t
pa_alsa_init_description(pa_proplist
*p
) {
763 if (pa_device_init_description(p
))
766 if (!(d
= pa_proplist_gets(p
, "alsa.card_name")))
767 d
= pa_proplist_gets(p
, "alsa.name");
772 k
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
775 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, _("%s %s"), d
, k
);
777 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, d
);
782 void pa_alsa_init_proplist_card(pa_core
*c
, pa_proplist
*p
, int card
) {
786 pa_assert(card
>= 0);
788 pa_proplist_setf(p
, "alsa.card", "%i", card
);
790 if (snd_card_get_name(card
, &cn
) >= 0) {
791 pa_proplist_sets(p
, "alsa.card_name", cn
);
795 if (snd_card_get_longname(card
, &lcn
) >= 0) {
796 pa_proplist_sets(p
, "alsa.long_card_name", lcn
);
800 if ((dn
= pa_alsa_get_driver_name(card
))) {
801 pa_proplist_sets(p
, "alsa.driver_name", dn
);
806 pa_udev_get_info(card
, p
);
810 pa_hal_get_info(c
, p
, card
);
814 void pa_alsa_init_proplist_pcm_info(pa_core
*c
, pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
816 static const char * const alsa_class_table
[SND_PCM_CLASS_LAST
+1] = {
817 [SND_PCM_CLASS_GENERIC
] = "generic",
818 [SND_PCM_CLASS_MULTI
] = "multi",
819 [SND_PCM_CLASS_MODEM
] = "modem",
820 [SND_PCM_CLASS_DIGITIZER
] = "digitizer"
822 static const char * const class_table
[SND_PCM_CLASS_LAST
+1] = {
823 [SND_PCM_CLASS_GENERIC
] = "sound",
824 [SND_PCM_CLASS_MULTI
] = NULL
,
825 [SND_PCM_CLASS_MODEM
] = "modem",
826 [SND_PCM_CLASS_DIGITIZER
] = NULL
828 static const char * const alsa_subclass_table
[SND_PCM_SUBCLASS_LAST
+1] = {
829 [SND_PCM_SUBCLASS_GENERIC_MIX
] = "generic-mix",
830 [SND_PCM_SUBCLASS_MULTI_MIX
] = "multi-mix"
833 snd_pcm_class_t
class;
834 snd_pcm_subclass_t subclass
;
835 const char *n
, *id
, *sdn
;
841 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
843 if ((class = snd_pcm_info_get_class(pcm_info
)) <= SND_PCM_CLASS_LAST
) {
844 if (class_table
[class])
845 pa_proplist_sets(p
, PA_PROP_DEVICE_CLASS
, class_table
[class]);
846 if (alsa_class_table
[class])
847 pa_proplist_sets(p
, "alsa.class", alsa_class_table
[class]);
850 if ((subclass
= snd_pcm_info_get_subclass(pcm_info
)) <= SND_PCM_SUBCLASS_LAST
)
851 if (alsa_subclass_table
[subclass
])
852 pa_proplist_sets(p
, "alsa.subclass", alsa_subclass_table
[subclass
]);
854 if ((n
= snd_pcm_info_get_name(pcm_info
)))
855 pa_proplist_sets(p
, "alsa.name", n
);
857 if ((id
= snd_pcm_info_get_id(pcm_info
)))
858 pa_proplist_sets(p
, "alsa.id", id
);
860 pa_proplist_setf(p
, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info
));
861 if ((sdn
= snd_pcm_info_get_subdevice_name(pcm_info
)))
862 pa_proplist_sets(p
, "alsa.subdevice_name", sdn
);
864 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
866 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0)
867 pa_alsa_init_proplist_card(c
, p
, card
);
870 void pa_alsa_init_proplist_pcm(pa_core
*c
, pa_proplist
*p
, snd_pcm_t
*pcm
) {
871 snd_pcm_hw_params_t
*hwparams
;
872 snd_pcm_info_t
*info
;
875 snd_pcm_hw_params_alloca(&hwparams
);
876 snd_pcm_info_alloca(&info
);
878 if ((err
= snd_pcm_hw_params_current(pcm
, hwparams
)) < 0)
879 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err
));
882 if ((bits
= snd_pcm_hw_params_get_sbits(hwparams
)) >= 0)
883 pa_proplist_setf(p
, "alsa.resolution_bits", "%i", bits
);
886 if ((err
= snd_pcm_info(pcm
, info
)) < 0)
887 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err
));
889 pa_alsa_init_proplist_pcm_info(c
, p
, info
);
892 void pa_alsa_init_proplist_ctl(pa_proplist
*p
, const char *name
) {
895 snd_ctl_card_info_t
*info
;
900 snd_ctl_card_info_alloca(&info
);
902 if ((err
= snd_ctl_open(&ctl
, name
, 0)) < 0) {
903 pa_log_warn("Error opening low-level control device '%s'", name
);
907 if ((err
= snd_ctl_card_info(ctl
, info
)) < 0) {
908 pa_log_warn("Control device %s card info: %s", name
, snd_strerror(err
));
913 if ((t
= snd_ctl_card_info_get_mixername(info
)) && *t
)
914 pa_proplist_sets(p
, "alsa.mixer_name", t
);
916 if ((t
= snd_ctl_card_info_get_components(info
)) && *t
)
917 pa_proplist_sets(p
, "alsa.components", t
);
922 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
923 snd_pcm_state_t state
;
928 if (revents
& POLLERR
)
929 pa_log_debug("Got POLLERR from ALSA");
930 if (revents
& POLLNVAL
)
931 pa_log_warn("Got POLLNVAL from ALSA");
932 if (revents
& POLLHUP
)
933 pa_log_warn("Got POLLHUP from ALSA");
934 if (revents
& POLLPRI
)
935 pa_log_warn("Got POLLPRI from ALSA");
936 if (revents
& POLLIN
)
937 pa_log_debug("Got POLLIN from ALSA");
938 if (revents
& POLLOUT
)
939 pa_log_debug("Got POLLOUT from ALSA");
941 state
= snd_pcm_state(pcm
);
942 pa_log_debug("PCM state is %s", snd_pcm_state_name(state
));
944 /* Try to recover from this error */
948 case SND_PCM_STATE_XRUN
:
949 if ((err
= snd_pcm_recover(pcm
, -EPIPE
, 1)) != 0) {
950 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err
));
955 case SND_PCM_STATE_SUSPENDED
:
956 if ((err
= snd_pcm_recover(pcm
, -ESTRPIPE
, 1)) != 0) {
957 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err
));
966 if ((err
= snd_pcm_prepare(pcm
)) < 0) {
967 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err
));
976 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
978 struct pollfd
*pollfd
;
979 pa_rtpoll_item
*item
;
983 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
984 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n
));
988 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
989 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
991 if ((err
= snd_pcm_poll_descriptors(pcm
, pollfd
, (unsigned) n
)) < 0) {
992 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err
));
993 pa_rtpoll_item_free(item
);
1000 snd_pcm_sframes_t
pa_alsa_safe_avail(snd_pcm_t
*pcm
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1001 snd_pcm_sframes_t n
;
1005 pa_assert(hwbuf_size
> 0);
1008 /* Some ALSA driver expose weird bugs, let's inform the user about
1009 * what is going on */
1011 n
= snd_pcm_avail(pcm
);
1016 k
= (size_t) n
* pa_frame_size(ss
);
1018 if (k
>= hwbuf_size
* 5 ||
1019 k
>= pa_bytes_per_second(ss
)*10) {
1022 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1023 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1024 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1026 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1029 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1032 /* Mhmm, let's try not to fail completely */
1033 n
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1039 int pa_alsa_safe_delay(snd_pcm_t
*pcm
, snd_pcm_sframes_t
*delay
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1046 pa_assert(hwbuf_size
> 0);
1049 /* Some ALSA driver expose weird bugs, let's inform the user about
1050 * what is going on */
1052 if ((r
= snd_pcm_delay(pcm
, delay
)) < 0)
1055 k
= (ssize_t
) *delay
* (ssize_t
) pa_frame_size(ss
);
1057 abs_k
= k
>= 0 ? (size_t) k
: (size_t) -k
;
1059 if (abs_k
>= hwbuf_size
* 5 ||
1060 abs_k
>= pa_bytes_per_second(ss
)*10) {
1063 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1064 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1065 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1068 (unsigned long) (pa_bytes_to_usec(abs_k
, ss
) / PA_USEC_PER_MSEC
),
1071 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1074 /* Mhmm, let's try not to fail completely */
1076 *delay
= -(snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1078 *delay
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1084 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
) {
1086 snd_pcm_uframes_t before
;
1093 pa_assert(hwbuf_size
> 0);
1098 r
= snd_pcm_mmap_begin(pcm
, areas
, offset
, frames
);
1103 k
= (size_t) *frames
* pa_frame_size(ss
);
1105 if (*frames
> before
||
1106 k
>= hwbuf_size
* 3 ||
1107 k
>= pa_bytes_per_second(ss
)*10)
1110 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1111 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1112 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1114 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1117 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1123 char *pa_alsa_get_driver_name(int card
) {
1126 pa_assert(card
>= 0);
1128 t
= pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card
);
1135 n
= pa_xstrdup(pa_path_get_filename(m
));
1141 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t
*pcm
) {
1143 snd_pcm_info_t
* info
;
1144 snd_pcm_info_alloca(&info
);
1148 if (snd_pcm_info(pcm
, info
) < 0)
1151 if ((card
= snd_pcm_info_get_card(info
)) < 0)
1154 return pa_alsa_get_driver_name(card
);
1157 char *pa_alsa_get_reserve_name(const char *device
) {
1163 if ((t
= strchr(device
, ':')))
1166 if ((i
= snd_card_get_index(device
)) < 0) {
1169 if (pa_atoi(device
, &k
) < 0)
1175 return pa_sprintf_malloc("Audio%i", i
);
1178 pa_bool_t
pa_alsa_pcm_is_hw(snd_pcm_t
*pcm
) {
1179 snd_pcm_info_t
* info
;
1180 snd_pcm_info_alloca(&info
);
1184 if (snd_pcm_info(pcm
, info
) < 0)
1187 return snd_pcm_info_get_card(info
) >= 0;
1190 pa_bool_t
pa_alsa_pcm_is_modem(snd_pcm_t
*pcm
) {
1191 snd_pcm_info_t
* info
;
1192 snd_pcm_info_alloca(&info
);
1196 if (snd_pcm_info(pcm
, info
) < 0)
1199 return snd_pcm_info_get_class(info
) == SND_PCM_CLASS_MODEM
;
1202 PA_STATIC_TLS_DECLARE(cstrerror
, pa_xfree
);
1204 const char* pa_alsa_strerror(int errnum
) {
1205 const char *original
= NULL
;
1206 char *translated
, *t
;
1209 if ((t
= PA_STATIC_TLS_GET(cstrerror
)))
1212 original
= snd_strerror(errnum
);
1215 pa_snprintf(errbuf
, sizeof(errbuf
), "Unknown error %i", errnum
);
1219 if (!(translated
= pa_locale_to_utf8(original
))) {
1220 pa_log_warn("Unable to convert error string to locale, filtering.");
1221 translated
= pa_utf8_filter(original
);
1224 PA_STATIC_TLS_SET(cstrerror
, translated
);