1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2009 Lennart Poettering
5  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
17  You should have received a copy of the GNU Lesser General Public License
18  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <sys/types.h>
26#include <alsa/asoundlib.h>
27
28#include <pulse/sample.h>
29#include <pulse/xmalloc.h>
30#include <pulse/timeval.h>
31#include <pulse/util.h>
32#include <pulse/utf8.h>
33
34#include <pulsecore/i18n.h>
35#include <pulsecore/log.h>
36#include <pulsecore/macro.h>
37#include <pulsecore/core-util.h>
38#include <pulsecore/atomic.h>
39#include <pulsecore/core-error.h>
40#include <pulsecore/thread.h>
41#include <pulsecore/conf-parser.h>
42#include <pulsecore/core-rtclock.h>
43
44#include "alsa-util.h"
45#include "alsa-mixer.h"
46
47#ifdef HAVE_UDEV
48#include <modules/udev-util.h>
49#endif
50
51static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
52
53    static const snd_pcm_format_t format_trans[] = {
54        [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8,
55        [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
56        [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
57        [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
58        [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
59        [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
60        [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
61        [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
62        [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
63        [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
64        [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
65        [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
66        [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE,
67    };
68
69    static const pa_sample_format_t try_order[] = {
70        PA_SAMPLE_FLOAT32NE,
71        PA_SAMPLE_FLOAT32RE,
72        PA_SAMPLE_S32NE,
73        PA_SAMPLE_S32RE,
74        PA_SAMPLE_S24_32NE,
75        PA_SAMPLE_S24_32RE,
76        PA_SAMPLE_S24NE,
77        PA_SAMPLE_S24RE,
78        PA_SAMPLE_S16NE,
79        PA_SAMPLE_S16RE,
80        PA_SAMPLE_ALAW,
81        PA_SAMPLE_ULAW,
82        PA_SAMPLE_U8
83    };
84
85    unsigned i;
86    int ret;
87
88    pa_assert(pcm_handle);
89    pa_assert(hwparams);
90    pa_assert(f);
91
92    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
93        return ret;
94
95    pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
96                 snd_pcm_format_description(format_trans[*f]),
97                 pa_alsa_strerror(ret));
98
99    if (*f == PA_SAMPLE_FLOAT32BE)
100        *f = PA_SAMPLE_FLOAT32LE;
101    else if (*f == PA_SAMPLE_FLOAT32LE)
102        *f = PA_SAMPLE_FLOAT32BE;
103    else if (*f == PA_SAMPLE_S24BE)
104        *f = PA_SAMPLE_S24LE;
105    else if (*f == PA_SAMPLE_S24LE)
106        *f = PA_SAMPLE_S24BE;
107    else if (*f == PA_SAMPLE_S24_32BE)
108        *f = PA_SAMPLE_S24_32LE;
109    else if (*f == PA_SAMPLE_S24_32LE)
110        *f = PA_SAMPLE_S24_32BE;
111    else if (*f == PA_SAMPLE_S16BE)
112        *f = PA_SAMPLE_S16LE;
113    else if (*f == PA_SAMPLE_S16LE)
114        *f = PA_SAMPLE_S16BE;
115    else if (*f == PA_SAMPLE_S32BE)
116        *f = PA_SAMPLE_S32LE;
117    else if (*f == PA_SAMPLE_S32LE)
118        *f = PA_SAMPLE_S32BE;
119    else
120        goto try_auto;
121
122    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
123        return ret;
124
125    pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
126                 snd_pcm_format_description(format_trans[*f]),
127                 pa_alsa_strerror(ret));
128
129try_auto:
130
131    for (i = 0; i < PA_ELEMENTSOF(try_order); i++) {
132        *f = try_order[i];
133
134        if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
135            return ret;
136
137        pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
138                     snd_pcm_format_description(format_trans[*f]),
139                     pa_alsa_strerror(ret));
140    }
141
142    return -1;
143}
144
145static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
146    snd_pcm_uframes_t s;
147    int d, ret;
148
149    pa_assert(pcm_handle);
150    pa_assert(hwparams);
151
152    s = size;
153    d = 0;
154    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
155        s = size;
156        d = -1;
157        if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
158            s = size;
159            d = 1;
160            if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
161                pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
162                return ret;
163            }
164        }
165    }
166
167    return 0;
168}
169
170static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
171    int ret;
172
173    pa_assert(pcm_handle);
174    pa_assert(hwparams);
175
176    if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
177        pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
178        return ret;
179    }
180
181    return 0;
182}
183
184static void check_access(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, bool use_mmap) {
185    if ((use_mmap && !snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) ||
186        !snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))
187        pa_log_error("Weird, PCM claims to support interleaved access, but snd_pcm_hw_params_set_access() failed.");
188
189    if ((use_mmap && !snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) ||
190        !snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_NONINTERLEAVED))
191        pa_log_debug("PCM seems to support non-interleaved access, but PA doesn't.");
192    else if (use_mmap && !snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_COMPLEX)) {
193        pa_log_debug("PCM seems to support mmapped complex access, but PA doesn't.");
194    }
195}
196
197/* Set the hardware parameters of the given ALSA device. Returns the
198 * selected fragment settings in *buffer_size and *period_size. Determine
199 * whether mmap and tsched mode can be enabled. */
200int pa_alsa_set_hw_params(
201        snd_pcm_t *pcm_handle,
202        pa_sample_spec *ss,
203        snd_pcm_uframes_t *period_size,
204        snd_pcm_uframes_t *buffer_size,
205        snd_pcm_uframes_t tsched_size,
206        bool *use_mmap,
207        bool *use_tsched,
208        bool require_exact_channel_number) {
209
210    int ret = -1;
211    snd_pcm_hw_params_t *hwparams, *hwparams_copy;
212    int dir;
213    snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
214    snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
215    bool _use_mmap = use_mmap && *use_mmap;
216    bool _use_tsched = use_tsched && *use_tsched;
217    pa_sample_spec _ss = *ss;
218
219    pa_assert(pcm_handle);
220    pa_assert(ss);
221
222    snd_pcm_hw_params_alloca(&hwparams);
223    snd_pcm_hw_params_alloca(&hwparams_copy);
224
225    if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
226        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
227        goto finish;
228    }
229
230    if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
231        pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret));
232        goto finish;
233    }
234
235    if (_use_mmap) {
236
237        if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
238
239            /* mmap() didn't work, fall back to interleaved */
240
241            if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
242                pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
243                check_access(pcm_handle, hwparams, true);
244                goto finish;
245            }
246
247            _use_mmap = false;
248        }
249
250    } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
251        pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
252        check_access(pcm_handle, hwparams, false);
253        goto finish;
254    }
255
256    if (!_use_mmap)
257        _use_tsched = false;
258
259    if (!pa_alsa_pcm_is_hw(pcm_handle))
260        _use_tsched = false;
261
262    /* The PCM pointer is only updated with period granularity */
263    if (snd_pcm_hw_params_is_batch(hwparams)) {
264        bool is_usb = false;
265        const char *id;
266        snd_pcm_info_t* pcm_info;
267        snd_pcm_info_alloca(&pcm_info);
268
269        if (snd_pcm_info(pcm_handle, pcm_info) == 0 &&
270            (id = snd_pcm_info_get_id(pcm_info))) {
271            /* This horrible hack makes sure we don't disable tsched on USB
272             * devices, which have a low enough transfer size for timer-based
273             * scheduling to work. This can go away when the ALSA API supprots
274             * querying the block transfer size. */
275            if (pa_streq(id, "USB Audio"))
276                is_usb = true;
277        }
278
279        if (!is_usb) {
280            pa_log_info("Disabling tsched mode since BATCH flag is set");
281            _use_tsched = false;
282        }
283    }
284
285#if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
286    if (_use_tsched) {
287
288        /* try to disable period wakeups if hardware can do so */
289        if (snd_pcm_hw_params_can_disable_period_wakeup(hwparams)) {
290
291            if ((ret = snd_pcm_hw_params_set_period_wakeup(pcm_handle, hwparams, false)) < 0)
292                /* don't bail, keep going with default mode with period wakeups */
293                pa_log_debug("snd_pcm_hw_params_set_period_wakeup() failed: %s", pa_alsa_strerror(ret));
294            else
295                pa_log_info("Trying to disable ALSA period wakeups, using timers only");
296        } else
297            pa_log_info("Cannot disable ALSA period wakeups");
298    }
299#endif
300
301    if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
302        goto finish;
303
304    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
305        pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
306        goto finish;
307    }
308
309    /* We ignore very small sampling rate deviations */
310    if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05)
311        _ss.rate = ss->rate;
312
313    if (require_exact_channel_number) {
314        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
315            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
316            goto finish;
317        }
318    } else {
319        unsigned int c = _ss.channels;
320
321        if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
322            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
323            goto finish;
324        }
325
326        _ss.channels = c;
327    }
328
329    if (_use_tsched && tsched_size > 0) {
330        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate);
331        _period_size = _buffer_size;
332    } else {
333        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate);
334        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate);
335    }
336
337    if (_buffer_size > 0 || _period_size > 0) {
338        snd_pcm_uframes_t max_frames = 0;
339
340        if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
341            pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
342        else
343            pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames * PA_MSEC_PER_SEC / _ss.rate));
344
345        /* Some ALSA drivers really don't like if we set the buffer
346         * size first and the number of periods second (which would
347         * make a lot more sense to me). So, try a few combinations
348         * before we give up. */
349
350        if (_buffer_size > 0 && _period_size > 0) {
351            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
352
353            /* First try: set buffer size first, followed by period size */
354            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
355                set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
356                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
357                pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size);
358                goto success;
359            }
360
361            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
362            /* Second try: set period size first, followed by buffer size */
363            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
364                set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
365                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
366                pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size, (unsigned long) _buffer_size);
367                goto success;
368            }
369        }
370
371        if (_buffer_size > 0) {
372            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
373
374            /* Third try: set only buffer size */
375            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
376                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
377                pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size);
378                goto success;
379            }
380        }
381
382        if (_period_size > 0) {
383            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
384
385            /* Fourth try: set only period size */
386            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
387                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
388                pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size);
389                goto success;
390            }
391        }
392    }
393
394    pa_log_debug("Set neither period nor buffer size.");
395
396    /* Last chance, set nothing */
397    if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
398        pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
399        goto finish;
400    }
401
402success:
403
404    if (ss->rate != _ss.rate)
405        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
406
407    if (ss->channels != _ss.channels)
408        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
409
410    if (ss->format != _ss.format)
411        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));
412
413    if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
414        pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
415        goto finish;
416    }
417
418    if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
419        (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
420        pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
421        goto finish;
422    }
423
424#if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
425    if (_use_tsched) {
426        unsigned int no_wakeup;
427        /* see if period wakeups were disabled */
428        snd_pcm_hw_params_get_period_wakeup(pcm_handle, hwparams, &no_wakeup);
429        if (no_wakeup == 0)
430            pa_log_info("ALSA period wakeups disabled");
431        else
432            pa_log_info("ALSA period wakeups were not disabled");
433    }
434#endif
435
436    ss->rate = _ss.rate;
437    ss->channels = _ss.channels;
438    ss->format = _ss.format;
439
440    pa_assert(_period_size > 0);
441    pa_assert(_buffer_size > 0);
442
443    if (buffer_size)
444        *buffer_size = _buffer_size;
445
446    if (period_size)
447        *period_size = _period_size;
448
449    if (use_mmap)
450        *use_mmap = _use_mmap;
451
452    if (use_tsched)
453        *use_tsched = _use_tsched;
454
455    ret = 0;
456
457finish:
458
459    return ret;
460}
461
462int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, bool period_event) {
463    snd_pcm_sw_params_t *swparams;
464    snd_pcm_uframes_t boundary;
465    int err;
466
467    pa_assert(pcm);
468
469    snd_pcm_sw_params_alloca(&swparams);
470
471    if ((err = snd_pcm_sw_params_current(pcm, swparams)) < 0) {
472        pa_log_warn("Unable to determine current swparams: %s", pa_alsa_strerror(err));
473        return err;
474    }
475
476    if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
477        pa_log_warn("Unable to disable period event: %s", pa_alsa_strerror(err));
478        return err;
479    }
480
481    if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
482        pa_log_warn("Unable to enable time stamping: %s", pa_alsa_strerror(err));
483        return err;
484    }
485
486    if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
487        pa_log_warn("Unable to get boundary: %s", pa_alsa_strerror(err));
488        return err;
489    }
490
491    if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
492        pa_log_warn("Unable to set stop threshold: %s", pa_alsa_strerror(err));
493        return err;
494    }
495
496    if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
497        pa_log_warn("Unable to set start threshold: %s", pa_alsa_strerror(err));
498        return err;
499    }
500
501    if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
502        pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
503        return err;
504    }
505
506    if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
507        pa_log_warn("Unable to set sw params: %s", pa_alsa_strerror(err));
508        return err;
509    }
510
511    return 0;
512}
513
514snd_pcm_t *pa_alsa_open_by_device_id_auto(
515        const char *dev_id,
516        char **dev,
517        pa_sample_spec *ss,
518        pa_channel_map* map,
519        int mode,
520        snd_pcm_uframes_t *period_size,
521        snd_pcm_uframes_t *buffer_size,
522        snd_pcm_uframes_t tsched_size,
523        bool *use_mmap,
524        bool *use_tsched,
525        pa_alsa_profile_set *ps,
526        pa_alsa_mapping **mapping) {
527
528    char *d;
529    snd_pcm_t *pcm_handle;
530    void *state;
531    pa_alsa_mapping *m;
532
533    pa_assert(dev_id);
534    pa_assert(dev);
535    pa_assert(ss);
536    pa_assert(map);
537    pa_assert(ps);
538
539    /* First we try to find a device string with a superset of the
540     * requested channel map. We iterate through our device table from
541     * top to bottom and take the first that matches. If we didn't
542     * find a working device that way, we iterate backwards, and check
543     * all devices that do not provide a superset of the requested
544     * channel map.*/
545
546    PA_HASHMAP_FOREACH(m, ps->mappings, state) {
547        if (!pa_channel_map_superset(&m->channel_map, map))
548            continue;
549
550        pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
551
552        pcm_handle = pa_alsa_open_by_device_id_mapping(
553                dev_id,
554                dev,
555                ss,
556                map,
557                mode,
558                period_size,
559                buffer_size,
560                tsched_size,
561                use_mmap,
562                use_tsched,
563                m);
564
565        if (pcm_handle) {
566            if (mapping)
567                *mapping = m;
568
569            return pcm_handle;
570        }
571    }
572
573    PA_HASHMAP_FOREACH_BACKWARDS(m, ps->mappings, state) {
574        if (pa_channel_map_superset(&m->channel_map, map))
575            continue;
576
577        pa_log_debug("Checking for subset %s (%s)", m->name, m->device_strings[0]);
578
579        pcm_handle = pa_alsa_open_by_device_id_mapping(
580                dev_id,
581                dev,
582                ss,
583                map,
584                mode,
585                period_size,
586                buffer_size,
587                tsched_size,
588                use_mmap,
589                use_tsched,
590                m);
591
592        if (pcm_handle) {
593            if (mapping)
594                *mapping = m;
595
596            return pcm_handle;
597        }
598    }
599
600    /* OK, we didn't find any good device, so let's try the raw hw: stuff */
601    d = pa_sprintf_malloc("hw:%s", dev_id);
602    pa_log_debug("Trying %s as last resort...", d);
603    pcm_handle = pa_alsa_open_by_device_string(
604            d,
605            dev,
606            ss,
607            map,
608            mode,
609            period_size,
610            buffer_size,
611            tsched_size,
612            use_mmap,
613            use_tsched,
614            false);
615    pa_xfree(d);
616
617    if (pcm_handle && mapping)
618        *mapping = NULL;
619
620    return pcm_handle;
621}
622
623snd_pcm_t *pa_alsa_open_by_device_id_mapping(
624        const char *dev_id,
625        char **dev,
626        pa_sample_spec *ss,
627        pa_channel_map* map,
628        int mode,
629        snd_pcm_uframes_t *period_size,
630        snd_pcm_uframes_t *buffer_size,
631        snd_pcm_uframes_t tsched_size,
632        bool *use_mmap,
633        bool *use_tsched,
634        pa_alsa_mapping *m) {
635
636    snd_pcm_t *pcm_handle;
637    pa_sample_spec try_ss;
638    pa_channel_map try_map;
639
640    pa_assert(dev_id);
641    pa_assert(dev);
642    pa_assert(ss);
643    pa_assert(map);
644    pa_assert(m);
645
646    try_ss.channels = m->channel_map.channels;
647    try_ss.rate = ss->rate;
648    try_ss.format = ss->format;
649    try_map = m->channel_map;
650
651    pcm_handle = pa_alsa_open_by_template(
652            m->device_strings,
653            dev_id,
654            dev,
655            &try_ss,
656            &try_map,
657            mode,
658            period_size,
659            buffer_size,
660            tsched_size,
661            use_mmap,
662            use_tsched,
663            pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */);
664
665    if (!pcm_handle)
666        return NULL;
667
668    *ss = try_ss;
669    *map = try_map;
670    pa_assert(map->channels == ss->channels);
671
672    return pcm_handle;
673}
674
675snd_pcm_t *pa_alsa_open_by_device_string(
676        const char *device,
677        char **dev,
678        pa_sample_spec *ss,
679        pa_channel_map* map,
680        int mode,
681        snd_pcm_uframes_t *period_size,
682        snd_pcm_uframes_t *buffer_size,
683        snd_pcm_uframes_t tsched_size,
684        bool *use_mmap,
685        bool *use_tsched,
686        bool require_exact_channel_number) {
687
688    int err;
689    char *d;
690    snd_pcm_t *pcm_handle;
691    bool reformat = false;
692
693    pa_assert(device);
694    pa_assert(ss);
695    pa_assert(map);
696
697    d = pa_xstrdup(device);
698
699    for (;;) {
700        pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
701
702        if ((err = snd_pcm_open(&pcm_handle, d, mode,
703                                SND_PCM_NONBLOCK|
704                                SND_PCM_NO_AUTO_RESAMPLE|
705                                SND_PCM_NO_AUTO_CHANNELS|
706                                (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
707            pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
708            goto fail;
709        }
710
711        pa_log_debug("Managed to open %s", d);
712
713        if ((err = pa_alsa_set_hw_params(
714                     pcm_handle,
715                     ss,
716                     period_size,
717                     buffer_size,
718                     tsched_size,
719                     use_mmap,
720                     use_tsched,
721                     require_exact_channel_number)) < 0) {
722
723            if (!reformat) {
724                reformat = true;
725
726                snd_pcm_close(pcm_handle);
727                continue;
728            }
729
730            /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
731            if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
732                char *t;
733
734                t = pa_sprintf_malloc("plug:SLAVE='%s'", d);
735                pa_xfree(d);
736                d = t;
737
738                reformat = false;
739
740                snd_pcm_close(pcm_handle);
741                continue;
742            }
743
744            pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
745            snd_pcm_close(pcm_handle);
746
747            goto fail;
748        }
749
750        if (ss->channels > PA_CHANNELS_MAX) {
751            pa_log("Device %s has %u channels, but PulseAudio supports only %u channels. Unable to use the device.",
752                   d, ss->channels, PA_CHANNELS_MAX);
753            snd_pcm_close(pcm_handle);
754            goto fail;
755        }
756
757        if (dev)
758            *dev = d;
759        else
760            pa_xfree(d);
761
762        if (ss->channels != map->channels)
763            pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
764
765        return pcm_handle;
766    }
767
768fail:
769    pa_xfree(d);
770
771    return NULL;
772}
773
774snd_pcm_t *pa_alsa_open_by_template(
775        char **template,
776        const char *dev_id,
777        char **dev,
778        pa_sample_spec *ss,
779        pa_channel_map* map,
780        int mode,
781        snd_pcm_uframes_t *period_size,
782        snd_pcm_uframes_t *buffer_size,
783        snd_pcm_uframes_t tsched_size,
784        bool *use_mmap,
785        bool *use_tsched,
786        bool require_exact_channel_number) {
787
788    snd_pcm_t *pcm_handle;
789    char **i;
790
791    for (i = template; *i; i++) {
792        char *d;
793
794        d = pa_replace(*i, "%f", dev_id);
795
796        pcm_handle = pa_alsa_open_by_device_string(
797                d,
798                dev,
799                ss,
800                map,
801                mode,
802                period_size,
803                buffer_size,
804                tsched_size,
805                use_mmap,
806                use_tsched,
807                require_exact_channel_number);
808
809        pa_xfree(d);
810
811        if (pcm_handle)
812            return pcm_handle;
813    }
814
815    return NULL;
816}
817
818void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
819    int err;
820    snd_output_t *out;
821
822    pa_assert(pcm);
823
824    pa_assert_se(snd_output_buffer_open(&out) == 0);
825
826    if ((err = snd_pcm_dump(pcm, out)) < 0)
827        pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
828    else {
829        char *s = NULL;
830        snd_output_buffer_string(out, &s);
831        pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
832    }
833
834    pa_assert_se(snd_output_close(out) == 0);
835}
836
837void pa_alsa_dump_status(snd_pcm_t *pcm) {
838    int err;
839    snd_output_t *out;
840    snd_pcm_status_t *status;
841    char *s = NULL;
842
843    pa_assert(pcm);
844
845    snd_pcm_status_alloca(&status);
846
847    if ((err = snd_output_buffer_open(&out)) < 0) {
848        pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err));
849        return;
850    }
851
852    if ((err = snd_pcm_status(pcm, status)) < 0) {
853        pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err));
854        goto finish;
855    }
856
857    if ((err = snd_pcm_status_dump(status, out)) < 0) {
858        pa_log_debug("snd_pcm_status_dump(): %s", pa_alsa_strerror(err));
859        goto finish;
860    }
861
862    snd_output_buffer_string(out, &s);
863    pa_log_debug("snd_pcm_status_dump():\n%s", pa_strnull(s));
864
865finish:
866
867    snd_output_close(out);
868}
869
870static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
871    va_list ap;
872    char *alsa_file;
873
874    alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
875
876    va_start(ap, fmt);
877
878    pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
879
880    va_end(ap);
881
882    pa_xfree(alsa_file);
883}
884
885static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
886
887void pa_alsa_refcnt_inc(void) {
888    /* This is not really thread safe, but we do our best */
889
890    if (pa_atomic_inc(&n_error_handler_installed) == 0)
891        snd_lib_error_set_handler(alsa_error_handler);
892}
893
894void pa_alsa_refcnt_dec(void) {
895    int r;
896
897    pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
898
899    if (r == 1) {
900        snd_lib_error_set_handler(NULL);
901        snd_config_update_free_global();
902    }
903}
904
905bool pa_alsa_init_description(pa_proplist *p, pa_card *card) {
906    const char *d, *k;
907    pa_assert(p);
908
909    if (pa_device_init_description(p, card))
910        return true;
911
912    if (!(d = pa_proplist_gets(p, "alsa.card_name")))
913        d = pa_proplist_gets(p, "alsa.name");
914
915    if (!d)
916        return false;
917
918    k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
919
920    if (d && k)
921        pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, "%s %s", d, k);
922    else if (d)
923        pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
924
925    return false;
926}
927
928void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
929    char *cn, *lcn, *dn;
930
931    pa_assert(p);
932    pa_assert(card >= 0);
933
934    pa_proplist_setf(p, "alsa.card", "%i", card);
935
936    if (snd_card_get_name(card, &cn) >= 0) {
937        pa_proplist_sets(p, "alsa.card_name", pa_strip(cn));
938        free(cn);
939    }
940
941    if (snd_card_get_longname(card, &lcn) >= 0) {
942        pa_proplist_sets(p, "alsa.long_card_name", pa_strip(lcn));
943        free(lcn);
944    }
945
946    if ((dn = pa_alsa_get_driver_name(card))) {
947        pa_proplist_sets(p, "alsa.driver_name", dn);
948        pa_xfree(dn);
949    }
950
951#ifdef HAVE_UDEV
952    pa_udev_get_info(card, p);
953#endif
954}
955
956void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
957
958    static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
959        [SND_PCM_CLASS_GENERIC] = "generic",
960        [SND_PCM_CLASS_MULTI] = "multi",
961        [SND_PCM_CLASS_MODEM] = "modem",
962        [SND_PCM_CLASS_DIGITIZER] = "digitizer"
963    };
964    static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
965        [SND_PCM_CLASS_GENERIC] = "sound",
966        [SND_PCM_CLASS_MULTI] = NULL,
967        [SND_PCM_CLASS_MODEM] = "modem",
968        [SND_PCM_CLASS_DIGITIZER] = NULL
969    };
970    static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
971        [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
972        [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
973    };
974
975    snd_pcm_class_t class;
976    snd_pcm_subclass_t subclass;
977    const char *n, *id, *sdn;
978    int card;
979
980    pa_assert(p);
981    pa_assert(pcm_info);
982
983    pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
984
985    if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
986        if (class_table[class])
987            pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
988        if (alsa_class_table[class])
989            pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
990    }
991
992    if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
993        if (alsa_subclass_table[subclass])
994            pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
995
996    if ((n = snd_pcm_info_get_name(pcm_info))) {
997        char *t = pa_xstrdup(n);
998        pa_proplist_sets(p, "alsa.name", pa_strip(t));
999        pa_xfree(t);
1000    }
1001
1002    if ((id = snd_pcm_info_get_id(pcm_info)))
1003        pa_proplist_sets(p, "alsa.id", id);
1004
1005    pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
1006    if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
1007        pa_proplist_sets(p, "alsa.subdevice_name", sdn);
1008
1009    pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
1010
1011    if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
1012        pa_alsa_init_proplist_card(c, p, card);
1013}
1014
1015void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
1016    snd_pcm_hw_params_t *hwparams;
1017    snd_pcm_info_t *info;
1018    int bits, err;
1019
1020    snd_pcm_hw_params_alloca(&hwparams);
1021    snd_pcm_info_alloca(&info);
1022
1023    if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
1024        pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
1025    else {
1026
1027        if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
1028            pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
1029    }
1030
1031    if ((err = snd_pcm_info(pcm, info)) < 0)
1032        pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
1033    else
1034        pa_alsa_init_proplist_pcm_info(c, p, info);
1035}
1036
1037void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
1038    int err;
1039    snd_ctl_t *ctl;
1040    snd_ctl_card_info_t *info;
1041    const char *t;
1042
1043    pa_assert(p);
1044
1045    snd_ctl_card_info_alloca(&info);
1046
1047    if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
1048        pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));
1049        return;
1050    }
1051
1052    if ((err = snd_ctl_card_info(ctl, info)) < 0) {
1053        pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
1054        snd_ctl_close(ctl);
1055        return;
1056    }
1057
1058    if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
1059        pa_proplist_sets(p, "alsa.mixer_name", t);
1060
1061    if ((t = snd_ctl_card_info_get_components(info)) && *t)
1062        pa_proplist_sets(p, "alsa.components", t);
1063
1064    snd_ctl_close(ctl);
1065}
1066
1067int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1068    snd_pcm_state_t state;
1069    snd_pcm_hw_params_t *hwparams;
1070    int err;
1071
1072    pa_assert(pcm);
1073
1074    if (revents & POLLERR)
1075        pa_log_debug("Got POLLERR from ALSA");
1076    if (revents & POLLNVAL)
1077        pa_log_warn("Got POLLNVAL from ALSA");
1078    if (revents & POLLHUP)
1079        pa_log_warn("Got POLLHUP from ALSA");
1080    if (revents & POLLPRI)
1081        pa_log_warn("Got POLLPRI from ALSA");
1082    if (revents & POLLIN)
1083        pa_log_debug("Got POLLIN from ALSA");
1084    if (revents & POLLOUT)
1085        pa_log_debug("Got POLLOUT from ALSA");
1086
1087    state = snd_pcm_state(pcm);
1088    pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1089
1090    /* Try to recover from this error */
1091
1092    switch (state) {
1093
1094        case SND_PCM_STATE_DISCONNECTED:
1095            /* Do not try to recover */
1096            pa_log_info("Device disconnected.");
1097            return -1;
1098
1099        case SND_PCM_STATE_XRUN:
1100            if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1101                pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1102                return -1;
1103            }
1104            break;
1105
1106        case SND_PCM_STATE_SUSPENDED:
1107            snd_pcm_hw_params_alloca(&hwparams);
1108
1109            if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
1110		pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(err));
1111		return -1;
1112            }
1113
1114            if (snd_pcm_hw_params_can_resume(hwparams)) {
1115                /* Retry resume 3 times before giving up, then fallback to restarting the stream. */
1116                for (int i = 0; i < 3; i++) {
1117                    if ((err = snd_pcm_resume(pcm)) == 0)
1118                        return 0;
1119                    if (err != -EAGAIN)
1120                        break;
1121                    pa_msleep(25);
1122                }
1123                pa_log_warn("Could not recover alsa device from SUSPENDED state, trying to restart PCM");
1124	    }
1125	    /* Fall through */
1126
1127        default:
1128
1129            snd_pcm_drop(pcm);
1130            return 1;
1131    }
1132
1133    return 0;
1134}
1135
1136pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1137    int n, err;
1138    struct pollfd *pollfd;
1139    pa_rtpoll_item *item;
1140
1141    pa_assert(pcm);
1142
1143    if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1144        pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1145        return NULL;
1146    }
1147
1148    item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1149    pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1150
1151    if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1152        pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1153        pa_rtpoll_item_free(item);
1154        return NULL;
1155    }
1156
1157    return item;
1158}
1159
1160snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1161    snd_pcm_sframes_t n;
1162    size_t k;
1163
1164    pa_assert(pcm);
1165    pa_assert(hwbuf_size > 0);
1166    pa_assert(ss);
1167
1168    /* Some ALSA driver expose weird bugs, let's inform the user about
1169     * what is going on */
1170
1171    n = snd_pcm_avail(pcm);
1172
1173    if (n <= 0)
1174        return n;
1175
1176    k = (size_t) n * pa_frame_size(ss);
1177
1178    if (PA_UNLIKELY(k >= hwbuf_size * 5 ||
1179                    k >= pa_bytes_per_second(ss)*10)) {
1180
1181        PA_ONCE_BEGIN {
1182            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1183            pa_log_debug(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n"
1184                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1185                            "snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1186                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1187                            (unsigned long) k),
1188                   (unsigned long) k,
1189                   (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1190                   pa_strnull(dn));
1191            pa_xfree(dn);
1192            pa_alsa_dump(PA_LOG_DEBUG, pcm);
1193        } PA_ONCE_END;
1194
1195        /* Mhmm, let's try not to fail completely */
1196        n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1197    }
1198
1199    return n;
1200}
1201
1202int 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,
1203                       bool capture) {
1204    ssize_t k;
1205    size_t abs_k;
1206    int err;
1207    snd_pcm_sframes_t avail = 0;
1208#if (SND_LIB_VERSION >= ((1<<16)|(1<<8)|0)) /* API additions in 1.1.0 */
1209    snd_pcm_audio_tstamp_config_t tstamp_config;
1210#endif
1211
1212    pa_assert(pcm);
1213    pa_assert(delay);
1214    pa_assert(hwbuf_size > 0);
1215    pa_assert(ss);
1216
1217    /* Some ALSA driver expose weird bugs, let's inform the user about
1218     * what is going on. We're going to get both the avail and delay values so
1219     * that we can compare and check them for capture.
1220     * This is done with snd_pcm_status() which provides
1221     * avail, delay and timestamp values in a single kernel call to improve
1222     * timer-based scheduling */
1223
1224#if (SND_LIB_VERSION >= ((1<<16)|(1<<8)|0)) /* API additions in 1.1.0 */
1225
1226    /* The time stamp configuration needs to be set so that the
1227     * ALSA code will use the internal delay reported by the driver.
1228     * The time stamp configuration was introduced in alsa version 1.1.0. */
1229    tstamp_config.type_requested = 1; /* ALSA default time stamp type */
1230    tstamp_config.report_delay = 1;
1231    snd_pcm_status_set_audio_htstamp_config(status, &tstamp_config);
1232#endif
1233
1234    if ((err = snd_pcm_status(pcm, status)) < 0)
1235        return err;
1236
1237    avail = snd_pcm_status_get_avail(status);
1238    *delay = snd_pcm_status_get_delay(status);
1239
1240    k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1241
1242    abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1243
1244    if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
1245                    abs_k >= pa_bytes_per_second(ss)*10)) {
1246
1247        PA_ONCE_BEGIN {
1248            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1249            pa_log_debug(ngettext("snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s%lu ms).\n"
1250                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1251                            "snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1252                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1253                            (signed long) k),
1254                   (signed long) k,
1255                   k < 0 ? "-" : "",
1256                   (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1257                   pa_strnull(dn));
1258            pa_xfree(dn);
1259            pa_alsa_dump(PA_LOG_DEBUG, pcm);
1260        } PA_ONCE_END;
1261
1262        /* Mhmm, let's try not to fail completely */
1263        if (k < 0)
1264            *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1265        else
1266            *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1267    }
1268
1269    if (capture) {
1270        abs_k = (size_t) avail * pa_frame_size(ss);
1271
1272        if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
1273                        abs_k >= pa_bytes_per_second(ss)*10)) {
1274
1275            PA_ONCE_BEGIN {
1276                char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1277                pa_log_debug(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n"
1278                                "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1279                                "snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1280                                "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1281                                (unsigned long) k),
1282                       (unsigned long) k,
1283                       (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1284                       pa_strnull(dn));
1285                pa_xfree(dn);
1286                pa_alsa_dump(PA_LOG_DEBUG, pcm);
1287            } PA_ONCE_END;
1288
1289            /* Mhmm, let's try not to fail completely */
1290            avail = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1291        }
1292
1293        if (PA_UNLIKELY(*delay < avail)) {
1294            PA_ONCE_BEGIN {
1295                char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1296                pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
1297                         "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1298                       (unsigned long) *delay,
1299                       (unsigned long) avail,
1300                       pa_strnull(dn));
1301                pa_xfree(dn);
1302                pa_alsa_dump(PA_LOG_ERROR, pcm);
1303            } PA_ONCE_END;
1304
1305            /* try to fixup */
1306            *delay = avail;
1307        }
1308    }
1309
1310    return 0;
1311}
1312
1313int 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) {
1314    int r;
1315    snd_pcm_uframes_t before;
1316    size_t k;
1317
1318    pa_assert(pcm);
1319    pa_assert(areas);
1320    pa_assert(offset);
1321    pa_assert(frames);
1322    pa_assert(hwbuf_size > 0);
1323    pa_assert(ss);
1324
1325    before = *frames;
1326
1327    r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1328
1329    if (r < 0)
1330        return r;
1331
1332    k = (size_t) *frames * pa_frame_size(ss);
1333
1334    if (PA_UNLIKELY(*frames > before ||
1335                    k >= hwbuf_size * 3 ||
1336                    k >= pa_bytes_per_second(ss)*10))
1337        PA_ONCE_BEGIN {
1338            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1339            pa_log_debug(ngettext("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte (%lu ms).\n"
1340                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1341                            "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1342                            "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.",
1343                            (unsigned long) k),
1344                   (unsigned long) k,
1345                   (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1346                   pa_strnull(dn));
1347            pa_xfree(dn);
1348            pa_alsa_dump(PA_LOG_DEBUG, pcm);
1349        } PA_ONCE_END;
1350
1351    return r;
1352}
1353
1354char *pa_alsa_get_driver_name(int card) {
1355    char *t, *m, *n;
1356
1357    pa_assert(card >= 0);
1358
1359    t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1360    m = pa_readlink(t);
1361    pa_xfree(t);
1362
1363    if (!m)
1364        return NULL;
1365
1366    n = pa_xstrdup(pa_path_get_filename(m));
1367    pa_xfree(m);
1368
1369    return n;
1370}
1371
1372char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1373    int card;
1374    snd_pcm_info_t* info;
1375    snd_pcm_info_alloca(&info);
1376
1377    pa_assert(pcm);
1378
1379    if (snd_pcm_info(pcm, info) < 0)
1380        return NULL;
1381
1382    if ((card = snd_pcm_info_get_card(info)) < 0)
1383        return NULL;
1384
1385    return pa_alsa_get_driver_name(card);
1386}
1387
1388char *pa_alsa_get_reserve_name(const char *device) {
1389    const char *t;
1390    int i;
1391
1392    pa_assert(device);
1393
1394    if ((t = strchr(device, ':')))
1395        device = t+1;
1396
1397    if ((i = snd_card_get_index(device)) < 0) {
1398        int32_t k;
1399
1400        if (pa_atoi(device, &k) < 0)
1401            return NULL;
1402
1403        i = (int) k;
1404    }
1405
1406    return pa_sprintf_malloc("Audio%i", i);
1407}
1408
1409unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) {
1410    static unsigned int all_rates[] = { 8000, 11025, 12000,
1411                                        16000, 22050, 24000,
1412                                        32000, 44100, 48000,
1413                                        64000, 88200, 96000,
1414                                        128000, 176400, 192000,
1415                                        384000 };
1416    bool supported[PA_ELEMENTSOF(all_rates)] = { false, };
1417    snd_pcm_hw_params_t *hwparams;
1418    unsigned int i, j, n, *rates = NULL;
1419    int ret;
1420
1421    snd_pcm_hw_params_alloca(&hwparams);
1422
1423    if ((ret = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
1424        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
1425        return NULL;
1426    }
1427
1428    for (i = 0, n = 0; i < PA_ELEMENTSOF(all_rates); i++) {
1429        if (snd_pcm_hw_params_test_rate(pcm, hwparams, all_rates[i], 0) == 0) {
1430            supported[i] = true;
1431            n++;
1432        }
1433    }
1434
1435    if (n > 0) {
1436        rates = pa_xnew(unsigned int, n + 1);
1437
1438        for (i = 0, j = 0; i < PA_ELEMENTSOF(all_rates); i++) {
1439            if (supported[i])
1440                rates[j++] = all_rates[i];
1441        }
1442
1443        rates[j] = 0;
1444    } else {
1445        rates = pa_xnew(unsigned int, 2);
1446
1447        rates[0] = fallback_rate;
1448        if ((ret = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rates[0], NULL)) < 0) {
1449            pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
1450            pa_xfree(rates);
1451            return NULL;
1452        }
1453
1454        rates[1] = 0;
1455    }
1456
1457    return rates;
1458}
1459
1460pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) {
1461    static const snd_pcm_format_t format_trans_to_pa[] = {
1462        [SND_PCM_FORMAT_U8] = PA_SAMPLE_U8,
1463        [SND_PCM_FORMAT_A_LAW] = PA_SAMPLE_ALAW,
1464        [SND_PCM_FORMAT_MU_LAW] = PA_SAMPLE_ULAW,
1465        [SND_PCM_FORMAT_S16_LE] = PA_SAMPLE_S16LE,
1466        [SND_PCM_FORMAT_S16_BE] = PA_SAMPLE_S16BE,
1467        [SND_PCM_FORMAT_FLOAT_LE] = PA_SAMPLE_FLOAT32LE,
1468        [SND_PCM_FORMAT_FLOAT_BE] = PA_SAMPLE_FLOAT32BE,
1469        [SND_PCM_FORMAT_S32_LE] = PA_SAMPLE_S32LE,
1470        [SND_PCM_FORMAT_S32_BE] = PA_SAMPLE_S32BE,
1471        [SND_PCM_FORMAT_S24_3LE] = PA_SAMPLE_S24LE,
1472        [SND_PCM_FORMAT_S24_3BE] = PA_SAMPLE_S24BE,
1473        [SND_PCM_FORMAT_S24_LE] = PA_SAMPLE_S24_32LE,
1474        [SND_PCM_FORMAT_S24_BE] = PA_SAMPLE_S24_32BE,
1475    };
1476    static const snd_pcm_format_t all_formats[] = {
1477        SND_PCM_FORMAT_U8,
1478        SND_PCM_FORMAT_A_LAW,
1479        SND_PCM_FORMAT_MU_LAW,
1480        SND_PCM_FORMAT_S16_LE,
1481        SND_PCM_FORMAT_S16_BE,
1482        SND_PCM_FORMAT_FLOAT_LE,
1483        SND_PCM_FORMAT_FLOAT_BE,
1484        SND_PCM_FORMAT_S32_LE,
1485        SND_PCM_FORMAT_S32_BE,
1486        SND_PCM_FORMAT_S24_3LE,
1487        SND_PCM_FORMAT_S24_3BE,
1488        SND_PCM_FORMAT_S24_LE,
1489        SND_PCM_FORMAT_S24_BE,
1490    };
1491    bool supported[PA_ELEMENTSOF(all_formats)] = {
1492        false,
1493    };
1494    snd_pcm_hw_params_t *hwparams;
1495    unsigned int i, j, n;
1496    pa_sample_format_t *formats = NULL;
1497    int ret;
1498
1499    snd_pcm_hw_params_alloca(&hwparams);
1500
1501    if ((ret = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
1502        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
1503        return NULL;
1504    }
1505
1506    for (i = 0, n = 0; i < PA_ELEMENTSOF(all_formats); i++) {
1507        if (snd_pcm_hw_params_test_format(pcm, hwparams, all_formats[i]) == 0) {
1508            supported[i] = true;
1509            n++;
1510        }
1511    }
1512
1513    if (n > 0) {
1514        formats = pa_xnew(pa_sample_format_t, n + 1);
1515
1516        for (i = 0, j = 0; i < PA_ELEMENTSOF(all_formats); i++) {
1517            if (supported[i])
1518                formats[j++] = format_trans_to_pa[all_formats[i]];
1519        }
1520
1521        formats[j] = PA_SAMPLE_MAX;
1522    } else {
1523        formats = pa_xnew(pa_sample_format_t, 2);
1524
1525        formats[0] = fallback_format;
1526        if ((ret = snd_pcm_hw_params_set_format(pcm, hwparams, format_trans_to_pa[formats[0]])) < 0) {
1527            pa_log_debug("snd_pcm_hw_params_set_format() failed: %s", pa_alsa_strerror(ret));
1528            pa_xfree(formats);
1529            return NULL;
1530        }
1531
1532        formats[1] = PA_SAMPLE_MAX;
1533    }
1534
1535    return formats;
1536}
1537
1538bool pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1539    snd_pcm_info_t* info;
1540    snd_pcm_info_alloca(&info);
1541
1542    pa_assert(pcm);
1543
1544    if (snd_pcm_info(pcm, info) < 0)
1545        return false;
1546
1547    return snd_pcm_info_get_card(info) >= 0;
1548}
1549
1550bool pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1551    snd_pcm_info_t* info;
1552    snd_pcm_info_alloca(&info);
1553
1554    pa_assert(pcm);
1555
1556    if (snd_pcm_info(pcm, info) < 0)
1557        return false;
1558
1559    return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1560}
1561
1562PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1563
1564const char* pa_alsa_strerror(int errnum) {
1565    const char *original = NULL;
1566    char *translated, *t;
1567    char errbuf[128];
1568
1569    if ((t = PA_STATIC_TLS_GET(cstrerror)))
1570        pa_xfree(t);
1571
1572    original = snd_strerror(errnum);
1573
1574    if (!original) {
1575        pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1576        original = errbuf;
1577    }
1578
1579    if (!(translated = pa_locale_to_utf8(original))) {
1580        pa_log_warn("Unable to convert error string to locale, filtering.");
1581        translated = pa_utf8_filter(original);
1582    }
1583
1584    PA_STATIC_TLS_SET(cstrerror, translated);
1585
1586    return translated;
1587}
1588
1589bool pa_alsa_may_tsched(bool want) {
1590
1591    if (!want)
1592        return false;
1593
1594    if (!pa_rtclock_hrtimer()) {
1595        /* We cannot depend on being woken up in time when the timers
1596        are inaccurate, so let's fallback to classic IO based playback
1597        then. */
1598        pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1599        return false; }
1600
1601    if (pa_running_in_vm()) {
1602        /* We cannot depend on being woken up when we ask for in a VM,
1603         * so let's fallback to classic IO based playback then. */
1604        pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
1605        return false;
1606    }
1607
1608    return true;
1609}
1610
1611#define SND_MIXER_ELEM_PULSEAUDIO (SND_MIXER_ELEM_LAST + 10)
1612
1613static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer,
1614                                            snd_ctl_elem_iface_t iface,
1615                                            const char *name,
1616                                            unsigned int index,
1617                                            unsigned int device) {
1618    snd_mixer_elem_t *elem;
1619
1620    for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
1621        snd_hctl_elem_t *helem;
1622        if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO)
1623            continue;
1624        helem = snd_mixer_elem_get_private(elem);
1625        if (snd_hctl_elem_get_interface(helem) != iface)
1626            continue;
1627        if (!pa_streq(snd_hctl_elem_get_name(helem), name))
1628            continue;
1629        if (snd_hctl_elem_get_index(helem) != index)
1630            continue;
1631        if (snd_hctl_elem_get_device(helem) != device)
1632            continue;
1633        return elem;
1634    }
1635    return NULL;
1636}
1637
1638snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, struct pa_alsa_mixer_id *alsa_id, unsigned int device) {
1639    return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_CARD, alsa_id->name, alsa_id->index, device);
1640}
1641
1642snd_mixer_elem_t *pa_alsa_mixer_find_pcm(snd_mixer_t *mixer, const char *name, unsigned int device) {
1643    return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_PCM, name, 0, device);
1644}
1645
1646static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
1647{
1648    /* Dummy compare function */
1649    return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1);
1650}
1651
1652static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
1653			snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
1654{
1655    int err;
1656    const char *name = snd_hctl_elem_get_name(helem);
1657    if (mask & SND_CTL_EVENT_MASK_ADD) {
1658        snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
1659        if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) {
1660            snd_mixer_elem_t *new_melem;
1661
1662            /* Put the hctl pointer as our private data - it will be useful for callbacks */
1663            if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
1664                pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
1665                return 0;
1666            }
1667
1668            if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
1669                pa_log_warn("snd_mixer_elem_attach failed: %s", pa_alsa_strerror(err));
1670		snd_mixer_elem_free(melem);
1671                return 0;
1672            }
1673
1674            if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
1675                pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err));
1676                return 0;
1677            }
1678        }
1679    }
1680    else if (mask & SND_CTL_EVENT_MASK_VALUE) {
1681        snd_mixer_elem_value(melem); /* Calls the element callback */
1682        return 0;
1683    }
1684    else
1685        pa_log_info("Got an unknown mixer class event for %s: mask 0x%x", name, mask);
1686
1687    return 0;
1688}
1689
1690static int prepare_mixer(snd_mixer_t *mixer, const char *dev, snd_hctl_t *hctl) {
1691    int err;
1692    snd_mixer_class_t *class;
1693
1694    pa_assert(mixer);
1695    pa_assert(dev);
1696
1697    if ((err = snd_mixer_attach_hctl(mixer, hctl)) < 0) {
1698        pa_log_info("Unable to attach to mixer %s: %s", dev, pa_alsa_strerror(err));
1699        return -1;
1700    }
1701
1702    if (snd_mixer_class_malloc(&class)) {
1703        pa_log_info("Failed to allocate mixer class for %s", dev);
1704        return -1;
1705    }
1706    snd_mixer_class_set_event(class, mixer_class_event);
1707    snd_mixer_class_set_compare(class, mixer_class_compare);
1708    if ((err = snd_mixer_class_register(class, mixer)) < 0) {
1709        pa_log_info("Unable register mixer class for %s: %s", dev, pa_alsa_strerror(err));
1710        snd_mixer_class_free(class);
1711        return -1;
1712    }
1713    /* From here on, the mixer class is deallocated by alsa on snd_mixer_close/free. */
1714
1715    if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
1716        pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err));
1717        return -1;
1718    }
1719
1720    if ((err = snd_mixer_load(mixer)) < 0) {
1721        pa_log_warn("Unable to load mixer: %s", pa_alsa_strerror(err));
1722        return -1;
1723    }
1724
1725    pa_log_info("Successfully attached to mixer '%s'", dev);
1726    return 0;
1727}
1728
1729snd_mixer_t *pa_alsa_open_mixer(pa_hashmap *mixers, int alsa_card_index, bool probe) {
1730    char *md = pa_sprintf_malloc("hw:%i", alsa_card_index);
1731    snd_mixer_t *m = pa_alsa_open_mixer_by_name(mixers, md, probe);
1732    pa_xfree(md);
1733    return m;
1734}
1735
1736pa_alsa_mixer *pa_alsa_create_mixer(pa_hashmap *mixers, const char *dev, snd_mixer_t *m, bool probe) {
1737    pa_alsa_mixer *pm;
1738
1739    pm = pa_xnew0(pa_alsa_mixer, 1);
1740    if (pm == NULL)
1741        return NULL;
1742
1743    pm->used_for_probe_only = probe;
1744    pm->mixer_handle = m;
1745    pa_hashmap_put(mixers, pa_xstrdup(dev), pm);
1746    return pm;
1747}
1748
1749snd_mixer_t *pa_alsa_open_mixer_by_name(pa_hashmap *mixers, const char *dev, bool probe) {
1750    int err;
1751    snd_mixer_t *m;
1752    snd_hctl_t *hctl;
1753    pa_alsa_mixer *pm;
1754
1755    pa_assert(mixers);
1756    pa_assert(dev);
1757
1758    pm = pa_hashmap_get(mixers, dev);
1759    if (pm) {
1760        if (!probe)
1761            pm->used_for_probe_only = false;
1762        return pm->mixer_handle;
1763    }
1764
1765    if ((err = snd_mixer_open(&m, 0)) < 0) {
1766        pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
1767        return NULL;
1768    }
1769
1770    err = snd_hctl_open(&hctl, dev, 0);
1771    if (err < 0) {
1772        pa_log("Error opening hctl device: %s", pa_alsa_strerror(err));
1773        goto __close;
1774    }
1775
1776    if (prepare_mixer(m, dev, hctl) >= 0) {
1777        /* get the ALSA card number (index) and ID (alias) and create two identical mixers */
1778        char *p, *dev2, *dev_idx, *dev_id;
1779        snd_ctl_card_info_t *info;
1780        snd_ctl_card_info_alloca(&info);
1781        err = snd_ctl_card_info(snd_hctl_ctl(hctl), info);
1782        if (err < 0)
1783            goto __std;
1784        dev2 = pa_xstrdup(dev);
1785        if (dev2 == NULL)
1786            goto __close;
1787        p = strchr(dev2, ':');
1788        /* sanity check - only hw: devices */
1789        if (p == NULL || (p - dev2) < 2 || !pa_strneq(p - 2, "hw:", 3)) {
1790            pa_xfree(dev2);
1791            goto __std;
1792        }
1793        *p = '\0';
1794        dev_idx = pa_sprintf_malloc("%s:%u", dev2, snd_ctl_card_info_get_card(info));
1795        dev_id = pa_sprintf_malloc("%s:%s", dev2, snd_ctl_card_info_get_id(info));
1796        pa_log_debug("ALSA alias mixers: %s = %s", dev_idx, dev_id);
1797        if (dev_idx && dev_id && (strcmp(dev, dev_idx) == 0 || strcmp(dev, dev_id) == 0)) {
1798            pm = pa_alsa_create_mixer(mixers, dev_idx, m, probe);
1799            if (pm) {
1800                pa_alsa_mixer *pm2;
1801                pm2 = pa_alsa_create_mixer(mixers, dev_id, m, probe);
1802                if (pm2) {
1803                    pm->alias = pm2;
1804                    pm2->alias = pm;
1805                }
1806            }
1807        }
1808        pa_xfree(dev_id);
1809        pa_xfree(dev_idx);
1810        pa_xfree(dev2);
1811   __std:
1812        if (pm == NULL)
1813            pm = pa_alsa_create_mixer(mixers, dev, m, probe);
1814        if (pm)
1815            return m;
1816    }
1817
1818__close:
1819    snd_mixer_close(m);
1820    return NULL;
1821}
1822
1823snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool probe) {
1824    snd_pcm_info_t* info;
1825    snd_pcm_info_alloca(&info);
1826
1827    pa_assert(pcm);
1828
1829    if (snd_pcm_info(pcm, info) >= 0) {
1830        int card_idx;
1831
1832        if ((card_idx = snd_pcm_info_get_card(info)) >= 0)
1833            return pa_alsa_open_mixer(mixers, card_idx, probe);
1834    }
1835
1836    return NULL;
1837}
1838
1839void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer_handle, pa_mainloop_api *ml)
1840{
1841    pa_alsa_mixer *pm;
1842    void *state;
1843
1844    PA_HASHMAP_FOREACH(pm, mixers, state)
1845        if (pm->mixer_handle == mixer_handle) {
1846            pm->used_for_probe_only = false;
1847            if (!pm->fdl) {
1848                pm->fdl = pa_alsa_fdlist_new();
1849                if (pm->fdl)
1850                    pa_alsa_fdlist_set_handle(pm->fdl, pm->mixer_handle, NULL, ml);
1851            }
1852        }
1853}
1854
1855void pa_alsa_mixer_free(pa_alsa_mixer *mixer)
1856{
1857    if (mixer->fdl)
1858        pa_alsa_fdlist_free(mixer->fdl);
1859    if (mixer->mixer_handle && mixer->alias == NULL)
1860        snd_mixer_close(mixer->mixer_handle);
1861    if (mixer->alias)
1862        mixer->alias->alias = NULL;
1863    pa_xfree(mixer);
1864}
1865
1866int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld) {
1867
1868    /* The ELD format is specific to HDA Intel sound cards and defined in the
1869       HDA specification: http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html */
1870    int err;
1871    snd_ctl_elem_info_t *info;
1872    snd_ctl_elem_value_t *value;
1873    uint8_t *elddata;
1874    unsigned int eldsize, mnl;
1875    unsigned int device;
1876
1877    pa_assert(eld != NULL);
1878    pa_assert(elem != NULL);
1879
1880    /* Does it have any contents? */
1881    snd_ctl_elem_info_alloca(&info);
1882    snd_ctl_elem_value_alloca(&value);
1883    if ((err = snd_hctl_elem_info(elem, info)) < 0 ||
1884       (err = snd_hctl_elem_read(elem, value)) < 0) {
1885        pa_log_warn("Accessing ELD control failed with error %s", snd_strerror(err));
1886        return -1;
1887    }
1888
1889    device = snd_hctl_elem_get_device(elem);
1890    eldsize = snd_ctl_elem_info_get_count(info);
1891    elddata = (unsigned char *) snd_ctl_elem_value_get_bytes(value);
1892    if (elddata == NULL || eldsize == 0) {
1893        pa_log_debug("ELD info empty (for device=%d)", device);
1894        return -1;
1895    }
1896    if (eldsize < 20 || eldsize > 256) {
1897        pa_log_debug("ELD info has wrong size (for device=%d)", device);
1898        return -1;
1899    }
1900
1901    /* Try to fetch monitor name */
1902    mnl = elddata[4] & 0x1f;
1903    if (mnl == 0 || mnl > 16 || 20 + mnl > eldsize) {
1904        pa_log_debug("No monitor name in ELD info (for device=%d)", device);
1905        mnl = 0;
1906    }
1907    memcpy(eld->monitor_name, &elddata[20], mnl);
1908    eld->monitor_name[mnl] = '\0';
1909    if (mnl)
1910        pa_log_debug("Monitor name in ELD info is '%s' (for device=%d)", eld->monitor_name, device);
1911
1912    return 0;
1913}
1914