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
))
252 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
255 /* try to disable period wakeups if hardware can do so */
256 if (snd_pcm_hw_params_can_disable_period_wakeup(hwparams
)) {
258 if ((ret
= snd_pcm_hw_params_set_period_wakeup(pcm_handle
, hwparams
, false)) < 0)
259 /* don't bail, keep going with default mode with period wakeups */
260 pa_log_debug("snd_pcm_hw_params_set_period_wakeup() failed: %s", pa_alsa_strerror(ret
));
262 pa_log_info("Trying to disable ALSA period wakeups, using timers only");
264 pa_log_info("cannot disable ALSA period wakeups");
268 if ((ret
= set_format(pcm_handle
, hwparams
, &_ss
.format
)) < 0)
271 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm_handle
, hwparams
, &_ss
.rate
, NULL
)) < 0) {
272 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret
));
276 /* We ignore very small sampling rate deviations */
277 if (_ss
.rate
>= ss
->rate
*.95 && _ss
.rate
<= ss
->rate
*1.05)
280 if (require_exact_channel_number
) {
281 if ((ret
= snd_pcm_hw_params_set_channels(pcm_handle
, hwparams
, _ss
.channels
)) < 0) {
282 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
286 unsigned int c
= _ss
.channels
;
288 if ((ret
= snd_pcm_hw_params_set_channels_near(pcm_handle
, hwparams
, &c
)) < 0) {
289 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss
.channels
, pa_alsa_strerror(ret
));
296 if (_use_tsched
&& tsched_size
> 0) {
297 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) tsched_size
* _ss
.rate
) / ss
->rate
);
298 _period_size
= _buffer_size
;
300 _period_size
= (snd_pcm_uframes_t
) (((uint64_t) _period_size
* _ss
.rate
) / ss
->rate
);
301 _buffer_size
= (snd_pcm_uframes_t
) (((uint64_t) _buffer_size
* _ss
.rate
) / ss
->rate
);
304 if (_buffer_size
> 0 || _period_size
> 0) {
305 snd_pcm_uframes_t max_frames
= 0;
307 if ((ret
= snd_pcm_hw_params_get_buffer_size_max(hwparams
, &max_frames
)) < 0)
308 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret
));
310 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames
* PA_MSEC_PER_SEC
/ _ss
.rate
));
312 /* Some ALSA drivers really don't like if we set the buffer
313 * size first and the number of periods second (which would
314 * make a lot more sense to me). So, try a few combinations
315 * before we give up. */
317 if (_buffer_size
> 0 && _period_size
> 0) {
318 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
320 /* First try: set buffer size first, followed by period size */
321 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
322 set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
323 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
324 pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size
, (unsigned long) _period_size
);
328 /* Second try: set period size first, followed by buffer size */
329 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
330 set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
331 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
332 pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size
, (unsigned long) _buffer_size
);
337 if (_buffer_size
> 0) {
338 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
340 /* Third try: set only buffer size */
341 if (set_buffer_size(pcm_handle
, hwparams_copy
, _buffer_size
) >= 0 &&
342 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
343 pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size
);
348 if (_period_size
> 0) {
349 snd_pcm_hw_params_copy(hwparams_copy
, hwparams
);
351 /* Fourth try: set only period size */
352 if (set_period_size(pcm_handle
, hwparams_copy
, _period_size
) >= 0 &&
353 snd_pcm_hw_params(pcm_handle
, hwparams_copy
) >= 0) {
354 pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size
);
360 pa_log_debug("Set neither period nor buffer size.");
362 /* Last chance, set nothing */
363 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0) {
364 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret
));
370 if (ss
->rate
!= _ss
.rate
)
371 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, _ss
.rate
);
373 if (ss
->channels
!= _ss
.channels
)
374 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, _ss
.channels
);
376 if (ss
->format
!= _ss
.format
)
377 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
));
379 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0) {
380 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret
));
384 if ((ret
= snd_pcm_hw_params_current(pcm_handle
, hwparams
)) < 0) {
385 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret
));
389 if ((ret
= snd_pcm_hw_params_get_period_size(hwparams
, &_period_size
, &dir
)) < 0 ||
390 (ret
= snd_pcm_hw_params_get_buffer_size(hwparams
, &_buffer_size
)) < 0) {
391 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret
));
395 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
397 unsigned int no_wakeup
;
398 /* see if period wakeups were disabled */
399 snd_pcm_hw_params_get_period_wakeup(pcm_handle
, hwparams
, &no_wakeup
);
401 pa_log_info("ALSA period wakeups disabled");
403 pa_log_info("ALSA period wakeups were not disabled");
408 ss
->channels
= _ss
.channels
;
409 ss
->format
= _ss
.format
;
411 pa_assert(_period_size
> 0);
412 pa_assert(_buffer_size
> 0);
415 *buffer_size
= _buffer_size
;
418 *period_size
= _period_size
;
421 *use_mmap
= _use_mmap
;
424 *use_tsched
= _use_tsched
;
433 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
, snd_pcm_uframes_t avail_min
, bool period_event
) {
434 snd_pcm_sw_params_t
*swparams
;
435 snd_pcm_uframes_t boundary
;
440 snd_pcm_sw_params_alloca(&swparams
);
442 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
443 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err
));
447 if ((err
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, period_event
)) < 0) {
448 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err
));
452 if ((err
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
)) < 0) {
453 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err
));
457 if ((err
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
)) < 0) {
458 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err
));
462 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
)) < 0) {
463 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err
));
467 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
468 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err
));
472 if ((err
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, avail_min
)) < 0) {
473 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err
));
477 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
478 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err
));
485 snd_pcm_t
*pa_alsa_open_by_device_id_auto(
491 snd_pcm_uframes_t
*period_size
,
492 snd_pcm_uframes_t
*buffer_size
,
493 snd_pcm_uframes_t tsched_size
,
496 pa_alsa_profile_set
*ps
,
497 pa_alsa_mapping
**mapping
) {
500 snd_pcm_t
*pcm_handle
;
510 /* First we try to find a device string with a superset of the
511 * requested channel map. We iterate through our device table from
512 * top to bottom and take the first that matches. If we didn't
513 * find a working device that way, we iterate backwards, and check
514 * all devices that do not provide a superset of the requested
517 PA_HASHMAP_FOREACH(m
, ps
->mappings
, state
) {
518 if (!pa_channel_map_superset(&m
->channel_map
, map
))
521 pa_log_debug("Checking for superset %s (%s)", m
->name
, m
->device_strings
[0]);
523 pcm_handle
= pa_alsa_open_by_device_id_mapping(
544 PA_HASHMAP_FOREACH_BACKWARDS(m
, ps
->mappings
, state
) {
545 if (pa_channel_map_superset(&m
->channel_map
, map
))
548 pa_log_debug("Checking for subset %s (%s)", m
->name
, m
->device_strings
[0]);
550 pcm_handle
= pa_alsa_open_by_device_id_mapping(
571 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
572 d
= pa_sprintf_malloc("hw:%s", dev_id
);
573 pa_log_debug("Trying %s as last resort...", d
);
574 pcm_handle
= pa_alsa_open_by_device_string(
588 if (pcm_handle
&& mapping
)
594 snd_pcm_t
*pa_alsa_open_by_device_id_mapping(
600 snd_pcm_uframes_t
*period_size
,
601 snd_pcm_uframes_t
*buffer_size
,
602 snd_pcm_uframes_t tsched_size
,
605 pa_alsa_mapping
*m
) {
607 snd_pcm_t
*pcm_handle
;
608 pa_sample_spec try_ss
;
609 pa_channel_map try_map
;
617 try_ss
.channels
= m
->channel_map
.channels
;
618 try_ss
.rate
= ss
->rate
;
619 try_ss
.format
= ss
->format
;
620 try_map
= m
->channel_map
;
622 pcm_handle
= pa_alsa_open_by_template(
634 pa_channel_map_valid(&m
->channel_map
) /* Query the channel count if we don't know what we want */);
641 pa_assert(map
->channels
== ss
->channels
);
646 snd_pcm_t
*pa_alsa_open_by_device_string(
652 snd_pcm_uframes_t
*period_size
,
653 snd_pcm_uframes_t
*buffer_size
,
654 snd_pcm_uframes_t tsched_size
,
657 bool require_exact_channel_number
) {
661 snd_pcm_t
*pcm_handle
;
662 bool reformat
= false;
668 d
= pa_xstrdup(device
);
671 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d
, reformat
? "without" : "with");
673 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
675 SND_PCM_NO_AUTO_RESAMPLE
|
676 SND_PCM_NO_AUTO_CHANNELS
|
677 (reformat
? 0 : SND_PCM_NO_AUTO_FORMAT
))) < 0) {
678 pa_log_info("Error opening PCM device %s: %s", d
, pa_alsa_strerror(err
));
682 pa_log_debug("Managed to open %s", d
);
684 if ((err
= pa_alsa_set_hw_params(
692 require_exact_channel_number
)) < 0) {
697 snd_pcm_close(pcm_handle
);
701 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
702 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
705 t
= pa_sprintf_malloc("plug:%s", d
);
711 snd_pcm_close(pcm_handle
);
715 pa_log_info("Failed to set hardware parameters on %s: %s", d
, pa_alsa_strerror(err
));
716 snd_pcm_close(pcm_handle
);
726 if (ss
->channels
!= map
->channels
)
727 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
738 snd_pcm_t
*pa_alsa_open_by_template(
745 snd_pcm_uframes_t
*period_size
,
746 snd_pcm_uframes_t
*buffer_size
,
747 snd_pcm_uframes_t tsched_size
,
750 bool require_exact_channel_number
) {
752 snd_pcm_t
*pcm_handle
;
755 for (i
= template; *i
; i
++) {
758 d
= pa_replace(*i
, "%f", dev_id
);
760 pcm_handle
= pa_alsa_open_by_device_string(
771 require_exact_channel_number
);
782 void pa_alsa_dump(pa_log_level_t level
, snd_pcm_t
*pcm
) {
788 pa_assert_se(snd_output_buffer_open(&out
) == 0);
790 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
791 pa_logl(level
, "snd_pcm_dump(): %s", pa_alsa_strerror(err
));
794 snd_output_buffer_string(out
, &s
);
795 pa_logl(level
, "snd_pcm_dump():\n%s", pa_strnull(s
));
798 pa_assert_se(snd_output_close(out
) == 0);
801 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
804 snd_pcm_status_t
*status
;
809 snd_pcm_status_alloca(&status
);
811 if ((err
= snd_output_buffer_open(&out
)) < 0) {
812 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err
));
816 if ((err
= snd_pcm_status(pcm
, status
)) < 0) {
817 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err
));
821 if ((err
= snd_pcm_status_dump(status
, out
)) < 0) {
822 pa_log_debug("snd_pcm_status_dump(): %s", pa_alsa_strerror(err
));
826 snd_output_buffer_string(out
, &s
);
827 pa_log_debug("snd_pcm_status_dump():\n%s", pa_strnull(s
));
831 snd_output_close(out
);
834 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
838 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
842 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
849 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
851 void pa_alsa_refcnt_inc(void) {
852 /* This is not really thread safe, but we do our best */
854 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
855 snd_lib_error_set_handler(alsa_error_handler
);
858 void pa_alsa_refcnt_dec(void) {
861 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
864 snd_lib_error_set_handler(NULL
);
865 snd_config_update_free_global();
869 bool pa_alsa_init_description(pa_proplist
*p
) {
873 if (pa_device_init_description(p
))
876 if (!(d
= pa_proplist_gets(p
, "alsa.card_name")))
877 d
= pa_proplist_gets(p
, "alsa.name");
882 k
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
885 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, "%s %s", d
, k
);
887 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, d
);
892 void pa_alsa_init_proplist_card(pa_core
*c
, pa_proplist
*p
, int card
) {
896 pa_assert(card
>= 0);
898 pa_proplist_setf(p
, "alsa.card", "%i", card
);
900 if (snd_card_get_name(card
, &cn
) >= 0) {
901 pa_proplist_sets(p
, "alsa.card_name", pa_strip(cn
));
905 if (snd_card_get_longname(card
, &lcn
) >= 0) {
906 pa_proplist_sets(p
, "alsa.long_card_name", pa_strip(lcn
));
910 if ((dn
= pa_alsa_get_driver_name(card
))) {
911 pa_proplist_sets(p
, "alsa.driver_name", dn
);
916 pa_udev_get_info(card
, p
);
920 void pa_alsa_init_proplist_pcm_info(pa_core
*c
, pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
922 static const char * const alsa_class_table
[SND_PCM_CLASS_LAST
+1] = {
923 [SND_PCM_CLASS_GENERIC
] = "generic",
924 [SND_PCM_CLASS_MULTI
] = "multi",
925 [SND_PCM_CLASS_MODEM
] = "modem",
926 [SND_PCM_CLASS_DIGITIZER
] = "digitizer"
928 static const char * const class_table
[SND_PCM_CLASS_LAST
+1] = {
929 [SND_PCM_CLASS_GENERIC
] = "sound",
930 [SND_PCM_CLASS_MULTI
] = NULL
,
931 [SND_PCM_CLASS_MODEM
] = "modem",
932 [SND_PCM_CLASS_DIGITIZER
] = NULL
934 static const char * const alsa_subclass_table
[SND_PCM_SUBCLASS_LAST
+1] = {
935 [SND_PCM_SUBCLASS_GENERIC_MIX
] = "generic-mix",
936 [SND_PCM_SUBCLASS_MULTI_MIX
] = "multi-mix"
939 snd_pcm_class_t
class;
940 snd_pcm_subclass_t subclass
;
941 const char *n
, *id
, *sdn
;
947 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
949 if ((class = snd_pcm_info_get_class(pcm_info
)) <= SND_PCM_CLASS_LAST
) {
950 if (class_table
[class])
951 pa_proplist_sets(p
, PA_PROP_DEVICE_CLASS
, class_table
[class]);
952 if (alsa_class_table
[class])
953 pa_proplist_sets(p
, "alsa.class", alsa_class_table
[class]);
956 if ((subclass
= snd_pcm_info_get_subclass(pcm_info
)) <= SND_PCM_SUBCLASS_LAST
)
957 if (alsa_subclass_table
[subclass
])
958 pa_proplist_sets(p
, "alsa.subclass", alsa_subclass_table
[subclass
]);
960 if ((n
= snd_pcm_info_get_name(pcm_info
))) {
961 char *t
= pa_xstrdup(n
);
962 pa_proplist_sets(p
, "alsa.name", pa_strip(t
));
966 if ((id
= snd_pcm_info_get_id(pcm_info
)))
967 pa_proplist_sets(p
, "alsa.id", id
);
969 pa_proplist_setf(p
, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info
));
970 if ((sdn
= snd_pcm_info_get_subdevice_name(pcm_info
)))
971 pa_proplist_sets(p
, "alsa.subdevice_name", sdn
);
973 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
975 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0)
976 pa_alsa_init_proplist_card(c
, p
, card
);
979 void pa_alsa_init_proplist_pcm(pa_core
*c
, pa_proplist
*p
, snd_pcm_t
*pcm
) {
980 snd_pcm_hw_params_t
*hwparams
;
981 snd_pcm_info_t
*info
;
984 snd_pcm_hw_params_alloca(&hwparams
);
985 snd_pcm_info_alloca(&info
);
987 if ((err
= snd_pcm_hw_params_current(pcm
, hwparams
)) < 0)
988 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err
));
991 if ((bits
= snd_pcm_hw_params_get_sbits(hwparams
)) >= 0)
992 pa_proplist_setf(p
, "alsa.resolution_bits", "%i", bits
);
995 if ((err
= snd_pcm_info(pcm
, info
)) < 0)
996 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err
));
998 pa_alsa_init_proplist_pcm_info(c
, p
, info
);
1001 void pa_alsa_init_proplist_ctl(pa_proplist
*p
, const char *name
) {
1004 snd_ctl_card_info_t
*info
;
1009 snd_ctl_card_info_alloca(&info
);
1011 if ((err
= snd_ctl_open(&ctl
, name
, 0)) < 0) {
1012 pa_log_warn("Error opening low-level control device '%s': %s", name
, snd_strerror(err
));
1016 if ((err
= snd_ctl_card_info(ctl
, info
)) < 0) {
1017 pa_log_warn("Control device %s card info: %s", name
, snd_strerror(err
));
1022 if ((t
= snd_ctl_card_info_get_mixername(info
)) && *t
)
1023 pa_proplist_sets(p
, "alsa.mixer_name", t
);
1025 if ((t
= snd_ctl_card_info_get_components(info
)) && *t
)
1026 pa_proplist_sets(p
, "alsa.components", t
);
1031 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
1032 snd_pcm_state_t state
;
1037 if (revents
& POLLERR
)
1038 pa_log_debug("Got POLLERR from ALSA");
1039 if (revents
& POLLNVAL
)
1040 pa_log_warn("Got POLLNVAL from ALSA");
1041 if (revents
& POLLHUP
)
1042 pa_log_warn("Got POLLHUP from ALSA");
1043 if (revents
& POLLPRI
)
1044 pa_log_warn("Got POLLPRI from ALSA");
1045 if (revents
& POLLIN
)
1046 pa_log_debug("Got POLLIN from ALSA");
1047 if (revents
& POLLOUT
)
1048 pa_log_debug("Got POLLOUT from ALSA");
1050 state
= snd_pcm_state(pcm
);
1051 pa_log_debug("PCM state is %s", snd_pcm_state_name(state
));
1053 /* Try to recover from this error */
1057 case SND_PCM_STATE_XRUN
:
1058 if ((err
= snd_pcm_recover(pcm
, -EPIPE
, 1)) != 0) {
1059 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err
));
1064 case SND_PCM_STATE_SUSPENDED
:
1065 if ((err
= snd_pcm_recover(pcm
, -ESTRPIPE
, 1)) != 0) {
1066 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err
));
1075 if ((err
= snd_pcm_prepare(pcm
)) < 0) {
1076 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err
));
1085 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
1087 struct pollfd
*pollfd
;
1088 pa_rtpoll_item
*item
;
1092 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
1093 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n
));
1097 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
1098 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
1100 if ((err
= snd_pcm_poll_descriptors(pcm
, pollfd
, (unsigned) n
)) < 0) {
1101 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err
));
1102 pa_rtpoll_item_free(item
);
1109 snd_pcm_sframes_t
pa_alsa_safe_avail(snd_pcm_t
*pcm
, size_t hwbuf_size
, const pa_sample_spec
*ss
) {
1110 snd_pcm_sframes_t n
;
1114 pa_assert(hwbuf_size
> 0);
1117 /* Some ALSA driver expose weird bugs, let's inform the user about
1118 * what is going on */
1120 n
= snd_pcm_avail(pcm
);
1125 k
= (size_t) n
* pa_frame_size(ss
);
1127 if (PA_UNLIKELY(k
>= hwbuf_size
* 5 ||
1128 k
>= pa_bytes_per_second(ss
)*10)) {
1131 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1132 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1133 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1135 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1138 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1141 /* Mhmm, let's try not to fail completely */
1142 n
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1148 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
,
1153 snd_pcm_sframes_t avail
= 0;
1157 pa_assert(hwbuf_size
> 0);
1160 /* Some ALSA driver expose weird bugs, let's inform the user about
1161 * what is going on. We're going to get both the avail and delay values so
1162 * that we can compare and check them for capture.
1163 * This is done with snd_pcm_status() which provides
1164 * avail, delay and timestamp values in a single kernel call to improve
1165 * timer-based scheduling */
1167 if ((err
= snd_pcm_status(pcm
, status
)) < 0)
1170 avail
= snd_pcm_status_get_avail(status
);
1171 *delay
= snd_pcm_status_get_delay(status
);
1173 k
= (ssize_t
) *delay
* (ssize_t
) pa_frame_size(ss
);
1175 abs_k
= k
>= 0 ? (size_t) k
: (size_t) -k
;
1177 if (PA_UNLIKELY(abs_k
>= hwbuf_size
* 5 ||
1178 abs_k
>= pa_bytes_per_second(ss
)*10)) {
1181 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1182 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1183 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1186 (unsigned long) (pa_bytes_to_usec(abs_k
, ss
) / PA_USEC_PER_MSEC
),
1189 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1192 /* Mhmm, let's try not to fail completely */
1194 *delay
= -(snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1196 *delay
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1200 abs_k
= (size_t) avail
* pa_frame_size(ss
);
1202 if (PA_UNLIKELY(abs_k
>= hwbuf_size
* 5 ||
1203 abs_k
>= pa_bytes_per_second(ss
)*10)) {
1206 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1207 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1208 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1210 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1213 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1216 /* Mhmm, let's try not to fail completely */
1217 avail
= (snd_pcm_sframes_t
) (hwbuf_size
/ pa_frame_size(ss
));
1220 if (PA_UNLIKELY(*delay
< avail
)) {
1222 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1223 pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
1224 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1225 (unsigned long) *delay
,
1226 (unsigned long) avail
,
1229 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1240 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
) {
1242 snd_pcm_uframes_t before
;
1249 pa_assert(hwbuf_size
> 0);
1254 r
= snd_pcm_mmap_begin(pcm
, areas
, offset
, frames
);
1259 k
= (size_t) *frames
* pa_frame_size(ss
);
1261 if (PA_UNLIKELY(*frames
> before
||
1262 k
>= hwbuf_size
* 3 ||
1263 k
>= pa_bytes_per_second(ss
)*10))
1265 char *dn
= pa_alsa_get_driver_name_by_pcm(pcm
);
1266 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1267 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1269 (unsigned long) (pa_bytes_to_usec(k
, ss
) / PA_USEC_PER_MSEC
),
1272 pa_alsa_dump(PA_LOG_ERROR
, pcm
);
1278 char *pa_alsa_get_driver_name(int card
) {
1281 pa_assert(card
>= 0);
1283 t
= pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card
);
1290 n
= pa_xstrdup(pa_path_get_filename(m
));
1296 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t
*pcm
) {
1298 snd_pcm_info_t
* info
;
1299 snd_pcm_info_alloca(&info
);
1303 if (snd_pcm_info(pcm
, info
) < 0)
1306 if ((card
= snd_pcm_info_get_card(info
)) < 0)
1309 return pa_alsa_get_driver_name(card
);
1312 char *pa_alsa_get_reserve_name(const char *device
) {
1318 if ((t
= strchr(device
, ':')))
1321 if ((i
= snd_card_get_index(device
)) < 0) {
1324 if (pa_atoi(device
, &k
) < 0)
1330 return pa_sprintf_malloc("Audio%i", i
);
1333 unsigned int *pa_alsa_get_supported_rates(snd_pcm_t
*pcm
, unsigned int fallback_rate
) {
1334 static unsigned int all_rates
[] = { 8000, 11025, 12000,
1335 16000, 22050, 24000,
1336 32000, 44100, 48000,
1337 64000, 88200, 96000,
1338 128000, 176400, 192000,
1340 bool supported
[PA_ELEMENTSOF(all_rates
)] = { false, };
1341 snd_pcm_hw_params_t
*hwparams
;
1342 unsigned int i
, j
, n
, *rates
= NULL
;
1345 snd_pcm_hw_params_alloca(&hwparams
);
1347 if ((ret
= snd_pcm_hw_params_any(pcm
, hwparams
)) < 0) {
1348 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret
));
1352 for (i
= 0, n
= 0; i
< PA_ELEMENTSOF(all_rates
); i
++) {
1353 if (snd_pcm_hw_params_test_rate(pcm
, hwparams
, all_rates
[i
], 0) == 0) {
1354 supported
[i
] = true;
1360 rates
= pa_xnew(unsigned int, n
+ 1);
1362 for (i
= 0, j
= 0; i
< PA_ELEMENTSOF(all_rates
); i
++) {
1364 rates
[j
++] = all_rates
[i
];
1369 rates
= pa_xnew(unsigned int, 2);
1371 rates
[0] = fallback_rate
;
1372 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rates
[0], NULL
)) < 0) {
1373 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret
));
1384 bool pa_alsa_pcm_is_hw(snd_pcm_t
*pcm
) {
1385 snd_pcm_info_t
* info
;
1386 snd_pcm_info_alloca(&info
);
1390 if (snd_pcm_info(pcm
, info
) < 0)
1393 return snd_pcm_info_get_card(info
) >= 0;
1396 bool pa_alsa_pcm_is_modem(snd_pcm_t
*pcm
) {
1397 snd_pcm_info_t
* info
;
1398 snd_pcm_info_alloca(&info
);
1402 if (snd_pcm_info(pcm
, info
) < 0)
1405 return snd_pcm_info_get_class(info
) == SND_PCM_CLASS_MODEM
;
1408 PA_STATIC_TLS_DECLARE(cstrerror
, pa_xfree
);
1410 const char* pa_alsa_strerror(int errnum
) {
1411 const char *original
= NULL
;
1412 char *translated
, *t
;
1415 if ((t
= PA_STATIC_TLS_GET(cstrerror
)))
1418 original
= snd_strerror(errnum
);
1421 pa_snprintf(errbuf
, sizeof(errbuf
), "Unknown error %i", errnum
);
1425 if (!(translated
= pa_locale_to_utf8(original
))) {
1426 pa_log_warn("Unable to convert error string to locale, filtering.");
1427 translated
= pa_utf8_filter(original
);
1430 PA_STATIC_TLS_SET(cstrerror
, translated
);
1435 bool pa_alsa_may_tsched(bool want
) {
1440 if (!pa_rtclock_hrtimer()) {
1441 /* We cannot depend on being woken up in time when the timers
1442 are inaccurate, so let's fallback to classic IO based playback
1444 pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1447 if (pa_running_in_vm()) {
1448 /* We cannot depend on being woken up when we ask for in a VM,
1449 * so let's fallback to classic IO based playback then. */
1450 pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
1457 snd_hctl_elem_t
* pa_alsa_find_jack(snd_hctl_t
*hctl
, const char* jack_name
) {
1458 snd_ctl_elem_id_t
*id
;
1460 snd_ctl_elem_id_alloca(&id
);
1461 snd_ctl_elem_id_clear(id
);
1462 snd_ctl_elem_id_set_interface(id
, SND_CTL_ELEM_IFACE_CARD
);
1463 snd_ctl_elem_id_set_name(id
, jack_name
);
1465 return snd_hctl_find_elem(hctl
, id
);
1468 snd_hctl_elem_t
* pa_alsa_find_eld_ctl(snd_hctl_t
*hctl
, int device
) {
1469 snd_ctl_elem_id_t
*id
;
1471 /* See if we can find the ELD control */
1472 snd_ctl_elem_id_alloca(&id
);
1473 snd_ctl_elem_id_clear(id
);
1474 snd_ctl_elem_id_set_interface(id
, SND_CTL_ELEM_IFACE_PCM
);
1475 snd_ctl_elem_id_set_name(id
, "ELD");
1476 snd_ctl_elem_id_set_device(id
, device
);
1478 return snd_hctl_find_elem(hctl
, id
);
1481 static int prepare_mixer(snd_mixer_t
*mixer
, const char *dev
, snd_hctl_t
**hctl
) {
1487 if ((err
= snd_mixer_attach(mixer
, dev
)) < 0) {
1488 pa_log_info("Unable to attach to mixer %s: %s", dev
, pa_alsa_strerror(err
));
1492 /* Note: The hctl handle returned should not be freed.
1493 It is closed/freed by alsa-lib on snd_mixer_close/free */
1494 if (hctl
&& (err
= snd_mixer_get_hctl(mixer
, dev
, hctl
)) < 0) {
1495 pa_log_info("Unable to get hctl of mixer %s: %s", dev
, pa_alsa_strerror(err
));
1499 if ((err
= snd_mixer_selem_register(mixer
, NULL
, NULL
)) < 0) {
1500 pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err
));
1504 if ((err
= snd_mixer_load(mixer
)) < 0) {
1505 pa_log_warn("Unable to load mixer: %s", pa_alsa_strerror(err
));
1509 pa_log_info("Successfully attached to mixer '%s'", dev
);
1513 snd_mixer_t
*pa_alsa_open_mixer(int alsa_card_index
, char **ctl_device
, snd_hctl_t
**hctl
) {
1517 snd_pcm_info_t
* info
;
1518 snd_pcm_info_alloca(&info
);
1520 if ((err
= snd_mixer_open(&m
, 0)) < 0) {
1521 pa_log("Error opening mixer: %s", pa_alsa_strerror(err
));
1525 /* Then, try by card index */
1526 md
= pa_sprintf_malloc("hw:%i", alsa_card_index
);
1527 if (prepare_mixer(m
, md
, hctl
) >= 0) {
1543 snd_mixer_t
*pa_alsa_open_mixer_for_pcm(snd_pcm_t
*pcm
, char **ctl_device
, snd_hctl_t
**hctl
) {
1547 snd_pcm_info_t
* info
;
1548 snd_pcm_info_alloca(&info
);
1552 if ((err
= snd_mixer_open(&m
, 0)) < 0) {
1553 pa_log("Error opening mixer: %s", pa_alsa_strerror(err
));
1557 /* First, try by name */
1558 if ((dev
= snd_pcm_name(pcm
)))
1559 if (prepare_mixer(m
, dev
, hctl
) >= 0) {
1561 *ctl_device
= pa_xstrdup(dev
);
1566 /* Then, try by card index */
1567 if (snd_pcm_info(pcm
, info
) >= 0) {
1571 if ((card_idx
= snd_pcm_info_get_card(info
)) >= 0) {
1573 md
= pa_sprintf_malloc("hw:%i", card_idx
);
1575 if (!dev
|| !pa_streq(dev
, md
))
1576 if (prepare_mixer(m
, md
, hctl
) >= 0) {
1594 int pa_alsa_get_hdmi_eld(snd_hctl_t
*hctl
, int device
, pa_hdmi_eld
*eld
) {
1596 /* The ELD format is specific to HDA Intel sound cards and defined in the
1597 HDA specification: http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html */
1599 snd_hctl_elem_t
*elem
;
1600 snd_ctl_elem_info_t
*info
;
1601 snd_ctl_elem_value_t
*value
;
1603 unsigned int eldsize
, mnl
;
1605 pa_assert(eld
!= NULL
);
1607 /* See if we can find the ELD control */
1608 elem
= pa_alsa_find_eld_ctl(hctl
, device
);
1610 pa_log_debug("No ELD info control found (for device=%d)", device
);
1614 /* Does it have any contents? */
1615 snd_ctl_elem_info_alloca(&info
);
1616 snd_ctl_elem_value_alloca(&value
);
1617 if ((err
= snd_hctl_elem_info(elem
, info
)) < 0 ||
1618 (err
= snd_hctl_elem_read(elem
, value
)) < 0) {
1619 pa_log_warn("Accessing ELD control failed with error %s", snd_strerror(err
));
1623 eldsize
= snd_ctl_elem_info_get_count(info
);
1624 elddata
= (unsigned char *) snd_ctl_elem_value_get_bytes(value
);
1625 if (elddata
== NULL
|| eldsize
== 0) {
1626 pa_log_debug("ELD info empty (for device=%d)", device
);
1629 if (eldsize
< 20 || eldsize
> 256) {
1630 pa_log_debug("ELD info has wrong size (for device=%d)", device
);
1634 /* Try to fetch monitor name */
1635 mnl
= elddata
[4] & 0x1f;
1636 if (mnl
== 0 || mnl
> 16 || 20 + mnl
> eldsize
) {
1637 pa_log_debug("No monitor name in ELD info (for device=%d)", device
);
1640 memcpy(eld
->monitor_name
, &elddata
[20], mnl
);
1641 eld
->monitor_name
[mnl
] = '\0';
1643 pa_log_debug("Monitor name in ELD info is '%s' (for device=%d)", eld
->monitor_name
, device
);