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