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>
28 #include <asoundlib.h>
30 #include <pulse/sample.h>
31 #include <pulse/xmalloc.h>
32 #include <pulse/timeval.h>
33 #include <pulse/util.h>
34 #include <pulse/utf8.h>
36 #include <pulsecore/i18n.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/atomic.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/thread.h>
43 #include <pulsecore/conf-parser.h>
44 #include <pulsecore/core-rtclock.h>
46 #include "alsa-util.h"
47 #include "alsa-mixer.h"
50 #include "udev-util.h"
53 static int set_format(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, pa_sample_format_t
*f
) {
55 static const snd_pcm_format_t format_trans
[] = {
56 [PA_SAMPLE_U8
] = SND_PCM_FORMAT_U8
,
57 [PA_SAMPLE_ALAW
] = SND_PCM_FORMAT_A_LAW
,
58 [PA_SAMPLE_ULAW
] = SND_PCM_FORMAT_MU_LAW
,
59 [PA_SAMPLE_S16LE
] = SND_PCM_FORMAT_S16_LE
,
60 [PA_SAMPLE_S16BE
] = SND_PCM_FORMAT_S16_BE
,
61 [PA_SAMPLE_FLOAT32LE
] = SND_PCM_FORMAT_FLOAT_LE
,
62 [PA_SAMPLE_FLOAT32BE
] = SND_PCM_FORMAT_FLOAT_BE
,
63 [PA_SAMPLE_S32LE
] = SND_PCM_FORMAT_S32_LE
,
64 [PA_SAMPLE_S32BE
] = SND_PCM_FORMAT_S32_BE
,
65 [PA_SAMPLE_S24LE
] = SND_PCM_FORMAT_S24_3LE
,
66 [PA_SAMPLE_S24BE
] = SND_PCM_FORMAT_S24_3BE
,
67 [PA_SAMPLE_S24_32LE
] = SND_PCM_FORMAT_S24_LE
,
68 [PA_SAMPLE_S24_32BE
] = SND_PCM_FORMAT_S24_BE
,
71 static const pa_sample_format_t try_order
[] = {
90 pa_assert(pcm_handle
);
94 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
97 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
98 snd_pcm_format_description(format_trans
[*f
]),
99 pa_alsa_strerror(ret
));
101 if (*f
== PA_SAMPLE_FLOAT32BE
)
102 *f
= PA_SAMPLE_FLOAT32LE
;
103 else if (*f
== PA_SAMPLE_FLOAT32LE
)
104 *f
= PA_SAMPLE_FLOAT32BE
;
105 else if (*f
== PA_SAMPLE_S24BE
)
106 *f
= PA_SAMPLE_S24LE
;
107 else if (*f
== PA_SAMPLE_S24LE
)
108 *f
= PA_SAMPLE_S24BE
;
109 else if (*f
== PA_SAMPLE_S24_32BE
)
110 *f
= PA_SAMPLE_S24_32LE
;
111 else if (*f
== PA_SAMPLE_S24_32LE
)
112 *f
= PA_SAMPLE_S24_32BE
;
113 else if (*f
== PA_SAMPLE_S16BE
)
114 *f
= PA_SAMPLE_S16LE
;
115 else if (*f
== PA_SAMPLE_S16LE
)
116 *f
= PA_SAMPLE_S16BE
;
117 else if (*f
== PA_SAMPLE_S32BE
)
118 *f
= PA_SAMPLE_S32LE
;
119 else if (*f
== PA_SAMPLE_S32LE
)
120 *f
= PA_SAMPLE_S32BE
;
124 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
127 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
128 snd_pcm_format_description(format_trans
[*f
]),
129 pa_alsa_strerror(ret
));
133 for (i
= 0; i
< PA_ELEMENTSOF(try_order
); i
++) {
136 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
139 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
140 snd_pcm_format_description(format_trans
[*f
]),
141 pa_alsa_strerror(ret
));
147 static int set_period_size(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, snd_pcm_uframes_t size
) {
151 pa_assert(pcm_handle
);
156 if (snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
) < 0) {
159 if (snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
) < 0) {
162 if ((ret
= snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, &s
, &d
)) < 0) {
163 pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret
));
172 static int set_buffer_size(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, snd_pcm_uframes_t size
) {
175 pa_assert(pcm_handle
);
178 if ((ret
= snd_pcm_hw_params_set_buffer_size_near(pcm_handle
, hwparams
, &size
)) < 0) {
179 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret
));
186 /* Set the hardware parameters of the given ALSA device. Returns the
187 * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */
188 int pa_alsa_set_hw_params(
189 snd_pcm_t
*pcm_handle
,
191 snd_pcm_uframes_t
*period_size
,
192 snd_pcm_uframes_t
*buffer_size
,
193 snd_pcm_uframes_t tsched_size
,
196 bool require_exact_channel_number
) {
199 snd_pcm_hw_params_t
*hwparams
, *hwparams_copy
;
201 snd_pcm_uframes_t _period_size
= period_size
? *period_size
: 0;
202 snd_pcm_uframes_t _buffer_size
= buffer_size
? *buffer_size
: 0;
203 bool _use_mmap
= use_mmap
&& *use_mmap
;
204 bool _use_tsched
= use_tsched
&& *use_tsched
;
205 pa_sample_spec _ss
= *ss
;
207 pa_assert(pcm_handle
);
210 snd_pcm_hw_params_alloca(&hwparams
);
211 snd_pcm_hw_params_alloca(&hwparams_copy
);
213 if ((ret
= snd_pcm_hw_params_any(pcm_handle
, hwparams
)) < 0) {
214 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret
));
218 if ((ret
= snd_pcm_hw_params_set_rate_resample(pcm_handle
, hwparams
, 0)) < 0) {
219 pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret
));
225 if (snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_MMAP_INTERLEAVED
) < 0) {
227 /* mmap() didn't work, fall back to interleaved */
229 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0) {
230 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret
));
237 } else if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0) {
238 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret
));
245 if (!pa_alsa_pcm_is_hw(pcm_handle
))
248 /* The PCM pointer is only updated with period granularity */
249 if (snd_pcm_hw_params_is_batch(hwparams
)) {
250 pa_log_info("Disabling tsched mode since BATCH flag is set");
254 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
257 /* try to disable period wakeups if hardware can do so */
258 if (snd_pcm_hw_params_can_disable_period_wakeup(hwparams
)) {
260 if ((ret
= snd_pcm_hw_params_set_period_wakeup(pcm_handle
, hwparams
, false)) < 0)
261 /* don't bail, keep going with default mode with period wakeups */
262 pa_log_debug("snd_pcm_hw_params_set_period_wakeup() failed: %s", pa_alsa_strerror(ret
));
264 pa_log_info("Trying to disable ALSA period wakeups, using timers only");
266 pa_log_info("cannot disable ALSA period wakeups");
270 if ((ret
= set_format(pcm_handle
, hwparams
, &_ss
.format
)) < 0)
273 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm_handle
, hwparams
, &_ss
.rate
, NULL
)) < 0) {
274 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret
));
278 /* We ignore very small sampling rate deviations */
279 if (_ss
.rate
>= ss
->rate
*.95 && _ss
.rate
<= ss
->rate
*1.05)
282 if (require_exact_channel_number
) {
283 if ((ret
= snd_pcm_hw_params_set_channels(pcm_handle
, hwparams
, _ss
.channels
)) < 0) {
284 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
288 unsigned int c
= _ss
.channels
;
290 if ((ret
= snd_pcm_hw_params_set_channels_near(pcm_handle
, hwparams
, &c
)) < 0) {
291 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
298 if (_use_tsched
&& tsched_size
> 0) {
299 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) tsched_size
* _ss
.rate
) / ss
->rate
);
300 _period_size
= _buffer_size
;
302 _period_size
= (snd_pcm_uframes_t
) (((uint64_t) _period_size
* _ss
.rate
) / ss
->rate
);
303 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) _buffer_size
* _ss
.rate
) / ss
->rate
);
306 if (_buffer_size
> 0 || _period_size
> 0) {
307 snd_pcm_uframes_t max_frames
= 0;
309 if ((ret
= snd_pcm_hw_params_get_buffer_size_max(hwparams
, &max_frames
)) < 0)
310 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret
));
312 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames
* PA_MSEC_PER_SEC
/ _ss
.rate
));
314 /* Some ALSA drivers really don't like if we set the buffer
315 * size first and the number of periods second (which would
316 * make a lot more sense to me). So, try a few combinations
317 * before we give up. */
319 if (_buffer_size
> 0 && _period_size
> 0) {
320 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
322 /* First try: set buffer size first, followed by period size */
323 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
324 set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
325 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
326 pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size
, (unsigned long) _period_size
);
330 /* Second try: set period size first, followed by buffer size */
331 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
332 set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
333 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
334 pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size
, (unsigned long) _buffer_size
);
339 if (_buffer_size
> 0) {
340 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
342 /* Third try: set only buffer size */
343 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
344 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
345 pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size
);
350 if (_period_size
> 0) {
351 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
353 /* Fourth try: set only period size */
354 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
355 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
356 pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size
);
362 pa_log_debug("Set neither period nor buffer size.");
364 /* Last chance, set nothing */
365 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0) {
366 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret
));
372 if (ss
->rate
!= _ss
.rate
)
373 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, _ss
.rate
);
375 if (ss
->channels
!= _ss
.channels
)
376 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, _ss
.channels
);
378 if (ss
->format
!= _ss
.format
)
379 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
));
381 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0) {
382 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret
));
386 if ((ret
= snd_pcm_hw_params_current(pcm_handle
, hwparams
)) < 0) {
387 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret
));
391 if ((ret
= snd_pcm_hw_params_get_period_size(hwparams
, &_period_size
, &dir
)) < 0 ||
392 (ret
= snd_pcm_hw_params_get_buffer_size(hwparams
, &_buffer_size
)) < 0) {
393 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret
));
397 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
399 unsigned int no_wakeup
;
400 /* see if period wakeups were disabled */
401 snd_pcm_hw_params_get_period_wakeup(pcm_handle
, hwparams
, &no_wakeup
);
403 pa_log_info("ALSA period wakeups disabled");
405 pa_log_info("ALSA period wakeups were not disabled");
410 ss
->channels
= _ss
.channels
;
411 ss
->format
= _ss
.format
;
413 pa_assert(_period_size
> 0);
414 pa_assert(_buffer_size
> 0);
417 *buffer_size
= _buffer_size
;
420 *period_size
= _period_size
;
423 *use_mmap
= _use_mmap
;
426 *use_tsched
= _use_tsched
;
435 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
, snd_pcm_uframes_t avail_min
, bool period_event
) {
436 snd_pcm_sw_params_t
*swparams
;
437 snd_pcm_uframes_t boundary
;
442 snd_pcm_sw_params_alloca(&swparams
);
444 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
445 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err
));
449 if ((err
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, period_event
)) < 0) {
450 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err
));
454 if ((err
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
)) < 0) {
455 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err
));
459 if ((err
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
)) < 0) {
460 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err
));
464 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
)) < 0) {
465 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err
));
469 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
470 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err
));
474 if ((err
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, avail_min
)) < 0) {
475 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err
));
479 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
480 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err
));
487 snd_pcm_t
*pa_alsa_open_by_device_id_auto(
493 snd_pcm_uframes_t
*period_size
,
494 snd_pcm_uframes_t
*buffer_size
,
495 snd_pcm_uframes_t tsched_size
,
498 pa_alsa_profile_set
*ps
,
499 pa_alsa_mapping
**mapping
) {
502 snd_pcm_t
*pcm_handle
;
512 /* First we try to find a device string with a superset of the
513 * requested channel map. We iterate through our device table from
514 * top to bottom and take the first that matches. If we didn't
515 * find a working device that way, we iterate backwards, and check
516 * all devices that do not provide a superset of the requested
519 PA_HASHMAP_FOREACH(m
, ps
->mappings
, state
) {
520 if (!pa_channel_map_superset(&m
->channel_map
, map
))
523 pa_log_debug("Checking for superset %s (%s)", m
->name
, m
->device_strings
[0]);
525 pcm_handle
= pa_alsa_open_by_device_id_mapping(
546 PA_HASHMAP_FOREACH_BACKWARDS(m
, ps
->mappings
, state
) {
547 if (pa_channel_map_superset(&m
->channel_map
, map
))
550 pa_log_debug("Checking for subset %s (%s)", m
->name
, m
->device_strings
[0]);
552 pcm_handle
= pa_alsa_open_by_device_id_mapping(
573 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
574 d
= pa_sprintf_malloc("hw:%s", dev_id
);
575 pa_log_debug("Trying %s as last resort...", d
);
576 pcm_handle
= pa_alsa_open_by_device_string(
590 if (pcm_handle
&& mapping
)
596 snd_pcm_t
*pa_alsa_open_by_device_id_mapping(
602 snd_pcm_uframes_t
*period_size
,
603 snd_pcm_uframes_t
*buffer_size
,
604 snd_pcm_uframes_t tsched_size
,
607 pa_alsa_mapping
*m
) {
609 snd_pcm_t
*pcm_handle
;
610 pa_sample_spec try_ss
;
611 pa_channel_map try_map
;
619 try_ss
.channels
= m
->channel_map
.channels
;
620 try_ss
.rate
= ss
->rate
;
621 try_ss
.format
= ss
->format
;
622 try_map
= m
->channel_map
;
624 pcm_handle
= pa_alsa_open_by_template(
636 pa_channel_map_valid(&m
->channel_map
) /* Query the channel count if we don't know what we want */);
643 pa_assert(map
->channels
== ss
->channels
);
648 snd_pcm_t
*pa_alsa_open_by_device_string(
654 snd_pcm_uframes_t
*period_size
,
655 snd_pcm_uframes_t
*buffer_size
,
656 snd_pcm_uframes_t tsched_size
,
659 bool require_exact_channel_number
) {
663 snd_pcm_t
*pcm_handle
;
664 bool reformat
= false;
670 d
= pa_xstrdup(device
);
673 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d
, reformat
? "without" : "with");
675 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
677 SND_PCM_NO_AUTO_RESAMPLE
|
678 SND_PCM_NO_AUTO_CHANNELS
|
679 (reformat
? 0 : SND_PCM_NO_AUTO_FORMAT
))) < 0) {
680 pa_log_info("Error opening PCM device %s: %s", d
, pa_alsa_strerror(err
));
684 pa_log_debug("Managed to open %s", d
);
686 if ((err
= pa_alsa_set_hw_params(
694 require_exact_channel_number
)) < 0) {
699 snd_pcm_close(pcm_handle
);
703 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
704 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
707 t
= pa_sprintf_malloc("plug:%s", d
);
713 snd_pcm_close(pcm_handle
);
717 pa_log_info("Failed to set hardware parameters on %s: %s", d
, pa_alsa_strerror(err
));
718 snd_pcm_close(pcm_handle
);
728 if (ss
->channels
!= map
->channels
)
729 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
740 snd_pcm_t
*pa_alsa_open_by_template(
747 snd_pcm_uframes_t
*period_size
,
748 snd_pcm_uframes_t
*buffer_size
,
749 snd_pcm_uframes_t tsched_size
,
752 bool require_exact_channel_number
) {
754 snd_pcm_t
*pcm_handle
;
757 for (i
= template; *i
; i
++) {
760 d
= pa_replace(*i
, "%f", dev_id
);
762 pcm_handle
= pa_alsa_open_by_device_string(
773 require_exact_channel_number
);
784 void pa_alsa_dump(pa_log_level_t level
, snd_pcm_t
*pcm
) {
790 pa_assert_se(snd_output_buffer_open(&out
) == 0);
792 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
793 pa_logl(level
, "snd_pcm_dump(): %s", pa_alsa_strerror(err
));
796 snd_output_buffer_string(out
, &s
);
797 pa_logl(level
, "snd_pcm_dump():\n%s", pa_strnull(s
));
800 pa_assert_se(snd_output_close(out
) == 0);
803 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
806 snd_pcm_status_t
*status
;
811 snd_pcm_status_alloca(&status
);
813 if ((err
= snd_output_buffer_open(&out
)) < 0) {
814 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err
));
818 if ((err
= snd_pcm_status(pcm
, status
)) < 0) {
819 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err
));
823 if ((err
= snd_pcm_status_dump(status
, out
)) < 0) {
824 pa_log_debug("snd_pcm_status_dump(): %s", pa_alsa_strerror(err
));
828 snd_output_buffer_string(out
, &s
);
829 pa_log_debug("snd_pcm_status_dump():\n%s", pa_strnull(s
));
833 snd_output_close(out
);
836 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
840 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
844 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
851 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
853 void pa_alsa_refcnt_inc(void) {
854 /* This is not really thread safe, but we do our best */
856 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
857 snd_lib_error_set_handler(alsa_error_handler
);
860 void pa_alsa_refcnt_dec(void) {
863 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
866 snd_lib_error_set_handler(NULL
);
867 snd_config_update_free_global();
871 bool pa_alsa_init_description(pa_proplist
*p
, pa_card
*card
) {
875 if (pa_device_init_description(p
, card
))
878 if (!(d
= pa_proplist_gets(p
, "alsa.card_name")))
879 d
= pa_proplist_gets(p
, "alsa.name");
884 k
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
887 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, "%s %s", d
, k
);
889 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, d
);
894 void pa_alsa_init_proplist_card(pa_core
*c
, pa_proplist
*p
, int card
) {
898 pa_assert(card
>= 0);
900 pa_proplist_setf(p
, "alsa.card", "%i", card
);
902 if (snd_card_get_name(card
, &cn
) >= 0) {
903 pa_proplist_sets(p
, "alsa.card_name", pa_strip(cn
));
907 if (snd_card_get_longname(card
, &lcn
) >= 0) {
908 pa_proplist_sets(p
, "alsa.long_card_name", pa_strip(lcn
));
912 if ((dn
= pa_alsa_get_driver_name(card
))) {
913 pa_proplist_sets(p
, "alsa.driver_name", dn
);
918 pa_udev_get_info(card
, p
);
922 void pa_alsa_init_proplist_pcm_info(pa_core
*c
, pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
924 static const char * const alsa_class_table
[SND_PCM_CLASS_LAST
+1] = {
925 [SND_PCM_CLASS_GENERIC
] = "generic",
926 [SND_PCM_CLASS_MULTI
] = "multi",
927 [SND_PCM_CLASS_MODEM
] = "modem",
928 [SND_PCM_CLASS_DIGITIZER
] = "digitizer"
930 static const char * const class_table
[SND_PCM_CLASS_LAST
+1] = {
931 [SND_PCM_CLASS_GENERIC
] = "sound",
932 [SND_PCM_CLASS_MULTI
] = NULL
,
933 [SND_PCM_CLASS_MODEM
] = "modem",
934 [SND_PCM_CLASS_DIGITIZER
] = NULL
936 static const char * const alsa_subclass_table
[SND_PCM_SUBCLASS_LAST
+1] = {
937 [SND_PCM_SUBCLASS_GENERIC_MIX
] = "generic-mix",
938 [SND_PCM_SUBCLASS_MULTI_MIX
] = "multi-mix"
941 snd_pcm_class_t
class;
942 snd_pcm_subclass_t subclass
;
943 const char *n
, *id
, *sdn
;
949 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
951 if ((class = snd_pcm_info_get_class(pcm_info
)) <= SND_PCM_CLASS_LAST
) {
952 if (class_table
[class])
953 pa_proplist_sets(p
, PA_PROP_DEVICE_CLASS
, class_table
[class]);
954 if (alsa_class_table
[class])
955 pa_proplist_sets(p
, "alsa.class", alsa_class_table
[class]);
958 if ((subclass
= snd_pcm_info_get_subclass(pcm_info
)) <= SND_PCM_SUBCLASS_LAST
)
959 if (alsa_subclass_table
[subclass
])
960 pa_proplist_sets(p
, "alsa.subclass", alsa_subclass_table
[subclass
]);
962 if ((n
= snd_pcm_info_get_name(pcm_info
))) {
963 char *t
= pa_xstrdup(n
);
964 pa_proplist_sets(p
, "alsa.name", pa_strip(t
));
968 if ((id
= snd_pcm_info_get_id(pcm_info
)))
969 pa_proplist_sets(p
, "alsa.id", id
);
971 pa_proplist_setf(p
, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info
));
972 if ((sdn
= snd_pcm_info_get_subdevice_name(pcm_info
)))
973 pa_proplist_sets(p
, "alsa.subdevice_name", sdn
);
975 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
977 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0)
978 pa_alsa_init_proplist_card(c
, p
, card
);
981 void pa_alsa_init_proplist_pcm(pa_core
*c
, pa_proplist
*p
, snd_pcm_t
*pcm
) {
982 snd_pcm_hw_params_t
*hwparams
;
983 snd_pcm_info_t
*info
;
986 snd_pcm_hw_params_alloca(&hwparams
);
987 snd_pcm_info_alloca(&info
);
989 if ((err
= snd_pcm_hw_params_current(pcm
, hwparams
)) < 0)
990 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err
));
993 if ((bits
= snd_pcm_hw_params_get_sbits(hwparams
)) >= 0)
994 pa_proplist_setf(p
, "alsa.resolution_bits", "%i", bits
);
997 if ((err
= snd_pcm_info(pcm
, info
)) < 0)
998 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err
));
1000 pa_alsa_init_proplist_pcm_info(c
, p
, info
);
1003 void pa_alsa_init_proplist_ctl(pa_proplist
*p
, const char *name
) {
1006 snd_ctl_card_info_t
*info
;
1011 snd_ctl_card_info_alloca(&info
);
1013 if ((err
= snd_ctl_open(&ctl
, name
, 0)) < 0) {
1014 pa_log_warn("Error opening low-level control device '%s': %s", name
, snd_strerror(err
));
1018 if ((err
= snd_ctl_card_info(ctl
, info
)) < 0) {
1019 pa_log_warn("Control device %s card info: %s", name
, snd_strerror(err
));
1024 if ((t
= snd_ctl_card_info_get_mixername(info
)) && *t
)
1025 pa_proplist_sets(p
, "alsa.mixer_name", t
);
1027 if ((t
= snd_ctl_card_info_get_components(info
)) && *t
)
1028 pa_proplist_sets(p
, "alsa.components", t
);
1033 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
1034 snd_pcm_state_t state
;
1039 if (revents
& POLLERR
)
1040 pa_log_debug("Got POLLERR from ALSA");
1041 if (revents
& POLLNVAL
)
1042 pa_log_warn("Got POLLNVAL from ALSA");
1043 if (revents
& POLLHUP
)
1044 pa_log_warn("Got POLLHUP from ALSA");
1045 if (revents
& POLLPRI
)
1046 pa_log_warn("Got POLLPRI from ALSA");
1047 if (revents
& POLLIN
)
1048 pa_log_debug("Got POLLIN from ALSA");
1049 if (revents
& POLLOUT
)
1050 pa_log_debug("Got POLLOUT from ALSA");
1052 state
= snd_pcm_state(pcm
);
1053 pa_log_debug("PCM state is %s", snd_pcm_state_name(state
));
1055 /* Try to recover from this error */
1059 case SND_PCM_STATE_XRUN
:
1060 if ((err
= snd_pcm_recover(pcm
, -EPIPE
, 1)) != 0) {
1061 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err
));
1066 case SND_PCM_STATE_SUSPENDED
:
1067 if ((err
= snd_pcm_recover(pcm
, -ESTRPIPE
, 1)) != 0) {
1068 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err
));
1077 if ((err
= snd_pcm_prepare(pcm
)) < 0) {
1078 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err
));
1087 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
1089 struct pollfd
*pollfd
;
1090 pa_rtpoll_item
*item
;
1094 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
1095 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n
));
1099 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
1100 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
1102 if ((err
= snd_pcm_poll_descriptors(pcm
, pollfd
, (unsigned) n
)) < 0) {
1103 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err
));
1104 pa_rtpoll_item_free(item
);
1111 snd_pcm_sframes_t
pa_alsa_safe_avail(snd_pcm_t
*pcm
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1112 snd_pcm_sframes_t n
;
1116 pa_assert(hwbuf_size
> 0);
1119 /* Some ALSA driver expose weird bugs, let's inform the user about
1120 * what is going on */
1122 n
= snd_pcm_avail(pcm
);
1127 k
= (size_t) n
* pa_frame_size(ss
);
1129 if (PA_UNLIKELY(k
>= hwbuf_size
* 5 ||
1130 k
>= pa_bytes_per_second(ss
)*10)) {
1133 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1134 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1135 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1137 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1140 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1143 /* Mhmm, let's try not to fail completely */
1144 n
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1150 int pa_alsa_safe_delay(snd_pcm_t
*pcm
, snd_pcm_status_t
*status
, snd_pcm_sframes_t
*delay
, size_t hwbuf_size
, const pa_sample_spec
*ss
,
1155 snd_pcm_sframes_t avail
= 0;
1159 pa_assert(hwbuf_size
> 0);
1162 /* Some ALSA driver expose weird bugs, let's inform the user about
1163 * what is going on. We're going to get both the avail and delay values so
1164 * that we can compare and check them for capture.
1165 * This is done with snd_pcm_status() which provides
1166 * avail, delay and timestamp values in a single kernel call to improve
1167 * timer-based scheduling */
1169 if ((err
= snd_pcm_status(pcm
, status
)) < 0)
1172 avail
= snd_pcm_status_get_avail(status
);
1173 *delay
= snd_pcm_status_get_delay(status
);
1175 k
= (ssize_t
) *delay
* (ssize_t
) pa_frame_size(ss
);
1177 abs_k
= k
>= 0 ? (size_t) k
: (size_t) -k
;
1179 if (PA_UNLIKELY(abs_k
>= hwbuf_size
* 5 ||
1180 abs_k
>= pa_bytes_per_second(ss
)*10)) {
1183 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1184 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1185 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1188 (unsigned long) (pa_bytes_to_usec(abs_k
, ss
) / PA_USEC_PER_MSEC
),
1191 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1194 /* Mhmm, let's try not to fail completely */
1196 *delay
= -(snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1198 *delay
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1202 abs_k
= (size_t) avail
* pa_frame_size(ss
);
1204 if (PA_UNLIKELY(abs_k
>= hwbuf_size
* 5 ||
1205 abs_k
>= pa_bytes_per_second(ss
)*10)) {
1208 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1209 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1210 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1212 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1215 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1218 /* Mhmm, let's try not to fail completely */
1219 avail
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1222 if (PA_UNLIKELY(*delay
< avail
)) {
1224 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1225 pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
1226 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1227 (unsigned long) *delay
,
1228 (unsigned long) avail
,
1231 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1242 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
) {
1244 snd_pcm_uframes_t before
;
1251 pa_assert(hwbuf_size
> 0);
1256 r
= snd_pcm_mmap_begin(pcm
, areas
, offset
, frames
);
1261 k
= (size_t) *frames
* pa_frame_size(ss
);
1263 if (PA_UNLIKELY(*frames
> before
||
1264 k
>= hwbuf_size
* 3 ||
1265 k
>= pa_bytes_per_second(ss
)*10))
1267 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1268 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1269 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1271 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1274 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1280 char *pa_alsa_get_driver_name(int card
) {
1283 pa_assert(card
>= 0);
1285 t
= pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card
);
1292 n
= pa_xstrdup(pa_path_get_filename(m
));
1298 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t
*pcm
) {
1300 snd_pcm_info_t
* info
;
1301 snd_pcm_info_alloca(&info
);
1305 if (snd_pcm_info(pcm
, info
) < 0)
1308 if ((card
= snd_pcm_info_get_card(info
)) < 0)
1311 return pa_alsa_get_driver_name(card
);
1314 char *pa_alsa_get_reserve_name(const char *device
) {
1320 if ((t
= strchr(device
, ':')))
1323 if ((i
= snd_card_get_index(device
)) < 0) {
1326 if (pa_atoi(device
, &k
) < 0)
1332 return pa_sprintf_malloc("Audio%i", i
);
1335 unsigned int *pa_alsa_get_supported_rates(snd_pcm_t
*pcm
, unsigned int fallback_rate
) {
1336 static unsigned int all_rates
[] = { 8000, 11025, 12000,
1337 16000, 22050, 24000,
1338 32000, 44100, 48000,
1339 64000, 88200, 96000,
1340 128000, 176400, 192000,
1342 bool supported
[PA_ELEMENTSOF(all_rates
)] = { false, };
1343 snd_pcm_hw_params_t
*hwparams
;
1344 unsigned int i
, j
, n
, *rates
= NULL
;
1347 snd_pcm_hw_params_alloca(&hwparams
);
1349 if ((ret
= snd_pcm_hw_params_any(pcm
, hwparams
)) < 0) {
1350 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret
));
1354 for (i
= 0, n
= 0; i
< PA_ELEMENTSOF(all_rates
); i
++) {
1355 if (snd_pcm_hw_params_test_rate(pcm
, hwparams
, all_rates
[i
], 0) == 0) {
1356 supported
[i
] = true;
1362 rates
= pa_xnew(unsigned int, n
+ 1);
1364 for (i
= 0, j
= 0; i
< PA_ELEMENTSOF(all_rates
); i
++) {
1366 rates
[j
++] = all_rates
[i
];
1371 rates
= pa_xnew(unsigned int, 2);
1373 rates
[0] = fallback_rate
;
1374 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rates
[0], NULL
)) < 0) {
1375 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret
));
1386 bool pa_alsa_pcm_is_hw(snd_pcm_t
*pcm
) {
1387 snd_pcm_info_t
* info
;
1388 snd_pcm_info_alloca(&info
);
1392 if (snd_pcm_info(pcm
, info
) < 0)
1395 return snd_pcm_info_get_card(info
) >= 0;
1398 bool pa_alsa_pcm_is_modem(snd_pcm_t
*pcm
) {
1399 snd_pcm_info_t
* info
;
1400 snd_pcm_info_alloca(&info
);
1404 if (snd_pcm_info(pcm
, info
) < 0)
1407 return snd_pcm_info_get_class(info
) == SND_PCM_CLASS_MODEM
;
1410 PA_STATIC_TLS_DECLARE(cstrerror
, pa_xfree
);
1412 const char* pa_alsa_strerror(int errnum
) {
1413 const char *original
= NULL
;
1414 char *translated
, *t
;
1417 if ((t
= PA_STATIC_TLS_GET(cstrerror
)))
1420 original
= snd_strerror(errnum
);
1423 pa_snprintf(errbuf
, sizeof(errbuf
), "Unknown error %i", errnum
);
1427 if (!(translated
= pa_locale_to_utf8(original
))) {
1428 pa_log_warn("Unable to convert error string to locale, filtering.");
1429 translated
= pa_utf8_filter(original
);
1432 PA_STATIC_TLS_SET(cstrerror
, translated
);
1437 bool pa_alsa_may_tsched(bool want
) {
1442 if (!pa_rtclock_hrtimer()) {
1443 /* We cannot depend on being woken up in time when the timers
1444 are inaccurate, so let's fallback to classic IO based playback
1446 pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1449 if (pa_running_in_vm()) {
1450 /* We cannot depend on being woken up when we ask for in a VM,
1451 * so let's fallback to classic IO based playback then. */
1452 pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
1459 snd_hctl_elem_t
* pa_alsa_find_jack(snd_hctl_t
*hctl
, const char* jack_name
) {
1460 snd_ctl_elem_id_t
*id
;
1462 snd_ctl_elem_id_alloca(&id
);
1463 snd_ctl_elem_id_clear(id
);
1464 snd_ctl_elem_id_set_interface(id
, SND_CTL_ELEM_IFACE_CARD
);
1465 snd_ctl_elem_id_set_name(id
, jack_name
);
1467 return snd_hctl_find_elem(hctl
, id
);
1470 snd_hctl_elem_t
* pa_alsa_find_eld_ctl(snd_hctl_t
*hctl
, int device
) {
1471 snd_ctl_elem_id_t
*id
;
1473 /* See if we can find the ELD control */
1474 snd_ctl_elem_id_alloca(&id
);
1475 snd_ctl_elem_id_clear(id
);
1476 snd_ctl_elem_id_set_interface(id
, SND_CTL_ELEM_IFACE_PCM
);
1477 snd_ctl_elem_id_set_name(id
, "ELD");
1478 snd_ctl_elem_id_set_device(id
, device
);
1480 return snd_hctl_find_elem(hctl
, id
);
1483 static int prepare_mixer(snd_mixer_t
*mixer
, const char *dev
, snd_hctl_t
**hctl
) {
1489 if ((err
= snd_mixer_attach(mixer
, dev
)) < 0) {
1490 pa_log_info("Unable to attach to mixer %s: %s", dev
, pa_alsa_strerror(err
));
1494 /* Note: The hctl handle returned should not be freed.
1495 It is closed/freed by alsa-lib on snd_mixer_close/free */
1496 if (hctl
&& (err
= snd_mixer_get_hctl(mixer
, dev
, hctl
)) < 0) {
1497 pa_log_info("Unable to get hctl of mixer %s: %s", dev
, pa_alsa_strerror(err
));
1501 if ((err
= snd_mixer_selem_register(mixer
, NULL
, NULL
)) < 0) {
1502 pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err
));
1506 if ((err
= snd_mixer_load(mixer
)) < 0) {
1507 pa_log_warn("Unable to load mixer: %s", pa_alsa_strerror(err
));
1511 pa_log_info("Successfully attached to mixer '%s'", dev
);
1515 snd_mixer_t
*pa_alsa_open_mixer(int alsa_card_index
, char **ctl_device
, snd_hctl_t
**hctl
) {
1519 snd_pcm_info_t
* info
;
1520 snd_pcm_info_alloca(&info
);
1522 if ((err
= snd_mixer_open(&m
, 0)) < 0) {
1523 pa_log("Error opening mixer: %s", pa_alsa_strerror(err
));
1527 /* Then, try by card index */
1528 md
= pa_sprintf_malloc("hw:%i", alsa_card_index
);
1529 if (prepare_mixer(m
, md
, hctl
) >= 0) {
1545 snd_mixer_t
*pa_alsa_open_mixer_for_pcm(snd_pcm_t
*pcm
, char **ctl_device
, snd_hctl_t
**hctl
) {
1549 snd_pcm_info_t
* info
;
1550 snd_pcm_info_alloca(&info
);
1554 if ((err
= snd_mixer_open(&m
, 0)) < 0) {
1555 pa_log("Error opening mixer: %s", pa_alsa_strerror(err
));
1559 /* First, try by name */
1560 if ((dev
= snd_pcm_name(pcm
)))
1561 if (prepare_mixer(m
, dev
, hctl
) >= 0) {
1563 *ctl_device
= pa_xstrdup(dev
);
1568 /* Then, try by card index */
1569 if (snd_pcm_info(pcm
, info
) >= 0) {
1573 if ((card_idx
= snd_pcm_info_get_card(info
)) >= 0) {
1575 md
= pa_sprintf_malloc("hw:%i", card_idx
);
1577 if (!dev
|| !pa_streq(dev
, md
))
1578 if (prepare_mixer(m
, md
, hctl
) >= 0) {
1596 int pa_alsa_get_hdmi_eld(snd_hctl_t
*hctl
, int device
, pa_hdmi_eld
*eld
) {
1598 /* The ELD format is specific to HDA Intel sound cards and defined in the
1599 HDA specification: http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html */
1601 snd_hctl_elem_t
*elem
;
1602 snd_ctl_elem_info_t
*info
;
1603 snd_ctl_elem_value_t
*value
;
1605 unsigned int eldsize
, mnl
;
1607 pa_assert(eld
!= NULL
);
1609 /* See if we can find the ELD control */
1610 elem
= pa_alsa_find_eld_ctl(hctl
, device
);
1612 pa_log_debug("No ELD info control found (for device=%d)", device
);
1616 /* Does it have any contents? */
1617 snd_ctl_elem_info_alloca(&info
);
1618 snd_ctl_elem_value_alloca(&value
);
1619 if ((err
= snd_hctl_elem_info(elem
, info
)) < 0 ||
1620 (err
= snd_hctl_elem_read(elem
, value
)) < 0) {
1621 pa_log_warn("Accessing ELD control failed with error %s", snd_strerror(err
));
1625 eldsize
= snd_ctl_elem_info_get_count(info
);
1626 elddata
= (unsigned char *) snd_ctl_elem_value_get_bytes(value
);
1627 if (elddata
== NULL
|| eldsize
== 0) {
1628 pa_log_debug("ELD info empty (for device=%d)", device
);
1631 if (eldsize
< 20 || eldsize
> 256) {
1632 pa_log_debug("ELD info has wrong size (for device=%d)", device
);
1636 /* Try to fetch monitor name */
1637 mnl
= elddata
[4] & 0x1f;
1638 if (mnl
== 0 || mnl
> 16 || 20 + mnl
> eldsize
) {
1639 pa_log_debug("No monitor name in ELD info (for device=%d)", device
);
1642 memcpy(eld
->monitor_name
, &elddata
[20], mnl
);
1643 eld
->monitor_name
[mnl
] = '\0';
1645 pa_log_debug("Monitor name in ELD info is '%s' (for device=%d)", eld
->monitor_name
, device
);