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