]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
add logic for initializing a useful icon name
[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 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_CENTER,
591 PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT,
592 PA_CHANNEL_POSITION_REAR_RIGHT, 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 }