• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
set_format(snd_pcm_t * pcm_handle,snd_pcm_hw_params_t * hwparams,pa_sample_format_t * f)51 static 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 
129 try_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 
set_period_size(snd_pcm_t * pcm_handle,snd_pcm_hw_params_t * hwparams,snd_pcm_uframes_t size)145 static 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 
set_buffer_size(snd_pcm_t * pcm_handle,snd_pcm_hw_params_t * hwparams,snd_pcm_uframes_t size)170 static 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 
check_access(snd_pcm_t * pcm_handle,snd_pcm_hw_params_t * hwparams,bool use_mmap)184 static 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. */
pa_alsa_set_hw_params(snd_pcm_t * pcm_handle,pa_sample_spec * ss,snd_pcm_uframes_t * period_size,snd_pcm_uframes_t * buffer_size,snd_pcm_uframes_t tsched_size,bool * use_mmap,bool * use_tsched,bool require_exact_channel_number)200 int 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 
402 success:
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 
457 finish:
458 
459     return ret;
460 }
461 
pa_alsa_set_sw_params(snd_pcm_t * pcm,snd_pcm_uframes_t avail_min,bool period_event)462 int 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 
pa_alsa_open_by_device_id_auto(const char * dev_id,char ** dev,pa_sample_spec * ss,pa_channel_map * map,int mode,snd_pcm_uframes_t * period_size,snd_pcm_uframes_t * buffer_size,snd_pcm_uframes_t tsched_size,bool * use_mmap,bool * use_tsched,pa_alsa_profile_set * ps,pa_alsa_mapping ** mapping)514 snd_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 
pa_alsa_open_by_device_id_mapping(const char * dev_id,char ** dev,pa_sample_spec * ss,pa_channel_map * map,int mode,snd_pcm_uframes_t * period_size,snd_pcm_uframes_t * buffer_size,snd_pcm_uframes_t tsched_size,bool * use_mmap,bool * use_tsched,pa_alsa_mapping * m)623 snd_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 
pa_alsa_open_by_device_string(const char * device,char ** dev,pa_sample_spec * ss,pa_channel_map * map,int mode,snd_pcm_uframes_t * period_size,snd_pcm_uframes_t * buffer_size,snd_pcm_uframes_t tsched_size,bool * use_mmap,bool * use_tsched,bool require_exact_channel_number)675 snd_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:%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 
768 fail:
769     pa_xfree(d);
770 
771     return NULL;
772 }
773 
pa_alsa_open_by_template(char ** template,const char * dev_id,char ** dev,pa_sample_spec * ss,pa_channel_map * map,int mode,snd_pcm_uframes_t * period_size,snd_pcm_uframes_t * buffer_size,snd_pcm_uframes_t tsched_size,bool * use_mmap,bool * use_tsched,bool require_exact_channel_number)774 snd_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 
pa_alsa_dump(pa_log_level_t level,snd_pcm_t * pcm)818 void 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 
pa_alsa_dump_status(snd_pcm_t * pcm)837 void 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 
865 finish:
866 
867     snd_output_close(out);
868 }
869 
alsa_error_handler(const char * file,int line,const char * function,int err,const char * fmt,...)870 static 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 
885 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
886 
pa_alsa_refcnt_inc(void)887 void 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 
pa_alsa_refcnt_dec(void)894 void 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 
pa_alsa_init_description(pa_proplist * p,pa_card * card)905 bool 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 
pa_alsa_init_proplist_card(pa_core * c,pa_proplist * p,int card)928 void 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 
pa_alsa_init_proplist_pcm_info(pa_core * c,pa_proplist * p,snd_pcm_info_t * pcm_info)956 void 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 
pa_alsa_init_proplist_pcm(pa_core * c,pa_proplist * p,snd_pcm_t * pcm)1015 void 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 
pa_alsa_init_proplist_ctl(pa_proplist * p,const char * name)1037 void 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 
pa_alsa_recover_from_poll(snd_pcm_t * pcm,int revents)1067 int 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 
pa_alsa_build_pollfd(snd_pcm_t * pcm,pa_rtpoll * rtpoll)1136 pa_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 
pa_alsa_safe_avail(snd_pcm_t * pcm,size_t hwbuf_size,const pa_sample_spec * ss)1160 snd_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 
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,bool capture)1202 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,
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 
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)1313 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) {
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 
pa_alsa_get_driver_name(int card)1354 char *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 
pa_alsa_get_driver_name_by_pcm(snd_pcm_t * pcm)1372 char *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 
pa_alsa_get_reserve_name(const char * device)1388 char *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 
pa_alsa_get_supported_rates(snd_pcm_t * pcm,unsigned int fallback_rate)1409 unsigned 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 
pa_alsa_get_supported_formats(snd_pcm_t * pcm,pa_sample_format_t fallback_format)1460 pa_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 
pa_alsa_pcm_is_hw(snd_pcm_t * pcm)1538 bool 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 
pa_alsa_pcm_is_modem(snd_pcm_t * pcm)1550 bool 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 
1562 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1563 
pa_alsa_strerror(int errnum)1564 const 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 
pa_alsa_may_tsched(bool want)1589 bool 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 
pa_alsa_mixer_find(snd_mixer_t * mixer,snd_ctl_elem_iface_t iface,const char * name,unsigned int index,unsigned int device)1613 static 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 
pa_alsa_mixer_find_card(snd_mixer_t * mixer,struct pa_alsa_mixer_id * alsa_id,unsigned int device)1638 snd_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 
pa_alsa_mixer_find_pcm(snd_mixer_t * mixer,const char * name,unsigned int device)1642 snd_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 
mixer_class_compare(const snd_mixer_elem_t * c1,const snd_mixer_elem_t * c2)1646 static 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 
mixer_class_event(snd_mixer_class_t * class,unsigned int mask,snd_hctl_elem_t * helem,snd_mixer_elem_t * melem)1652 static 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 
prepare_mixer(snd_mixer_t * mixer,const char * dev)1690 static int prepare_mixer(snd_mixer_t *mixer, const char *dev) {
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(mixer, dev)) < 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 
pa_alsa_open_mixer(pa_hashmap * mixers,int alsa_card_index,bool probe)1729 snd_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 
pa_alsa_open_mixer_by_name(pa_hashmap * mixers,const char * dev,bool probe)1736 snd_mixer_t *pa_alsa_open_mixer_by_name(pa_hashmap *mixers, const char *dev, bool probe) {
1737     int err;
1738     snd_mixer_t *m;
1739     pa_alsa_mixer *pm;
1740     char *dev2;
1741     void *state;
1742 
1743     pa_assert(mixers);
1744     pa_assert(dev);
1745 
1746     pm = pa_hashmap_get(mixers, dev);
1747 
1748     /* The quick card number/index lookup (hw:#)
1749      * We already know the card number/index, thus use the mixer
1750      * from the cache at first.
1751      */
1752     if (!pm && pa_strneq(dev, "hw:", 3)) {
1753         const char *s = dev + 3;
1754         int card_index;
1755         while (*s && *s >= '0' && *s <= '9') s++;
1756         if (*s == '\0' && pa_atoi(dev + 3, &card_index) >= 0) {
1757             PA_HASHMAP_FOREACH_KV(dev2, pm, mixers, state) {
1758                 if (pm->card_index == card_index) {
1759                     dev = dev2;
1760                     pm = pa_hashmap_get(mixers, dev);
1761                     break;
1762                 }
1763             }
1764         }
1765     }
1766 
1767     if (pm) {
1768         if (!probe)
1769             pm->used_for_probe_only = false;
1770         return pm->mixer_handle;
1771     }
1772 
1773     if ((err = snd_mixer_open(&m, 0)) < 0) {
1774         pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
1775         return NULL;
1776     }
1777 
1778     if (prepare_mixer(m, dev) >= 0) {
1779         pm = pa_xnew0(pa_alsa_mixer, 1);
1780         if (pm) {
1781             snd_hctl_t *hctl;
1782             pm->card_index = -1;
1783             /* determine the ALSA card number (index) and store it to card_index */
1784             err = snd_mixer_get_hctl(m, dev, &hctl);
1785             if (err >= 0) {
1786                 snd_ctl_card_info_t *info;
1787                 snd_ctl_card_info_alloca(&info);
1788                 err = snd_ctl_card_info(snd_hctl_ctl(hctl), info);
1789                 if (err >= 0)
1790                     pm->card_index = snd_ctl_card_info_get_card(info);
1791             }
1792             pm->used_for_probe_only = probe;
1793             pm->mixer_handle = m;
1794             pa_hashmap_put(mixers, pa_xstrdup(dev), pm);
1795             return m;
1796         }
1797     }
1798 
1799     snd_mixer_close(m);
1800     return NULL;
1801 }
1802 
pa_alsa_open_mixer_for_pcm(pa_hashmap * mixers,snd_pcm_t * pcm,bool probe)1803 snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool probe) {
1804     snd_pcm_info_t* info;
1805     snd_pcm_info_alloca(&info);
1806 
1807     pa_assert(pcm);
1808 
1809     if (snd_pcm_info(pcm, info) >= 0) {
1810         int card_idx;
1811 
1812         if ((card_idx = snd_pcm_info_get_card(info)) >= 0)
1813             return pa_alsa_open_mixer(mixers, card_idx, probe);
1814     }
1815 
1816     return NULL;
1817 }
1818 
pa_alsa_mixer_set_fdlist(pa_hashmap * mixers,snd_mixer_t * mixer_handle,pa_mainloop_api * ml)1819 void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer_handle, pa_mainloop_api *ml)
1820 {
1821     pa_alsa_mixer *pm;
1822     void *state;
1823 
1824     PA_HASHMAP_FOREACH(pm, mixers, state)
1825         if (pm->mixer_handle == mixer_handle) {
1826             pm->used_for_probe_only = false;
1827             if (!pm->fdl) {
1828                 pm->fdl = pa_alsa_fdlist_new();
1829                 if (pm->fdl)
1830                     pa_alsa_fdlist_set_handle(pm->fdl, pm->mixer_handle, NULL, ml);
1831             }
1832         }
1833 }
1834 
pa_alsa_mixer_free(pa_alsa_mixer * mixer)1835 void pa_alsa_mixer_free(pa_alsa_mixer *mixer)
1836 {
1837     if (mixer->fdl)
1838         pa_alsa_fdlist_free(mixer->fdl);
1839     if (mixer->mixer_handle)
1840         snd_mixer_close(mixer->mixer_handle);
1841     pa_xfree(mixer);
1842 }
1843 
pa_alsa_get_hdmi_eld(snd_hctl_elem_t * elem,pa_hdmi_eld * eld)1844 int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld) {
1845 
1846     /* The ELD format is specific to HDA Intel sound cards and defined in the
1847        HDA specification: http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html */
1848     int err;
1849     snd_ctl_elem_info_t *info;
1850     snd_ctl_elem_value_t *value;
1851     uint8_t *elddata;
1852     unsigned int eldsize, mnl;
1853     unsigned int device;
1854 
1855     pa_assert(eld != NULL);
1856     pa_assert(elem != NULL);
1857 
1858     /* Does it have any contents? */
1859     snd_ctl_elem_info_alloca(&info);
1860     snd_ctl_elem_value_alloca(&value);
1861     if ((err = snd_hctl_elem_info(elem, info)) < 0 ||
1862        (err = snd_hctl_elem_read(elem, value)) < 0) {
1863         pa_log_warn("Accessing ELD control failed with error %s", snd_strerror(err));
1864         return -1;
1865     }
1866 
1867     device = snd_hctl_elem_get_device(elem);
1868     eldsize = snd_ctl_elem_info_get_count(info);
1869     elddata = (unsigned char *) snd_ctl_elem_value_get_bytes(value);
1870     if (elddata == NULL || eldsize == 0) {
1871         pa_log_debug("ELD info empty (for device=%d)", device);
1872         return -1;
1873     }
1874     if (eldsize < 20 || eldsize > 256) {
1875         pa_log_debug("ELD info has wrong size (for device=%d)", device);
1876         return -1;
1877     }
1878 
1879     /* Try to fetch monitor name */
1880     mnl = elddata[4] & 0x1f;
1881     if (mnl == 0 || mnl > 16 || 20 + mnl > eldsize) {
1882         pa_log_debug("No monitor name in ELD info (for device=%d)", device);
1883         mnl = 0;
1884     }
1885     memcpy(eld->monitor_name, &elddata[20], mnl);
1886     eld->monitor_name[mnl] = '\0';
1887     if (mnl)
1888         pa_log_debug("Monitor name in ELD info is '%s' (for device=%d)", eld->monitor_name, device);
1889 
1890     return 0;
1891 }
1892