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