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