]> code.delx.au - pulseaudio/blob - src/modules/alsa/alsa-util.c
Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[pulseaudio] / src / modules / alsa / alsa-util.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2009 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.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 ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
255 goto finish;
256
257 if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
258 pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
259 goto finish;
260 }
261
262 /* We ignore very small sampling rate deviations */
263 if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05)
264 _ss.rate = ss->rate;
265
266 if (require_exact_channel_number) {
267 if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
268 pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
269 goto finish;
270 }
271 } else {
272 unsigned int c = _ss.channels;
273
274 if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
275 pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
276 goto finish;
277 }
278
279 _ss.channels = c;
280 }
281
282 if (_use_tsched && tsched_size > 0) {
283 _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate);
284 _period_size = _buffer_size;
285 } else {
286 _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate);
287 _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate);
288 }
289
290 if (_buffer_size > 0 || _period_size > 0) {
291 snd_pcm_uframes_t max_frames = 0;
292
293 if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
294 pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
295 else
296 pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames * PA_MSEC_PER_SEC / _ss.rate));
297
298 /* Some ALSA drivers really don't like if we set the buffer
299 * size first and the number of periods second. (which would
300 * make a lot more sense to me) So, try a few combinations
301 * before we give up. */
302
303 if (_buffer_size > 0 && _period_size > 0) {
304 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
305
306 /* First try: set buffer size first, followed by period size */
307 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
308 set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
309 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
310 pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size);
311 goto success;
312 }
313
314 /* Second try: set period size first, followed by buffer size */
315 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
316 set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
317 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
318 pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size, (unsigned long) _buffer_size);
319 goto success;
320 }
321 }
322
323 if (_buffer_size > 0) {
324 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
325
326 /* Third try: set only buffer size */
327 if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
328 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
329 pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size);
330 goto success;
331 }
332 }
333
334 if (_period_size > 0) {
335 snd_pcm_hw_params_copy(hwparams_copy, hwparams);
336
337 /* Fourth try: set only period size */
338 if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
339 snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
340 pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size);
341 goto success;
342 }
343 }
344 }
345
346 pa_log_debug("Set neither period nor buffer size.");
347
348 /* Last chance, set nothing */
349 if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
350 pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
351 goto finish;
352 }
353
354 success:
355
356 if (ss->rate != _ss.rate)
357 pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
358
359 if (ss->channels != _ss.channels)
360 pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
361
362 if (ss->format != _ss.format)
363 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));
364
365 if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
366 pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
367 goto finish;
368 }
369
370 if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
371 pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
372 goto finish;
373 }
374
375 if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
376 (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
377 pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
378 goto finish;
379 }
380
381 ss->rate = _ss.rate;
382 ss->channels = _ss.channels;
383 ss->format = _ss.format;
384
385 pa_assert(_period_size > 0);
386 pa_assert(_buffer_size > 0);
387
388 if (buffer_size)
389 *buffer_size = _buffer_size;
390
391 if (period_size)
392 *period_size = _period_size;
393
394 if (use_mmap)
395 *use_mmap = _use_mmap;
396
397 if (use_tsched)
398 *use_tsched = _use_tsched;
399
400 ret = 0;
401
402 snd_pcm_nonblock(pcm_handle, 1);
403
404 finish:
405
406 return ret;
407 }
408
409 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, pa_bool_t period_event) {
410 snd_pcm_sw_params_t *swparams;
411 snd_pcm_uframes_t boundary;
412 int err;
413
414 pa_assert(pcm);
415
416 snd_pcm_sw_params_alloca(&swparams);
417
418 if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
419 pa_log_warn("Unable to determine current swparams: %s\n", pa_alsa_strerror(err));
420 return err;
421 }
422
423 if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
424 pa_log_warn("Unable to disable period event: %s\n", pa_alsa_strerror(err));
425 return err;
426 }
427
428 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
429 pa_log_warn("Unable to enable time stamping: %s\n", pa_alsa_strerror(err));
430 return err;
431 }
432
433 if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
434 pa_log_warn("Unable to get boundary: %s\n", pa_alsa_strerror(err));
435 return err;
436 }
437
438 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
439 pa_log_warn("Unable to set stop threshold: %s\n", pa_alsa_strerror(err));
440 return err;
441 }
442
443 if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
444 pa_log_warn("Unable to set start threshold: %s\n", pa_alsa_strerror(err));
445 return err;
446 }
447
448 if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
449 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", pa_alsa_strerror(err));
450 return err;
451 }
452
453 if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
454 pa_log_warn("Unable to set sw params: %s\n", pa_alsa_strerror(err));
455 return err;
456 }
457
458 return 0;
459 }
460
461 snd_pcm_t *pa_alsa_open_by_device_id_auto(
462 const char *dev_id,
463 char **dev,
464 pa_sample_spec *ss,
465 pa_channel_map* map,
466 int mode,
467 snd_pcm_uframes_t *period_size,
468 snd_pcm_uframes_t *buffer_size,
469 snd_pcm_uframes_t tsched_size,
470 pa_bool_t *use_mmap,
471 pa_bool_t *use_tsched,
472 pa_alsa_profile_set *ps,
473 pa_alsa_mapping **mapping) {
474
475 char *d;
476 snd_pcm_t *pcm_handle;
477 void *state;
478 pa_alsa_mapping *m;
479
480 pa_assert(dev_id);
481 pa_assert(dev);
482 pa_assert(ss);
483 pa_assert(map);
484 pa_assert(ps);
485
486 /* First we try to find a device string with a superset of the
487 * requested channel map. We iterate through our device table from
488 * top to bottom and take the first that matches. If we didn't
489 * find a working device that way, we iterate backwards, and check
490 * all devices that do not provide a superset of the requested
491 * channel map.*/
492
493 PA_HASHMAP_FOREACH(m, ps->mappings, state) {
494 if (!pa_channel_map_superset(&m->channel_map, map))
495 continue;
496
497 pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
498
499 pcm_handle = pa_alsa_open_by_device_id_mapping(
500 dev_id,
501 dev,
502 ss,
503 map,
504 mode,
505 period_size,
506 buffer_size,
507 tsched_size,
508 use_mmap,
509 use_tsched,
510 m);
511
512 if (pcm_handle) {
513 if (mapping)
514 *mapping = m;
515
516 return pcm_handle;
517 }
518 }
519
520 PA_HASHMAP_FOREACH_BACKWARDS(m, ps->mappings, state) {
521 if (pa_channel_map_superset(&m->channel_map, map))
522 continue;
523
524 pa_log_debug("Checking for subset %s (%s)", m->name, m->device_strings[0]);
525
526 pcm_handle = pa_alsa_open_by_device_id_mapping(
527 dev_id,
528 dev,
529 ss,
530 map,
531 mode,
532 period_size,
533 buffer_size,
534 tsched_size,
535 use_mmap,
536 use_tsched,
537 m);
538
539 if (pcm_handle) {
540 if (mapping)
541 *mapping = m;
542
543 return pcm_handle;
544 }
545 }
546
547 /* OK, we didn't find any good device, so let's try the raw hw: stuff */
548 d = pa_sprintf_malloc("hw:%s", dev_id);
549 pa_log_debug("Trying %s as last resort...", d);
550 pcm_handle = pa_alsa_open_by_device_string(
551 d,
552 dev,
553 ss,
554 map,
555 mode,
556 period_size,
557 buffer_size,
558 tsched_size,
559 use_mmap,
560 use_tsched,
561 FALSE);
562 pa_xfree(d);
563
564 if (pcm_handle && mapping)
565 *mapping = NULL;
566
567 return pcm_handle;
568 }
569
570 snd_pcm_t *pa_alsa_open_by_device_id_mapping(
571 const char *dev_id,
572 char **dev,
573 pa_sample_spec *ss,
574 pa_channel_map* map,
575 int mode,
576 snd_pcm_uframes_t *period_size,
577 snd_pcm_uframes_t *buffer_size,
578 snd_pcm_uframes_t tsched_size,
579 pa_bool_t *use_mmap,
580 pa_bool_t *use_tsched,
581 pa_alsa_mapping *m) {
582
583 snd_pcm_t *pcm_handle;
584 pa_sample_spec try_ss;
585 pa_channel_map try_map;
586
587 pa_assert(dev_id);
588 pa_assert(dev);
589 pa_assert(ss);
590 pa_assert(map);
591 pa_assert(m);
592
593 try_ss.channels = m->channel_map.channels;
594 try_ss.rate = ss->rate;
595 try_ss.format = ss->format;
596 try_map = m->channel_map;
597
598 pcm_handle = pa_alsa_open_by_template(
599 m->device_strings,
600 dev_id,
601 dev,
602 &try_ss,
603 &try_map,
604 mode,
605 period_size,
606 buffer_size,
607 tsched_size,
608 use_mmap,
609 use_tsched,
610 TRUE);
611
612 if (!pcm_handle)
613 return NULL;
614
615 *ss = try_ss;
616 *map = try_map;
617 pa_assert(map->channels == ss->channels);
618
619 return pcm_handle;
620 }
621
622 snd_pcm_t *pa_alsa_open_by_device_string(
623 const char *device,
624 char **dev,
625 pa_sample_spec *ss,
626 pa_channel_map* map,
627 int mode,
628 snd_pcm_uframes_t *period_size,
629 snd_pcm_uframes_t *buffer_size,
630 snd_pcm_uframes_t tsched_size,
631 pa_bool_t *use_mmap,
632 pa_bool_t *use_tsched,
633 pa_bool_t require_exact_channel_number) {
634
635 int err;
636 char *d;
637 snd_pcm_t *pcm_handle;
638 pa_bool_t reformat = FALSE;
639
640 pa_assert(device);
641 pa_assert(ss);
642 pa_assert(map);
643
644 d = pa_xstrdup(device);
645
646 for (;;) {
647 pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with");
648
649 if ((err = snd_pcm_open(&pcm_handle, d, mode,
650 SND_PCM_NONBLOCK|
651 SND_PCM_NO_AUTO_RESAMPLE|
652 SND_PCM_NO_AUTO_CHANNELS|
653 (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) {
654 pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err));
655 goto fail;
656 }
657
658 pa_log_debug("Managed to open %s", d);
659
660 if ((err = pa_alsa_set_hw_params(
661 pcm_handle,
662 ss,
663 period_size,
664 buffer_size,
665 tsched_size,
666 use_mmap,
667 use_tsched,
668 require_exact_channel_number)) < 0) {
669
670 if (!reformat) {
671 reformat = TRUE;
672
673 snd_pcm_close(pcm_handle);
674 continue;
675 }
676
677 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
678 if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) {
679 char *t;
680
681 t = pa_sprintf_malloc("plug:%s", d);
682 pa_xfree(d);
683 d = t;
684
685 reformat = FALSE;
686
687 snd_pcm_close(pcm_handle);
688 continue;
689 }
690
691 pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err));
692 snd_pcm_close(pcm_handle);
693
694 goto fail;
695 }
696
697 if (dev)
698 *dev = d;
699 else
700 pa_xfree(d);
701
702 if (ss->channels != map->channels)
703 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
704
705 return pcm_handle;
706 }
707
708 fail:
709 pa_xfree(d);
710
711 return NULL;
712 }
713
714 snd_pcm_t *pa_alsa_open_by_template(
715 char **template,
716 const char *dev_id,
717 char **dev,
718 pa_sample_spec *ss,
719 pa_channel_map* map,
720 int mode,
721 snd_pcm_uframes_t *period_size,
722 snd_pcm_uframes_t *buffer_size,
723 snd_pcm_uframes_t tsched_size,
724 pa_bool_t *use_mmap,
725 pa_bool_t *use_tsched,
726 pa_bool_t require_exact_channel_number) {
727
728 snd_pcm_t *pcm_handle;
729 char **i;
730
731 for (i = template; *i; i++) {
732 char *d;
733
734 d = pa_replace(*i, "%f", dev_id);
735
736 pcm_handle = pa_alsa_open_by_device_string(
737 d,
738 dev,
739 ss,
740 map,
741 mode,
742 period_size,
743 buffer_size,
744 tsched_size,
745 use_mmap,
746 use_tsched,
747 require_exact_channel_number);
748
749 pa_xfree(d);
750
751 if (pcm_handle)
752 return pcm_handle;
753 }
754
755 return NULL;
756 }
757
758 void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm) {
759 int err;
760 snd_output_t *out;
761
762 pa_assert(pcm);
763
764 pa_assert_se(snd_output_buffer_open(&out) == 0);
765
766 if ((err = snd_pcm_dump(pcm, out)) < 0)
767 pa_logl(level, "snd_pcm_dump(): %s", pa_alsa_strerror(err));
768 else {
769 char *s = NULL;
770 snd_output_buffer_string(out, &s);
771 pa_logl(level, "snd_pcm_dump():\n%s", pa_strnull(s));
772 }
773
774 pa_assert_se(snd_output_close(out) == 0);
775 }
776
777 void pa_alsa_dump_status(snd_pcm_t *pcm) {
778 int err;
779 snd_output_t *out;
780 snd_pcm_status_t *status;
781 char *s = NULL;
782
783 pa_assert(pcm);
784
785 snd_pcm_status_alloca(&status);
786
787 if ((err = snd_output_buffer_open(&out)) < 0) {
788 pa_log_debug("snd_output_buffer_open() failed: %s", pa_cstrerror(err));
789 return;
790 }
791
792 if ((err = snd_pcm_status(pcm, status)) < 0) {
793 pa_log_debug("snd_pcm_status() failed: %s", pa_cstrerror(err));
794 goto finish;
795 }
796
797 if ((err = snd_pcm_status_dump(status, out)) < 0) {
798 pa_log_debug("snd_pcm_dump(): %s", pa_alsa_strerror(err));
799 goto finish;
800 }
801
802 snd_output_buffer_string(out, &s);
803 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s));
804
805 finish:
806
807 snd_output_close(out);
808 }
809
810 static void alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt,...) {
811 va_list ap;
812 char *alsa_file;
813
814 alsa_file = pa_sprintf_malloc("(alsa-lib)%s", file);
815
816 va_start(ap, fmt);
817
818 pa_log_levelv_meta(PA_LOG_INFO, alsa_file, line, function, fmt, ap);
819
820 va_end(ap);
821
822 pa_xfree(alsa_file);
823 }
824
825 static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
826
827 void pa_alsa_refcnt_inc(void) {
828 /* This is not really thread safe, but we do our best */
829
830 if (pa_atomic_inc(&n_error_handler_installed) == 0)
831 snd_lib_error_set_handler(alsa_error_handler);
832 }
833
834 void pa_alsa_refcnt_dec(void) {
835 int r;
836
837 pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
838
839 if (r == 1) {
840 snd_lib_error_set_handler(NULL);
841 snd_config_update_free_global();
842 }
843 }
844
845 pa_bool_t pa_alsa_init_description(pa_proplist *p) {
846 const char *d, *k;
847 pa_assert(p);
848
849 if (pa_device_init_description(p))
850 return TRUE;
851
852 if (!(d = pa_proplist_gets(p, "alsa.card_name")))
853 d = pa_proplist_gets(p, "alsa.name");
854
855 if (!d)
856 return FALSE;
857
858 k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
859
860 if (d && k)
861 pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
862 else if (d)
863 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
864
865 return FALSE;
866 }
867
868 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
869 char *cn, *lcn, *dn;
870
871 pa_assert(p);
872 pa_assert(card >= 0);
873
874 pa_proplist_setf(p, "alsa.card", "%i", card);
875
876 if (snd_card_get_name(card, &cn) >= 0) {
877 pa_proplist_sets(p, "alsa.card_name", cn);
878 free(cn);
879 }
880
881 if (snd_card_get_longname(card, &lcn) >= 0) {
882 pa_proplist_sets(p, "alsa.long_card_name", lcn);
883 free(lcn);
884 }
885
886 if ((dn = pa_alsa_get_driver_name(card))) {
887 pa_proplist_sets(p, "alsa.driver_name", dn);
888 pa_xfree(dn);
889 }
890
891 #ifdef HAVE_UDEV
892 pa_udev_get_info(card, p);
893 #endif
894
895 #ifdef HAVE_HAL
896 pa_hal_get_info(c, p, card);
897 #endif
898 }
899
900 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
901
902 static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
903 [SND_PCM_CLASS_GENERIC] = "generic",
904 [SND_PCM_CLASS_MULTI] = "multi",
905 [SND_PCM_CLASS_MODEM] = "modem",
906 [SND_PCM_CLASS_DIGITIZER] = "digitizer"
907 };
908 static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
909 [SND_PCM_CLASS_GENERIC] = "sound",
910 [SND_PCM_CLASS_MULTI] = NULL,
911 [SND_PCM_CLASS_MODEM] = "modem",
912 [SND_PCM_CLASS_DIGITIZER] = NULL
913 };
914 static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
915 [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
916 [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
917 };
918
919 snd_pcm_class_t class;
920 snd_pcm_subclass_t subclass;
921 const char *n, *id, *sdn;
922 int card;
923
924 pa_assert(p);
925 pa_assert(pcm_info);
926
927 pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
928
929 if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
930 if (class_table[class])
931 pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
932 if (alsa_class_table[class])
933 pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
934 }
935
936 if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
937 if (alsa_subclass_table[subclass])
938 pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
939
940 if ((n = snd_pcm_info_get_name(pcm_info)))
941 pa_proplist_sets(p, "alsa.name", n);
942
943 if ((id = snd_pcm_info_get_id(pcm_info)))
944 pa_proplist_sets(p, "alsa.id", id);
945
946 pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
947 if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
948 pa_proplist_sets(p, "alsa.subdevice_name", sdn);
949
950 pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
951
952 if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
953 pa_alsa_init_proplist_card(c, p, card);
954 }
955
956 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
957 snd_pcm_hw_params_t *hwparams;
958 snd_pcm_info_t *info;
959 int bits, err;
960
961 snd_pcm_hw_params_alloca(&hwparams);
962 snd_pcm_info_alloca(&info);
963
964 if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
965 pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
966 else {
967
968 if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
969 pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
970 }
971
972 if ((err = snd_pcm_info(pcm, info)) < 0)
973 pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
974 else
975 pa_alsa_init_proplist_pcm_info(c, p, info);
976 }
977
978 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
979 int err;
980 snd_ctl_t *ctl;
981 snd_ctl_card_info_t *info;
982 const char *t;
983
984 pa_assert(p);
985
986 snd_ctl_card_info_alloca(&info);
987
988 if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
989 pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));
990 return;
991 }
992
993 if ((err = snd_ctl_card_info(ctl, info)) < 0) {
994 pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
995 snd_ctl_close(ctl);
996 return;
997 }
998
999 if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
1000 pa_proplist_sets(p, "alsa.mixer_name", t);
1001
1002 if ((t = snd_ctl_card_info_get_components(info)) && *t)
1003 pa_proplist_sets(p, "alsa.components", t);
1004
1005 snd_ctl_close(ctl);
1006 }
1007
1008 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
1009 snd_pcm_state_t state;
1010 int err;
1011
1012 pa_assert(pcm);
1013
1014 if (revents & POLLERR)
1015 pa_log_debug("Got POLLERR from ALSA");
1016 if (revents & POLLNVAL)
1017 pa_log_warn("Got POLLNVAL from ALSA");
1018 if (revents & POLLHUP)
1019 pa_log_warn("Got POLLHUP from ALSA");
1020 if (revents & POLLPRI)
1021 pa_log_warn("Got POLLPRI from ALSA");
1022 if (revents & POLLIN)
1023 pa_log_debug("Got POLLIN from ALSA");
1024 if (revents & POLLOUT)
1025 pa_log_debug("Got POLLOUT from ALSA");
1026
1027 state = snd_pcm_state(pcm);
1028 pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
1029
1030 /* Try to recover from this error */
1031
1032 switch (state) {
1033
1034 case SND_PCM_STATE_XRUN:
1035 if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
1036 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
1037 return -1;
1038 }
1039 break;
1040
1041 case SND_PCM_STATE_SUSPENDED:
1042 if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
1043 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
1044 return -1;
1045 }
1046 break;
1047
1048 default:
1049
1050 snd_pcm_drop(pcm);
1051
1052 if ((err = snd_pcm_prepare(pcm)) < 0) {
1053 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
1054 return -1;
1055 }
1056 break;
1057 }
1058
1059 return 0;
1060 }
1061
1062 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
1063 int n, err;
1064 struct pollfd *pollfd;
1065 pa_rtpoll_item *item;
1066
1067 pa_assert(pcm);
1068
1069 if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
1070 pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
1071 return NULL;
1072 }
1073
1074 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
1075 pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
1076
1077 if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
1078 pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
1079 pa_rtpoll_item_free(item);
1080 return NULL;
1081 }
1082
1083 return item;
1084 }
1085
1086 snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
1087 snd_pcm_sframes_t n;
1088 size_t k;
1089
1090 pa_assert(pcm);
1091 pa_assert(hwbuf_size > 0);
1092 pa_assert(ss);
1093
1094 /* Some ALSA driver expose weird bugs, let's inform the user about
1095 * what is going on */
1096
1097 n = snd_pcm_avail(pcm);
1098
1099 if (n <= 0)
1100 return n;
1101
1102 k = (size_t) n * pa_frame_size(ss);
1103
1104 if (k >= hwbuf_size * 5 ||
1105 k >= pa_bytes_per_second(ss)*10) {
1106
1107 PA_ONCE_BEGIN {
1108 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1109 pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1110 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1111 (unsigned long) k,
1112 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1113 pa_strnull(dn));
1114 pa_xfree(dn);
1115 pa_alsa_dump(PA_LOG_ERROR, pcm);
1116 } PA_ONCE_END;
1117
1118 /* Mhmm, let's try not to fail completely */
1119 n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1120 }
1121
1122 return n;
1123 }
1124
1125 int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) {
1126 ssize_t k;
1127 size_t abs_k;
1128 int r;
1129
1130 pa_assert(pcm);
1131 pa_assert(delay);
1132 pa_assert(hwbuf_size > 0);
1133 pa_assert(ss);
1134
1135 /* Some ALSA driver expose weird bugs, let's inform the user about
1136 * what is going on */
1137
1138 if ((r = snd_pcm_delay(pcm, delay)) < 0)
1139 return r;
1140
1141 k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
1142
1143 abs_k = k >= 0 ? (size_t) k : (size_t) -k;
1144
1145 if (abs_k >= hwbuf_size * 5 ||
1146 abs_k >= pa_bytes_per_second(ss)*10) {
1147
1148 PA_ONCE_BEGIN {
1149 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1150 pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
1151 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1152 (signed long) k,
1153 k < 0 ? "-" : "",
1154 (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
1155 pa_strnull(dn));
1156 pa_xfree(dn);
1157 pa_alsa_dump(PA_LOG_ERROR, pcm);
1158 } PA_ONCE_END;
1159
1160 /* Mhmm, let's try not to fail completely */
1161 if (k < 0)
1162 *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1163 else
1164 *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
1165 }
1166
1167 return 0;
1168 }
1169
1170 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) {
1171 int r;
1172 snd_pcm_uframes_t before;
1173 size_t k;
1174
1175 pa_assert(pcm);
1176 pa_assert(areas);
1177 pa_assert(offset);
1178 pa_assert(frames);
1179 pa_assert(hwbuf_size > 0);
1180 pa_assert(ss);
1181
1182 before = *frames;
1183
1184 r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
1185
1186 if (r < 0)
1187 return r;
1188
1189 k = (size_t) *frames * pa_frame_size(ss);
1190
1191 if (*frames > before ||
1192 k >= hwbuf_size * 3 ||
1193 k >= pa_bytes_per_second(ss)*10)
1194
1195 PA_ONCE_BEGIN {
1196 char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
1197 pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
1198 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
1199 (unsigned long) k,
1200 (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
1201 pa_strnull(dn));
1202 pa_xfree(dn);
1203 pa_alsa_dump(PA_LOG_ERROR, pcm);
1204 } PA_ONCE_END;
1205
1206 return r;
1207 }
1208
1209 char *pa_alsa_get_driver_name(int card) {
1210 char *t, *m, *n;
1211
1212 pa_assert(card >= 0);
1213
1214 t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
1215 m = pa_readlink(t);
1216 pa_xfree(t);
1217
1218 if (!m)
1219 return NULL;
1220
1221 n = pa_xstrdup(pa_path_get_filename(m));
1222 pa_xfree(m);
1223
1224 return n;
1225 }
1226
1227 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
1228 int card;
1229 snd_pcm_info_t* info;
1230 snd_pcm_info_alloca(&info);
1231
1232 pa_assert(pcm);
1233
1234 if (snd_pcm_info(pcm, info) < 0)
1235 return NULL;
1236
1237 if ((card = snd_pcm_info_get_card(info)) < 0)
1238 return NULL;
1239
1240 return pa_alsa_get_driver_name(card);
1241 }
1242
1243 char *pa_alsa_get_reserve_name(const char *device) {
1244 const char *t;
1245 int i;
1246
1247 pa_assert(device);
1248
1249 if ((t = strchr(device, ':')))
1250 device = t+1;
1251
1252 if ((i = snd_card_get_index(device)) < 0) {
1253 int32_t k;
1254
1255 if (pa_atoi(device, &k) < 0)
1256 return NULL;
1257
1258 i = (int) k;
1259 }
1260
1261 return pa_sprintf_malloc("Audio%i", i);
1262 }
1263
1264 pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
1265 snd_pcm_info_t* info;
1266 snd_pcm_info_alloca(&info);
1267
1268 pa_assert(pcm);
1269
1270 if (snd_pcm_info(pcm, info) < 0)
1271 return FALSE;
1272
1273 return snd_pcm_info_get_card(info) >= 0;
1274 }
1275
1276 pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
1277 snd_pcm_info_t* info;
1278 snd_pcm_info_alloca(&info);
1279
1280 pa_assert(pcm);
1281
1282 if (snd_pcm_info(pcm, info) < 0)
1283 return FALSE;
1284
1285 return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
1286 }
1287
1288 PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
1289
1290 const char* pa_alsa_strerror(int errnum) {
1291 const char *original = NULL;
1292 char *translated, *t;
1293 char errbuf[128];
1294
1295 if ((t = PA_STATIC_TLS_GET(cstrerror)))
1296 pa_xfree(t);
1297
1298 original = snd_strerror(errnum);
1299
1300 if (!original) {
1301 pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
1302 original = errbuf;
1303 }
1304
1305 if (!(translated = pa_locale_to_utf8(original))) {
1306 pa_log_warn("Unable to convert error string to locale, filtering.");
1307 translated = pa_utf8_filter(original);
1308 }
1309
1310 PA_STATIC_TLS_SET(cstrerror, translated);
1311
1312 return translated;
1313 }
1314
1315 pa_bool_t pa_alsa_may_tsched(pa_bool_t want) {
1316
1317 if (!want)
1318 return FALSE;
1319
1320 if (!pa_rtclock_hrtimer()) {
1321 /* We cannot depend on being woken up in time when the timers
1322 are inaccurate, so let's fallback to classic IO based playback
1323 then. */
1324 pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
1325 return FALSE; }
1326
1327 if (pa_running_in_vm()) {
1328 /* We cannot depend on being woken up when we ask for in a VM,
1329 * so let's fallback to classic IO based playback then. */
1330 pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
1331 return FALSE;
1332 }
1333
1334
1335 return TRUE;
1336 }