]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
alsa: allow configuration of fallback device strings in profiles
[pulseaudio] / src / modules / alsa / alsa-util.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <sys/types.h>
28 #include <limits.h>
29 #include <asoundlib.h>
30
31 #include <pulse/sample.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
35 #include <pulse/i18n.h>
36 #include <pulse/utf8.h>
37
38 #include <pulsecore/log.h>
39 #include <pulsecore/macro.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/atomic.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/once.h>
44 #include <pulsecore/thread.h>
45
46 #include "alsa-util.h"
47
48 #ifdef HAVE_HAL
49 #include "hal-util.h"
50 #endif
51
52 #ifdef HAVE_UDEV
53 #include "udev-util.h"
54 #endif
55
56 struct pa_alsa_fdlist {
57 unsigned num_fds;
58 struct pollfd *fds;
59 /* This is a temporary buffer used to avoid lots of mallocs */
60 struct pollfd *work_fds;
61
62 snd_mixer_t *mixer;
63
64 pa_mainloop_api *m;
65 pa_defer_event *defer;
66 pa_io_event **ios;
67
68 pa_bool_t polled;
69
70 void (*cb)(void *userdata);
71 void *userdata;
72 };
73
74 static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
75
76 struct pa_alsa_fdlist *fdl = userdata;
77 int err;
78 unsigned i;
79 unsigned short revents;
80
81 pa_assert(a);
82 pa_assert(fdl);
83 pa_assert(fdl->mixer);
84 pa_assert(fdl->fds);
85 pa_assert(fdl->work_fds);
86
87 if (fdl->polled)
88 return;
89
90 fdl->polled = TRUE;
91
92 memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds);
93
94 for (i = 0; i < fdl->num_fds; i++) {
95 if (e == fdl->ios[i]) {
96 if (events & PA_IO_EVENT_INPUT)
97 fdl->work_fds[i].revents |= POLLIN;
98 if (events & PA_IO_EVENT_OUTPUT)
99 fdl->work_fds[i].revents |= POLLOUT;
100 if (events & PA_IO_EVENT_ERROR)
101 fdl->work_fds[i].revents |= POLLERR;
102 if (events & PA_IO_EVENT_HANGUP)
103 fdl->work_fds[i].revents |= POLLHUP;
104 break;
105 }
106 }
107
108 pa_assert(i != fdl->num_fds);
109
110 if ((err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents)) < 0) {
111 pa_log_error("Unable to get poll revent: %s", pa_alsa_strerror(err));
112 return;
113 }
114
115 a->defer_enable(fdl->defer, 1);
116
117 if (revents)
118 snd_mixer_handle_events(fdl->mixer);
119 }
120
121 static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) {
122 struct pa_alsa_fdlist *fdl = userdata;
123 unsigned num_fds, i;
124 int err, n;
125 struct pollfd *temp;
126
127 pa_assert(a);
128 pa_assert(fdl);
129 pa_assert(fdl->mixer);
130
131 a->defer_enable(fdl->defer, 0);
132
133 if ((n = snd_mixer_poll_descriptors_count(fdl->mixer)) < 0) {
134 pa_log("snd_mixer_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
135 return;
136 }
137 num_fds = (unsigned) n;
138
139 if (num_fds != fdl->num_fds) {
140 if (fdl->fds)
141 pa_xfree(fdl->fds);
142 if (fdl->work_fds)
143 pa_xfree(fdl->work_fds);
144 fdl->fds = pa_xnew0(struct pollfd, num_fds);
145 fdl->work_fds = pa_xnew(struct pollfd, num_fds);
146 }
147
148 memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds);
149
150 if ((err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds)) < 0) {
151 pa_log_error("Unable to get poll descriptors: %s", pa_alsa_strerror(err));
152 return;
153 }
154
155 fdl->polled = FALSE;
156
157 if (memcmp(fdl->fds, fdl->work_fds, sizeof(struct pollfd) * num_fds) == 0)
158 return;
159
160 if (fdl->ios) {
161 for (i = 0; i < fdl->num_fds; i++)
162 a->io_free(fdl->ios[i]);
163
164 if (num_fds != fdl->num_fds) {
165 pa_xfree(fdl->ios);
166 fdl->ios = NULL;
167 }
168 }
169
170 if (!fdl->ios)
171 fdl->ios = pa_xnew(pa_io_event*, num_fds);
172
173 /* Swap pointers */
174 temp = fdl->work_fds;
175 fdl->work_fds = fdl->fds;
176 fdl->fds = temp;
177
178 fdl->num_fds = num_fds;
179
180 for (i = 0;i < num_fds;i++)
181 fdl->ios[i] = a->io_new(a, fdl->fds[i].fd,
182 ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) |
183 ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0),
184 io_cb, fdl);
185 }
186
187 struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) {
188 struct pa_alsa_fdlist *fdl;
189
190 fdl = pa_xnew0(struct pa_alsa_fdlist, 1);
191
192 fdl->num_fds = 0;
193 fdl->fds = NULL;
194 fdl->work_fds = NULL;
195 fdl->mixer = NULL;
196 fdl->m = NULL;
197 fdl->defer = NULL;
198 fdl->ios = NULL;
199 fdl->polled = FALSE;
200
201 return fdl;
202 }
203
204 void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) {
205 pa_assert(fdl);
206
207 if (fdl->defer) {
208 pa_assert(fdl->m);
209 fdl->m->defer_free(fdl->defer);
210 }
211
212 if (fdl->ios) {
213 unsigned i;
214 pa_assert(fdl->m);
215 for (i = 0; i < fdl->num_fds; i++)
216 fdl->m->io_free(fdl->ios[i]);
217 pa_xfree(fdl->ios);
218 }
219
220 if (fdl->fds)
221 pa_xfree(fdl->fds);
222 if (fdl->work_fds)
223 pa_xfree(fdl->work_fds);
224
225 pa_xfree(fdl);
226 }
227
228 int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) {
229 pa_assert(fdl);
230 pa_assert(mixer_handle);
231 pa_assert(m);
232 pa_assert(!fdl->m);
233
234 fdl->mixer = mixer_handle;
235 fdl->m = m;
236 fdl->defer = m->defer_new(m, defer_cb, fdl);
237
238 return 0;
239 }
240
241 static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
242
243 static const snd_pcm_format_t format_trans[] = {
244 [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8,
245 [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
246 [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
247 [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
248 [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
249 [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
250 [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
251 [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
252 [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
253 [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
254 [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
255 [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
256 [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE,
257 };
258
259 static const pa_sample_format_t try_order[] = {
260 PA_SAMPLE_FLOAT32NE,
261 PA_SAMPLE_FLOAT32RE,
262 PA_SAMPLE_S32NE,
263 PA_SAMPLE_S32RE,
264 PA_SAMPLE_S24_32NE,
265 PA_SAMPLE_S24_32RE,
266 PA_SAMPLE_S24NE,
267 PA_SAMPLE_S24RE,
268 PA_SAMPLE_S16NE,
269 PA_SAMPLE_S16RE,
270 PA_SAMPLE_ALAW,
271 PA_SAMPLE_ULAW,
272 PA_SAMPLE_U8,
273 PA_SAMPLE_INVALID
274 };
275
276 int i, ret;
277
278 pa_assert(pcm_handle);
279 pa_assert(f);
280
281 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
282 return ret;
283
284 if (*f == PA_SAMPLE_FLOAT32BE)
285 *f = PA_SAMPLE_FLOAT32LE;
286 else if (*f == PA_SAMPLE_FLOAT32LE)
287 *f = PA_SAMPLE_FLOAT32BE;
288 else if (*f == PA_SAMPLE_S24BE)
289 *f = PA_SAMPLE_S24LE;
290 else if (*f == PA_SAMPLE_S24LE)
291 *f = PA_SAMPLE_S24BE;
292 else if (*f == PA_SAMPLE_S24_32BE)
293 *f = PA_SAMPLE_S24_32LE;
294 else if (*f == PA_SAMPLE_S24_32LE)
295 *f = PA_SAMPLE_S24_32BE;
296 else if (*f == PA_SAMPLE_S16BE)
297 *f = PA_SAMPLE_S16LE;
298 else if (*f == PA_SAMPLE_S16LE)
299 *f = PA_SAMPLE_S16BE;
300 else if (*f == PA_SAMPLE_S32BE)
301 *f = PA_SAMPLE_S32LE;
302 else if (*f == PA_SAMPLE_S32LE)
303 *f = PA_SAMPLE_S32BE;
304 else
305 goto try_auto;
306
307 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
308 return ret;
309
310 try_auto:
311
312 for (i = 0; try_order[i] != PA_SAMPLE_INVALID; i++) {
313 *f = try_order[i];
314
315 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
316 return ret;
317 }
318
319 return -1;
320 }
321
322 /* Set the hardware parameters of the given ALSA device. Returns the
323 * selected fragment settings in *period and *period_size */
324 int pa_alsa_set_hw_params(
325 snd_pcm_t *pcm_handle,
326 pa_sample_spec *ss,
327 uint32_t *periods,
328 snd_pcm_uframes_t *period_size,
329 snd_pcm_uframes_t tsched_size,
330 pa_bool_t *use_mmap,
331 pa_bool_t *use_tsched,
332 pa_bool_t require_exact_channel_number) {
333
334 int ret = -1;
335 snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
336 unsigned int _periods = periods ? *periods : 0;
337 snd_pcm_uframes_t buffer_size;
338 unsigned int r = ss->rate;
339 unsigned int c = ss->channels;
340 pa_sample_format_t f = ss->format;
341 snd_pcm_hw_params_t *hwparams;
342 pa_bool_t _use_mmap = use_mmap && *use_mmap;
343 pa_bool_t _use_tsched = use_tsched && *use_tsched;
344 int dir;
345
346 pa_assert(pcm_handle);
347 pa_assert(ss);
348
349 snd_pcm_hw_params_alloca(&hwparams);
350
351 if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
352 goto finish;
353
354 if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0)
355 goto finish;
356
357 if (_use_mmap) {
358
359 if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
360
361 /* mmap() didn't work, fall back to interleaved */
362
363 if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
364 goto finish;
365
366 _use_mmap = FALSE;
367 }
368
369 } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
370 goto finish;
371
372 if (!_use_mmap)
373 _use_tsched = FALSE;
374
375 if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
376 goto finish;
377
378 if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0)
379 goto finish;
380
381 if (require_exact_channel_number) {
382 if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0)
383 goto finish;
384 } else {
385 if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0)
386 goto finish;
387 }
388
389 if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0)
390 goto finish;
391
392 if (_period_size && tsched_size && _periods) {
393 /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
394 _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
395 tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
396
397 if (_use_tsched) {
398 _period_size = tsched_size;
399 _periods = 1;
400
401 pa_assert_se(snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size) == 0);
402 pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
403 }
404
405 buffer_size = _periods * _period_size;
406
407 if (_periods > 0) {
408
409 /* First we pass 0 as direction to get exactly what we asked
410 * for. That this is necessary is presumably a bug in ALSA */
411
412 dir = 0;
413 if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
414 dir = 1;
415 if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
416 dir = -1;
417 if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
418 goto finish;
419 }
420 }
421 }
422
423 if (_period_size > 0)
424 if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
425 goto finish;
426 }
427
428 if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
429 goto finish;
430
431 if (ss->rate != r)
432 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
433
434 if (ss->channels != c)
435 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
436
437 if (ss->format != f)
438 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(f));
439
440 if ((ret = snd_pcm_prepare(pcm_handle)) < 0)
441 goto finish;
442
443 if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
444 (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0)
445 goto finish;
446
447 /* If the sample rate deviates too much, we need to resample */
448 if (r < ss->rate*.95 || r > ss->rate*1.05)
449 ss->rate = r;
450 ss->channels = (uint8_t) c;
451 ss->format = f;
452
453 pa_assert(_periods > 0);
454 pa_assert(_period_size > 0);
455
456 if (periods)
457 *periods = _periods;
458
459 if (period_size)
460 *period_size = _period_size;
461
462 if (use_mmap)
463 *use_mmap = _use_mmap;
464
465 if (use_tsched)
466 *use_tsched = _use_tsched;
467
468 ret = 0;
469
470 snd_pcm_nonblock(pcm_handle, 1);
471
472 finish:
473
474 return ret;
475 }
476
477 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) {
478 snd_pcm_sw_params_t *swparams;
479 snd_pcm_uframes_t boundary;
480 int err;
481
482 pa_assert(pcm);
483
484 snd_pcm_sw_params_alloca(&swparams);
485
486 if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
487 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err));
488 return err;
489 }
490
491 if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, 0)) < 0) {
492 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err));
493 return err;
494 }
495
496 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
497 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err));
498 return err;
499 }
500
501 if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
502 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err));
503 return err;
504 }
505
506 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
507 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err));
508 return err;
509 }
510
511 if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
512 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err));
513 return err;
514 }
515
516 if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
517 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
518 return err;
519 }
520
521 if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
522 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err));
523 return err;
524 }
525
526 return 0;
527 }
528
529 static const struct pa_alsa_profile_info device_table[] = {
530 {{ 1, { PA_CHANNEL_POSITION_MONO }},
531 "hw", NULL,
532 N_("Analog Mono"),
533 "analog-mono",
534 1,
535 "Master", "PCM",
536 "Capture", "Mic" },
537
538 {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
539 "front", "hw",
540 N_("Analog Stereo"),
541 "analog-stereo",
542 10,
543 "Master", "PCM",
544 "Capture", "Mic" },
545
546 {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
547 "iec958", NULL,
548 N_("Digital Stereo (IEC958)"),
549 "iec958-stereo",
550 5,
551 "IEC958", NULL,
552 "IEC958 In", NULL },
553
554 {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
555 "hdmi", NULL,
556 N_("Digital Stereo (HDMI)"),
557 "hdmi-stereo",
558 4,
559 "IEC958", NULL,
560 "IEC958 In", NULL },
561
562 {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
563 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
564 "surround40", NULL,
565 N_("Analog Surround 4.0"),
566 "analog-surround-40",
567 7,
568 "Master", "PCM",
569 "Capture", "Mic" },
570
571 {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
572 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
573 "a52", NULL,
574 N_("Digital Surround 4.0 (IEC958/AC3)"),
575 "iec958-ac3-surround-40",
576 2,
577 "Master", "PCM",
578 "Capture", "Mic" },
579
580 {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
581 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
582 PA_CHANNEL_POSITION_LFE }},
583 "surround41", NULL,
584 N_("Analog Surround 4.1"),
585 "analog-surround-41",
586 7,
587 "Master", "PCM",
588 "Capture", "Mic" },
589
590 {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
591 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
592 PA_CHANNEL_POSITION_CENTER }},
593 "surround50", NULL,
594 N_("Analog Surround 5.0"),
595 "analog-surround-50",
596 7,
597 "Master", "PCM",
598 "Capture", "Mic" },
599
600 {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
601 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
602 PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }},
603 "surround51", NULL,
604 N_("Analog Surround 5.1"),
605 "analog-surround-51",
606 8,
607 "Master", "PCM",
608 "Capture", "Mic" },
609
610 {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
611 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
612 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE}},
613 "a52", NULL,
614 N_("Digital Surround 5.1 (IEC958/AC3)"),
615 "iec958-ac3-surround-51",
616 3,
617 "IEC958", NULL,
618 "IEC958 In", NULL },
619
620 {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
621 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
622 PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE,
623 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }},
624 "surround71", NULL,
625 N_("Analog Surround 7.1"),
626 "analog-surround-71",
627 7,
628 "Master", "PCM",
629 "Capture", "Mic" },
630
631 {{ 0, { 0 }}, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
632 };
633
634 static snd_pcm_t *open_by_device_string_with_fallback(
635 const char *prefix,
636 const char *prefix_fallback,
637 const char *dev_id,
638 char **dev,
639 pa_sample_spec *ss,
640 pa_channel_map* map,
641 int mode,
642 uint32_t *nfrags,
643 snd_pcm_uframes_t *period_size,
644 snd_pcm_uframes_t tsched_size,
645 pa_bool_t *use_mmap,
646 pa_bool_t *use_tsched,
647 pa_bool_t require_exact_channel_number) {
648
649 snd_pcm_t *pcm_handle;
650 char *d;
651
652 d = pa_sprintf_malloc("%s:%s", prefix, dev_id);
653
654 pcm_handle = pa_alsa_open_by_device_string(
655 d,
656 dev,
657 ss,
658 map,
659 mode,
660 nfrags,
661 period_size,
662 tsched_size,
663 use_mmap,
664 use_tsched,
665 require_exact_channel_number);
666 pa_xfree(d);
667
668 if (!pcm_handle && prefix_fallback) {
669
670 d = pa_sprintf_malloc("%s:%s", prefix_fallback, dev_id);
671
672 pcm_handle = pa_alsa_open_by_device_string(
673 d,
674 dev,
675 ss,
676 map,
677 mode,
678 nfrags,
679 period_size,
680 tsched_size,
681 use_mmap,
682 use_tsched,
683 require_exact_channel_number);
684 pa_xfree(d);
685 }
686
687 return pcm_handle;
688 }
689
690 snd_pcm_t *pa_alsa_open_by_device_id_auto(
691 const char *dev_id,
692 char **dev,
693 pa_sample_spec *ss,
694 pa_channel_map* map,
695 int mode,
696 uint32_t *nfrags,
697 snd_pcm_uframes_t *period_size,
698 snd_pcm_uframes_t tsched_size,
699 pa_bool_t *use_mmap,
700 pa_bool_t *use_tsched,
701 const pa_alsa_profile_info **profile) {
702
703 int i;
704 int direction = 1;
705 char *d;
706 snd_pcm_t *pcm_handle;
707
708 pa_assert(dev_id);
709 pa_assert(dev);
710 pa_assert(ss);
711 pa_assert(map);
712 pa_assert(nfrags);
713 pa_assert(period_size);
714
715 /* First we try to find a device string with a superset of the
716 * requested channel map and open it without the plug: prefix. We
717 * iterate through our device table from top to bottom and take
718 * the first that matches. If we didn't find a working device that
719 * way, we iterate backwards, and check all devices that do not
720 * provide a superset of the requested channel map.*/
721
722 i = 0;
723 for (;;) {
724
725 if ((direction > 0) == pa_channel_map_superset(&device_table[i].map, map)) {
726 pa_sample_spec try_ss;
727
728 pa_log_debug("Checking for %s (%s)", device_table[i].name, device_table[i].alsa_name);
729
730 try_ss.channels = device_table[i].map.channels;
731 try_ss.rate = ss->rate;
732 try_ss.format = ss->format;
733
734 pcm_handle = open_by_device_string_with_fallback(
735 device_table[i].alsa_name,
736 device_table[i].alsa_name_fallback,
737 dev_id,
738 dev,
739 &try_ss,
740 map,
741 mode,
742 nfrags,
743 period_size,
744 tsched_size,
745 use_mmap,
746 use_tsched,
747 TRUE);
748
749 if (pcm_handle) {
750
751 *ss = try_ss;
752 *map = device_table[i].map;
753 pa_assert(map->channels == ss->channels);
754
755 if (profile)
756 *profile = &device_table[i];
757
758 return pcm_handle;
759 }
760
761 }
762
763 if (direction > 0) {
764 if (!device_table[i+1].alsa_name) {
765 /* OK, so we are at the end of our list. Let's turn
766 * back. */
767 direction = -1;
768 } else {
769 /* We are not at the end of the list, so let's simply
770 * try the next entry */
771 i++;
772 }
773 }
774
775 if (direction < 0) {
776
777 if (device_table[i+1].alsa_name &&
778 device_table[i].map.channels == device_table[i+1].map.channels) {
779
780 /* OK, the next entry has the same number of channels,
781 * let's try it */
782 i++;
783
784 } else {
785 /* Hmm, so the next entry does not have the same
786 * number of channels, so let's go backwards until we
787 * find the next entry with a different number of
788 * channels */
789
790 for (i--; i >= 0; i--)
791 if (device_table[i].map.channels != device_table[i+1].map.channels)
792 break;
793
794 /* Hmm, there is no entry with a different number of
795 * entries, then we're done */
796 if (i < 0)
797 break;
798
799 /* OK, now lets find go back as long as we have the same number of channels */
800 for (; i > 0; i--)
801 if (device_table[i].map.channels != device_table[i-1].map.channels)
802 break;
803 }
804 }
805 }
806
807 /* OK, we didn't find any good device, so let's try the raw plughw: stuff */
808
809 d = pa_sprintf_malloc("hw:%s", dev_id);
810 pa_log_debug("Trying %s as last resort...", d);
811 pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE);
812 pa_xfree(d);
813
814 if (pcm_handle && profile)
815 *profile = NULL;
816
817 return pcm_handle;
818 }
819
820 snd_pcm_t *pa_alsa_open_by_device_id_profile(
821 const char *dev_id,
822 char **dev,
823 pa_sample_spec *ss,
824 pa_channel_map* map,
825 int mode,
826 uint32_t *nfrags,
827 snd_pcm_uframes_t *period_size,
828 snd_pcm_uframes_t tsched_size,
829 pa_bool_t *use_mmap,
830 pa_bool_t *use_tsched,
831 const pa_alsa_profile_info *profile) {
832
833 snd_pcm_t *pcm_handle;
834 pa_sample_spec try_ss;
835
836 pa_assert(dev_id);
837 pa_assert(dev);
838 pa_assert(ss);
839 pa_assert(map);
840 pa_assert(nfrags);
841 pa_assert(period_size);
842 pa_assert(profile);
843
844 try_ss.channels = profile->map.channels;
845 try_ss.rate = ss->rate;
846 try_ss.format = ss->format;
847
848 pcm_handle = open_by_device_string_with_fallback(
849 profile->alsa_name,
850 profile->alsa_name_fallback,
851 dev_id,
852 dev,
853 &try_ss,
854 map,
855 mode,
856 nfrags,
857 period_size,
858 tsched_size,
859 use_mmap,
860 use_tsched,
861 TRUE);
862
863 if (!pcm_handle)
864 return NULL;
865
866 *ss = try_ss;
867 *map = profile->map;
868 pa_assert(map->channels == ss->channels);
869
870 return pcm_handle;
871 }
872
873 snd_pcm_t *pa_alsa_open_by_device_string(
874 const char *device,
875 char **dev,
876 pa_sample_spec *ss,
877 pa_channel_map* map,
878 int mode,
879 uint32_t *nfrags,
880 snd_pcm_uframes_t *period_size,
881 snd_pcm_uframes_t tsched_size,
882 pa_bool_t *use_mmap,
883 pa_bool_t *use_tsched,
884 pa_bool_t require_exact_channel_number) {
885
886 int err;
887 char *d;
888 snd_pcm_t *pcm_handle;
889 pa_bool_t reformat = FALSE;
890
891 pa_assert(device);
892 pa_assert(ss);
893 pa_assert(map);
894
895 d = pa_xstrdup(device);
896
897 for (;;) {
898 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
899
900 /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <=
901 * 1.0.17a would then ignore the SND_PCM_NO_xxx flags. Instead
902 * we enable nonblock mode afterwards via
903 * snd_pcm_nonblock(). Also see
904 * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */
905
906 if ((err = snd_pcm_open(&pcm_handle, d, mode,
907 /*SND_PCM_NONBLOCK|*/
908 SND_PCM_NO_AUTO_RESAMPLE|
909 SND_PCM_NO_AUTO_CHANNELS|
910 (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
911 pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
912 goto fail;
913 }
914
915 pa_log_debug("Managed to open %s", d);
916
917 if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
918
919 if (!reformat) {
920 reformat = TRUE;
921
922 snd_pcm_close(pcm_handle);
923 continue;
924 }
925
926 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
927
928 if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
929 char *t;
930
931 t = pa_sprintf_malloc("plug:%s", d);
932 pa_xfree(d);
933 d = t;
934
935 reformat = FALSE;
936
937 snd_pcm_close(pcm_handle);
938 continue;
939 }
940
941 pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
942 snd_pcm_close(pcm_handle);
943
944 goto fail;
945 }
946
947 if (dev)
948 *dev = d;
949 else
950 pa_xfree(d);
951
952 if (ss->channels != map->channels)
953 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
954
955 return pcm_handle;
956 }
957
958 fail:
959 pa_xfree(d);
960
961 return NULL;
962 }
963
964 int pa_alsa_probe_profiles(
965 const char *dev_id,
966 const pa_sample_spec *ss,
967 void (*cb)(const pa_alsa_profile_info *sink, const pa_alsa_profile_info *source, void *userdata),
968 void *userdata) {
969
970 const pa_alsa_profile_info *i;
971
972 pa_assert(dev_id);
973 pa_assert(ss);
974 pa_assert(cb);
975
976 /* We try each combination of playback/capture. We also try to
977 * open only for capture resp. only for sink. Don't get confused
978 * by the trailing entry in device_table we use for this! */
979
980 for (i = device_table; i < device_table + PA_ELEMENTSOF(device_table); i++) {
981 const pa_alsa_profile_info *j;
982 snd_pcm_t *pcm_i = NULL;
983
984 if (i->alsa_name) {
985 pa_sample_spec try_ss;
986 pa_channel_map try_map;
987
988 pa_log_debug("Checking for playback on %s (%s)", i->name, i->alsa_name);
989
990 try_ss = *ss;
991 try_ss.channels = i->map.channels;
992 try_map = i->map;
993
994 pcm_i = open_by_device_string_with_fallback(
995 i->alsa_name,
996 i->alsa_name_fallback,
997 dev_id,
998 NULL,
999 &try_ss, &try_map,
1000 SND_PCM_STREAM_PLAYBACK,
1001 NULL, NULL, 0, NULL, NULL,
1002 TRUE);
1003
1004 if (!pcm_i)
1005 continue;
1006 }
1007
1008 for (j = device_table; j < device_table + PA_ELEMENTSOF(device_table); j++) {
1009 snd_pcm_t *pcm_j = NULL;
1010
1011 if (j->alsa_name) {
1012 pa_sample_spec try_ss;
1013 pa_channel_map try_map;
1014
1015 pa_log_debug("Checking for capture on %s (%s)", j->name, j->alsa_name);
1016
1017 try_ss = *ss;
1018 try_ss.channels = j->map.channels;
1019 try_map = j->map;
1020
1021 pcm_j = open_by_device_string_with_fallback(
1022 j->alsa_name,
1023 j->alsa_name_fallback,
1024 dev_id,
1025 NULL,
1026 &try_ss, &try_map,
1027 SND_PCM_STREAM_CAPTURE,
1028 NULL, NULL, 0, NULL, NULL,
1029 TRUE);
1030
1031 if (!pcm_j)
1032 continue;
1033 }
1034
1035 if (pcm_j)
1036 snd_pcm_close(pcm_j);
1037
1038 if (i->alsa_name || j->alsa_name)
1039 cb(i->alsa_name ? i : NULL,
1040 j->alsa_name ? j : NULL, userdata);
1041 }
1042
1043 if (pcm_i)
1044 snd_pcm_close(pcm_i);
1045 }
1046
1047 return TRUE;
1048 }
1049
1050 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) {
1051 int err;
1052
1053 pa_assert(mixer);
1054 pa_assert(dev);
1055
1056 if ((err = snd_mixer_attach(mixer, dev)) < 0) {
1057 pa_log_info("Unable to attach to mixer %s: %s", dev, pa_alsa_strerror(err));
1058 return -1;
1059 }
1060
1061 if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
1062 pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err));
1063 return -1;
1064 }
1065
1066 if ((err = snd_mixer_load(mixer)) < 0) {
1067 pa_log_warn("Unable to load mixer: %s", pa_alsa_strerror(err));
1068 return -1;
1069 }
1070
1071 pa_log_info("Successfully attached to mixer '%s'", dev);
1072
1073 return 0;
1074 }
1075
1076 static pa_bool_t elem_has_volume(snd_mixer_elem_t *elem, pa_bool_t playback) {
1077 pa_assert(elem);
1078
1079 if (playback && snd_mixer_selem_has_playback_volume(elem))
1080 return TRUE;
1081
1082 if (!playback && snd_mixer_selem_has_capture_volume(elem))
1083 return TRUE;
1084
1085 return FALSE;
1086 }
1087
1088 static pa_bool_t elem_has_switch(snd_mixer_elem_t *elem, pa_bool_t playback) {
1089 pa_assert(elem);
1090
1091 if (playback && snd_mixer_selem_has_playback_switch(elem))
1092 return TRUE;
1093
1094 if (!playback && snd_mixer_selem_has_capture_switch(elem))
1095 return TRUE;
1096
1097 return FALSE;
1098 }
1099
1100 snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback) {
1101 snd_mixer_elem_t *elem = NULL, *fallback_elem = NULL;
1102 snd_mixer_selem_id_t *sid = NULL;
1103
1104 snd_mixer_selem_id_alloca(&sid);
1105
1106 pa_assert(mixer);
1107 pa_assert(name);
1108
1109 snd_mixer_selem_id_set_name(sid, name);
1110 snd_mixer_selem_id_set_index(sid, 0);
1111
1112 if ((elem = snd_mixer_find_selem(mixer, sid))) {
1113
1114 if (elem_has_volume(elem, playback) &&
1115 elem_has_switch(elem, playback))
1116 goto success;
1117
1118 if (!elem_has_volume(elem, playback) &&
1119 !elem_has_switch(elem, playback))
1120 elem = NULL;
1121 }
1122
1123 pa_log_info("Cannot find mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid));
1124
1125 if (fallback) {
1126 snd_mixer_selem_id_set_name(sid, fallback);
1127 snd_mixer_selem_id_set_index(sid, 0);
1128
1129 if ((fallback_elem = snd_mixer_find_selem(mixer, sid))) {
1130
1131 if (elem_has_volume(fallback_elem, playback) &&
1132 elem_has_switch(fallback_elem, playback)) {
1133 elem = fallback_elem;
1134 goto success;
1135 }
1136
1137 if (!elem_has_volume(fallback_elem, playback) &&
1138 !elem_has_switch(fallback_elem, playback))
1139 fallback_elem = NULL;
1140 }
1141
1142 pa_log_info("Cannot find fallback mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid));
1143 }
1144
1145 if (elem && fallback_elem) {
1146
1147 /* Hmm, so we have both elements, but neither has both mute
1148 * and volume. Let's prefer the one with the volume */
1149
1150 if (elem_has_volume(elem, playback))
1151 goto success;
1152
1153 if (elem_has_volume(fallback_elem, playback)) {
1154 elem = fallback_elem;
1155 goto success;
1156 }
1157 }
1158
1159 if (!elem && fallback_elem)
1160 elem = fallback_elem;
1161
1162 success:
1163
1164 if (elem)
1165 pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid));
1166
1167 return elem;
1168 }
1169
1170 int pa_alsa_find_mixer_and_elem(
1171 snd_pcm_t *pcm,
1172 snd_mixer_t **_m,
1173 snd_mixer_elem_t **_e,
1174 const char *control_name,
1175 const pa_alsa_profile_info *profile) {
1176
1177 int err;
1178 snd_mixer_t *m;
1179 snd_mixer_elem_t *e;
1180 pa_bool_t found = FALSE;
1181 const char *dev;
1182
1183 pa_assert(pcm);
1184 pa_assert(_m);
1185 pa_assert(_e);
1186
1187 if (control_name && *control_name == 0) {
1188 pa_log_debug("Hardware mixer usage disabled because empty control name passed");
1189 return -1;
1190 }
1191
1192 if ((err = snd_mixer_open(&m, 0)) < 0) {
1193 pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
1194 return -1;
1195 }
1196
1197 /* First, try by name */
1198 if ((dev = snd_pcm_name(pcm)))
1199 if (pa_alsa_prepare_mixer(m, dev) >= 0)
1200 found = TRUE;
1201
1202 /* Then, try by card index */
1203 if (!found) {
1204 snd_pcm_info_t* info;
1205 snd_pcm_info_alloca(&info);
1206
1207 if (snd_pcm_info(pcm, info) >= 0) {
1208 char *md;
1209 int card_idx;
1210
1211 if ((card_idx = snd_pcm_info_get_card(info)) >= 0) {
1212
1213 md = pa_sprintf_malloc("hw:%i", card_idx);
1214
1215 if (!dev || !pa_streq(dev, md))
1216 if (pa_alsa_prepare_mixer(m, md) >= 0)
1217 found = TRUE;
1218
1219 pa_xfree(md);
1220 }
1221 }
1222 }
1223
1224 if (!found) {
1225 snd_mixer_close(m);
1226 return -1;
1227 }
1228
1229 switch (snd_pcm_stream(pcm)) {
1230
1231 case SND_PCM_STREAM_PLAYBACK:
1232 if (control_name)
1233 e = pa_alsa_find_elem(m, control_name, NULL, TRUE);
1234 else if (profile)
1235 e = pa_alsa_find_elem(m, profile->playback_control_name, profile->playback_control_fallback, TRUE);
1236 else
1237 e = pa_alsa_find_elem(m, "Master", "PCM", TRUE);
1238 break;
1239
1240 case SND_PCM_STREAM_CAPTURE:
1241 if (control_name)
1242 e = pa_alsa_find_elem(m, control_name, NULL, FALSE);
1243 else if (profile)
1244 e = pa_alsa_find_elem(m, profile->record_control_name, profile->record_control_fallback, FALSE);
1245 else
1246 e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE);
1247 break;
1248
1249 default:
1250 pa_assert_not_reached();
1251 }
1252
1253 if (!e) {
1254 snd_mixer_close(m);
1255 return -1;
1256 }
1257
1258 pa_assert(e && m);
1259
1260 *_m = m;
1261 *_e = e;
1262
1263 return 0;
1264 }
1265
1266 static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = {
1267 [PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */
1268
1269 [PA_CHANNEL_POSITION_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER,
1270 [PA_CHANNEL_POSITION_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT,
1271 [PA_CHANNEL_POSITION_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT,
1272
1273 [PA_CHANNEL_POSITION_REAR_CENTER] = SND_MIXER_SCHN_REAR_CENTER,
1274 [PA_CHANNEL_POSITION_REAR_LEFT] = SND_MIXER_SCHN_REAR_LEFT,
1275 [PA_CHANNEL_POSITION_REAR_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT,
1276
1277 [PA_CHANNEL_POSITION_LFE] = SND_MIXER_SCHN_WOOFER,
1278
1279 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1280 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1281
1282 [PA_CHANNEL_POSITION_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT,
1283 [PA_CHANNEL_POSITION_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT,
1284
1285 [PA_CHANNEL_POSITION_AUX0] = SND_MIXER_SCHN_UNKNOWN,
1286 [PA_CHANNEL_POSITION_AUX1] = SND_MIXER_SCHN_UNKNOWN,
1287 [PA_CHANNEL_POSITION_AUX2] = SND_MIXER_SCHN_UNKNOWN,
1288 [PA_CHANNEL_POSITION_AUX3] = SND_MIXER_SCHN_UNKNOWN,
1289 [PA_CHANNEL_POSITION_AUX4] = SND_MIXER_SCHN_UNKNOWN,
1290 [PA_CHANNEL_POSITION_AUX5] = SND_MIXER_SCHN_UNKNOWN,
1291 [PA_CHANNEL_POSITION_AUX6] = SND_MIXER_SCHN_UNKNOWN,
1292 [PA_CHANNEL_POSITION_AUX7] = SND_MIXER_SCHN_UNKNOWN,
1293 [PA_CHANNEL_POSITION_AUX8] = SND_MIXER_SCHN_UNKNOWN,
1294 [PA_CHANNEL_POSITION_AUX9] = SND_MIXER_SCHN_UNKNOWN,
1295 [PA_CHANNEL_POSITION_AUX10] = SND_MIXER_SCHN_UNKNOWN,
1296 [PA_CHANNEL_POSITION_AUX11] = SND_MIXER_SCHN_UNKNOWN,
1297 [PA_CHANNEL_POSITION_AUX12] = SND_MIXER_SCHN_UNKNOWN,
1298 [PA_CHANNEL_POSITION_AUX13] = SND_MIXER_SCHN_UNKNOWN,
1299 [PA_CHANNEL_POSITION_AUX14] = SND_MIXER_SCHN_UNKNOWN,
1300 [PA_CHANNEL_POSITION_AUX15] = SND_MIXER_SCHN_UNKNOWN,
1301 [PA_CHANNEL_POSITION_AUX16] = SND_MIXER_SCHN_UNKNOWN,
1302 [PA_CHANNEL_POSITION_AUX17] = SND_MIXER_SCHN_UNKNOWN,
1303 [PA_CHANNEL_POSITION_AUX18] = SND_MIXER_SCHN_UNKNOWN,
1304 [PA_CHANNEL_POSITION_AUX19] = SND_MIXER_SCHN_UNKNOWN,
1305 [PA_CHANNEL_POSITION_AUX20] = SND_MIXER_SCHN_UNKNOWN,
1306 [PA_CHANNEL_POSITION_AUX21] = SND_MIXER_SCHN_UNKNOWN,
1307 [PA_CHANNEL_POSITION_AUX22] = SND_MIXER_SCHN_UNKNOWN,
1308 [PA_CHANNEL_POSITION_AUX23] = SND_MIXER_SCHN_UNKNOWN,
1309 [PA_CHANNEL_POSITION_AUX24] = SND_MIXER_SCHN_UNKNOWN,
1310 [PA_CHANNEL_POSITION_AUX25] = SND_MIXER_SCHN_UNKNOWN,
1311 [PA_CHANNEL_POSITION_AUX26] = SND_MIXER_SCHN_UNKNOWN,
1312 [PA_CHANNEL_POSITION_AUX27] = SND_MIXER_SCHN_UNKNOWN,
1313 [PA_CHANNEL_POSITION_AUX28] = SND_MIXER_SCHN_UNKNOWN,
1314 [PA_CHANNEL_POSITION_AUX29] = SND_MIXER_SCHN_UNKNOWN,
1315 [PA_CHANNEL_POSITION_AUX30] = SND_MIXER_SCHN_UNKNOWN,
1316 [PA_CHANNEL_POSITION_AUX31] = SND_MIXER_SCHN_UNKNOWN,
1317
1318 [PA_CHANNEL_POSITION_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1319
1320 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1321 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN,
1322 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN,
1323
1324 [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1325 [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SND_MIXER_SCHN_UNKNOWN,
1326 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SND_MIXER_SCHN_UNKNOWN
1327 };
1328
1329
1330 int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback) {
1331 unsigned i;
1332 pa_bool_t alsa_channel_used[SND_MIXER_SCHN_LAST];
1333 pa_bool_t mono_used = FALSE;
1334
1335 pa_assert(elem);
1336 pa_assert(channel_map);
1337 pa_assert(mixer_map);
1338
1339 memset(&alsa_channel_used, 0, sizeof(alsa_channel_used));
1340
1341 if (channel_map->channels > 1 &&
1342 ((playback && snd_mixer_selem_has_playback_volume_joined(elem)) ||
1343 (!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) {
1344 pa_log_info("ALSA device lacks independant volume controls for each channel.");
1345 return -1;
1346 }
1347
1348 for (i = 0; i < channel_map->channels; i++) {
1349 snd_mixer_selem_channel_id_t id;
1350 pa_bool_t is_mono;
1351
1352 is_mono = channel_map->map[i] == PA_CHANNEL_POSITION_MONO;
1353 id = alsa_channel_ids[channel_map->map[i]];
1354
1355 if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) {
1356 pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer.", pa_channel_position_to_string(channel_map->map[i]));
1357 return -1;
1358 }
1359
1360 if ((is_mono && mono_used) || (!is_mono && alsa_channel_used[id])) {
1361 pa_log_info("Channel map has duplicate channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
1362 return -1;
1363 }
1364
1365 if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) ||
1366 (!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) {
1367
1368 pa_log_info("ALSA device lacks separate volumes control for channel '%s'", pa_channel_position_to_string(channel_map->map[i]));
1369 return -1;
1370 }
1371
1372 if (is_mono) {
1373 mixer_map[i] = SND_MIXER_SCHN_MONO;
1374 mono_used = TRUE;
1375 } else {
1376 mixer_map[i] = id;
1377 alsa_channel_used[id] = TRUE;
1378 }
1379 }
1380
1381 pa_log_info("All %u channels can be mapped to mixer channels.", channel_map->channels);
1382
1383 return 0;
1384 }
1385
1386 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
1387 int err;
1388 snd_output_t *out;
1389
1390 pa_assert(pcm);
1391
1392 pa_assert_se(snd_output_buffer_open(&out) == 0);
1393
1394 if ((err = snd_pcm_dump(pcm, out)) < 0)
1395 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
1396 else {
1397 char *s = NULL;
1398 snd_output_buffer_string(out, &s);
1399 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
1400 }
1401
1402 pa_assert_se(snd_output_close(out) == 0);
1403 }
1404
1405 void pa_alsa_dump_status(snd_pcm_t *pcm) {
1406 int err;
1407 snd_output_t *out;
1408 snd_pcm_status_t *status;
1409
1410 pa_assert(pcm);
1411
1412 snd_pcm_status_alloca(&status);
1413
1414 pa_assert_se(snd_output_buffer_open(&out) == 0);
1415
1416 pa_assert_se(snd_pcm_status(pcm, status) == 0);
1417
1418 if ((err = snd_pcm_status_dump(status, out)) < 0)
1419 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
1420 else {
1421 char *s = NULL;
1422 snd_output_buffer_string(out, &s);
1423 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
1424 }
1425
1426 pa_assert_se(snd_output_close(out) == 0);
1427 }
1428
1429 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
1430 va_list ap;
1431 char *alsa_file;
1432
1433 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
1434
1435 va_start(ap, fmt);
1436
1437 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
1438
1439 va_end(ap);
1440
1441 pa_xfree(alsa_file);
1442 }
1443
1444 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
1445
1446 void pa_alsa_redirect_errors_inc(void) {
1447 /* This is not really thread safe, but we do our best */
1448
1449 if (pa_atomic_inc(&n_error_handler_installed) == 0)
1450 snd_lib_error_set_handler(alsa_error_handler);
1451 }
1452
1453 void pa_alsa_redirect_errors_dec(void) {
1454 int r;
1455
1456 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
1457
1458 if (r == 1)
1459 snd_lib_error_set_handler(NULL);
1460 }
1461
1462 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
1463 const char *s;
1464 pa_assert(p);
1465
1466 if (pa_device_init_description(p))
1467 return TRUE;
1468
1469 if ((s = pa_proplist_gets(p, "alsa.card_name"))) {
1470 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
1471 return TRUE;
1472 }
1473
1474 if ((s = pa_proplist_gets(p, "alsa.name"))) {
1475 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
1476 return TRUE;
1477 }
1478
1479 return FALSE;
1480 }
1481
1482 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
1483 char *cn, *lcn, *dn;
1484
1485 pa_assert(p);
1486 pa_assert(card >= 0);
1487
1488 pa_proplist_setf(p, "alsa.card", "%i", card);
1489
1490 if (snd_card_get_name(card, &cn) >= 0) {
1491 pa_proplist_sets(p, "alsa.card_name", cn);
1492 free(cn);
1493 }
1494
1495 if (snd_card_get_longname(card, &lcn) >= 0) {
1496 pa_proplist_sets(p, "alsa.long_card_name", lcn);
1497 free(lcn);
1498 }
1499
1500 if ((dn = pa_alsa_get_driver_name(card))) {
1501 pa_proplist_sets(p, "alsa.driver_name", dn);
1502 pa_xfree(dn);
1503 }
1504
1505 #ifdef HAVE_UDEV
1506 pa_udev_get_info(c, p, card);
1507 #endif
1508
1509 #ifdef HAVE_HAL
1510 pa_hal_get_info(c, p, card);
1511 #endif
1512 }
1513
1514 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
1515
1516 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
1517 [SND_PCM_CLASS_GENERIC] = "generic",
1518 [SND_PCM_CLASS_MULTI] = "multi",
1519 [SND_PCM_CLASS_MODEM] = "modem",
1520 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
1521 };
1522 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
1523 [SND_PCM_CLASS_GENERIC] = "sound",
1524 [SND_PCM_CLASS_MULTI] = NULL,
1525 [SND_PCM_CLASS_MODEM] = "modem",
1526 [SND_PCM_CLASS_DIGITIZER] = NULL
1527 };
1528 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
1529 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
1530 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
1531 };
1532
1533 snd_pcm_class_t class;
1534 snd_pcm_subclass_t subclass;
1535 const char *n, *id, *sdn;
1536 int card;
1537
1538 pa_assert(p);
1539 pa_assert(pcm_info);
1540
1541 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
1542
1543 class = snd_pcm_info_get_class(pcm_info);
1544 if (class <= SND_PCM_CLASS_LAST) {
1545 if (class_table[class])
1546 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
1547 if (alsa_class_table[class])
1548 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
1549 }
1550
1551 subclass = snd_pcm_info_get_subclass(pcm_info);
1552 if (subclass <= SND_PCM_SUBCLASS_LAST)
1553 if (alsa_subclass_table[subclass])
1554 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
1555
1556 if ((n = snd_pcm_info_get_name(pcm_info)))
1557 pa_proplist_sets(p, "alsa.name", n);
1558
1559 if ((id = snd_pcm_info_get_id(pcm_info)))
1560 pa_proplist_sets(p, "alsa.id", id);
1561
1562 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
1563 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
1564 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
1565
1566 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
1567
1568 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
1569 pa_alsa_init_proplist_card(c, p, card);
1570 }
1571
1572 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem) {
1573 snd_pcm_hw_params_t *hwparams;
1574 snd_pcm_info_t *info;
1575 int bits, err;
1576
1577 snd_pcm_hw_params_alloca(&hwparams);
1578 snd_pcm_info_alloca(&info);
1579
1580 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
1581 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
1582 else {
1583
1584 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
1585 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
1586 }
1587
1588 if (elem)
1589 pa_proplist_sets(p, "alsa.mixer_element", snd_mixer_selem_get_name(elem));
1590
1591 if ((err = snd_pcm_info(pcm, info)) < 0)
1592 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
1593 else
1594 pa_alsa_init_proplist_pcm_info(c, p, info);
1595 }
1596
1597 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1598 snd_pcm_state_t state;
1599 int err;
1600
1601 pa_assert(pcm);
1602
1603 if (revents & POLLERR)
1604 pa_log_debug("Got POLLERR from ALSA");
1605 if (revents & POLLNVAL)
1606 pa_log_warn("Got POLLNVAL from ALSA");
1607 if (revents & POLLHUP)
1608 pa_log_warn("Got POLLHUP from ALSA");
1609 if (revents & POLLPRI)
1610 pa_log_warn("Got POLLPRI from ALSA");
1611 if (revents & POLLIN)
1612 pa_log_debug("Got POLLIN from ALSA");
1613 if (revents & POLLOUT)
1614 pa_log_debug("Got POLLOUT from ALSA");
1615
1616 state = snd_pcm_state(pcm);
1617 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1618
1619 /* Try to recover from this error */
1620
1621 switch (state) {
1622
1623 case SND_PCM_STATE_XRUN:
1624 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1625 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1626 return -1;
1627 }
1628 break;
1629
1630 case SND_PCM_STATE_SUSPENDED:
1631 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
1632 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
1633 return -1;
1634 }
1635 break;
1636
1637 default:
1638
1639 snd_pcm_drop(pcm);
1640
1641 if ((err = snd_pcm_prepare(pcm)) < 0) {
1642 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
1643 return -1;
1644 }
1645 break;
1646 }
1647
1648 return 0;
1649 }
1650
1651 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1652 int n, err;
1653 struct pollfd *pollfd;
1654 pa_rtpoll_item *item;
1655
1656 pa_assert(pcm);
1657
1658 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1659 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1660 return NULL;
1661 }
1662
1663 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1664 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1665
1666 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1667 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1668 pa_rtpoll_item_free(item);
1669 return NULL;
1670 }
1671
1672 return item;
1673 }
1674
1675 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1676 snd_pcm_sframes_t n;
1677 size_t k;
1678
1679 pa_assert(pcm);
1680 pa_assert(hwbuf_size > 0);
1681 pa_assert(ss);
1682
1683 /* Some ALSA driver expose weird bugs, let's inform the user about
1684 * what is going on */
1685
1686 n = snd_pcm_avail(pcm);
1687
1688 if (n <= 0)
1689 return n;
1690
1691 k = (size_t) n * pa_frame_size(ss);
1692
1693 if (k >= hwbuf_size * 5 ||
1694 k >= pa_bytes_per_second(ss)*10) {
1695
1696 PA_ONCE_BEGIN {
1697 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1698 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1699 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1700 (unsigned long) k,
1701 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1702 pa_strnull(dn));
1703 pa_xfree(dn);
1704 pa_alsa_dump(PA_LOG_ERROR, pcm);
1705 } PA_ONCE_END;
1706
1707 /* Mhmm, let's try not to fail completely */
1708 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1709 }
1710
1711 return n;
1712 }
1713
1714 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) {
1715 ssize_t k;
1716 size_t abs_k;
1717 int r;
1718
1719 pa_assert(pcm);
1720 pa_assert(delay);
1721 pa_assert(hwbuf_size > 0);
1722 pa_assert(ss);
1723
1724 /* Some ALSA driver expose weird bugs, let's inform the user about
1725 * what is going on */
1726
1727 if ((r = snd_pcm_delay(pcm, delay)) < 0)
1728 return r;
1729
1730 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1731
1732 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1733
1734 if (abs_k >= hwbuf_size * 5 ||
1735 abs_k >= pa_bytes_per_second(ss)*10) {
1736
1737 PA_ONCE_BEGIN {
1738 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1739 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1740 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1741 (signed long) k,
1742 k < 0 ? "-" : "",
1743 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1744 pa_strnull(dn));
1745 pa_xfree(dn);
1746 pa_alsa_dump(PA_LOG_ERROR, pcm);
1747 } PA_ONCE_END;
1748
1749 /* Mhmm, let's try not to fail completely */
1750 if (k < 0)
1751 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1752 else
1753 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1754 }
1755
1756 return 0;
1757 }
1758
1759 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) {
1760 int r;
1761 snd_pcm_uframes_t before;
1762 size_t k;
1763
1764 pa_assert(pcm);
1765 pa_assert(areas);
1766 pa_assert(offset);
1767 pa_assert(frames);
1768 pa_assert(hwbuf_size > 0);
1769 pa_assert(ss);
1770
1771 before = *frames;
1772
1773 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1774
1775 if (r < 0)
1776 return r;
1777
1778 k = (size_t) *frames * pa_frame_size(ss);
1779
1780 if (*frames > before ||
1781 k >= hwbuf_size * 3 ||
1782 k >= pa_bytes_per_second(ss)*10)
1783
1784 PA_ONCE_BEGIN {
1785 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1786 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1787 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1788 (unsigned long) k,
1789 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1790 pa_strnull(dn));
1791 pa_xfree(dn);
1792 pa_alsa_dump(PA_LOG_ERROR, pcm);
1793 } PA_ONCE_END;
1794
1795 return r;
1796 }
1797
1798 char *pa_alsa_get_driver_name(int card) {
1799 char *t, *m, *n;
1800
1801 pa_assert(card >= 0);
1802
1803 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1804 m = pa_readlink(t);
1805 pa_xfree(t);
1806
1807 if (!m)
1808 return NULL;
1809
1810 n = pa_xstrdup(pa_path_get_filename(m));
1811 pa_xfree(m);
1812
1813 return n;
1814 }
1815
1816 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1817 int card;
1818 snd_pcm_info_t* info;
1819 snd_pcm_info_alloca(&info);
1820
1821 pa_assert(pcm);
1822
1823 if (snd_pcm_info(pcm, info) < 0)
1824 return NULL;
1825
1826 if ((card = snd_pcm_info_get_card(info)) < 0)
1827 return NULL;
1828
1829 return pa_alsa_get_driver_name(card);
1830 }
1831
1832 char *pa_alsa_get_reserve_name(const char *device) {
1833 const char *t;
1834 int i;
1835
1836 pa_assert(device);
1837
1838 if ((t = strchr(device, ':')))
1839 device = t+1;
1840
1841 if ((i = snd_card_get_index(device)) < 0) {
1842 int32_t k;
1843
1844 if (pa_atoi(device, &k) < 0)
1845 return NULL;
1846
1847 i = (int) k;
1848 }
1849
1850 return pa_sprintf_malloc("Audio%i", i);
1851 }
1852
1853 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1854 snd_pcm_info_t* info;
1855 snd_pcm_info_alloca(&info);
1856
1857 pa_assert(pcm);
1858
1859 if (snd_pcm_info(pcm, info) < 0)
1860 return FALSE;
1861
1862 return snd_pcm_info_get_card(info) >= 0;
1863 }
1864
1865 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1866 snd_pcm_info_t* info;
1867 snd_pcm_info_alloca(&info);
1868
1869 pa_assert(pcm);
1870
1871 if (snd_pcm_info(pcm, info) < 0)
1872 return FALSE;
1873
1874 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1875 }
1876
1877 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1878
1879 const char* pa_alsa_strerror(int errnum) {
1880 const char *original = NULL;
1881 char *translated, *t;
1882 char errbuf[128];
1883
1884 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1885 pa_xfree(t);
1886
1887 original = snd_strerror(errnum);
1888
1889 if (!original) {
1890 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1891 original = errbuf;
1892 }
1893
1894 if (!(translated = pa_locale_to_utf8(original))) {
1895 pa_log_warn("Unable to convert error string to locale, filtering.");
1896 translated = pa_utf8_filter(original);
1897 }
1898
1899 PA_STATIC_TLS_SET(cstrerror, translated);
1900
1901 return translated;
1902 }