]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
Merge commit 'origin/master-tx'
[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
1295 snd_mixer_close(m);
1296 return -1;
1297 }
1298
1299 pa_assert(e && m);
1300
1301 *_m = m;
1302 *_e = e;
1303
1304 return 0;
1305 }
1306
1307 static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = {
1308 [PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */
1309
1310 [PA_CHANNEL_POSITION_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER,
1311 [PA_CHANNEL_POSITION_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT,
1312 [PA_CHANNEL_POSITION_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT,
1313
1314 [PA_CHANNEL_POSITION_REAR_CENTER] = SND_MIXER_SCHN_REAR_CENTER,
1315 [PA_CHANNEL_POSITION_REAR_LEFT] = SND_MIXER_SCHN_REAR_LEFT,
1316 [PA_CHANNEL_POSITION_REAR_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT,
1317
1318 [PA_CHANNEL_POSITION_LFE] = SND_MIXER_SCHN_WOOFER,
1319
1320 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1321 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1322
1323 [PA_CHANNEL_POSITION_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT,
1324 [PA_CHANNEL_POSITION_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT,
1325
1326 [PA_CHANNEL_POSITION_AUX0] = SND_MIXER_SCHN_UNKNOWN,
1327 [PA_CHANNEL_POSITION_AUX1] = SND_MIXER_SCHN_UNKNOWN,
1328 [PA_CHANNEL_POSITION_AUX2] = SND_MIXER_SCHN_UNKNOWN,
1329 [PA_CHANNEL_POSITION_AUX3] = SND_MIXER_SCHN_UNKNOWN,
1330 [PA_CHANNEL_POSITION_AUX4] = SND_MIXER_SCHN_UNKNOWN,
1331 [PA_CHANNEL_POSITION_AUX5] = SND_MIXER_SCHN_UNKNOWN,
1332 [PA_CHANNEL_POSITION_AUX6] = SND_MIXER_SCHN_UNKNOWN,
1333 [PA_CHANNEL_POSITION_AUX7] = SND_MIXER_SCHN_UNKNOWN,
1334 [PA_CHANNEL_POSITION_AUX8] = SND_MIXER_SCHN_UNKNOWN,
1335 [PA_CHANNEL_POSITION_AUX9] = SND_MIXER_SCHN_UNKNOWN,
1336 [PA_CHANNEL_POSITION_AUX10] = SND_MIXER_SCHN_UNKNOWN,
1337 [PA_CHANNEL_POSITION_AUX11] = SND_MIXER_SCHN_UNKNOWN,
1338 [PA_CHANNEL_POSITION_AUX12] = SND_MIXER_SCHN_UNKNOWN,
1339 [PA_CHANNEL_POSITION_AUX13] = SND_MIXER_SCHN_UNKNOWN,
1340 [PA_CHANNEL_POSITION_AUX14] = SND_MIXER_SCHN_UNKNOWN,
1341 [PA_CHANNEL_POSITION_AUX15] = SND_MIXER_SCHN_UNKNOWN,
1342 [PA_CHANNEL_POSITION_AUX16] = SND_MIXER_SCHN_UNKNOWN,
1343 [PA_CHANNEL_POSITION_AUX17] = SND_MIXER_SCHN_UNKNOWN,
1344 [PA_CHANNEL_POSITION_AUX18] = SND_MIXER_SCHN_UNKNOWN,
1345 [PA_CHANNEL_POSITION_AUX19] = SND_MIXER_SCHN_UNKNOWN,
1346 [PA_CHANNEL_POSITION_AUX20] = SND_MIXER_SCHN_UNKNOWN,
1347 [PA_CHANNEL_POSITION_AUX21] = SND_MIXER_SCHN_UNKNOWN,
1348 [PA_CHANNEL_POSITION_AUX22] = SND_MIXER_SCHN_UNKNOWN,
1349 [PA_CHANNEL_POSITION_AUX23] = SND_MIXER_SCHN_UNKNOWN,
1350 [PA_CHANNEL_POSITION_AUX24] = SND_MIXER_SCHN_UNKNOWN,
1351 [PA_CHANNEL_POSITION_AUX25] = SND_MIXER_SCHN_UNKNOWN,
1352 [PA_CHANNEL_POSITION_AUX26] = SND_MIXER_SCHN_UNKNOWN,
1353 [PA_CHANNEL_POSITION_AUX27] = SND_MIXER_SCHN_UNKNOWN,
1354 [PA_CHANNEL_POSITION_AUX28] = SND_MIXER_SCHN_UNKNOWN,
1355 [PA_CHANNEL_POSITION_AUX29] = SND_MIXER_SCHN_UNKNOWN,
1356 [PA_CHANNEL_POSITION_AUX30] = SND_MIXER_SCHN_UNKNOWN,
1357 [PA_CHANNEL_POSITION_AUX31] = SND_MIXER_SCHN_UNKNOWN,
1358
1359 [PA_CHANNEL_POSITION_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1360
1361 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1362 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN,
1363 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN,
1364
1365 [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SND_MIXER_SCHN_UNKNOWN,
1366 [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SND_MIXER_SCHN_UNKNOWN,
1367 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SND_MIXER_SCHN_UNKNOWN
1368 };
1369
1370
1371 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) {
1372 unsigned i;
1373 pa_bool_t alsa_channel_used[SND_MIXER_SCHN_LAST];
1374 pa_bool_t mono_used = FALSE;
1375
1376 pa_assert(elem);
1377 pa_assert(channel_map);
1378 pa_assert(mixer_map);
1379
1380 memset(&alsa_channel_used, 0, sizeof(alsa_channel_used));
1381
1382 if (channel_map->channels > 1 &&
1383 ((playback && snd_mixer_selem_has_playback_volume_joined(elem)) ||
1384 (!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) {
1385 pa_log_info("ALSA device lacks independant volume controls for each channel.");
1386 return -1;
1387 }
1388
1389 for (i = 0; i < channel_map->channels; i++) {
1390 snd_mixer_selem_channel_id_t id;
1391 pa_bool_t is_mono;
1392
1393 is_mono = channel_map->map[i] == PA_CHANNEL_POSITION_MONO;
1394 id = alsa_channel_ids[channel_map->map[i]];
1395
1396 if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) {
1397 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]));
1398 return -1;
1399 }
1400
1401 if ((is_mono && mono_used) || (!is_mono && alsa_channel_used[id])) {
1402 pa_log_info("Channel map has duplicate channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
1403 return -1;
1404 }
1405
1406 if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) ||
1407 (!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) {
1408
1409 pa_log_info("ALSA device lacks separate volumes control for channel '%s'", pa_channel_position_to_string(channel_map->map[i]));
1410 return -1;
1411 }
1412
1413 if (is_mono) {
1414 mixer_map[i] = SND_MIXER_SCHN_MONO;
1415 mono_used = TRUE;
1416 } else {
1417 mixer_map[i] = id;
1418 alsa_channel_used[id] = TRUE;
1419 }
1420 }
1421
1422 pa_log_info("All %u channels can be mapped to mixer channels.", channel_map->channels);
1423
1424 return 0;
1425 }
1426
1427 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
1428 int err;
1429 snd_output_t *out;
1430
1431 pa_assert(pcm);
1432
1433 pa_assert_se(snd_output_buffer_open(&out) == 0);
1434
1435 if ((err = snd_pcm_dump(pcm, out)) < 0)
1436 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
1437 else {
1438 char *s = NULL;
1439 snd_output_buffer_string(out, &s);
1440 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
1441 }
1442
1443 pa_assert_se(snd_output_close(out) == 0);
1444 }
1445
1446 void pa_alsa_dump_status(snd_pcm_t *pcm) {
1447 int err;
1448 snd_output_t *out;
1449 snd_pcm_status_t *status;
1450
1451 pa_assert(pcm);
1452
1453 snd_pcm_status_alloca(&status);
1454
1455 pa_assert_se(snd_output_buffer_open(&out) == 0);
1456
1457 pa_assert_se(snd_pcm_status(pcm, status) == 0);
1458
1459 if ((err = snd_pcm_status_dump(status, out)) < 0)
1460 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
1461 else {
1462 char *s = NULL;
1463 snd_output_buffer_string(out, &s);
1464 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
1465 }
1466
1467 pa_assert_se(snd_output_close(out) == 0);
1468 }
1469
1470 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
1471 va_list ap;
1472 char *alsa_file;
1473
1474 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
1475
1476 va_start(ap, fmt);
1477
1478 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
1479
1480 va_end(ap);
1481
1482 pa_xfree(alsa_file);
1483 }
1484
1485 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
1486
1487 void pa_alsa_redirect_errors_inc(void) {
1488 /* This is not really thread safe, but we do our best */
1489
1490 if (pa_atomic_inc(&n_error_handler_installed) == 0)
1491 snd_lib_error_set_handler(alsa_error_handler);
1492 }
1493
1494 void pa_alsa_redirect_errors_dec(void) {
1495 int r;
1496
1497 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
1498
1499 if (r == 1)
1500 snd_lib_error_set_handler(NULL);
1501 }
1502
1503 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
1504 const char *s;
1505 pa_assert(p);
1506
1507 if (pa_device_init_description(p))
1508 return TRUE;
1509
1510 if ((s = pa_proplist_gets(p, "alsa.card_name"))) {
1511 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
1512 return TRUE;
1513 }
1514
1515 if ((s = pa_proplist_gets(p, "alsa.name"))) {
1516 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
1517 return TRUE;
1518 }
1519
1520 return FALSE;
1521 }
1522
1523 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
1524 char *cn, *lcn, *dn;
1525
1526 pa_assert(p);
1527 pa_assert(card >= 0);
1528
1529 pa_proplist_setf(p, "alsa.card", "%i", card);
1530
1531 if (snd_card_get_name(card, &cn) >= 0) {
1532 pa_proplist_sets(p, "alsa.card_name", cn);
1533 free(cn);
1534 }
1535
1536 if (snd_card_get_longname(card, &lcn) >= 0) {
1537 pa_proplist_sets(p, "alsa.long_card_name", lcn);
1538 free(lcn);
1539 }
1540
1541 if ((dn = pa_alsa_get_driver_name(card))) {
1542 pa_proplist_sets(p, "alsa.driver_name", dn);
1543 pa_xfree(dn);
1544 }
1545
1546 #ifdef HAVE_UDEV
1547 pa_udev_get_info(c, p, card);
1548 #endif
1549
1550 #ifdef HAVE_HAL
1551 pa_hal_get_info(c, p, card);
1552 #endif
1553 }
1554
1555 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
1556
1557 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
1558 [SND_PCM_CLASS_GENERIC] = "generic",
1559 [SND_PCM_CLASS_MULTI] = "multi",
1560 [SND_PCM_CLASS_MODEM] = "modem",
1561 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
1562 };
1563 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
1564 [SND_PCM_CLASS_GENERIC] = "sound",
1565 [SND_PCM_CLASS_MULTI] = NULL,
1566 [SND_PCM_CLASS_MODEM] = "modem",
1567 [SND_PCM_CLASS_DIGITIZER] = NULL
1568 };
1569 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
1570 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
1571 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
1572 };
1573
1574 snd_pcm_class_t class;
1575 snd_pcm_subclass_t subclass;
1576 const char *n, *id, *sdn;
1577 int card;
1578
1579 pa_assert(p);
1580 pa_assert(pcm_info);
1581
1582 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
1583
1584 class = snd_pcm_info_get_class(pcm_info);
1585 if (class <= SND_PCM_CLASS_LAST) {
1586 if (class_table[class])
1587 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
1588 if (alsa_class_table[class])
1589 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
1590 }
1591
1592 subclass = snd_pcm_info_get_subclass(pcm_info);
1593 if (subclass <= SND_PCM_SUBCLASS_LAST)
1594 if (alsa_subclass_table[subclass])
1595 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
1596
1597 if ((n = snd_pcm_info_get_name(pcm_info)))
1598 pa_proplist_sets(p, "alsa.name", n);
1599
1600 if ((id = snd_pcm_info_get_id(pcm_info)))
1601 pa_proplist_sets(p, "alsa.id", id);
1602
1603 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
1604 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
1605 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
1606
1607 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
1608
1609 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
1610 pa_alsa_init_proplist_card(c, p, card);
1611 }
1612
1613 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem) {
1614 snd_pcm_hw_params_t *hwparams;
1615 snd_pcm_info_t *info;
1616 int bits, err;
1617
1618 snd_pcm_hw_params_alloca(&hwparams);
1619 snd_pcm_info_alloca(&info);
1620
1621 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
1622 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
1623 else {
1624
1625 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
1626 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
1627 }
1628
1629 if (elem)
1630 pa_proplist_sets(p, "alsa.mixer_element", snd_mixer_selem_get_name(elem));
1631
1632 if ((err = snd_pcm_info(pcm, info)) < 0)
1633 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
1634 else
1635 pa_alsa_init_proplist_pcm_info(c, p, info);
1636 }
1637
1638 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
1639 int err;
1640 snd_ctl_t *ctl;
1641 snd_ctl_card_info_t *info;
1642 const char *t;
1643
1644 pa_assert(p);
1645
1646 snd_ctl_card_info_alloca(&info);
1647
1648 if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
1649 pa_log_warn("Error opening low-level control device '%s'", name);
1650 return;
1651 }
1652
1653 if ((err = snd_ctl_card_info(ctl, info)) < 0) {
1654 pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
1655 snd_ctl_close(ctl);
1656 return;
1657 }
1658
1659 if ((t = snd_ctl_card_info_get_mixername(info)))
1660 pa_proplist_sets(p, "alsa.mixer_name", t);
1661
1662 if ((t = snd_ctl_card_info_get_components(info)))
1663 pa_proplist_sets(p, "alsa.components", t);
1664
1665 snd_ctl_close(ctl);
1666 }
1667
1668 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1669 snd_pcm_state_t state;
1670 int err;
1671
1672 pa_assert(pcm);
1673
1674 if (revents & POLLERR)
1675 pa_log_debug("Got POLLERR from ALSA");
1676 if (revents & POLLNVAL)
1677 pa_log_warn("Got POLLNVAL from ALSA");
1678 if (revents & POLLHUP)
1679 pa_log_warn("Got POLLHUP from ALSA");
1680 if (revents & POLLPRI)
1681 pa_log_warn("Got POLLPRI from ALSA");
1682 if (revents & POLLIN)
1683 pa_log_debug("Got POLLIN from ALSA");
1684 if (revents & POLLOUT)
1685 pa_log_debug("Got POLLOUT from ALSA");
1686
1687 state = snd_pcm_state(pcm);
1688 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1689
1690 /* Try to recover from this error */
1691
1692 switch (state) {
1693
1694 case SND_PCM_STATE_XRUN:
1695 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1696 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1697 return -1;
1698 }
1699 break;
1700
1701 case SND_PCM_STATE_SUSPENDED:
1702 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
1703 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
1704 return -1;
1705 }
1706 break;
1707
1708 default:
1709
1710 snd_pcm_drop(pcm);
1711
1712 if ((err = snd_pcm_prepare(pcm)) < 0) {
1713 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
1714 return -1;
1715 }
1716 break;
1717 }
1718
1719 return 0;
1720 }
1721
1722 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1723 int n, err;
1724 struct pollfd *pollfd;
1725 pa_rtpoll_item *item;
1726
1727 pa_assert(pcm);
1728
1729 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1730 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1731 return NULL;
1732 }
1733
1734 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1735 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1736
1737 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1738 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1739 pa_rtpoll_item_free(item);
1740 return NULL;
1741 }
1742
1743 return item;
1744 }
1745
1746 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1747 snd_pcm_sframes_t n;
1748 size_t k;
1749
1750 pa_assert(pcm);
1751 pa_assert(hwbuf_size > 0);
1752 pa_assert(ss);
1753
1754 /* Some ALSA driver expose weird bugs, let's inform the user about
1755 * what is going on */
1756
1757 n = snd_pcm_avail(pcm);
1758
1759 if (n <= 0)
1760 return n;
1761
1762 k = (size_t) n * pa_frame_size(ss);
1763
1764 if (k >= hwbuf_size * 5 ||
1765 k >= pa_bytes_per_second(ss)*10) {
1766
1767 PA_ONCE_BEGIN {
1768 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1769 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1770 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1771 (unsigned long) k,
1772 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1773 pa_strnull(dn));
1774 pa_xfree(dn);
1775 pa_alsa_dump(PA_LOG_ERROR, pcm);
1776 } PA_ONCE_END;
1777
1778 /* Mhmm, let's try not to fail completely */
1779 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1780 }
1781
1782 return n;
1783 }
1784
1785 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) {
1786 ssize_t k;
1787 size_t abs_k;
1788 int r;
1789
1790 pa_assert(pcm);
1791 pa_assert(delay);
1792 pa_assert(hwbuf_size > 0);
1793 pa_assert(ss);
1794
1795 /* Some ALSA driver expose weird bugs, let's inform the user about
1796 * what is going on */
1797
1798 if ((r = snd_pcm_delay(pcm, delay)) < 0)
1799 return r;
1800
1801 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1802
1803 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1804
1805 if (abs_k >= hwbuf_size * 5 ||
1806 abs_k >= pa_bytes_per_second(ss)*10) {
1807
1808 PA_ONCE_BEGIN {
1809 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1810 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1811 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1812 (signed long) k,
1813 k < 0 ? "-" : "",
1814 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1815 pa_strnull(dn));
1816 pa_xfree(dn);
1817 pa_alsa_dump(PA_LOG_ERROR, pcm);
1818 } PA_ONCE_END;
1819
1820 /* Mhmm, let's try not to fail completely */
1821 if (k < 0)
1822 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1823 else
1824 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1825 }
1826
1827 return 0;
1828 }
1829
1830 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) {
1831 int r;
1832 snd_pcm_uframes_t before;
1833 size_t k;
1834
1835 pa_assert(pcm);
1836 pa_assert(areas);
1837 pa_assert(offset);
1838 pa_assert(frames);
1839 pa_assert(hwbuf_size > 0);
1840 pa_assert(ss);
1841
1842 before = *frames;
1843
1844 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1845
1846 if (r < 0)
1847 return r;
1848
1849 k = (size_t) *frames * pa_frame_size(ss);
1850
1851 if (*frames > before ||
1852 k >= hwbuf_size * 3 ||
1853 k >= pa_bytes_per_second(ss)*10)
1854
1855 PA_ONCE_BEGIN {
1856 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1857 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1858 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1859 (unsigned long) k,
1860 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1861 pa_strnull(dn));
1862 pa_xfree(dn);
1863 pa_alsa_dump(PA_LOG_ERROR, pcm);
1864 } PA_ONCE_END;
1865
1866 return r;
1867 }
1868
1869 char *pa_alsa_get_driver_name(int card) {
1870 char *t, *m, *n;
1871
1872 pa_assert(card >= 0);
1873
1874 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1875 m = pa_readlink(t);
1876 pa_xfree(t);
1877
1878 if (!m)
1879 return NULL;
1880
1881 n = pa_xstrdup(pa_path_get_filename(m));
1882 pa_xfree(m);
1883
1884 return n;
1885 }
1886
1887 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1888 int card;
1889 snd_pcm_info_t* info;
1890 snd_pcm_info_alloca(&info);
1891
1892 pa_assert(pcm);
1893
1894 if (snd_pcm_info(pcm, info) < 0)
1895 return NULL;
1896
1897 if ((card = snd_pcm_info_get_card(info)) < 0)
1898 return NULL;
1899
1900 return pa_alsa_get_driver_name(card);
1901 }
1902
1903 char *pa_alsa_get_reserve_name(const char *device) {
1904 const char *t;
1905 int i;
1906
1907 pa_assert(device);
1908
1909 if ((t = strchr(device, ':')))
1910 device = t+1;
1911
1912 if ((i = snd_card_get_index(device)) < 0) {
1913 int32_t k;
1914
1915 if (pa_atoi(device, &k) < 0)
1916 return NULL;
1917
1918 i = (int) k;
1919 }
1920
1921 return pa_sprintf_malloc("Audio%i", i);
1922 }
1923
1924 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1925 snd_pcm_info_t* info;
1926 snd_pcm_info_alloca(&info);
1927
1928 pa_assert(pcm);
1929
1930 if (snd_pcm_info(pcm, info) < 0)
1931 return FALSE;
1932
1933 return snd_pcm_info_get_card(info) >= 0;
1934 }
1935
1936 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1937 snd_pcm_info_t* info;
1938 snd_pcm_info_alloca(&info);
1939
1940 pa_assert(pcm);
1941
1942 if (snd_pcm_info(pcm, info) < 0)
1943 return FALSE;
1944
1945 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1946 }
1947
1948 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1949
1950 const char* pa_alsa_strerror(int errnum) {
1951 const char *original = NULL;
1952 char *translated, *t;
1953 char errbuf[128];
1954
1955 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1956 pa_xfree(t);
1957
1958 original = snd_strerror(errnum);
1959
1960 if (!original) {
1961 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1962 original = errbuf;
1963 }
1964
1965 if (!(translated = pa_locale_to_utf8(original))) {
1966 pa_log_warn("Unable to convert error string to locale, filtering.");
1967 translated = pa_utf8_filter(original);
1968 }
1969
1970 PA_STATIC_TLS_SET(cstrerror, translated);
1971
1972 return translated;
1973 }