]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
alsa-mixer: When figuring out the max_dB of a path, use only channels that are used...
[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 #include <pulsecore/conf-parser.h>
46 #include <pulsecore/core-rtclock.h>
47
48 #include "alsa-util.h"
49 #include "alsa-mixer.h"
50
51 #ifdef HAVE_HAL
52 #include "hal-util.h"
53 #endif
54
55 #ifdef HAVE_UDEV
56 #include "udev-util.h"
57 #endif
58
59 static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
60
61 static const snd_pcm_format_t format_trans[] = {
62 [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8,
63 [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
64 [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
65 [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
66 [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
67 [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
68 [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
69 [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
70 [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
71 [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
72 [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
73 [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
74 [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE,
75 };
76
77 static const pa_sample_format_t try_order[] = {
78 PA_SAMPLE_FLOAT32NE,
79 PA_SAMPLE_FLOAT32RE,
80 PA_SAMPLE_S32NE,
81 PA_SAMPLE_S32RE,
82 PA_SAMPLE_S24_32NE,
83 PA_SAMPLE_S24_32RE,
84 PA_SAMPLE_S24NE,
85 PA_SAMPLE_S24RE,
86 PA_SAMPLE_S16NE,
87 PA_SAMPLE_S16RE,
88 PA_SAMPLE_ALAW,
89 PA_SAMPLE_ULAW,
90 PA_SAMPLE_U8
91 };
92
93 unsigned i;
94 int ret;
95
96 pa_assert(pcm_handle);
97 pa_assert(hwparams);
98 pa_assert(f);
99
100 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
101 return ret;
102
103 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
104 snd_pcm_format_description(format_trans[*f]),
105 pa_alsa_strerror(ret));
106
107 if (*f == PA_SAMPLE_FLOAT32BE)
108 *f = PA_SAMPLE_FLOAT32LE;
109 else if (*f == PA_SAMPLE_FLOAT32LE)
110 *f = PA_SAMPLE_FLOAT32BE;
111 else if (*f == PA_SAMPLE_S24BE)
112 *f = PA_SAMPLE_S24LE;
113 else if (*f == PA_SAMPLE_S24LE)
114 *f = PA_SAMPLE_S24BE;
115 else if (*f == PA_SAMPLE_S24_32BE)
116 *f = PA_SAMPLE_S24_32LE;
117 else if (*f == PA_SAMPLE_S24_32LE)
118 *f = PA_SAMPLE_S24_32BE;
119 else if (*f == PA_SAMPLE_S16BE)
120 *f = PA_SAMPLE_S16LE;
121 else if (*f == PA_SAMPLE_S16LE)
122 *f = PA_SAMPLE_S16BE;
123 else if (*f == PA_SAMPLE_S32BE)
124 *f = PA_SAMPLE_S32LE;
125 else if (*f == PA_SAMPLE_S32LE)
126 *f = PA_SAMPLE_S32BE;
127 else
128 goto try_auto;
129
130 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
131 return ret;
132
133 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
134 snd_pcm_format_description(format_trans[*f]),
135 pa_alsa_strerror(ret));
136
137 try_auto:
138
139 for (i = 0; i < PA_ELEMENTSOF(try_order); i++) {
140 *f = try_order[i];
141
142 if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
143 return ret;
144
145 pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
146 snd_pcm_format_description(format_trans[*f]),
147 pa_alsa_strerror(ret));
148 }
149
150 return -1;
151 }
152
153 static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
154 snd_pcm_uframes_t s;
155 int d, ret;
156
157 pa_assert(pcm_handle);
158 pa_assert(hwparams);
159
160 s = size;
161 d = 0;
162 if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
163 s = size;
164 d = -1;
165 if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
166 s = size;
167 d = 1;
168 if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
169 pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
170 return ret;
171 }
172 }
173 }
174
175 return 0;
176 }
177
178 static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
179 int ret;
180
181 pa_assert(pcm_handle);
182 pa_assert(hwparams);
183
184 if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
185 pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
186 return ret;
187 }
188
189 return 0;
190 }
191
192 /* Set the hardware parameters of the given ALSA device. Returns the
193 * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */
194 int pa_alsa_set_hw_params(
195 snd_pcm_t *pcm_handle,
196 pa_sample_spec *ss,
197 snd_pcm_uframes_t *period_size,
198 snd_pcm_uframes_t *buffer_size,
199 snd_pcm_uframes_t tsched_size,
200 pa_bool_t *use_mmap,
201 pa_bool_t *use_tsched,
202 pa_bool_t require_exact_channel_number) {
203
204 int ret = -1;
205 snd_pcm_hw_params_t *hwparams, *hwparams_copy;
206 int dir;
207 snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
208 snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
209 pa_bool_t _use_mmap = use_mmap && *use_mmap;
210 pa_bool_t _use_tsched = use_tsched && *use_tsched;
211 pa_sample_spec _ss = *ss;
212
213 pa_assert(pcm_handle);
214 pa_assert(ss);
215
216 snd_pcm_hw_params_alloca(&hwparams);
217 snd_pcm_hw_params_alloca(&hwparams_copy);
218
219 if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
220 pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
221 goto finish;
222 }
223
224 if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
225 pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret));
226 goto finish;
227 }
228
229 if (_use_mmap) {
230
231 if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
232
233 /* mmap() didn't work, fall back to interleaved */
234
235 if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
236 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
237 goto finish;
238 }
239
240 _use_mmap = FALSE;
241 }
242
243 } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
244 pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
245 goto finish;
246 }
247
248 if (!_use_mmap)
249 _use_tsched = FALSE;
250
251 if (!pa_alsa_pcm_is_hw(pcm_handle))
252 _use_tsched = FALSE;
253
254 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
255 if (_use_tsched) {
256
257 /* try to disable period wakeups if hardware can do so */
258 if (snd_pcm_hw_params_can_disable_period_wakeup(hwparams)) {
259
260 if (snd_pcm_hw_params_set_period_wakeup(pcm_handle, hwparams, FALSE) < 0)
261 /* don't bail, keep going with default mode with period wakeups */
262 pa_log_debug("snd_pcm_hw_params_set_period_wakeup() failed: %s", pa_alsa_strerror(ret));
263 else
264 pa_log_info("Trying to disable ALSA period wakeups, using timers only");
265 } else
266 pa_log_info("cannot disable ALSA period wakeups");
267 }
268 #endif
269
270 if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
271 goto finish;
272
273 if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
274 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
275 goto finish;
276 }
277
278 /* We ignore very small sampling rate deviations */
279 if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05)
280 _ss.rate = ss->rate;
281
282 if (require_exact_channel_number) {
283 if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
284 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
285 goto finish;
286 }
287 } else {
288 unsigned int c = _ss.channels;
289
290 if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
291 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
292 goto finish;
293 }
294
295 _ss.channels = c;
296 }
297
298 if (_use_tsched && tsched_size > 0) {
299 _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate);
300 _period_size = _buffer_size;
301 } else {
302 _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate);
303 _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate);
304 }
305
306 if (_buffer_size > 0 || _period_size > 0) {
307 snd_pcm_uframes_t max_frames = 0;
308
309 if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
310 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
311 else
312 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames * PA_MSEC_PER_SEC / _ss.rate));
313
314 /* Some ALSA drivers really don't like if we set the buffer
315 * size first and the number of periods second. (which would
316 * make a lot more sense to me) So, try a few combinations
317 * before we give up. */
318
319 if (_buffer_size > 0 && _period_size > 0) {
320 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
321
322 /* First try: set buffer size first, followed by period size */
323 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
324 set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
325 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
326 pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size);
327 goto success;
328 }
329
330 /* Second try: set period size first, followed by buffer size */
331 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
332 set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
333 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
334 pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size, (unsigned long) _buffer_size);
335 goto success;
336 }
337 }
338
339 if (_buffer_size > 0) {
340 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
341
342 /* Third try: set only buffer size */
343 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
344 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
345 pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size);
346 goto success;
347 }
348 }
349
350 if (_period_size > 0) {
351 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
352
353 /* Fourth try: set only period size */
354 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
355 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
356 pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size);
357 goto success;
358 }
359 }
360 }
361
362 pa_log_debug("Set neither period nor buffer size.");
363
364 /* Last chance, set nothing */
365 if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
366 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
367 goto finish;
368 }
369
370 success:
371
372 if (ss->rate != _ss.rate)
373 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
374
375 if (ss->channels != _ss.channels)
376 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
377
378 if (ss->format != _ss.format)
379 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(_ss.format));
380
381 if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
382 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
383 goto finish;
384 }
385
386 if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
387 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
388 goto finish;
389 }
390
391 if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
392 (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
393 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
394 goto finish;
395 }
396
397 #if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
398 if (_use_tsched) {
399 unsigned int no_wakeup;
400 /* see if period wakeups were disabled */
401 snd_pcm_hw_params_get_period_wakeup(pcm_handle, hwparams, &no_wakeup);
402 if (no_wakeup == 0)
403 pa_log_info("ALSA period wakeups disabled");
404 else
405 pa_log_info("ALSA period wakeups were not disabled");
406 }
407 #endif
408
409 ss->rate = _ss.rate;
410 ss->channels = _ss.channels;
411 ss->format = _ss.format;
412
413 pa_assert(_period_size > 0);
414 pa_assert(_buffer_size > 0);
415
416 if (buffer_size)
417 *buffer_size = _buffer_size;
418
419 if (period_size)
420 *period_size = _period_size;
421
422 if (use_mmap)
423 *use_mmap = _use_mmap;
424
425 if (use_tsched)
426 *use_tsched = _use_tsched;
427
428 ret = 0;
429
430 finish:
431
432 return ret;
433 }
434
435 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, pa_bool_t period_event) {
436 snd_pcm_sw_params_t *swparams;
437 snd_pcm_uframes_t boundary;
438 int err;
439
440 pa_assert(pcm);
441
442 snd_pcm_sw_params_alloca(&swparams);
443
444 if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
445 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err));
446 return err;
447 }
448
449 if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
450 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err));
451 return err;
452 }
453
454 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
455 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err));
456 return err;
457 }
458
459 if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
460 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err));
461 return err;
462 }
463
464 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
465 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err));
466 return err;
467 }
468
469 if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
470 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err));
471 return err;
472 }
473
474 if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
475 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
476 return err;
477 }
478
479 if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
480 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err));
481 return err;
482 }
483
484 return 0;
485 }
486
487 snd_pcm_t *pa_alsa_open_by_device_id_auto(
488 const char *dev_id,
489 char **dev,
490 pa_sample_spec *ss,
491 pa_channel_map* map,
492 int mode,
493 snd_pcm_uframes_t *period_size,
494 snd_pcm_uframes_t *buffer_size,
495 snd_pcm_uframes_t tsched_size,
496 pa_bool_t *use_mmap,
497 pa_bool_t *use_tsched,
498 pa_alsa_profile_set *ps,
499 pa_alsa_mapping **mapping) {
500
501 char *d;
502 snd_pcm_t *pcm_handle;
503 void *state;
504 pa_alsa_mapping *m;
505
506 pa_assert(dev_id);
507 pa_assert(dev);
508 pa_assert(ss);
509 pa_assert(map);
510 pa_assert(ps);
511
512 /* First we try to find a device string with a superset of the
513 * requested channel map. We iterate through our device table from
514 * top to bottom and take the first that matches. If we didn't
515 * find a working device that way, we iterate backwards, and check
516 * all devices that do not provide a superset of the requested
517 * channel map.*/
518
519 PA_HASHMAP_FOREACH(m, ps->mappings, state) {
520 if (!pa_channel_map_superset(&m->channel_map, map))
521 continue;
522
523 pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
524
525 pcm_handle = pa_alsa_open_by_device_id_mapping(
526 dev_id,
527 dev,
528 ss,
529 map,
530 mode,
531 period_size,
532 buffer_size,
533 tsched_size,
534 use_mmap,
535 use_tsched,
536 m);
537
538 if (pcm_handle) {
539 if (mapping)
540 *mapping = m;
541
542 return pcm_handle;
543 }
544 }
545
546 PA_HASHMAP_FOREACH_BACKWARDS(m, ps->mappings, state) {
547 if (pa_channel_map_superset(&m->channel_map, map))
548 continue;
549
550 pa_log_debug("Checking for subset %s (%s)", m->name, m->device_strings[0]);
551
552 pcm_handle = pa_alsa_open_by_device_id_mapping(
553 dev_id,
554 dev,
555 ss,
556 map,
557 mode,
558 period_size,
559 buffer_size,
560 tsched_size,
561 use_mmap,
562 use_tsched,
563 m);
564
565 if (pcm_handle) {
566 if (mapping)
567 *mapping = m;
568
569 return pcm_handle;
570 }
571 }
572
573 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
574 d = pa_sprintf_malloc("hw:%s", dev_id);
575 pa_log_debug("Trying %s as last resort...", d);
576 pcm_handle = pa_alsa_open_by_device_string(
577 d,
578 dev,
579 ss,
580 map,
581 mode,
582 period_size,
583 buffer_size,
584 tsched_size,
585 use_mmap,
586 use_tsched,
587 FALSE);
588 pa_xfree(d);
589
590 if (pcm_handle && mapping)
591 *mapping = NULL;
592
593 return pcm_handle;
594 }
595
596 snd_pcm_t *pa_alsa_open_by_device_id_mapping(
597 const char *dev_id,
598 char **dev,
599 pa_sample_spec *ss,
600 pa_channel_map* map,
601 int mode,
602 snd_pcm_uframes_t *period_size,
603 snd_pcm_uframes_t *buffer_size,
604 snd_pcm_uframes_t tsched_size,
605 pa_bool_t *use_mmap,
606 pa_bool_t *use_tsched,
607 pa_alsa_mapping *m) {
608
609 snd_pcm_t *pcm_handle;
610 pa_sample_spec try_ss;
611 pa_channel_map try_map;
612
613 pa_assert(dev_id);
614 pa_assert(dev);
615 pa_assert(ss);
616 pa_assert(map);
617 pa_assert(m);
618
619 try_ss.channels = m->channel_map.channels;
620 try_ss.rate = ss->rate;
621 try_ss.format = ss->format;
622 try_map = m->channel_map;
623
624 pcm_handle = pa_alsa_open_by_template(
625 m->device_strings,
626 dev_id,
627 dev,
628 &try_ss,
629 &try_map,
630 mode,
631 period_size,
632 buffer_size,
633 tsched_size,
634 use_mmap,
635 use_tsched,
636 TRUE);
637
638 if (!pcm_handle)
639 return NULL;
640
641 *ss = try_ss;
642 *map = try_map;
643 pa_assert(map->channels == ss->channels);
644
645 return pcm_handle;
646 }
647
648 snd_pcm_t *pa_alsa_open_by_device_string(
649 const char *device,
650 char **dev,
651 pa_sample_spec *ss,
652 pa_channel_map* map,
653 int mode,
654 snd_pcm_uframes_t *period_size,
655 snd_pcm_uframes_t *buffer_size,
656 snd_pcm_uframes_t tsched_size,
657 pa_bool_t *use_mmap,
658 pa_bool_t *use_tsched,
659 pa_bool_t require_exact_channel_number) {
660
661 int err;
662 char *d;
663 snd_pcm_t *pcm_handle;
664 pa_bool_t reformat = FALSE;
665
666 pa_assert(device);
667 pa_assert(ss);
668 pa_assert(map);
669
670 d = pa_xstrdup(device);
671
672 for (;;) {
673 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
674
675 if ((err = snd_pcm_open(&pcm_handle, d, mode,
676 SND_PCM_NONBLOCK|
677 SND_PCM_NO_AUTO_RESAMPLE|
678 SND_PCM_NO_AUTO_CHANNELS|
679 (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
680 pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
681 goto fail;
682 }
683
684 pa_log_debug("Managed to open %s", d);
685
686 if ((err = pa_alsa_set_hw_params(
687 pcm_handle,
688 ss,
689 period_size,
690 buffer_size,
691 tsched_size,
692 use_mmap,
693 use_tsched,
694 require_exact_channel_number)) < 0) {
695
696 if (!reformat) {
697 reformat = TRUE;
698
699 snd_pcm_close(pcm_handle);
700 continue;
701 }
702
703 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
704 if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
705 char *t;
706
707 t = pa_sprintf_malloc("plug:%s", d);
708 pa_xfree(d);
709 d = t;
710
711 reformat = FALSE;
712
713 snd_pcm_close(pcm_handle);
714 continue;
715 }
716
717 pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
718 snd_pcm_close(pcm_handle);
719
720 goto fail;
721 }
722
723 if (dev)
724 *dev = d;
725 else
726 pa_xfree(d);
727
728 if (ss->channels != map->channels)
729 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
730
731 return pcm_handle;
732 }
733
734 fail:
735 pa_xfree(d);
736
737 return NULL;
738 }
739
740 snd_pcm_t *pa_alsa_open_by_template(
741 char **template,
742 const char *dev_id,
743 char **dev,
744 pa_sample_spec *ss,
745 pa_channel_map* map,
746 int mode,
747 snd_pcm_uframes_t *period_size,
748 snd_pcm_uframes_t *buffer_size,
749 snd_pcm_uframes_t tsched_size,
750 pa_bool_t *use_mmap,
751 pa_bool_t *use_tsched,
752 pa_bool_t require_exact_channel_number) {
753
754 snd_pcm_t *pcm_handle;
755 char **i;
756
757 for (i = template; *i; i++) {
758 char *d;
759
760 d = pa_replace(*i, "%f", dev_id);
761
762 pcm_handle = pa_alsa_open_by_device_string(
763 d,
764 dev,
765 ss,
766 map,
767 mode,
768 period_size,
769 buffer_size,
770 tsched_size,
771 use_mmap,
772 use_tsched,
773 require_exact_channel_number);
774
775 pa_xfree(d);
776
777 if (pcm_handle)
778 return pcm_handle;
779 }
780
781 return NULL;
782 }
783
784 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
785 int err;
786 snd_output_t *out;
787
788 pa_assert(pcm);
789
790 pa_assert_se(snd_output_buffer_open(&out) == 0);
791
792 if ((err = snd_pcm_dump(pcm, out)) < 0)
793 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
794 else {
795 char *s = NULL;
796 snd_output_buffer_string(out, &s);
797 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
798 }
799
800 pa_assert_se(snd_output_close(out) == 0);
801 }
802
803 void pa_alsa_dump_status(snd_pcm_t *pcm) {
804 int err;
805 snd_output_t *out;
806 snd_pcm_status_t *status;
807 char *s = NULL;
808
809 pa_assert(pcm);
810
811 snd_pcm_status_alloca(&status);
812
813 if ((err = snd_output_buffer_open(&out)) < 0) {
814 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err));
815 return;
816 }
817
818 if ((err = snd_pcm_status(pcm, status)) < 0) {
819 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err));
820 goto finish;
821 }
822
823 if ((err = snd_pcm_status_dump(status, out)) < 0) {
824 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
825 goto finish;
826 }
827
828 snd_output_buffer_string(out, &s);
829 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
830
831 finish:
832
833 snd_output_close(out);
834 }
835
836 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
837 va_list ap;
838 char *alsa_file;
839
840 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
841
842 va_start(ap, fmt);
843
844 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
845
846 va_end(ap);
847
848 pa_xfree(alsa_file);
849 }
850
851 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
852
853 void pa_alsa_refcnt_inc(void) {
854 /* This is not really thread safe, but we do our best */
855
856 if (pa_atomic_inc(&n_error_handler_installed) == 0)
857 snd_lib_error_set_handler(alsa_error_handler);
858 }
859
860 void pa_alsa_refcnt_dec(void) {
861 int r;
862
863 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
864
865 if (r == 1) {
866 snd_lib_error_set_handler(NULL);
867 snd_config_update_free_global();
868 }
869 }
870
871 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
872 const char *d, *k;
873 pa_assert(p);
874
875 if (pa_device_init_description(p))
876 return TRUE;
877
878 if (!(d = pa_proplist_gets(p, "alsa.card_name")))
879 d = pa_proplist_gets(p, "alsa.name");
880
881 if (!d)
882 return FALSE;
883
884 k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
885
886 if (d && k)
887 pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
888 else if (d)
889 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
890
891 return FALSE;
892 }
893
894 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
895 char *cn, *lcn, *dn;
896
897 pa_assert(p);
898 pa_assert(card >= 0);
899
900 pa_proplist_setf(p, "alsa.card", "%i", card);
901
902 if (snd_card_get_name(card, &cn) >= 0) {
903 pa_proplist_sets(p, "alsa.card_name", pa_strip(cn));
904 free(cn);
905 }
906
907 if (snd_card_get_longname(card, &lcn) >= 0) {
908 pa_proplist_sets(p, "alsa.long_card_name", pa_strip(lcn));
909 free(lcn);
910 }
911
912 if ((dn = pa_alsa_get_driver_name(card))) {
913 pa_proplist_sets(p, "alsa.driver_name", dn);
914 pa_xfree(dn);
915 }
916
917 #ifdef HAVE_UDEV
918 pa_udev_get_info(card, p);
919 #endif
920
921 #ifdef HAVE_HAL
922 pa_hal_get_info(c, p, card);
923 #endif
924 }
925
926 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
927
928 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
929 [SND_PCM_CLASS_GENERIC] = "generic",
930 [SND_PCM_CLASS_MULTI] = "multi",
931 [SND_PCM_CLASS_MODEM] = "modem",
932 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
933 };
934 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
935 [SND_PCM_CLASS_GENERIC] = "sound",
936 [SND_PCM_CLASS_MULTI] = NULL,
937 [SND_PCM_CLASS_MODEM] = "modem",
938 [SND_PCM_CLASS_DIGITIZER] = NULL
939 };
940 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
941 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
942 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
943 };
944
945 snd_pcm_class_t class;
946 snd_pcm_subclass_t subclass;
947 const char *n, *id, *sdn;
948 int card;
949
950 pa_assert(p);
951 pa_assert(pcm_info);
952
953 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
954
955 if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
956 if (class_table[class])
957 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
958 if (alsa_class_table[class])
959 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
960 }
961
962 if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
963 if (alsa_subclass_table[subclass])
964 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
965
966 if ((n = snd_pcm_info_get_name(pcm_info))) {
967 char *t = pa_xstrdup(n);
968 pa_proplist_sets(p, "alsa.name", pa_strip(t));
969 pa_xfree(t);
970 }
971
972 if ((id = snd_pcm_info_get_id(pcm_info)))
973 pa_proplist_sets(p, "alsa.id", id);
974
975 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
976 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
977 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
978
979 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
980
981 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
982 pa_alsa_init_proplist_card(c, p, card);
983 }
984
985 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
986 snd_pcm_hw_params_t *hwparams;
987 snd_pcm_info_t *info;
988 int bits, err;
989
990 snd_pcm_hw_params_alloca(&hwparams);
991 snd_pcm_info_alloca(&info);
992
993 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
994 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
995 else {
996
997 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
998 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
999 }
1000
1001 if ((err = snd_pcm_info(pcm, info)) < 0)
1002 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
1003 else
1004 pa_alsa_init_proplist_pcm_info(c, p, info);
1005 }
1006
1007 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
1008 int err;
1009 snd_ctl_t *ctl;
1010 snd_ctl_card_info_t *info;
1011 const char *t;
1012
1013 pa_assert(p);
1014
1015 snd_ctl_card_info_alloca(&info);
1016
1017 if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
1018 pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));
1019 return;
1020 }
1021
1022 if ((err = snd_ctl_card_info(ctl, info)) < 0) {
1023 pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
1024 snd_ctl_close(ctl);
1025 return;
1026 }
1027
1028 if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
1029 pa_proplist_sets(p, "alsa.mixer_name", t);
1030
1031 if ((t = snd_ctl_card_info_get_components(info)) && *t)
1032 pa_proplist_sets(p, "alsa.components", t);
1033
1034 snd_ctl_close(ctl);
1035 }
1036
1037 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1038 snd_pcm_state_t state;
1039 int err;
1040
1041 pa_assert(pcm);
1042
1043 if (revents & POLLERR)
1044 pa_log_debug("Got POLLERR from ALSA");
1045 if (revents & POLLNVAL)
1046 pa_log_warn("Got POLLNVAL from ALSA");
1047 if (revents & POLLHUP)
1048 pa_log_warn("Got POLLHUP from ALSA");
1049 if (revents & POLLPRI)
1050 pa_log_warn("Got POLLPRI from ALSA");
1051 if (revents & POLLIN)
1052 pa_log_debug("Got POLLIN from ALSA");
1053 if (revents & POLLOUT)
1054 pa_log_debug("Got POLLOUT from ALSA");
1055
1056 state = snd_pcm_state(pcm);
1057 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1058
1059 /* Try to recover from this error */
1060
1061 switch (state) {
1062
1063 case SND_PCM_STATE_XRUN:
1064 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1065 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1066 return -1;
1067 }
1068 break;
1069
1070 case SND_PCM_STATE_SUSPENDED:
1071 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
1072 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
1073 return -1;
1074 }
1075 break;
1076
1077 default:
1078
1079 snd_pcm_drop(pcm);
1080
1081 if ((err = snd_pcm_prepare(pcm)) < 0) {
1082 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
1083 return -1;
1084 }
1085 break;
1086 }
1087
1088 return 0;
1089 }
1090
1091 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1092 int n, err;
1093 struct pollfd *pollfd;
1094 pa_rtpoll_item *item;
1095
1096 pa_assert(pcm);
1097
1098 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1099 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1100 return NULL;
1101 }
1102
1103 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1104 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1105
1106 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1107 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1108 pa_rtpoll_item_free(item);
1109 return NULL;
1110 }
1111
1112 return item;
1113 }
1114
1115 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1116 snd_pcm_sframes_t n;
1117 size_t k;
1118
1119 pa_assert(pcm);
1120 pa_assert(hwbuf_size > 0);
1121 pa_assert(ss);
1122
1123 /* Some ALSA driver expose weird bugs, let's inform the user about
1124 * what is going on */
1125
1126 n = snd_pcm_avail(pcm);
1127
1128 if (n <= 0)
1129 return n;
1130
1131 k = (size_t) n * pa_frame_size(ss);
1132
1133 if (PA_UNLIKELY(k >= hwbuf_size * 5 ||
1134 k >= pa_bytes_per_second(ss)*10)) {
1135
1136 PA_ONCE_BEGIN {
1137 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1138 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1139 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1140 (unsigned long) k,
1141 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1142 pa_strnull(dn));
1143 pa_xfree(dn);
1144 pa_alsa_dump(PA_LOG_ERROR, pcm);
1145 } PA_ONCE_END;
1146
1147 /* Mhmm, let's try not to fail completely */
1148 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1149 }
1150
1151 return n;
1152 }
1153
1154 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, pa_bool_t capture) {
1155 ssize_t k;
1156 size_t abs_k;
1157 int r;
1158 snd_pcm_sframes_t avail = 0;
1159
1160 pa_assert(pcm);
1161 pa_assert(delay);
1162 pa_assert(hwbuf_size > 0);
1163 pa_assert(ss);
1164
1165 /* Some ALSA driver expose weird bugs, let's inform the user about
1166 * what is going on. We're going to get both the avail and delay values so
1167 * that we can compare and check them for capture */
1168
1169 if ((r = snd_pcm_avail_delay(pcm, &avail, delay)) < 0)
1170 return r;
1171
1172 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1173
1174 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1175
1176 if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
1177 abs_k >= pa_bytes_per_second(ss)*10)) {
1178
1179 PA_ONCE_BEGIN {
1180 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1181 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1182 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1183 (signed long) k,
1184 k < 0 ? "-" : "",
1185 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1186 pa_strnull(dn));
1187 pa_xfree(dn);
1188 pa_alsa_dump(PA_LOG_ERROR, pcm);
1189 } PA_ONCE_END;
1190
1191 /* Mhmm, let's try not to fail completely */
1192 if (k < 0)
1193 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1194 else
1195 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1196 }
1197
1198 if (capture) {
1199 abs_k = (size_t) avail * pa_frame_size(ss);
1200
1201 if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
1202 abs_k >= pa_bytes_per_second(ss)*10)) {
1203
1204 PA_ONCE_BEGIN {
1205 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1206 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1207 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1208 (unsigned long) k,
1209 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1210 pa_strnull(dn));
1211 pa_xfree(dn);
1212 pa_alsa_dump(PA_LOG_ERROR, pcm);
1213 } PA_ONCE_END;
1214
1215 /* Mhmm, let's try not to fail completely */
1216 avail = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1217 }
1218
1219 if (PA_UNLIKELY(*delay < avail)) {
1220 PA_ONCE_BEGIN {
1221 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1222 pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
1223 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1224 (unsigned long) *delay,
1225 (unsigned long) avail,
1226 pa_strnull(dn));
1227 pa_xfree(dn);
1228 pa_alsa_dump(PA_LOG_ERROR, pcm);
1229 } PA_ONCE_END;
1230
1231 /* try to fixup */
1232 *delay = avail;
1233 }
1234 }
1235
1236 return 0;
1237 }
1238
1239 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) {
1240 int r;
1241 snd_pcm_uframes_t before;
1242 size_t k;
1243
1244 pa_assert(pcm);
1245 pa_assert(areas);
1246 pa_assert(offset);
1247 pa_assert(frames);
1248 pa_assert(hwbuf_size > 0);
1249 pa_assert(ss);
1250
1251 before = *frames;
1252
1253 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1254
1255 if (r < 0)
1256 return r;
1257
1258 k = (size_t) *frames * pa_frame_size(ss);
1259
1260 if (PA_UNLIKELY(*frames > before ||
1261 k >= hwbuf_size * 3 ||
1262 k >= pa_bytes_per_second(ss)*10))
1263 PA_ONCE_BEGIN {
1264 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1265 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1266 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1267 (unsigned long) k,
1268 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1269 pa_strnull(dn));
1270 pa_xfree(dn);
1271 pa_alsa_dump(PA_LOG_ERROR, pcm);
1272 } PA_ONCE_END;
1273
1274 return r;
1275 }
1276
1277 char *pa_alsa_get_driver_name(int card) {
1278 char *t, *m, *n;
1279
1280 pa_assert(card >= 0);
1281
1282 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1283 m = pa_readlink(t);
1284 pa_xfree(t);
1285
1286 if (!m)
1287 return NULL;
1288
1289 n = pa_xstrdup(pa_path_get_filename(m));
1290 pa_xfree(m);
1291
1292 return n;
1293 }
1294
1295 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1296 int card;
1297 snd_pcm_info_t* info;
1298 snd_pcm_info_alloca(&info);
1299
1300 pa_assert(pcm);
1301
1302 if (snd_pcm_info(pcm, info) < 0)
1303 return NULL;
1304
1305 if ((card = snd_pcm_info_get_card(info)) < 0)
1306 return NULL;
1307
1308 return pa_alsa_get_driver_name(card);
1309 }
1310
1311 char *pa_alsa_get_reserve_name(const char *device) {
1312 const char *t;
1313 int i;
1314
1315 pa_assert(device);
1316
1317 if ((t = strchr(device, ':')))
1318 device = t+1;
1319
1320 if ((i = snd_card_get_index(device)) < 0) {
1321 int32_t k;
1322
1323 if (pa_atoi(device, &k) < 0)
1324 return NULL;
1325
1326 i = (int) k;
1327 }
1328
1329 return pa_sprintf_malloc("Audio%i", i);
1330 }
1331
1332 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1333 snd_pcm_info_t* info;
1334 snd_pcm_info_alloca(&info);
1335
1336 pa_assert(pcm);
1337
1338 if (snd_pcm_info(pcm, info) < 0)
1339 return FALSE;
1340
1341 return snd_pcm_info_get_card(info) >= 0;
1342 }
1343
1344 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1345 snd_pcm_info_t* info;
1346 snd_pcm_info_alloca(&info);
1347
1348 pa_assert(pcm);
1349
1350 if (snd_pcm_info(pcm, info) < 0)
1351 return FALSE;
1352
1353 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1354 }
1355
1356 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1357
1358 const char* pa_alsa_strerror(int errnum) {
1359 const char *original = NULL;
1360 char *translated, *t;
1361 char errbuf[128];
1362
1363 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1364 pa_xfree(t);
1365
1366 original = snd_strerror(errnum);
1367
1368 if (!original) {
1369 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1370 original = errbuf;
1371 }
1372
1373 if (!(translated = pa_locale_to_utf8(original))) {
1374 pa_log_warn("Unable to convert error string to locale, filtering.");
1375 translated = pa_utf8_filter(original);
1376 }
1377
1378 PA_STATIC_TLS_SET(cstrerror, translated);
1379
1380 return translated;
1381 }
1382
1383 pa_bool_t pa_alsa_may_tsched(pa_bool_t want) {
1384
1385 if (!want)
1386 return FALSE;
1387
1388 if (!pa_rtclock_hrtimer()) {
1389 /* We cannot depend on being woken up in time when the timers
1390 are inaccurate, so let's fallback to classic IO based playback
1391 then. */
1392 pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1393 return FALSE; }
1394
1395 if (pa_running_in_vm()) {
1396 /* We cannot depend on being woken up when we ask for in a VM,
1397 * so let's fallback to classic IO based playback then. */
1398 pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
1399 return FALSE;
1400 }
1401
1402 return TRUE;
1403 }