2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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 of the License,
10 or (at your option) any later version.
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.
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
27 #include <sys/types.h>
29 #include <asoundlib.h>
31 #include <pulse/sample.h>
32 #include <pulse/xmalloc.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/macro.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/atomic.h>
39 #include "alsa-util.h"
41 struct pa_alsa_fdlist
{
44 /* This is a temporary buffer used to avoid lots of mallocs */
45 struct pollfd
*work_fds
;
50 pa_defer_event
*defer
;
55 void (*cb
)(void *userdata
);
59 static void io_cb(pa_mainloop_api
*a
, pa_io_event
* e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
61 struct pa_alsa_fdlist
*fdl
= userdata
;
64 unsigned short revents
;
68 pa_assert(fdl
->mixer
);
70 pa_assert(fdl
->work_fds
);
77 memcpy(fdl
->work_fds
, fdl
->fds
, sizeof(struct pollfd
) * fdl
->num_fds
);
79 for (i
= 0; i
< fdl
->num_fds
; i
++) {
80 if (e
== fdl
->ios
[i
]) {
81 if (events
& PA_IO_EVENT_INPUT
)
82 fdl
->work_fds
[i
].revents
|= POLLIN
;
83 if (events
& PA_IO_EVENT_OUTPUT
)
84 fdl
->work_fds
[i
].revents
|= POLLOUT
;
85 if (events
& PA_IO_EVENT_ERROR
)
86 fdl
->work_fds
[i
].revents
|= POLLERR
;
87 if (events
& PA_IO_EVENT_HANGUP
)
88 fdl
->work_fds
[i
].revents
|= POLLHUP
;
93 pa_assert(i
!= fdl
->num_fds
);
95 if ((err
= snd_mixer_poll_descriptors_revents(fdl
->mixer
, fdl
->work_fds
, fdl
->num_fds
, &revents
)) < 0) {
96 pa_log_error("Unable to get poll revent: %s", snd_strerror(err
));
100 a
->defer_enable(fdl
->defer
, 1);
103 snd_mixer_handle_events(fdl
->mixer
);
106 static void defer_cb(pa_mainloop_api
*a
, pa_defer_event
* e
, void *userdata
) {
107 struct pa_alsa_fdlist
*fdl
= userdata
;
114 pa_assert(fdl
->mixer
);
116 a
->defer_enable(fdl
->defer
, 0);
118 num_fds
= (unsigned) snd_mixer_poll_descriptors_count(fdl
->mixer
);
120 if (num_fds
!= fdl
->num_fds
) {
124 pa_xfree(fdl
->work_fds
);
125 fdl
->fds
= pa_xnew0(struct pollfd
, num_fds
);
126 fdl
->work_fds
= pa_xnew(struct pollfd
, num_fds
);
129 memset(fdl
->work_fds
, 0, sizeof(struct pollfd
) * num_fds
);
131 if ((err
= snd_mixer_poll_descriptors(fdl
->mixer
, fdl
->work_fds
, num_fds
)) < 0) {
132 pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err
));
138 if (memcmp(fdl
->fds
, fdl
->work_fds
, sizeof(struct pollfd
) * num_fds
) == 0)
142 for (i
= 0; i
< fdl
->num_fds
; i
++)
143 a
->io_free(fdl
->ios
[i
]);
145 if (num_fds
!= fdl
->num_fds
) {
152 fdl
->ios
= pa_xnew(pa_io_event
*, num_fds
);
155 temp
= fdl
->work_fds
;
156 fdl
->work_fds
= fdl
->fds
;
159 fdl
->num_fds
= num_fds
;
161 for (i
= 0;i
< num_fds
;i
++)
162 fdl
->ios
[i
] = a
->io_new(a
, fdl
->fds
[i
].fd
,
163 ((fdl
->fds
[i
].events
& POLLIN
) ? PA_IO_EVENT_INPUT
: 0) |
164 ((fdl
->fds
[i
].events
& POLLOUT
) ? PA_IO_EVENT_OUTPUT
: 0),
168 struct pa_alsa_fdlist
*pa_alsa_fdlist_new(void) {
169 struct pa_alsa_fdlist
*fdl
;
171 fdl
= pa_xnew0(struct pa_alsa_fdlist
, 1);
175 fdl
->work_fds
= NULL
;
185 void pa_alsa_fdlist_free(struct pa_alsa_fdlist
*fdl
) {
190 fdl
->m
->defer_free(fdl
->defer
);
196 for (i
= 0; i
< fdl
->num_fds
; i
++)
197 fdl
->m
->io_free(fdl
->ios
[i
]);
204 pa_xfree(fdl
->work_fds
);
209 int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist
*fdl
, snd_mixer_t
*mixer_handle
, pa_mainloop_api
* m
) {
211 pa_assert(mixer_handle
);
215 fdl
->mixer
= mixer_handle
;
217 fdl
->defer
= m
->defer_new(m
, defer_cb
, fdl
);
222 static int set_format(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, pa_sample_format_t
*f
) {
224 static const snd_pcm_format_t format_trans
[] = {
225 [PA_SAMPLE_U8
] = SND_PCM_FORMAT_U8
,
226 [PA_SAMPLE_ALAW
] = SND_PCM_FORMAT_A_LAW
,
227 [PA_SAMPLE_ULAW
] = SND_PCM_FORMAT_MU_LAW
,
228 [PA_SAMPLE_S16LE
] = SND_PCM_FORMAT_S16_LE
,
229 [PA_SAMPLE_S16BE
] = SND_PCM_FORMAT_S16_BE
,
230 [PA_SAMPLE_FLOAT32LE
] = SND_PCM_FORMAT_FLOAT_LE
,
231 [PA_SAMPLE_FLOAT32BE
] = SND_PCM_FORMAT_FLOAT_BE
,
232 [PA_SAMPLE_S32LE
] = SND_PCM_FORMAT_S32_LE
,
233 [PA_SAMPLE_S32BE
] = SND_PCM_FORMAT_S32_BE
,
236 static const pa_sample_format_t try_order
[] = {
251 pa_assert(pcm_handle
);
254 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
257 if (*f
== PA_SAMPLE_FLOAT32BE
)
258 *f
= PA_SAMPLE_FLOAT32LE
;
259 else if (*f
== PA_SAMPLE_FLOAT32LE
)
260 *f
= PA_SAMPLE_FLOAT32BE
;
261 else if (*f
== PA_SAMPLE_S16BE
)
262 *f
= PA_SAMPLE_S16LE
;
263 else if (*f
== PA_SAMPLE_S16LE
)
264 *f
= PA_SAMPLE_S16BE
;
265 else if (*f
== PA_SAMPLE_S32BE
)
266 *f
= PA_SAMPLE_S32LE
;
267 else if (*f
== PA_SAMPLE_S32LE
)
268 *f
= PA_SAMPLE_S32BE
;
272 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
277 for (i
= 0; try_order
[i
] != PA_SAMPLE_INVALID
; i
++) {
280 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
287 /* Set the hardware parameters of the given ALSA device. Returns the
288 * selected fragment settings in *period and *period_size */
289 int pa_alsa_set_hw_params(
290 snd_pcm_t
*pcm_handle
,
293 snd_pcm_uframes_t
*period_size
,
294 snd_pcm_uframes_t tsched_size
,
296 pa_bool_t
*use_tsched
,
297 pa_bool_t require_exact_channel_number
) {
300 snd_pcm_uframes_t _period_size
= *period_size
;
301 unsigned int _periods
= *periods
;
302 snd_pcm_uframes_t buffer_size
;
303 unsigned int r
= ss
->rate
;
304 unsigned int c
= ss
->channels
;
305 pa_sample_format_t f
= ss
->format
;
306 snd_pcm_hw_params_t
*hwparams
;
307 pa_bool_t _use_mmap
= use_mmap
&& *use_mmap
;
308 pa_bool_t _use_tsched
= use_tsched
&& *use_tsched
;
311 pa_assert(pcm_handle
);
314 pa_assert(period_size
);
316 snd_pcm_hw_params_alloca(&hwparams
);
318 if ((ret
= snd_pcm_hw_params_any(pcm_handle
, hwparams
)) < 0)
321 if ((ret
= snd_pcm_hw_params_set_rate_resample(pcm_handle
, hwparams
, 0)) < 0)
325 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_MMAP_INTERLEAVED
)) < 0) {
327 /* mmap() didn't work, fall back to interleaved */
329 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
335 } else if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
341 if ((ret
= set_format(pcm_handle
, hwparams
, &f
)) < 0)
344 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm_handle
, hwparams
, &r
, NULL
)) < 0)
347 /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
348 _period_size
= (snd_pcm_uframes_t
) (((uint64_t) _period_size
* r
) / ss
->rate
);
349 tsched_size
= (snd_pcm_uframes_t
) (((uint64_t) tsched_size
* r
) / ss
->rate
);
351 if (require_exact_channel_number
) {
352 if ((ret
= snd_pcm_hw_params_set_channels(pcm_handle
, hwparams
, c
)) < 0)
355 if ((ret
= snd_pcm_hw_params_set_channels_near(pcm_handle
, hwparams
, &c
)) < 0)
360 _period_size
= tsched_size
;
363 pa_assert_se(snd_pcm_hw_params_get_buffer_size_max(hwparams
, &buffer_size
) == 0);
364 pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size
* 1000 / r
);
367 buffer_size
= _periods
* _period_size
;
369 if ((ret
= snd_pcm_hw_params_set_periods_integer(pcm_handle
, hwparams
)) < 0)
374 /* First we pass 0 as direction to get exactly what we asked
375 * for. That this is necessary is presumably a bug in ALSA */
378 if ((ret
= snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &_periods
, &dir
)) < 0) {
380 if ((ret
= snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &_periods
, &dir
)) < 0) {
382 if ((ret
= snd_pcm_hw_params_set_periods_near(pcm_handle
, hwparams
, &_periods
, &dir
)) < 0)
388 if (_period_size
> 0)
389 if ((ret
= snd_pcm_hw_params_set_buffer_size_near(pcm_handle
, hwparams
, &buffer_size
)) < 0)
392 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0)
396 pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, r
);
398 if (ss
->channels
!= c
)
399 pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, c
);
402 pa_log_warn("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(f
));
404 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0)
407 if ((ret
= snd_pcm_hw_params_get_period_size(hwparams
, &_period_size
, &dir
)) < 0 ||
408 (ret
= snd_pcm_hw_params_get_periods(hwparams
, &_periods
, &dir
)) < 0)
411 /* If the sample rate deviates too much, we need to resample */
412 if (r
< ss
->rate
*.95 || r
> ss
->rate
*1.05)
414 ss
->channels
= (uint8_t) c
;
417 pa_assert(_periods
> 0);
418 pa_assert(_period_size
> 0);
421 *period_size
= _period_size
;
424 *use_mmap
= _use_mmap
;
427 *use_tsched
= _use_tsched
;
431 snd_pcm_nonblock(pcm_handle
, 1);
438 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
, snd_pcm_uframes_t avail_min
) {
439 snd_pcm_sw_params_t
*swparams
;
444 snd_pcm_sw_params_alloca(&swparams
);
446 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
447 pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err
));
451 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
452 pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err
));
456 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
457 pa_log_warn("Unable to set start threshold: %s\n", snd_strerror(err
));
461 if ((err
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, avail_min
)) < 0) {
462 pa_log_error("snd_pcm_sw_params_set_avail_min() failed: %s", snd_strerror(err
));
466 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
467 pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err
));
479 static const struct device_info device_table
[] = {
480 {{ 2, { PA_CHANNEL_POSITION_LEFT
, PA_CHANNEL_POSITION_RIGHT
} }, "front" },
482 {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT
, PA_CHANNEL_POSITION_FRONT_RIGHT
,
483 PA_CHANNEL_POSITION_REAR_LEFT
, PA_CHANNEL_POSITION_REAR_RIGHT
}}, "surround40" },
485 {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT
, PA_CHANNEL_POSITION_FRONT_RIGHT
,
486 PA_CHANNEL_POSITION_REAR_LEFT
, PA_CHANNEL_POSITION_REAR_RIGHT
,
487 PA_CHANNEL_POSITION_LFE
}}, "surround41" },
489 {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT
, PA_CHANNEL_POSITION_FRONT_RIGHT
,
490 PA_CHANNEL_POSITION_REAR_LEFT
, PA_CHANNEL_POSITION_REAR_RIGHT
,
491 PA_CHANNEL_POSITION_CENTER
}}, "surround50" },
493 {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT
, PA_CHANNEL_POSITION_FRONT_RIGHT
,
494 PA_CHANNEL_POSITION_REAR_LEFT
, PA_CHANNEL_POSITION_REAR_RIGHT
,
495 PA_CHANNEL_POSITION_CENTER
, PA_CHANNEL_POSITION_LFE
}}, "surround51" },
497 {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT
, PA_CHANNEL_POSITION_FRONT_RIGHT
,
498 PA_CHANNEL_POSITION_REAR_LEFT
, PA_CHANNEL_POSITION_REAR_RIGHT
,
499 PA_CHANNEL_POSITION_CENTER
, PA_CHANNEL_POSITION_LFE
,
500 PA_CHANNEL_POSITION_SIDE_LEFT
, PA_CHANNEL_POSITION_SIDE_RIGHT
}} , "surround71" },
505 static pa_bool_t
channel_map_superset(const pa_channel_map
*a
, const pa_channel_map
*b
) {
506 pa_bool_t in_a
[PA_CHANNEL_POSITION_MAX
];
512 memset(in_a
, 0, sizeof(in_a
));
514 for (i
= 0; i
< a
->channels
; i
++)
515 in_a
[a
->map
[i
]] = TRUE
;
517 for (i
= 0; i
< b
->channels
; i
++)
518 if (!in_a
[b
->map
[i
]])
524 snd_pcm_t
*pa_alsa_open_by_device_id(
531 snd_pcm_uframes_t
*period_size
,
532 snd_pcm_uframes_t tsched_size
,
534 pa_bool_t
*use_tsched
) {
540 snd_pcm_t
*pcm_handle
;
547 pa_assert(period_size
);
549 /* First we try to find a device string with a superset of the
550 * requested channel map and open it without the plug: prefix. We
551 * iterate through our device table from top to bottom and take
552 * the first that matches. If we didn't find a working device that
553 * way, we iterate backwards, and check all devices that do not
554 * provide a superset of the requested channel map.*/
556 for (i
= 0;; i
+= direction
) {
557 pa_sample_spec try_ss
;
560 pa_assert(direction
== -1);
562 /* OK, so we iterated backwards, and now are at the
563 * beginning of our list. */
567 } else if (!device_table
[i
].name
) {
568 pa_assert(direction
== 1);
570 /* OK, so we are at the end of our list. at iterated
577 if ((direction
> 0) == !channel_map_superset(&device_table
[i
].map
, map
))
580 d
= pa_sprintf_malloc("%s:%s", device_table
[i
].name
, dev_id
);
583 pa_log_debug("Trying %s...", d
);
585 /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <=
586 * 1.0.17a would then ignore the SND_PCM_NO_xxx
587 * flags. Instead we enable nonblock mode afterwards via
588 * snd_pcm_nonblock(). Also see
589 * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */
591 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
592 /* SND_PCM_NONBLOCK| */
593 SND_PCM_NO_AUTO_RESAMPLE
|
594 SND_PCM_NO_AUTO_CHANNELS
|
595 SND_PCM_NO_AUTO_FORMAT
)) < 0) {
596 pa_log_info("Couldn't open PCM device %s: %s", d
, snd_strerror(err
));
600 try_ss
.channels
= device_table
[i
].map
.channels
;
601 try_ss
.rate
= ss
->rate
;
602 try_ss
.format
= ss
->format
;
604 if ((err
= pa_alsa_set_hw_params(pcm_handle
, &try_ss
, nfrags
, period_size
, tsched_size
, use_mmap
, use_tsched
, TRUE
)) < 0) {
606 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
609 t
= pa_sprintf_malloc("plug:%s", d
);
613 snd_pcm_close(pcm_handle
);
617 pa_log_info("PCM device %s refused our hw parameters: %s", d
, snd_strerror(err
));
618 snd_pcm_close(pcm_handle
);
623 *map
= device_table
[i
].map
;
624 pa_assert(map
->channels
== ss
->channels
);
632 /* OK, we didn't find any good device, so let's try the raw plughw: stuff */
634 d
= pa_sprintf_malloc("hw:%s", dev_id
);
635 pa_log_debug("Trying %s as last resort...", d
);
636 pcm_handle
= pa_alsa_open_by_device_string(d
, dev
, ss
, map
, mode
, nfrags
, period_size
, tsched_size
, use_mmap
, use_tsched
);
642 snd_pcm_t
*pa_alsa_open_by_device_string(
649 snd_pcm_uframes_t
*period_size
,
650 snd_pcm_uframes_t tsched_size
,
652 pa_bool_t
*use_tsched
) {
656 snd_pcm_t
*pcm_handle
;
663 pa_assert(period_size
);
665 d
= pa_xstrdup(device
);
668 pa_log_debug("Trying %s...", d
);
670 /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <=
671 * 1.0.17a would then ignore the SND_PCM_NO_xxx flags. Instead
672 * we enable nonblock mode afterwards via
673 * snd_pcm_nonblock(). Also see
674 * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */
676 if ((err
= snd_pcm_open(&pcm_handle
, d
, mode
,
677 /*SND_PCM_NONBLOCK|*/
678 SND_PCM_NO_AUTO_RESAMPLE
|
679 SND_PCM_NO_AUTO_CHANNELS
|
680 SND_PCM_NO_AUTO_FORMAT
)) < 0) {
681 pa_log("Error opening PCM device %s: %s", d
, snd_strerror(err
));
686 if ((err
= pa_alsa_set_hw_params(pcm_handle
, ss
, nfrags
, period_size
, tsched_size
, use_mmap
, use_tsched
, FALSE
)) < 0) {
688 /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */
690 if (!pa_startswith(d
, "plug:") && !pa_startswith(d
, "plughw:")) {
693 t
= pa_sprintf_malloc("plug:%s", d
);
697 snd_pcm_close(pcm_handle
);
701 pa_log("Failed to set hardware parameters on %s: %s", d
, snd_strerror(err
));
703 snd_pcm_close(pcm_handle
);
709 if (ss
->channels
!= map
->channels
)
710 pa_channel_map_init_extend(map
, ss
->channels
, PA_CHANNEL_MAP_ALSA
);
716 int pa_alsa_prepare_mixer(snd_mixer_t
*mixer
, const char *dev
) {
722 if ((err
= snd_mixer_attach(mixer
, dev
)) < 0) {
723 pa_log_info("Unable to attach to mixer %s: %s", dev
, snd_strerror(err
));
727 if ((err
= snd_mixer_selem_register(mixer
, NULL
, NULL
)) < 0) {
728 pa_log_warn("Unable to register mixer: %s", snd_strerror(err
));
732 if ((err
= snd_mixer_load(mixer
)) < 0) {
733 pa_log_warn("Unable to load mixer: %s", snd_strerror(err
));
737 pa_log_info("Successfully attached to mixer '%s'", dev
);
742 snd_mixer_elem_t
*pa_alsa_find_elem(snd_mixer_t
*mixer
, const char *name
, const char *fallback
) {
743 snd_mixer_elem_t
*elem
;
744 snd_mixer_selem_id_t
*sid
= NULL
;
746 snd_mixer_selem_id_alloca(&sid
);
751 snd_mixer_selem_id_set_name(sid
, name
);
753 if (!(elem
= snd_mixer_find_selem(mixer
, sid
))) {
754 pa_log_info("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));
757 snd_mixer_selem_id_set_name(sid
, fallback
);
759 if (!(elem
= snd_mixer_find_selem(mixer
, sid
)))
760 pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));
765 pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));
770 static const snd_mixer_selem_channel_id_t alsa_channel_ids
[PA_CHANNEL_POSITION_MAX
] = {
771 [PA_CHANNEL_POSITION_MONO
] = SND_MIXER_SCHN_MONO
, /* The ALSA name is just an alias! */
773 [PA_CHANNEL_POSITION_FRONT_CENTER
] = SND_MIXER_SCHN_FRONT_CENTER
,
774 [PA_CHANNEL_POSITION_FRONT_LEFT
] = SND_MIXER_SCHN_FRONT_LEFT
,
775 [PA_CHANNEL_POSITION_FRONT_RIGHT
] = SND_MIXER_SCHN_FRONT_RIGHT
,
777 [PA_CHANNEL_POSITION_REAR_CENTER
] = SND_MIXER_SCHN_REAR_CENTER
,
778 [PA_CHANNEL_POSITION_REAR_LEFT
] = SND_MIXER_SCHN_REAR_LEFT
,
779 [PA_CHANNEL_POSITION_REAR_RIGHT
] = SND_MIXER_SCHN_REAR_RIGHT
,
781 [PA_CHANNEL_POSITION_LFE
] = SND_MIXER_SCHN_WOOFER
,
783 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
] = SND_MIXER_SCHN_UNKNOWN
,
784 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
] = SND_MIXER_SCHN_UNKNOWN
,
786 [PA_CHANNEL_POSITION_SIDE_LEFT
] = SND_MIXER_SCHN_SIDE_LEFT
,
787 [PA_CHANNEL_POSITION_SIDE_RIGHT
] = SND_MIXER_SCHN_SIDE_RIGHT
,
789 [PA_CHANNEL_POSITION_AUX0
] = SND_MIXER_SCHN_UNKNOWN
,
790 [PA_CHANNEL_POSITION_AUX1
] = SND_MIXER_SCHN_UNKNOWN
,
791 [PA_CHANNEL_POSITION_AUX2
] = SND_MIXER_SCHN_UNKNOWN
,
792 [PA_CHANNEL_POSITION_AUX3
] = SND_MIXER_SCHN_UNKNOWN
,
793 [PA_CHANNEL_POSITION_AUX4
] = SND_MIXER_SCHN_UNKNOWN
,
794 [PA_CHANNEL_POSITION_AUX5
] = SND_MIXER_SCHN_UNKNOWN
,
795 [PA_CHANNEL_POSITION_AUX6
] = SND_MIXER_SCHN_UNKNOWN
,
796 [PA_CHANNEL_POSITION_AUX7
] = SND_MIXER_SCHN_UNKNOWN
,
797 [PA_CHANNEL_POSITION_AUX8
] = SND_MIXER_SCHN_UNKNOWN
,
798 [PA_CHANNEL_POSITION_AUX9
] = SND_MIXER_SCHN_UNKNOWN
,
799 [PA_CHANNEL_POSITION_AUX10
] = SND_MIXER_SCHN_UNKNOWN
,
800 [PA_CHANNEL_POSITION_AUX11
] = SND_MIXER_SCHN_UNKNOWN
,
801 [PA_CHANNEL_POSITION_AUX12
] = SND_MIXER_SCHN_UNKNOWN
,
802 [PA_CHANNEL_POSITION_AUX13
] = SND_MIXER_SCHN_UNKNOWN
,
803 [PA_CHANNEL_POSITION_AUX14
] = SND_MIXER_SCHN_UNKNOWN
,
804 [PA_CHANNEL_POSITION_AUX15
] = SND_MIXER_SCHN_UNKNOWN
,
805 [PA_CHANNEL_POSITION_AUX16
] = SND_MIXER_SCHN_UNKNOWN
,
806 [PA_CHANNEL_POSITION_AUX17
] = SND_MIXER_SCHN_UNKNOWN
,
807 [PA_CHANNEL_POSITION_AUX18
] = SND_MIXER_SCHN_UNKNOWN
,
808 [PA_CHANNEL_POSITION_AUX19
] = SND_MIXER_SCHN_UNKNOWN
,
809 [PA_CHANNEL_POSITION_AUX20
] = SND_MIXER_SCHN_UNKNOWN
,
810 [PA_CHANNEL_POSITION_AUX21
] = SND_MIXER_SCHN_UNKNOWN
,
811 [PA_CHANNEL_POSITION_AUX22
] = SND_MIXER_SCHN_UNKNOWN
,
812 [PA_CHANNEL_POSITION_AUX23
] = SND_MIXER_SCHN_UNKNOWN
,
813 [PA_CHANNEL_POSITION_AUX24
] = SND_MIXER_SCHN_UNKNOWN
,
814 [PA_CHANNEL_POSITION_AUX25
] = SND_MIXER_SCHN_UNKNOWN
,
815 [PA_CHANNEL_POSITION_AUX26
] = SND_MIXER_SCHN_UNKNOWN
,
816 [PA_CHANNEL_POSITION_AUX27
] = SND_MIXER_SCHN_UNKNOWN
,
817 [PA_CHANNEL_POSITION_AUX28
] = SND_MIXER_SCHN_UNKNOWN
,
818 [PA_CHANNEL_POSITION_AUX29
] = SND_MIXER_SCHN_UNKNOWN
,
819 [PA_CHANNEL_POSITION_AUX30
] = SND_MIXER_SCHN_UNKNOWN
,
820 [PA_CHANNEL_POSITION_AUX31
] = SND_MIXER_SCHN_UNKNOWN
,
822 [PA_CHANNEL_POSITION_TOP_CENTER
] = SND_MIXER_SCHN_UNKNOWN
,
824 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER
] = SND_MIXER_SCHN_UNKNOWN
,
825 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT
] = SND_MIXER_SCHN_UNKNOWN
,
826 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
] = SND_MIXER_SCHN_UNKNOWN
,
828 [PA_CHANNEL_POSITION_TOP_REAR_CENTER
] = SND_MIXER_SCHN_UNKNOWN
,
829 [PA_CHANNEL_POSITION_TOP_REAR_LEFT
] = SND_MIXER_SCHN_UNKNOWN
,
830 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT
] = SND_MIXER_SCHN_UNKNOWN
834 int pa_alsa_calc_mixer_map(snd_mixer_elem_t
*elem
, const pa_channel_map
*channel_map
, snd_mixer_selem_channel_id_t mixer_map
[], pa_bool_t playback
) {
836 pa_bool_t alsa_channel_used
[SND_MIXER_SCHN_LAST
];
837 pa_bool_t mono_used
= FALSE
;
840 pa_assert(channel_map
);
841 pa_assert(mixer_map
);
843 memset(&alsa_channel_used
, 0, sizeof(alsa_channel_used
));
845 if (channel_map
->channels
> 1 &&
846 ((playback
&& snd_mixer_selem_has_playback_volume_joined(elem
)) ||
847 (!playback
&& snd_mixer_selem_has_capture_volume_joined(elem
)))) {
848 pa_log_info("ALSA device lacks independant volume controls for each channel.");
852 for (i
= 0; i
< channel_map
->channels
; i
++) {
853 snd_mixer_selem_channel_id_t id
;
856 is_mono
= channel_map
->map
[i
] == PA_CHANNEL_POSITION_MONO
;
857 id
= alsa_channel_ids
[channel_map
->map
[i
]];
859 if (!is_mono
&& id
== SND_MIXER_SCHN_UNKNOWN
) {
860 pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer.", pa_channel_position_to_string(channel_map
->map
[i
]));
864 if ((is_mono
&& mono_used
) || (!is_mono
&& alsa_channel_used
[id
])) {
865 pa_log_info("Channel map has duplicate channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map
->map
[i
]));
869 if ((playback
&& (!snd_mixer_selem_has_playback_channel(elem
, id
) || (is_mono
&& !snd_mixer_selem_is_playback_mono(elem
)))) ||
870 (!playback
&& (!snd_mixer_selem_has_capture_channel(elem
, id
) || (is_mono
&& !snd_mixer_selem_is_capture_mono(elem
))))) {
872 pa_log_info("ALSA device lacks separate volumes control for channel '%s'", pa_channel_position_to_string(channel_map
->map
[i
]));
877 mixer_map
[i
] = SND_MIXER_SCHN_MONO
;
881 alsa_channel_used
[id
] = TRUE
;
885 pa_log_info("All %u channels can be mapped to mixer channels.", channel_map
->channels
);
890 void pa_alsa_dump(snd_pcm_t
*pcm
) {
896 pa_assert_se(snd_output_buffer_open(&out
) == 0);
898 if ((err
= snd_pcm_dump(pcm
, out
)) < 0)
899 pa_log_debug("snd_pcm_dump(): %s", snd_strerror(err
));
902 snd_output_buffer_string(out
, &s
);
903 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s
));
906 pa_assert_se(snd_output_close(out
) == 0);
909 void pa_alsa_dump_status(snd_pcm_t
*pcm
) {
912 snd_pcm_status_t
*status
;
916 snd_pcm_status_alloca(&status
);
918 pa_assert_se(snd_output_buffer_open(&out
) == 0);
920 pa_assert_se(snd_pcm_status(pcm
, status
) == 0);
922 if ((err
= snd_pcm_status_dump(status
, out
)) < 0)
923 pa_log_debug("snd_pcm_dump(): %s", snd_strerror(err
));
926 snd_output_buffer_string(out
, &s
);
927 pa_log_debug("snd_pcm_dump():\n%s", pa_strnull(s
));
930 pa_assert_se(snd_output_close(out
) == 0);
933 static void alsa_error_handler(const char *file
, int line
, const char *function
, int err
, const char *fmt
,...) {
937 alsa_file
= pa_sprintf_malloc("(alsa-lib)%s", file
);
941 pa_log_levelv_meta(PA_LOG_INFO
, alsa_file
, line
, function
, fmt
, ap
);
948 static pa_atomic_t n_error_handler_installed
= PA_ATOMIC_INIT(0);
950 void pa_alsa_redirect_errors_inc(void) {
951 /* This is not really thread safe, but we do our best */
953 if (pa_atomic_inc(&n_error_handler_installed
) == 0)
954 snd_lib_error_set_handler(alsa_error_handler
);
957 void pa_alsa_redirect_errors_dec(void) {
960 pa_assert_se((r
= pa_atomic_dec(&n_error_handler_installed
)) >= 1);
963 snd_lib_error_set_handler(NULL
);
966 void pa_alsa_init_proplist(pa_proplist
*p
, snd_pcm_info_t
*pcm_info
) {
968 static const char * const alsa_class_table
[SND_PCM_CLASS_LAST
+1] = {
969 [SND_PCM_CLASS_GENERIC
] = "generic",
970 [SND_PCM_CLASS_MULTI
] = "multi",
971 [SND_PCM_CLASS_MODEM
] = "modem",
972 [SND_PCM_CLASS_DIGITIZER
] = "digitizer"
974 static const char * const class_table
[SND_PCM_CLASS_LAST
+1] = {
975 [SND_PCM_CLASS_GENERIC
] = "sound",
976 [SND_PCM_CLASS_MULTI
] = NULL
,
977 [SND_PCM_CLASS_MODEM
] = "modem",
978 [SND_PCM_CLASS_DIGITIZER
] = NULL
980 static const char * const alsa_subclass_table
[SND_PCM_SUBCLASS_LAST
+1] = {
981 [SND_PCM_SUBCLASS_GENERIC_MIX
] = "generic-mix",
982 [SND_PCM_SUBCLASS_MULTI_MIX
] = "multi-mix"
985 snd_pcm_class_t
class;
986 snd_pcm_subclass_t subclass
;
987 const char *n
, *id
, *sdn
;
988 char *cn
= NULL
, *lcn
= NULL
;
994 pa_proplist_sets(p
, PA_PROP_DEVICE_API
, "alsa");
996 class = snd_pcm_info_get_class(pcm_info
);
997 if (class <= SND_PCM_CLASS_LAST
) {
998 if (class_table
[class])
999 pa_proplist_sets(p
, PA_PROP_DEVICE_CLASS
, class_table
[class]);
1000 if (alsa_class_table
[class])
1001 pa_proplist_sets(p
, "alsa.class", alsa_class_table
[class]);
1003 subclass
= snd_pcm_info_get_subclass(pcm_info
);
1004 if (subclass
<= SND_PCM_SUBCLASS_LAST
)
1005 if (alsa_subclass_table
[subclass
])
1006 pa_proplist_sets(p
, "alsa.subclass", alsa_subclass_table
[subclass
]);
1008 if ((n
= snd_pcm_info_get_name(pcm_info
)))
1009 pa_proplist_sets(p
, "alsa.name", n
);
1011 if ((id
= snd_pcm_info_get_id(pcm_info
)))
1012 pa_proplist_sets(p
, "alsa.id", id
);
1014 pa_proplist_setf(p
, "alsa.subdevice", "%u", snd_pcm_info_get_subdevice(pcm_info
));
1015 if ((sdn
= snd_pcm_info_get_subdevice_name(pcm_info
)))
1016 pa_proplist_sets(p
, "alsa.subdevice_name", sdn
);
1018 pa_proplist_setf(p
, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info
));
1020 if ((card
= snd_pcm_info_get_card(pcm_info
)) >= 0) {
1021 pa_proplist_setf(p
, "alsa.card", "%i", card
);
1023 if (snd_card_get_name(card
, &cn
) >= 0)
1024 pa_proplist_sets(p
, "alsa.card_name", cn
);
1026 if (snd_card_get_longname(card
, &lcn
) >= 0)
1027 pa_proplist_sets(p
, "alsa.long_card_name", lcn
);
1031 pa_proplist_setf(p
, PA_PROP_DEVICE_DESCRIPTION
, "%s - %s", cn
, n
);
1033 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, cn
);
1035 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, n
);
1041 int pa_alsa_recover_from_poll(snd_pcm_t
*pcm
, int revents
) {
1042 snd_pcm_state_t state
;
1047 if (revents
& POLLERR
)
1048 pa_log_warn("Got POLLERR from ALSA");
1049 if (revents
& POLLNVAL
)
1050 pa_log_warn("Got POLLNVAL from ALSA");
1051 if (revents
& POLLHUP
)
1052 pa_log_warn("Got POLLHUP from ALSA");
1054 state
= snd_pcm_state(pcm
);
1055 pa_log_warn("PCM state is %s", snd_pcm_state_name(state
));
1057 /* Try to recover from this error */
1061 case SND_PCM_STATE_XRUN
:
1062 if ((err
= snd_pcm_recover(pcm
, -EPIPE
, 1)) != 0) {
1063 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err
));
1068 case SND_PCM_STATE_SUSPENDED
:
1069 if ((err
= snd_pcm_recover(pcm
, -ESTRPIPE
, 1)) != 0) {
1070 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err
));
1079 if ((err
= snd_pcm_prepare(pcm
)) < 0) {
1080 pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err
));
1089 pa_rtpoll_item
* pa_alsa_build_pollfd(snd_pcm_t
*pcm
, pa_rtpoll
*rtpoll
) {
1091 struct pollfd
*pollfd
;
1092 pa_rtpoll_item
*item
;
1096 if ((n
= snd_pcm_poll_descriptors_count(pcm
)) < 0) {
1097 pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n
));
1101 item
= pa_rtpoll_item_new(rtpoll
, PA_RTPOLL_NEVER
, (unsigned) n
);
1102 pollfd
= pa_rtpoll_item_get_pollfd(item
, NULL
);
1104 if ((err
= snd_pcm_poll_descriptors(pcm
, pollfd
, (unsigned) n
)) < 0) {
1105 pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err
));
1106 pa_rtpoll_item_free(item
);
1113 pa_cvolume
*pa_alsa_volume_divide(pa_cvolume
*r
, const pa_cvolume
*t
) {
1118 pa_assert(r
->channels
== t
->channels
);
1120 for (i
= 0; i
< r
->channels
; i
++) {
1123 a
= pa_sw_volume_to_linear(r
->values
[i
]); /* the hw volume */
1124 b
= pa_sw_volume_to_linear(t
->values
[i
]); /* the intended volume */
1131 r
->values
[i
] = pa_sw_volume_from_linear(c
);