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