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