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