mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
Completely rework ALSA device selection code: choose the device to open depending on the requested number of channels and channel map. In most cases it will now suffice to set default-channels=6 to enable 5.1 sound for all devices that support it
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2050 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
f752882525
commit
d17bb53d3e
15 changed files with 350 additions and 122 deletions
|
|
@ -57,6 +57,7 @@ PA_MODULE_LOAD_ONCE(FALSE);
|
|||
PA_MODULE_USAGE(
|
||||
"sink_name=<name for the sink> "
|
||||
"device=<ALSA device> "
|
||||
"device_id=<ALSA device id> "
|
||||
"format=<sample format> "
|
||||
"channels=<number of channels> "
|
||||
"rate=<sample rate> "
|
||||
|
|
@ -89,15 +90,16 @@ struct userdata {
|
|||
|
||||
char *device_name;
|
||||
|
||||
int use_mmap;
|
||||
pa_bool_t use_mmap;
|
||||
|
||||
int first;
|
||||
pa_bool_t first;
|
||||
|
||||
pa_rtpoll_item *alsa_rtpoll_item;
|
||||
};
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
"device",
|
||||
"device_id",
|
||||
"sink_name",
|
||||
"format",
|
||||
"channels",
|
||||
|
|
@ -127,7 +129,7 @@ static int mmap_write(struct userdata *u) {
|
|||
|
||||
if (n == -EPIPE) {
|
||||
pa_log_debug("snd_pcm_avail_update: Buffer underrun!");
|
||||
u->first = 1;
|
||||
u->first = TRUE;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0)
|
||||
|
|
@ -151,7 +153,7 @@ static int mmap_write(struct userdata *u) {
|
|||
|
||||
if (err == -EPIPE) {
|
||||
pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!");
|
||||
u->first = 1;
|
||||
u->first = TRUE;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
|
||||
|
|
@ -188,7 +190,7 @@ static int mmap_write(struct userdata *u) {
|
|||
|
||||
if (err == -EPIPE) {
|
||||
pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!");
|
||||
u->first = 1;
|
||||
u->first = TRUE;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
|
||||
|
|
@ -355,7 +357,8 @@ static int suspend(struct userdata *u) {
|
|||
|
||||
static int unsuspend(struct userdata *u) {
|
||||
pa_sample_spec ss;
|
||||
int err, b;
|
||||
int err;
|
||||
pa_bool_t b;
|
||||
unsigned nfrags;
|
||||
snd_pcm_uframes_t period_size;
|
||||
|
||||
|
|
@ -375,7 +378,7 @@ static int unsuspend(struct userdata *u) {
|
|||
period_size = u->fragment_size / u->frame_size;
|
||||
b = u->use_mmap;
|
||||
|
||||
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
|
||||
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b, TRUE)) < 0) {
|
||||
pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -405,7 +408,7 @@ static int unsuspend(struct userdata *u) {
|
|||
|
||||
/* FIXME: We need to reload the volume somehow */
|
||||
|
||||
u->first = 1;
|
||||
u->first = TRUE;
|
||||
|
||||
pa_log_info("Resumed successfully...");
|
||||
|
||||
|
|
@ -628,7 +631,7 @@ static void thread_func(void *userdata) {
|
|||
if (work_done && u->first) {
|
||||
pa_log_info("Starting playback.");
|
||||
snd_pcm_start(u->pcm_handle);
|
||||
u->first = 0;
|
||||
u->first = FALSE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -709,7 +712,7 @@ int pa__init(pa_module*m) {
|
|||
|
||||
pa_modargs *ma = NULL;
|
||||
struct userdata *u = NULL;
|
||||
char *dev;
|
||||
const char *dev_id;
|
||||
pa_sample_spec ss;
|
||||
pa_channel_map map;
|
||||
uint32_t nfrags, frag_size;
|
||||
|
|
@ -721,7 +724,7 @@ int pa__init(pa_module*m) {
|
|||
const char *name;
|
||||
char *name_buf = NULL;
|
||||
int namereg_fail;
|
||||
int use_mmap = 1, b;
|
||||
pa_bool_t use_mmap = TRUE, b;
|
||||
|
||||
snd_pcm_info_alloca(&pcm_info);
|
||||
|
||||
|
|
@ -761,7 +764,7 @@ int pa__init(pa_module*m) {
|
|||
u->module = m;
|
||||
m->userdata = u;
|
||||
u->use_mmap = use_mmap;
|
||||
u->first = 1;
|
||||
u->first = TRUE;
|
||||
pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
|
||||
u->rtpoll = pa_rtpoll_new();
|
||||
u->alsa_rtpoll_item = NULL;
|
||||
|
|
@ -769,43 +772,35 @@ int pa__init(pa_module*m) {
|
|||
|
||||
snd_config_update_free_global();
|
||||
|
||||
dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
|
||||
b = use_mmap;
|
||||
|
||||
for (;;) {
|
||||
if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
|
||||
|
||||
if (!(u->pcm_handle = pa_alsa_open_by_device_id(
|
||||
dev_id,
|
||||
&u->device_name,
|
||||
&ss, &map,
|
||||
SND_PCM_STREAM_PLAYBACK,
|
||||
&nfrags, &period_size,
|
||||
&b)))
|
||||
|
||||
if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
|
||||
pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err));
|
||||
pa_xfree(dev);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
b = use_mmap;
|
||||
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
|
||||
} else {
|
||||
|
||||
if (err == -EPERM) {
|
||||
/* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */
|
||||
|
||||
if (pa_startswith(dev, "hw:")) {
|
||||
char *d = pa_sprintf_malloc("plughw:%s", dev+3);
|
||||
pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d);
|
||||
pa_xfree(dev);
|
||||
dev = d;
|
||||
|
||||
snd_pcm_close(u->pcm_handle);
|
||||
u->pcm_handle = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
|
||||
pa_xfree(dev);
|
||||
if (!(u->pcm_handle = pa_alsa_open_by_device_string(
|
||||
pa_modargs_get_value(ma, "device", DEFAULT_DEVICE),
|
||||
&u->device_name,
|
||||
&ss, &map,
|
||||
SND_PCM_STREAM_PLAYBACK,
|
||||
&nfrags, &period_size,
|
||||
&b)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
u->device_name = dev;
|
||||
pa_assert(u->device_name);
|
||||
pa_log_info("Successfully opened device %s.", u->device_name);
|
||||
|
||||
if (use_mmap && !b) {
|
||||
pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode.");
|
||||
|
|
@ -828,15 +823,11 @@ int pa__init(pa_module*m) {
|
|||
/* ALSA might tweak the sample spec, so recalculate the frame size */
|
||||
frame_size = pa_frame_size(&ss);
|
||||
|
||||
if (ss.channels != map.channels)
|
||||
/* Seems ALSA didn't like the channel number, so let's fix the channel map */
|
||||
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
|
||||
|
||||
if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
|
||||
pa_log_warn("Error opening mixer: %s", snd_strerror(err));
|
||||
else {
|
||||
|
||||
if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) ||
|
||||
if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) ||
|
||||
!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) {
|
||||
|
||||
snd_mixer_close(u->mixer_handle);
|
||||
|
|
@ -847,7 +838,7 @@ int pa__init(pa_module*m) {
|
|||
if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
|
||||
namereg_fail = 1;
|
||||
else {
|
||||
name = name_buf = pa_sprintf_malloc("alsa_output.%s", dev);
|
||||
name = name_buf = pa_sprintf_malloc("alsa_output.%s", u->device_name);
|
||||
namereg_fail = 0;
|
||||
}
|
||||
|
||||
|
|
@ -867,7 +858,7 @@ int pa__init(pa_module*m) {
|
|||
pa_sink_set_rtpoll(u->sink, u->rtpoll);
|
||||
pa_sink_set_description(u->sink, t = pa_sprintf_malloc(
|
||||
"ALSA PCM on %s (%s)%s",
|
||||
dev,
|
||||
u->device_name,
|
||||
snd_pcm_info_get_name(pcm_info),
|
||||
use_mmap ? " via DMA" : ""));
|
||||
pa_xfree(t);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue