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