~binli/ubuntu/vivid/pulseaudio/load-extcon-module

« back to all changes in this revision

Viewing changes to src/modules/alsa/alsa-util.c

  • Committer: Bin Li
  • Date: 2016-01-23 15:04:48 UTC
  • Revision ID: bin.li@canonical.com-20160123150448-5ockvw4p5xxntda4
init the 1:6.0-0ubuntu9.15 from silo 12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, see <http://www.gnu.org/licenses/>.
 
19
***/
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <sys/types.h>
 
26
#include <asoundlib.h>
 
27
 
 
28
#include <pulse/sample.h>
 
29
#include <pulse/xmalloc.h>
 
30
#include <pulse/timeval.h>
 
31
#include <pulse/util.h>
 
32
#include <pulse/utf8.h>
 
33
 
 
34
#include <pulsecore/i18n.h>
 
35
#include <pulsecore/log.h>
 
36
#include <pulsecore/macro.h>
 
37
#include <pulsecore/core-util.h>
 
38
#include <pulsecore/atomic.h>
 
39
#include <pulsecore/core-error.h>
 
40
#include <pulsecore/thread.h>
 
41
#include <pulsecore/conf-parser.h>
 
42
#include <pulsecore/core-rtclock.h>
 
43
 
 
44
#include "alsa-util.h"
 
45
#include "alsa-mixer.h"
 
46
 
 
47
#ifdef HAVE_UDEV
 
48
#include "udev-util.h"
 
49
#endif
 
50
 
 
51
static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) {
 
52
 
 
53
    static const snd_pcm_format_t format_trans[] = {
 
54
        [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8,
 
55
        [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
 
56
        [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
 
57
        [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
 
58
        [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
 
59
        [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
 
60
        [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
 
61
        [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
 
62
        [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
 
63
        [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
 
64
        [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
 
65
        [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
 
66
        [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE,
 
67
    };
 
68
 
 
69
    static const pa_sample_format_t try_order[] = {
 
70
        PA_SAMPLE_FLOAT32NE,
 
71
        PA_SAMPLE_FLOAT32RE,
 
72
        PA_SAMPLE_S32NE,
 
73
        PA_SAMPLE_S32RE,
 
74
        PA_SAMPLE_S24_32NE,
 
75
        PA_SAMPLE_S24_32RE,
 
76
        PA_SAMPLE_S24NE,
 
77
        PA_SAMPLE_S24RE,
 
78
        PA_SAMPLE_S16NE,
 
79
        PA_SAMPLE_S16RE,
 
80
        PA_SAMPLE_ALAW,
 
81
        PA_SAMPLE_ULAW,
 
82
        PA_SAMPLE_U8
 
83
    };
 
84
 
 
85
    unsigned i;
 
86
    int ret;
 
87
 
 
88
    pa_assert(pcm_handle);
 
89
    pa_assert(hwparams);
 
90
    pa_assert(f);
 
91
 
 
92
    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
 
93
        return ret;
 
94
 
 
95
    pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
 
96
                 snd_pcm_format_description(format_trans[*f]),
 
97
                 pa_alsa_strerror(ret));
 
98
 
 
99
    if (*f == PA_SAMPLE_FLOAT32BE)
 
100
        *f = PA_SAMPLE_FLOAT32LE;
 
101
    else if (*f == PA_SAMPLE_FLOAT32LE)
 
102
        *f = PA_SAMPLE_FLOAT32BE;
 
103
    else if (*f == PA_SAMPLE_S24BE)
 
104
        *f = PA_SAMPLE_S24LE;
 
105
    else if (*f == PA_SAMPLE_S24LE)
 
106
        *f = PA_SAMPLE_S24BE;
 
107
    else if (*f == PA_SAMPLE_S24_32BE)
 
108
        *f = PA_SAMPLE_S24_32LE;
 
109
    else if (*f == PA_SAMPLE_S24_32LE)
 
110
        *f = PA_SAMPLE_S24_32BE;
 
111
    else if (*f == PA_SAMPLE_S16BE)
 
112
        *f = PA_SAMPLE_S16LE;
 
113
    else if (*f == PA_SAMPLE_S16LE)
 
114
        *f = PA_SAMPLE_S16BE;
 
115
    else if (*f == PA_SAMPLE_S32BE)
 
116
        *f = PA_SAMPLE_S32LE;
 
117
    else if (*f == PA_SAMPLE_S32LE)
 
118
        *f = PA_SAMPLE_S32BE;
 
119
    else
 
120
        goto try_auto;
 
121
 
 
122
    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
 
123
        return ret;
 
124
 
 
125
    pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
 
126
                 snd_pcm_format_description(format_trans[*f]),
 
127
                 pa_alsa_strerror(ret));
 
128
 
 
129
try_auto:
 
130
 
 
131
    for (i = 0; i < PA_ELEMENTSOF(try_order); i++) {
 
132
        *f = try_order[i];
 
133
 
 
134
        if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
 
135
            return ret;
 
136
 
 
137
        pa_log_debug("snd_pcm_hw_params_set_format(%s) failed: %s",
 
138
                     snd_pcm_format_description(format_trans[*f]),
 
139
                     pa_alsa_strerror(ret));
 
140
    }
 
141
 
 
142
    return -1;
 
143
}
 
144
 
 
145
static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
 
146
    snd_pcm_uframes_t s;
 
147
    int d, ret;
 
148
 
 
149
    pa_assert(pcm_handle);
 
150
    pa_assert(hwparams);
 
151
 
 
152
    s = size;
 
153
    d = 0;
 
154
    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
 
155
        s = size;
 
156
        d = -1;
 
157
        if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
 
158
            s = size;
 
159
            d = 1;
 
160
            if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
 
161
                pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
 
162
                return ret;
 
163
            }
 
164
        }
 
165
    }
 
166
 
 
167
    return 0;
 
168
}
 
169
 
 
170
static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
 
171
    int ret;
 
172
 
 
173
    pa_assert(pcm_handle);
 
174
    pa_assert(hwparams);
 
175
 
 
176
    if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
 
177
        pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
 
178
        return ret;
 
179
    }
 
180
 
 
181
    return 0;
 
182
}
 
183
 
 
184
/* Set the hardware parameters of the given ALSA device. Returns the
 
185
 * selected fragment settings in *buffer_size and *period_size. Determine
 
186
 * whether mmap and tsched mode can be enabled. */
 
187
int pa_alsa_set_hw_params(
 
188
        snd_pcm_t *pcm_handle,
 
189
        pa_sample_spec *ss,
 
190
        snd_pcm_uframes_t *period_size,
 
191
        snd_pcm_uframes_t *buffer_size,
 
192
        snd_pcm_uframes_t tsched_size,
 
193
        bool *use_mmap,
 
194
        bool *use_tsched,
 
195
        bool require_exact_channel_number) {
 
196
 
 
197
    int ret = -1;
 
198
    snd_pcm_hw_params_t *hwparams, *hwparams_copy;
 
199
    int dir;
 
200
    snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
 
201
    snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
 
202
    bool _use_mmap = use_mmap && *use_mmap;
 
203
    bool _use_tsched = use_tsched && *use_tsched;
 
204
    pa_sample_spec _ss = *ss;
 
205
 
 
206
    pa_assert(pcm_handle);
 
207
    pa_assert(ss);
 
208
 
 
209
    snd_pcm_hw_params_alloca(&hwparams);
 
210
    snd_pcm_hw_params_alloca(&hwparams_copy);
 
211
 
 
212
    if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
 
213
        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
 
214
        goto finish;
 
215
    }
 
216
 
 
217
    if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
 
218
        pa_log_debug("snd_pcm_hw_params_set_rate_resample() failed: %s", pa_alsa_strerror(ret));
 
219
        goto finish;
 
220
    }
 
221
 
 
222
    if (_use_mmap) {
 
223
 
 
224
        if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
 
225
 
 
226
            /* mmap() didn't work, fall back to interleaved */
 
227
 
 
228
            if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
 
229
                pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
 
230
                goto finish;
 
231
            }
 
232
 
 
233
            _use_mmap = false;
 
234
        }
 
235
 
 
236
    } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
 
237
        pa_log_debug("snd_pcm_hw_params_set_access() failed: %s", pa_alsa_strerror(ret));
 
238
        goto finish;
 
239
    }
 
240
 
 
241
    if (!_use_mmap)
 
242
        _use_tsched = false;
 
243
 
 
244
    if (!pa_alsa_pcm_is_hw(pcm_handle))
 
245
        _use_tsched = false;
 
246
 
 
247
    /* The PCM pointer is only updated with period granularity */
 
248
    if (snd_pcm_hw_params_is_batch(hwparams)) {
 
249
        pa_log_info("Disabling tsched mode since BATCH flag is set");
 
250
        _use_tsched = false;
 
251
    }
 
252
 
 
253
#if (SND_LIB_VERSION >= ((1<<16)|(0<<8)|24)) /* API additions in 1.0.24 */
 
254
    if (_use_tsched) {
 
255
 
 
256
        /* try to disable period wakeups if hardware can do so */
 
257
        if (snd_pcm_hw_params_can_disable_period_wakeup(hwparams)) {
 
258
 
 
259
            if ((ret = snd_pcm_hw_params_set_period_wakeup(pcm_handle, hwparams, false)) < 0)
 
260
                /* don't bail, keep going with default mode with period wakeups */
 
261
                pa_log_debug("snd_pcm_hw_params_set_period_wakeup() failed: %s", pa_alsa_strerror(ret));
 
262
            else
 
263
                pa_log_info("Trying to disable ALSA period wakeups, using timers only");
 
264
        } else
 
265
            pa_log_info("Cannot disable ALSA period wakeups");
 
266
    }
 
267
#endif
 
268
 
 
269
    if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
 
270
        goto finish;
 
271
 
 
272
    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
 
273
        pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
 
274
        goto finish;
 
275
    }
 
276
 
 
277
    /* We ignore very small sampling rate deviations */
 
278
    if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05)
 
279
        _ss.rate = ss->rate;
 
280
 
 
281
    if (require_exact_channel_number) {
 
282
        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
 
283
            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
 
284
            goto finish;
 
285
        }
 
286
    } else {
 
287
        unsigned int c = _ss.channels;
 
288
 
 
289
        if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
 
290
            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
 
291
            goto finish;
 
292
        }
 
293
 
 
294
        _ss.channels = c;
 
295
    }
 
296
 
 
297
    if (_use_tsched && tsched_size > 0) {
 
298
        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate);
 
299
        _period_size = _buffer_size;
 
300
    } else {
 
301
        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate);
 
302
        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate);
 
303
    }
 
304
 
 
305
    if (_buffer_size > 0 || _period_size > 0) {
 
306
        snd_pcm_uframes_t max_frames = 0;
 
307
 
 
308
        if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
 
309
            pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
 
310
        else
 
311
            pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames * PA_MSEC_PER_SEC / _ss.rate));
 
312
 
 
313
        /* Some ALSA drivers really don't like if we set the buffer
 
314
         * size first and the number of periods second (which would
 
315
         * make a lot more sense to me). So, try a few combinations
 
316
         * before we give up. */
 
317
 
 
318
        if (_buffer_size > 0 && _period_size > 0) {
 
319
            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
 
320
 
 
321
            /* First try: set buffer size first, followed by period size */
 
322
            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
 
323
                set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
 
324
                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
 
325
                pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size);
 
326
                goto success;
 
327
            }
 
328
 
 
329
            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
 
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, bool 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
        bool *use_mmap,
 
497
        bool *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
        bool *use_mmap,
 
606
        bool *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
            pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */);
 
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
        bool *use_mmap,
 
658
        bool *use_tsched,
 
659
        bool require_exact_channel_number) {
 
660
 
 
661
    int err;
 
662
    char *d;
 
663
    snd_pcm_t *pcm_handle;
 
664
    bool 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
        bool *use_mmap,
 
751
        bool *use_tsched,
 
752
        bool 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_status_dump(): %s", pa_alsa_strerror(err));
 
825
        goto finish;
 
826
    }
 
827
 
 
828
    snd_output_buffer_string(out, &s);
 
829
    pa_log_debug("snd_pcm_status_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
bool pa_alsa_init_description(pa_proplist *p, pa_card *card) {
 
872
    const char *d, *k;
 
873
    pa_assert(p);
 
874
 
 
875
    if (pa_device_init_description(p, card))
 
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
 
 
922
void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) {
 
923
 
 
924
    static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = {
 
925
        [SND_PCM_CLASS_GENERIC] = "generic",
 
926
        [SND_PCM_CLASS_MULTI] = "multi",
 
927
        [SND_PCM_CLASS_MODEM] = "modem",
 
928
        [SND_PCM_CLASS_DIGITIZER] = "digitizer"
 
929
    };
 
930
    static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
 
931
        [SND_PCM_CLASS_GENERIC] = "sound",
 
932
        [SND_PCM_CLASS_MULTI] = NULL,
 
933
        [SND_PCM_CLASS_MODEM] = "modem",
 
934
        [SND_PCM_CLASS_DIGITIZER] = NULL
 
935
    };
 
936
    static const char * const alsa_subclass_table[SND_PCM_SUBCLASS_LAST+1] = {
 
937
        [SND_PCM_SUBCLASS_GENERIC_MIX] = "generic-mix",
 
938
        [SND_PCM_SUBCLASS_MULTI_MIX] = "multi-mix"
 
939
    };
 
940
 
 
941
    snd_pcm_class_t class;
 
942
    snd_pcm_subclass_t subclass;
 
943
    const char *n, *id, *sdn;
 
944
    int card;
 
945
 
 
946
    pa_assert(p);
 
947
    pa_assert(pcm_info);
 
948
 
 
949
    pa_proplist_sets(p, PA_PROP_DEVICE_API, "alsa");
 
950
 
 
951
    if ((class = snd_pcm_info_get_class(pcm_info)) <= SND_PCM_CLASS_LAST) {
 
952
        if (class_table[class])
 
953
            pa_proplist_sets(p, PA_PROP_DEVICE_CLASS, class_table[class]);
 
954
        if (alsa_class_table[class])
 
955
            pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
 
956
    }
 
957
 
 
958
    if ((subclass = snd_pcm_info_get_subclass(pcm_info)) <= SND_PCM_SUBCLASS_LAST)
 
959
        if (alsa_subclass_table[subclass])
 
960
            pa_proplist_sets(p, "alsa.subclass", alsa_subclass_table[subclass]);
 
961
 
 
962
    if ((n = snd_pcm_info_get_name(pcm_info))) {
 
963
        char *t = pa_xstrdup(n);
 
964
        pa_proplist_sets(p, "alsa.name", pa_strip(t));
 
965
        pa_xfree(t);
 
966
    }
 
967
 
 
968
    if ((id = snd_pcm_info_get_id(pcm_info)))
 
969
        pa_proplist_sets(p, "alsa.id", id);
 
970
 
 
971
    pa_proplist_setf(p, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info));
 
972
    if ((sdn = snd_pcm_info_get_subdevice_name(pcm_info)))
 
973
        pa_proplist_sets(p, "alsa.subdevice_name", sdn);
 
974
 
 
975
    pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
 
976
 
 
977
    if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
 
978
        pa_alsa_init_proplist_card(c, p, card);
 
979
}
 
980
 
 
981
void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
 
982
    snd_pcm_hw_params_t *hwparams;
 
983
    snd_pcm_info_t *info;
 
984
    int bits, err;
 
985
 
 
986
    snd_pcm_hw_params_alloca(&hwparams);
 
987
    snd_pcm_info_alloca(&info);
 
988
 
 
989
    if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0)
 
990
        pa_log_warn("Error fetching hardware parameter info: %s", pa_alsa_strerror(err));
 
991
    else {
 
992
 
 
993
        if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0)
 
994
            pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
 
995
    }
 
996
 
 
997
    if ((err = snd_pcm_info(pcm, info)) < 0)
 
998
        pa_log_warn("Error fetching PCM info: %s", pa_alsa_strerror(err));
 
999
    else
 
1000
        pa_alsa_init_proplist_pcm_info(c, p, info);
 
1001
}
 
1002
 
 
1003
void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {
 
1004
    int err;
 
1005
    snd_ctl_t *ctl;
 
1006
    snd_ctl_card_info_t *info;
 
1007
    const char *t;
 
1008
 
 
1009
    pa_assert(p);
 
1010
 
 
1011
    snd_ctl_card_info_alloca(&info);
 
1012
 
 
1013
    if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
 
1014
        pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));
 
1015
        return;
 
1016
    }
 
1017
 
 
1018
    if ((err = snd_ctl_card_info(ctl, info)) < 0) {
 
1019
        pa_log_warn("Control device %s card info: %s", name, snd_strerror(err));
 
1020
        snd_ctl_close(ctl);
 
1021
        return;
 
1022
    }
 
1023
 
 
1024
    if ((t = snd_ctl_card_info_get_mixername(info)) && *t)
 
1025
        pa_proplist_sets(p, "alsa.mixer_name", t);
 
1026
 
 
1027
    if ((t = snd_ctl_card_info_get_components(info)) && *t)
 
1028
        pa_proplist_sets(p, "alsa.components", t);
 
1029
 
 
1030
    snd_ctl_close(ctl);
 
1031
}
 
1032
 
 
1033
int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) {
 
1034
    snd_pcm_state_t state;
 
1035
    int err;
 
1036
 
 
1037
    pa_assert(pcm);
 
1038
 
 
1039
    if (revents & POLLERR)
 
1040
        pa_log_debug("Got POLLERR from ALSA");
 
1041
    if (revents & POLLNVAL)
 
1042
        pa_log_warn("Got POLLNVAL from ALSA");
 
1043
    if (revents & POLLHUP)
 
1044
        pa_log_warn("Got POLLHUP from ALSA");
 
1045
    if (revents & POLLPRI)
 
1046
        pa_log_warn("Got POLLPRI from ALSA");
 
1047
    if (revents & POLLIN)
 
1048
        pa_log_debug("Got POLLIN from ALSA");
 
1049
    if (revents & POLLOUT)
 
1050
        pa_log_debug("Got POLLOUT from ALSA");
 
1051
 
 
1052
    state = snd_pcm_state(pcm);
 
1053
    pa_log_debug("PCM state is %s", snd_pcm_state_name(state));
 
1054
 
 
1055
    /* Try to recover from this error */
 
1056
 
 
1057
    switch (state) {
 
1058
 
 
1059
        case SND_PCM_STATE_XRUN:
 
1060
            if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) {
 
1061
                pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err));
 
1062
                return -1;
 
1063
            }
 
1064
            break;
 
1065
 
 
1066
        case SND_PCM_STATE_SUSPENDED:
 
1067
            if ((err = snd_pcm_recover(pcm, -ESTRPIPE, 1)) != 0) {
 
1068
                pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", pa_alsa_strerror(err));
 
1069
                return -1;
 
1070
            }
 
1071
            break;
 
1072
 
 
1073
        default:
 
1074
 
 
1075
            snd_pcm_drop(pcm);
 
1076
 
 
1077
            if ((err = snd_pcm_prepare(pcm)) < 0) {
 
1078
                pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", pa_alsa_strerror(err));
 
1079
                return -1;
 
1080
            }
 
1081
            break;
 
1082
    }
 
1083
 
 
1084
    return 0;
 
1085
}
 
1086
 
 
1087
pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
 
1088
    int n, err;
 
1089
    struct pollfd *pollfd;
 
1090
    pa_rtpoll_item *item;
 
1091
 
 
1092
    pa_assert(pcm);
 
1093
 
 
1094
    if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) {
 
1095
        pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
 
1096
        return NULL;
 
1097
    }
 
1098
 
 
1099
    item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n);
 
1100
    pollfd = pa_rtpoll_item_get_pollfd(item, NULL);
 
1101
 
 
1102
    if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) {
 
1103
        pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err));
 
1104
        pa_rtpoll_item_free(item);
 
1105
        return NULL;
 
1106
    }
 
1107
 
 
1108
    return item;
 
1109
}
 
1110
 
 
1111
snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
 
1112
    snd_pcm_sframes_t n;
 
1113
    size_t k;
 
1114
 
 
1115
    pa_assert(pcm);
 
1116
    pa_assert(hwbuf_size > 0);
 
1117
    pa_assert(ss);
 
1118
 
 
1119
    /* Some ALSA driver expose weird bugs, let's inform the user about
 
1120
     * what is going on */
 
1121
 
 
1122
    n = snd_pcm_avail(pcm);
 
1123
 
 
1124
    if (n <= 0)
 
1125
        return n;
 
1126
 
 
1127
    k = (size_t) n * pa_frame_size(ss);
 
1128
 
 
1129
    if (PA_UNLIKELY(k >= hwbuf_size * 5 ||
 
1130
                    k >= pa_bytes_per_second(ss)*10)) {
 
1131
 
 
1132
        PA_ONCE_BEGIN {
 
1133
            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
 
1134
            pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
 
1135
                     "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
 
1136
                   (unsigned long) k,
 
1137
                   (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
 
1138
                   pa_strnull(dn));
 
1139
            pa_xfree(dn);
 
1140
            pa_alsa_dump(PA_LOG_ERROR, pcm);
 
1141
        } PA_ONCE_END;
 
1142
 
 
1143
        /* Mhmm, let's try not to fail completely */
 
1144
        n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
 
1145
    }
 
1146
 
 
1147
    return n;
 
1148
}
 
1149
 
 
1150
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,
 
1151
                       bool capture) {
 
1152
    ssize_t k;
 
1153
    size_t abs_k;
 
1154
    int err;
 
1155
    snd_pcm_sframes_t avail = 0;
 
1156
 
 
1157
    pa_assert(pcm);
 
1158
    pa_assert(delay);
 
1159
    pa_assert(hwbuf_size > 0);
 
1160
    pa_assert(ss);
 
1161
 
 
1162
    /* Some ALSA driver expose weird bugs, let's inform the user about
 
1163
     * what is going on. We're going to get both the avail and delay values so
 
1164
     * that we can compare and check them for capture.
 
1165
     * This is done with snd_pcm_status() which provides
 
1166
     * avail, delay and timestamp values in a single kernel call to improve
 
1167
     * timer-based scheduling */
 
1168
 
 
1169
    if ((err = snd_pcm_status(pcm, status)) < 0)
 
1170
        return err;
 
1171
 
 
1172
    avail = snd_pcm_status_get_avail(status);
 
1173
    *delay = snd_pcm_status_get_delay(status);
 
1174
 
 
1175
    k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
 
1176
 
 
1177
    abs_k = k >= 0 ? (size_t) k : (size_t) -k;
 
1178
 
 
1179
    if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
 
1180
                    abs_k >= pa_bytes_per_second(ss)*10)) {
 
1181
 
 
1182
        PA_ONCE_BEGIN {
 
1183
            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
 
1184
            pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
 
1185
                     "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
 
1186
                   (signed long) k,
 
1187
                   k < 0 ? "-" : "",
 
1188
                   (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC),
 
1189
                   pa_strnull(dn));
 
1190
            pa_xfree(dn);
 
1191
            pa_alsa_dump(PA_LOG_ERROR, pcm);
 
1192
        } PA_ONCE_END;
 
1193
 
 
1194
        /* Mhmm, let's try not to fail completely */
 
1195
        if (k < 0)
 
1196
            *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
 
1197
        else
 
1198
            *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
 
1199
    }
 
1200
 
 
1201
    if (capture) {
 
1202
        abs_k = (size_t) avail * pa_frame_size(ss);
 
1203
 
 
1204
        if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 ||
 
1205
                        abs_k >= pa_bytes_per_second(ss)*10)) {
 
1206
 
 
1207
            PA_ONCE_BEGIN {
 
1208
                char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
 
1209
                pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
 
1210
                         "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
 
1211
                       (unsigned long) k,
 
1212
                       (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
 
1213
                       pa_strnull(dn));
 
1214
                pa_xfree(dn);
 
1215
                pa_alsa_dump(PA_LOG_ERROR, pcm);
 
1216
            } PA_ONCE_END;
 
1217
 
 
1218
            /* Mhmm, let's try not to fail completely */
 
1219
            avail = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
 
1220
        }
 
1221
 
 
1222
        if (PA_UNLIKELY(*delay < avail)) {
 
1223
            PA_ONCE_BEGIN {
 
1224
                char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
 
1225
                pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
 
1226
                         "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
 
1227
                       (unsigned long) *delay,
 
1228
                       (unsigned long) avail,
 
1229
                       pa_strnull(dn));
 
1230
                pa_xfree(dn);
 
1231
                pa_alsa_dump(PA_LOG_ERROR, pcm);
 
1232
            } PA_ONCE_END;
 
1233
 
 
1234
            /* try to fixup */
 
1235
            *delay = avail;
 
1236
        }
 
1237
    }
 
1238
 
 
1239
    return 0;
 
1240
}
 
1241
 
 
1242
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) {
 
1243
    int r;
 
1244
    snd_pcm_uframes_t before;
 
1245
    size_t k;
 
1246
 
 
1247
    pa_assert(pcm);
 
1248
    pa_assert(areas);
 
1249
    pa_assert(offset);
 
1250
    pa_assert(frames);
 
1251
    pa_assert(hwbuf_size > 0);
 
1252
    pa_assert(ss);
 
1253
 
 
1254
    before = *frames;
 
1255
 
 
1256
    r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
 
1257
 
 
1258
    if (r < 0)
 
1259
        return r;
 
1260
 
 
1261
    k = (size_t) *frames * pa_frame_size(ss);
 
1262
 
 
1263
    if (PA_UNLIKELY(*frames > before ||
 
1264
                    k >= hwbuf_size * 3 ||
 
1265
                    k >= pa_bytes_per_second(ss)*10))
 
1266
        PA_ONCE_BEGIN {
 
1267
            char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
 
1268
            pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
 
1269
                     "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
 
1270
                   (unsigned long) k,
 
1271
                   (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
 
1272
                   pa_strnull(dn));
 
1273
            pa_xfree(dn);
 
1274
            pa_alsa_dump(PA_LOG_ERROR, pcm);
 
1275
        } PA_ONCE_END;
 
1276
 
 
1277
    return r;
 
1278
}
 
1279
 
 
1280
char *pa_alsa_get_driver_name(int card) {
 
1281
    char *t, *m, *n;
 
1282
 
 
1283
    pa_assert(card >= 0);
 
1284
 
 
1285
    t = pa_sprintf_malloc("/sys/class/sound/card%i/device/driver/module", card);
 
1286
    m = pa_readlink(t);
 
1287
    pa_xfree(t);
 
1288
 
 
1289
    if (!m)
 
1290
        return NULL;
 
1291
 
 
1292
    n = pa_xstrdup(pa_path_get_filename(m));
 
1293
    pa_xfree(m);
 
1294
 
 
1295
    return n;
 
1296
}
 
1297
 
 
1298
char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
 
1299
    int card;
 
1300
    snd_pcm_info_t* info;
 
1301
    snd_pcm_info_alloca(&info);
 
1302
 
 
1303
    pa_assert(pcm);
 
1304
 
 
1305
    if (snd_pcm_info(pcm, info) < 0)
 
1306
        return NULL;
 
1307
 
 
1308
    if ((card = snd_pcm_info_get_card(info)) < 0)
 
1309
        return NULL;
 
1310
 
 
1311
    return pa_alsa_get_driver_name(card);
 
1312
}
 
1313
 
 
1314
char *pa_alsa_get_reserve_name(const char *device) {
 
1315
    const char *t;
 
1316
    int i;
 
1317
 
 
1318
    pa_assert(device);
 
1319
 
 
1320
    if ((t = strchr(device, ':')))
 
1321
        device = t+1;
 
1322
 
 
1323
    if ((i = snd_card_get_index(device)) < 0) {
 
1324
        int32_t k;
 
1325
 
 
1326
        if (pa_atoi(device, &k) < 0)
 
1327
            return NULL;
 
1328
 
 
1329
        i = (int) k;
 
1330
    }
 
1331
 
 
1332
    return pa_sprintf_malloc("Audio%i", i);
 
1333
}
 
1334
 
 
1335
unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) {
 
1336
    static unsigned int all_rates[] = { 8000, 11025, 12000,
 
1337
                                        16000, 22050, 24000,
 
1338
                                        32000, 44100, 48000,
 
1339
                                        64000, 88200, 96000,
 
1340
                                        128000, 176400, 192000,
 
1341
                                        384000 };
 
1342
    bool supported[PA_ELEMENTSOF(all_rates)] = { false, };
 
1343
    snd_pcm_hw_params_t *hwparams;
 
1344
    unsigned int i, j, n, *rates = NULL;
 
1345
    int ret;
 
1346
 
 
1347
    snd_pcm_hw_params_alloca(&hwparams);
 
1348
 
 
1349
    if ((ret = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
 
1350
        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
 
1351
        return NULL;
 
1352
    }
 
1353
 
 
1354
    for (i = 0, n = 0; i < PA_ELEMENTSOF(all_rates); i++) {
 
1355
        if (snd_pcm_hw_params_test_rate(pcm, hwparams, all_rates[i], 0) == 0) {
 
1356
            supported[i] = true;
 
1357
            n++;
 
1358
        }
 
1359
    }
 
1360
 
 
1361
    if (n > 0) {
 
1362
        rates = pa_xnew(unsigned int, n + 1);
 
1363
 
 
1364
        for (i = 0, j = 0; i < PA_ELEMENTSOF(all_rates); i++) {
 
1365
            if (supported[i])
 
1366
                rates[j++] = all_rates[i];
 
1367
        }
 
1368
 
 
1369
        rates[j] = 0;
 
1370
    } else {
 
1371
        rates = pa_xnew(unsigned int, 2);
 
1372
 
 
1373
        rates[0] = fallback_rate;
 
1374
        if ((ret = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rates[0], NULL)) < 0) {
 
1375
            pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
 
1376
            pa_xfree(rates);
 
1377
            return NULL;
 
1378
        }
 
1379
 
 
1380
        rates[1] = 0;
 
1381
    }
 
1382
 
 
1383
    return rates;
 
1384
}
 
1385
 
 
1386
bool pa_alsa_pcm_is_hw(snd_pcm_t *pcm) {
 
1387
    snd_pcm_info_t* info;
 
1388
    snd_pcm_info_alloca(&info);
 
1389
 
 
1390
    pa_assert(pcm);
 
1391
 
 
1392
    if (snd_pcm_info(pcm, info) < 0)
 
1393
        return false;
 
1394
 
 
1395
    return snd_pcm_info_get_card(info) >= 0;
 
1396
}
 
1397
 
 
1398
bool pa_alsa_pcm_is_modem(snd_pcm_t *pcm) {
 
1399
    snd_pcm_info_t* info;
 
1400
    snd_pcm_info_alloca(&info);
 
1401
 
 
1402
    pa_assert(pcm);
 
1403
 
 
1404
    if (snd_pcm_info(pcm, info) < 0)
 
1405
        return false;
 
1406
 
 
1407
    return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM;
 
1408
}
 
1409
 
 
1410
PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
 
1411
 
 
1412
const char* pa_alsa_strerror(int errnum) {
 
1413
    const char *original = NULL;
 
1414
    char *translated, *t;
 
1415
    char errbuf[128];
 
1416
 
 
1417
    if ((t = PA_STATIC_TLS_GET(cstrerror)))
 
1418
        pa_xfree(t);
 
1419
 
 
1420
    original = snd_strerror(errnum);
 
1421
 
 
1422
    if (!original) {
 
1423
        pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
 
1424
        original = errbuf;
 
1425
    }
 
1426
 
 
1427
    if (!(translated = pa_locale_to_utf8(original))) {
 
1428
        pa_log_warn("Unable to convert error string to locale, filtering.");
 
1429
        translated = pa_utf8_filter(original);
 
1430
    }
 
1431
 
 
1432
    PA_STATIC_TLS_SET(cstrerror, translated);
 
1433
 
 
1434
    return translated;
 
1435
}
 
1436
 
 
1437
bool pa_alsa_may_tsched(bool want) {
 
1438
 
 
1439
    if (!want)
 
1440
        return false;
 
1441
 
 
1442
    if (!pa_rtclock_hrtimer()) {
 
1443
        /* We cannot depend on being woken up in time when the timers
 
1444
        are inaccurate, so let's fallback to classic IO based playback
 
1445
        then. */
 
1446
        pa_log_notice("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
 
1447
        return false; }
 
1448
 
 
1449
    if (pa_running_in_vm()) {
 
1450
        /* We cannot depend on being woken up when we ask for in a VM,
 
1451
         * so let's fallback to classic IO based playback then. */
 
1452
        pa_log_notice("Disabling timer-based scheduling because running inside a VM.");
 
1453
        return false;
 
1454
    }
 
1455
 
 
1456
    return true;
 
1457
}
 
1458
 
 
1459
#define SND_MIXER_ELEM_PULSEAUDIO (SND_MIXER_ELEM_LAST + 10)
 
1460
 
 
1461
snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device) {
 
1462
    snd_mixer_elem_t *elem;
 
1463
 
 
1464
    for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
 
1465
        snd_hctl_elem_t *helem;
 
1466
        if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO)
 
1467
            continue;
 
1468
        helem = snd_mixer_elem_get_private(elem);
 
1469
        if (!pa_streq(snd_hctl_elem_get_name(helem), name))
 
1470
            continue;
 
1471
        if (snd_hctl_elem_get_device(helem) != device)
 
1472
            continue;
 
1473
        return elem;
 
1474
    }
 
1475
    return NULL;
 
1476
}
 
1477
 
 
1478
static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
 
1479
{
 
1480
    /* Dummy compare function */
 
1481
    return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1);
 
1482
}
 
1483
 
 
1484
static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
 
1485
                        snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
 
1486
{
 
1487
    int err;
 
1488
    const char *name = snd_hctl_elem_get_name(helem);
 
1489
    if (mask & SND_CTL_EVENT_MASK_ADD) {
 
1490
        snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
 
1491
        if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) {
 
1492
            snd_mixer_elem_t *new_melem;
 
1493
 
 
1494
            /* Put the hctl pointer as our private data - it will be useful for callbacks */
 
1495
            if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
 
1496
                pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
 
1497
                return 0;
 
1498
            }
 
1499
 
 
1500
            if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
 
1501
                pa_log_warn("snd_mixer_elem_attach failed: %s", pa_alsa_strerror(err));
 
1502
                snd_mixer_elem_free(melem);
 
1503
                return 0;
 
1504
            }
 
1505
 
 
1506
            if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
 
1507
                pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err));
 
1508
                return 0;
 
1509
            }
 
1510
        }
 
1511
    }
 
1512
    else if (mask & SND_CTL_EVENT_MASK_VALUE) {
 
1513
        snd_mixer_elem_value(melem); /* Calls the element callback */
 
1514
        return 0;
 
1515
    }
 
1516
    else
 
1517
        pa_log_info("Got an unknown mixer class event for %s: mask 0x%x\n", name, mask);
 
1518
 
 
1519
    return 0;
 
1520
}
 
1521
 
 
1522
static int prepare_mixer(snd_mixer_t *mixer, const char *dev) {
 
1523
    int err;
 
1524
    snd_mixer_class_t *class;
 
1525
 
 
1526
    pa_assert(mixer);
 
1527
    pa_assert(dev);
 
1528
 
 
1529
    if ((err = snd_mixer_attach(mixer, dev)) < 0) {
 
1530
        pa_log_info("Unable to attach to mixer %s: %s", dev, pa_alsa_strerror(err));
 
1531
        return -1;
 
1532
    }
 
1533
 
 
1534
    if (snd_mixer_class_malloc(&class)) {
 
1535
        pa_log_info("Failed to allocate mixer class for %s", dev);
 
1536
        return -1;
 
1537
    }
 
1538
    snd_mixer_class_set_event(class, mixer_class_event);
 
1539
    snd_mixer_class_set_compare(class, mixer_class_compare);
 
1540
    if ((err = snd_mixer_class_register(class, mixer)) < 0) {
 
1541
        pa_log_info("Unable register mixer class for %s: %s", dev, pa_alsa_strerror(err));
 
1542
        snd_mixer_class_free(class);
 
1543
        return -1;
 
1544
    }
 
1545
    /* From here on, the mixer class is deallocated by alsa on snd_mixer_close/free. */
 
1546
 
 
1547
    if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
 
1548
        pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err));
 
1549
        return -1;
 
1550
    }
 
1551
 
 
1552
    if ((err = snd_mixer_load(mixer)) < 0) {
 
1553
        pa_log_warn("Unable to load mixer: %s", pa_alsa_strerror(err));
 
1554
        return -1;
 
1555
    }
 
1556
 
 
1557
    pa_log_info("Successfully attached to mixer '%s'", dev);
 
1558
    return 0;
 
1559
}
 
1560
 
 
1561
snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device) {
 
1562
    int err;
 
1563
    snd_mixer_t *m;
 
1564
    char *md;
 
1565
    snd_pcm_info_t* info;
 
1566
    snd_pcm_info_alloca(&info);
 
1567
 
 
1568
    if ((err = snd_mixer_open(&m, 0)) < 0) {
 
1569
        pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
 
1570
        return NULL;
 
1571
    }
 
1572
 
 
1573
    /* Then, try by card index */
 
1574
    md = pa_sprintf_malloc("hw:%i", alsa_card_index);
 
1575
    if (prepare_mixer(m, md) >= 0) {
 
1576
 
 
1577
        if (ctl_device)
 
1578
            *ctl_device = md;
 
1579
        else
 
1580
            pa_xfree(md);
 
1581
 
 
1582
        return m;
 
1583
    }
 
1584
 
 
1585
    pa_xfree(md);
 
1586
 
 
1587
    snd_mixer_close(m);
 
1588
    return NULL;
 
1589
}
 
1590
 
 
1591
snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device) {
 
1592
    int err;
 
1593
    snd_mixer_t *m;
 
1594
    const char *dev;
 
1595
    snd_pcm_info_t* info;
 
1596
    snd_pcm_info_alloca(&info);
 
1597
 
 
1598
    pa_assert(pcm);
 
1599
 
 
1600
    if ((err = snd_mixer_open(&m, 0)) < 0) {
 
1601
        pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
 
1602
        return NULL;
 
1603
    }
 
1604
 
 
1605
    /* First, try by name */
 
1606
    if ((dev = snd_pcm_name(pcm)))
 
1607
        if (prepare_mixer(m, dev) >= 0) {
 
1608
            if (ctl_device)
 
1609
                *ctl_device = pa_xstrdup(dev);
 
1610
 
 
1611
            return m;
 
1612
        }
 
1613
 
 
1614
    /* Then, try by card index */
 
1615
    if (snd_pcm_info(pcm, info) >= 0) {
 
1616
        char *md;
 
1617
        int card_idx;
 
1618
 
 
1619
        if ((card_idx = snd_pcm_info_get_card(info)) >= 0) {
 
1620
 
 
1621
            md = pa_sprintf_malloc("hw:%i", card_idx);
 
1622
 
 
1623
            if (!dev || !pa_streq(dev, md))
 
1624
                if (prepare_mixer(m, md) >= 0) {
 
1625
 
 
1626
                    if (ctl_device)
 
1627
                        *ctl_device = md;
 
1628
                    else
 
1629
                        pa_xfree(md);
 
1630
 
 
1631
                    return m;
 
1632
                }
 
1633
 
 
1634
            pa_xfree(md);
 
1635
        }
 
1636
    }
 
1637
 
 
1638
    snd_mixer_close(m);
 
1639
    return NULL;
 
1640
}
 
1641
 
 
1642
int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld) {
 
1643
 
 
1644
    /* The ELD format is specific to HDA Intel sound cards and defined in the
 
1645
       HDA specification: http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html */
 
1646
    int err;
 
1647
    snd_ctl_elem_info_t *info;
 
1648
    snd_ctl_elem_value_t *value;
 
1649
    uint8_t *elddata;
 
1650
    unsigned int eldsize, mnl;
 
1651
    unsigned int device;
 
1652
 
 
1653
    pa_assert(eld != NULL);
 
1654
    pa_assert(elem != NULL);
 
1655
 
 
1656
    /* Does it have any contents? */
 
1657
    snd_ctl_elem_info_alloca(&info);
 
1658
    snd_ctl_elem_value_alloca(&value);
 
1659
    if ((err = snd_hctl_elem_info(elem, info)) < 0 ||
 
1660
       (err = snd_hctl_elem_read(elem, value)) < 0) {
 
1661
        pa_log_warn("Accessing ELD control failed with error %s", snd_strerror(err));
 
1662
        return -1;
 
1663
    }
 
1664
 
 
1665
    device = snd_hctl_elem_get_device(elem);
 
1666
    eldsize = snd_ctl_elem_info_get_count(info);
 
1667
    elddata = (unsigned char *) snd_ctl_elem_value_get_bytes(value);
 
1668
    if (elddata == NULL || eldsize == 0) {
 
1669
        pa_log_debug("ELD info empty (for device=%d)", device);
 
1670
        return -1;
 
1671
    }
 
1672
    if (eldsize < 20 || eldsize > 256) {
 
1673
        pa_log_debug("ELD info has wrong size (for device=%d)", device);
 
1674
        return -1;
 
1675
    }
 
1676
 
 
1677
    /* Try to fetch monitor name */
 
1678
    mnl = elddata[4] & 0x1f;
 
1679
    if (mnl == 0 || mnl > 16 || 20 + mnl > eldsize) {
 
1680
        pa_log_debug("No monitor name in ELD info (for device=%d)", device);
 
1681
        mnl = 0;
 
1682
    }
 
1683
    memcpy(eld->monitor_name, &elddata[20], mnl);
 
1684
    eld->monitor_name[mnl] = '\0';
 
1685
    if (mnl)
 
1686
        pa_log_debug("Monitor name in ELD info is '%s' (for device=%d)", eld->monitor_name, device);
 
1687
 
 
1688
    return 0;
 
1689
}