diff options
Diffstat (limited to 'src/modules/alsa/alsa-util.c')
-rw-r--r-- | src/modules/alsa/alsa-util.c | 185 |
1 files changed, 157 insertions, 28 deletions
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 5236d02f..d00a80f1 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2004-2006 Lennart Poettering + Copyright 2004-2009 Lennart Poettering Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB PulseAudio is free software; you can redistribute it and/or modify @@ -32,11 +32,13 @@ #include <pulse/xmalloc.h> #include <pulse/timeval.h> #include <pulse/util.h> +#include <pulse/i18n.h> #include <pulsecore/log.h> #include <pulsecore/macro.h> #include <pulsecore/core-util.h> #include <pulsecore/atomic.h> +#include <pulsecore/core-error.h> #include "alsa-util.h" @@ -112,7 +114,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { struct pa_alsa_fdlist *fdl = userdata; unsigned num_fds, i; - int err; + int err, n; struct pollfd *temp; pa_assert(a); @@ -121,7 +123,11 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { a->defer_enable(fdl->defer, 0); - num_fds = (unsigned) snd_mixer_poll_descriptors_count(fdl->mixer); + if ((n = snd_mixer_poll_descriptors_count(fdl->mixer)) < 0) { + pa_log("snd_mixer_poll_descriptors_count() failed: %s", snd_strerror(n)); + return; + } + num_fds = (unsigned) n; if (num_fds != fdl->num_fds) { if (fdl->fds) @@ -342,7 +348,8 @@ int pa_alsa_set_hw_params( goto finish; if (_use_mmap) { - if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + + if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* mmap() didn't work, fall back to interleaved */ @@ -462,6 +469,7 @@ finish: int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) { snd_pcm_sw_params_t *swparams; + snd_pcm_uframes_t boundary; int err; pa_assert(pcm); @@ -473,7 +481,22 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) { return err; } - if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, 0)) < 0) { + pa_log_warn("Unable to disable period event: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) { + pa_log_warn("Unable to enable time stamping: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) { + pa_log_warn("Unable to get boundary: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) { pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err)); return err; } @@ -499,39 +522,39 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) { static const struct pa_alsa_profile_info device_table[] = { {{ 1, { PA_CHANNEL_POSITION_MONO }}, "hw", - "Analog Mono", + N_("Analog Mono"), "analog-mono", 1 }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "front", - "Analog Stereo", + N_("Analog Stereo"), "analog-stereo", 10 }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "iec958", - "IEC958 Digital Stereo", + N_("Digital Stereo (IEC958)"), "iec958-stereo", 5 }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "hdmi", - "HDMI Digital Stereo", + N_("Digital Stereo (HDMI)"), "hdmi-stereo", 4 }, {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "surround40", - "Analog Surround 4.0", + N_("Analog Surround 4.0"), "analog-surround-40", 7 }, {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "a52", - "IEC958/AC3 Digital Surround 4.0", + N_("Digital Surround 4.0 (IEC958/AC3)"), "iec958-ac3-surround-40", 2 }, @@ -539,7 +562,7 @@ static const struct pa_alsa_profile_info device_table[] = { PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE }}, "surround41", - "Analog Surround 4.1", + N_("Analog Surround 4.1"), "analog-surround-41", 7 }, @@ -547,7 +570,7 @@ static const struct pa_alsa_profile_info device_table[] = { PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_CENTER }}, "surround50", - "Analog Surround 5.0", + N_("Analog Surround 5.0"), "analog-surround-50", 7 }, @@ -555,7 +578,7 @@ static const struct pa_alsa_profile_info device_table[] = { PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }}, "surround51", - "Analog Surround 5.1", + N_("Analog Surround 5.1"), "analog-surround-51", 8 }, @@ -563,7 +586,7 @@ static const struct pa_alsa_profile_info device_table[] = { PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE}}, "a52", - "IEC958/AC3 Digital Surround 5.1", + N_("Digital Surround 5.1 (IEC958/AC3)"), "iec958-ac3-surround-51", 3 }, @@ -572,7 +595,7 @@ static const struct pa_alsa_profile_info device_table[] = { PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }}, "surround71", - "Analog Surround 7.1", + N_("Analog Surround 7.1"), "analog-surround-71", 7 }, @@ -805,8 +828,7 @@ snd_pcm_t *pa_alsa_open_by_device_string( SND_PCM_NO_AUTO_CHANNELS| (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) { pa_log_info("Error opening PCM device %s: %s", d, snd_strerror(err)); - pa_xfree(d); - return NULL; + goto fail; } if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) { @@ -834,9 +856,9 @@ snd_pcm_t *pa_alsa_open_by_device_string( } pa_log_info("Failed to set hardware parameters on %s: %s", d, snd_strerror(err)); - pa_xfree(d); snd_pcm_close(pcm_handle); - return NULL; + + goto fail; } if (dev) @@ -849,6 +871,11 @@ snd_pcm_t *pa_alsa_open_by_device_string( return pcm_handle; } + +fail: + pa_xfree(d); + + return NULL; } int pa_alsa_probe_profiles( @@ -1057,6 +1084,86 @@ success: return elem; } + +int pa_alsa_find_mixer_and_elem( + snd_pcm_t *pcm, + snd_mixer_t **_m, + snd_mixer_elem_t **_e) { + + int err; + snd_mixer_t *m; + snd_mixer_elem_t *e; + pa_bool_t found = FALSE; + const char *dev; + + pa_assert(pcm); + pa_assert(_m); + pa_assert(_e); + + if ((err = snd_mixer_open(&m, 0)) < 0) { + pa_log("Error opening mixer: %s", snd_strerror(err)); + return -1; + } + + /* First, try by name */ + if ((dev = snd_pcm_name(pcm))) + if (pa_alsa_prepare_mixer(m, dev) >= 0) + found = TRUE; + + /* Then, try by card index */ + if (!found) { + snd_pcm_info_t* info; + snd_pcm_info_alloca(&info); + + if (snd_pcm_info(pcm, info) >= 0) { + char *md; + int card_idx; + + if ((card_idx = snd_pcm_info_get_card(info)) >= 0) { + + md = pa_sprintf_malloc("hw:%i", card_idx); + + if (!dev || !pa_streq(dev, md)) + if (pa_alsa_prepare_mixer(m, md) >= 0) + found = TRUE; + + pa_xfree(md); + } + } + } + + if (!found) { + snd_mixer_close(m); + return -1; + } + + switch (snd_pcm_stream(pcm)) { + + case SND_PCM_STREAM_PLAYBACK: + e = pa_alsa_find_elem(m, "Master", "PCM", TRUE); + break; + + case SND_PCM_STREAM_CAPTURE: + e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE); + break; + + default: + pa_assert_not_reached(); + } + + if (!e) { + snd_mixer_close(m); + return -1; + } + + pa_assert(e && m); + + *_m = m; + *_e = e; + + return 0; +} + static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = { [PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */ @@ -1281,7 +1388,7 @@ void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) { #endif } -void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) { +void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info) { static const char * const alsa_class_table[SND_PCM_CLASS_LAST+1] = { [SND_PCM_CLASS_GENERIC] = "generic", @@ -1302,7 +1409,7 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_i snd_pcm_class_t class; snd_pcm_subclass_t subclass; - const char *n, *id, *sdn, *cn; + const char *n, *id, *sdn, *cn = NULL; int card; pa_assert(p); @@ -1347,6 +1454,28 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_i pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, n); } +void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) { + snd_pcm_hw_params_t *hwparams; + snd_pcm_info_t *info; + int bits, err; + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_info_alloca(&info); + + if ((err = snd_pcm_hw_params_current(pcm, hwparams)) < 0) + pa_log_warn("Error fetching hardware parameter info: %s", snd_strerror(err)); + else { + + if ((bits = snd_pcm_hw_params_get_sbits(hwparams)) >= 0) + pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits); + } + + if ((err = snd_pcm_info(pcm, info)) < 0) + pa_log_warn("Error fetching PCM info: %s", snd_strerror(err)); + else + pa_alsa_init_proplist_pcm_info(c, p, info); +} + int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) { snd_pcm_state_t state; int err; @@ -1425,7 +1554,7 @@ pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) { return item; } -snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) { +snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) { snd_pcm_sframes_t n; size_t k; @@ -1436,7 +1565,7 @@ snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, c /* Some ALSA driver expose weird bugs, let's inform the user about * what is going on */ - n = snd_pcm_avail_update(pcm); + n = snd_pcm_avail(pcm); if (n <= 0) return n; @@ -1445,8 +1574,8 @@ snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, c if (k >= hwbuf_size * 3 || k >= pa_bytes_per_second(ss)*10) - pa_log("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms) " - "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.", + pa_log(_("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms). " + "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers."), (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); return n; @@ -1477,8 +1606,8 @@ int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas k >= hwbuf_size * 3 || k >= pa_bytes_per_second(ss)*10) - pa_log("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms) " - "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.", + pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms). " + "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers."), (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); return r; |