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