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