4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <sys/types.h>
30 #include <asoundlib.h>
32 #include <pulse/sample.h>
33 #include <pulse/xmalloc.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/macro.h>
38 #include "alsa-util.h"
40 struct pa_alsa_fdlist
{
43 /* This is a temporary buffer used to avoid lots of mallocs */
44 struct pollfd
*work_fds
;
49 pa_defer_event
*defer
;
54 void (*cb
)(void *userdata
);
58 static void io_cb(pa_mainloop_api
*a
, pa_io_event
* e
, PA_GCC_UNUSED
int fd
, pa_io_event_flags_t events
, void *userdata
) {
60 struct pa_alsa_fdlist
*fdl
= userdata
;
62 unsigned short revents
;
66 pa_assert(fdl
->mixer
);
68 pa_assert(fdl
->work_fds
);
75 memcpy(fdl
->work_fds
, fdl
->fds
, sizeof(struct pollfd
) * fdl
->num_fds
);
77 for (i
= 0;i
< fdl
->num_fds
; i
++) {
78 if (e
== fdl
->ios
[i
]) {
79 if (events
& PA_IO_EVENT_INPUT
)
80 fdl
->work_fds
[i
].revents
|= POLLIN
;
81 if (events
& PA_IO_EVENT_OUTPUT
)
82 fdl
->work_fds
[i
].revents
|= POLLOUT
;
83 if (events
& PA_IO_EVENT_ERROR
)
84 fdl
->work_fds
[i
].revents
|= POLLERR
;
85 if (events
& PA_IO_EVENT_HANGUP
)
86 fdl
->work_fds
[i
].revents
|= POLLHUP
;
91 assert(i
!= fdl
->num_fds
);
93 if ((err
= snd_mixer_poll_descriptors_revents(fdl
->mixer
, fdl
->work_fds
, fdl
->num_fds
, &revents
)) < 0) {
94 pa_log_error("Unable to get poll revent: %s", snd_strerror(err
));
98 a
->defer_enable(fdl
->defer
, 1);
101 snd_mixer_handle_events(fdl
->mixer
);
104 static void defer_cb(pa_mainloop_api
*a
, PA_GCC_UNUSED pa_defer_event
* e
, void *userdata
) {
105 struct pa_alsa_fdlist
*fdl
= userdata
;
111 pa_assert(fdl
->mixer
);
113 a
->defer_enable(fdl
->defer
, 0);
115 num_fds
= snd_mixer_poll_descriptors_count(fdl
->mixer
);
116 pa_assert(num_fds
> 0);
118 if (num_fds
!= fdl
->num_fds
) {
122 pa_xfree(fdl
->work_fds
);
123 fdl
->fds
= pa_xnew0(struct pollfd
, num_fds
);
124 fdl
->work_fds
= pa_xnew(struct pollfd
, num_fds
);
127 memset(fdl
->work_fds
, 0, sizeof(struct pollfd
) * num_fds
);
129 if ((err
= snd_mixer_poll_descriptors(fdl
->mixer
, fdl
->work_fds
, num_fds
)) < 0) {
130 pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err
));
136 if (memcmp(fdl
->fds
, fdl
->work_fds
, sizeof(struct pollfd
) * num_fds
) == 0)
140 for (i
= 0; i
< fdl
->num_fds
; i
++)
141 a
->io_free(fdl
->ios
[i
]);
143 if (num_fds
!= fdl
->num_fds
) {
150 fdl
->ios
= pa_xnew(pa_io_event
*, num_fds
);
153 temp
= fdl
->work_fds
;
154 fdl
->work_fds
= fdl
->fds
;
157 fdl
->num_fds
= num_fds
;
159 for (i
= 0;i
< num_fds
;i
++)
160 fdl
->ios
[i
] = a
->io_new(a
, fdl
->fds
[i
].fd
,
161 ((fdl
->fds
[i
].events
& POLLIN
) ? PA_IO_EVENT_INPUT
: 0) |
162 ((fdl
->fds
[i
].events
& POLLOUT
) ? PA_IO_EVENT_OUTPUT
: 0),
166 struct pa_alsa_fdlist
*pa_alsa_fdlist_new(void) {
167 struct pa_alsa_fdlist
*fdl
;
169 fdl
= pa_xnew0(struct pa_alsa_fdlist
, 1);
173 fdl
->work_fds
= NULL
;
183 void pa_alsa_fdlist_free(struct pa_alsa_fdlist
*fdl
) {
188 fdl
->m
->defer_free(fdl
->defer
);
194 for (i
= 0;i
< fdl
->num_fds
;i
++)
195 fdl
->m
->io_free(fdl
->ios
[i
]);
202 pa_xfree(fdl
->work_fds
);
207 int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist
*fdl
, snd_mixer_t
*mixer_handle
, pa_mainloop_api
* m
) {
209 pa_assert(mixer_handle
);
213 fdl
->mixer
= mixer_handle
;
215 fdl
->defer
= m
->defer_new(m
, defer_cb
, fdl
);
220 static int set_format(snd_pcm_t
*pcm_handle
, snd_pcm_hw_params_t
*hwparams
, pa_sample_format_t
*f
) {
222 static const snd_pcm_format_t format_trans
[] = {
223 [PA_SAMPLE_U8
] = SND_PCM_FORMAT_U8
,
224 [PA_SAMPLE_ALAW
] = SND_PCM_FORMAT_A_LAW
,
225 [PA_SAMPLE_ULAW
] = SND_PCM_FORMAT_MU_LAW
,
226 [PA_SAMPLE_S16LE
] = SND_PCM_FORMAT_S16_LE
,
227 [PA_SAMPLE_S16BE
] = SND_PCM_FORMAT_S16_BE
,
228 [PA_SAMPLE_FLOAT32LE
] = SND_PCM_FORMAT_FLOAT_LE
,
229 [PA_SAMPLE_FLOAT32BE
] = SND_PCM_FORMAT_FLOAT_BE
,
232 static const pa_sample_format_t try_order
[] = {
245 pa_assert(pcm_handle
);
248 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
251 if (*f
== PA_SAMPLE_FLOAT32BE
)
252 *f
= PA_SAMPLE_FLOAT32LE
;
253 else if (*f
== PA_SAMPLE_FLOAT32LE
)
254 *f
= PA_SAMPLE_FLOAT32BE
;
255 else if (*f
== PA_SAMPLE_S16BE
)
256 *f
= PA_SAMPLE_S16LE
;
257 else if (*f
== PA_SAMPLE_S16LE
)
258 *f
= PA_SAMPLE_S16BE
;
262 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
267 for (i
= 0; try_order
[i
] != PA_SAMPLE_INVALID
; i
++) {
270 if ((ret
= snd_pcm_hw_params_set_format(pcm_handle
, hwparams
, format_trans
[*f
])) >= 0)
277 /* Set the hardware parameters of the given ALSA device. Returns the
278 * selected fragment settings in *period and *period_size */
279 int pa_alsa_set_hw_params(snd_pcm_t
*pcm_handle
, pa_sample_spec
*ss
, uint32_t *periods
, snd_pcm_uframes_t
*period_size
, int *use_mmap
) {
281 snd_pcm_uframes_t buffer_size
;
282 unsigned int r
= ss
->rate
;
283 unsigned int c
= ss
->channels
;
284 pa_sample_format_t f
= ss
->format
;
285 snd_pcm_hw_params_t
*hwparams
;
287 pa_assert(pcm_handle
);
290 pa_assert(period_size
);
292 snd_pcm_hw_params_alloca(&hwparams
);
294 buffer_size
= *periods
* *period_size
;
296 if ((ret
= snd_pcm_hw_params_any(pcm_handle
, hwparams
)) < 0 ||
297 (ret
= snd_pcm_hw_params_set_rate_resample(pcm_handle
, hwparams
, 0)) < 0)
300 if (use_mmap
&& *use_mmap
) {
301 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_MMAP_INTERLEAVED
)) < 0)
302 if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
305 } else if ((ret
= snd_pcm_hw_params_set_access(pcm_handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
310 if ((ret
= set_format(pcm_handle
, hwparams
, &f
)) < 0)
313 if ((ret
= snd_pcm_hw_params_set_rate_near(pcm_handle
, hwparams
, &r
, NULL
)) < 0)
316 if ((ret
= snd_pcm_hw_params_set_channels_near(pcm_handle
, hwparams
, &c
)) < 0)
319 if ((*period_size
> 0 && (ret
= snd_pcm_hw_params_set_period_size_near(pcm_handle
, hwparams
, period_size
, NULL
)) < 0) ||
320 (*periods
> 0 && (ret
= snd_pcm_hw_params_set_buffer_size_near(pcm_handle
, hwparams
, &buffer_size
)) < 0))
323 if ((ret
= snd_pcm_hw_params(pcm_handle
, hwparams
)) < 0)
327 pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle
), ss
->rate
, r
);
329 /* If the sample rate deviates too much, we need to resample */
330 if (r
< ss
->rate
*.95 || r
> ss
->rate
*1.05)
334 if (ss
->channels
!= c
) {
335 pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle
), ss
->channels
, c
);
339 if (ss
->format
!= f
) {
340 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
));
344 if ((ret
= snd_pcm_prepare(pcm_handle
)) < 0)
347 if ((ret
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
)) < 0 ||
348 (ret
= snd_pcm_hw_params_get_period_size(hwparams
, period_size
, NULL
)) < 0)
351 pa_assert(buffer_size
> 0);
352 pa_assert(*period_size
> 0);
353 *periods
= buffer_size
/ *period_size
;
354 pa_assert(*periods
> 0);
363 int pa_alsa_set_sw_params(snd_pcm_t
*pcm
) {
364 snd_pcm_sw_params_t
*swparams
;
369 snd_pcm_sw_params_alloca(&swparams
);
371 if ((err
= snd_pcm_sw_params_current(pcm
, swparams
) < 0)) {
372 pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err
));
376 if ((err
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
377 pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err
));
381 if ((err
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, (snd_pcm_uframes_t
) -1)) < 0) {
382 pa_log_warn("Unable to set start threshold: %s\n", snd_strerror(err
));
386 if ((err
= snd_pcm_sw_params(pcm
, swparams
)) < 0) {
387 pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err
));
394 int pa_alsa_prepare_mixer(snd_mixer_t
*mixer
, const char *dev
) {
400 if ((err
= snd_mixer_attach(mixer
, dev
)) < 0) {
401 pa_log_warn("Unable to attach to mixer %s: %s", dev
, snd_strerror(err
));
405 if ((err
= snd_mixer_selem_register(mixer
, NULL
, NULL
)) < 0) {
406 pa_log_warn("Unable to register mixer: %s", snd_strerror(err
));
410 if ((err
= snd_mixer_load(mixer
)) < 0) {
411 pa_log_warn("Unable to load mixer: %s", snd_strerror(err
));
418 snd_mixer_elem_t
*pa_alsa_find_elem(snd_mixer_t
*mixer
, const char *name
, const char *fallback
) {
419 snd_mixer_elem_t
*elem
;
420 snd_mixer_selem_id_t
*sid
= NULL
;
422 snd_mixer_selem_id_alloca(&sid
);
427 snd_mixer_selem_id_set_name(sid
, name
);
429 if (!(elem
= snd_mixer_find_selem(mixer
, sid
))) {
430 pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));
433 snd_mixer_selem_id_set_name(sid
, fallback
);
435 if (!(elem
= snd_mixer_find_selem(mixer
, sid
)))
436 pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));
441 pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid
));