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