From d17bb53d3ebfbd7046719400264bd87830c140d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:37:44 +0000 Subject: 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 --- src/modules/module-alsa-sink.c | 85 +++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 47 deletions(-) (limited to 'src/modules/module-alsa-sink.c') diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 636b413c..e62b8a06 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -57,6 +57,7 @@ PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "device= " + "device_id= " "format= " "channels= " "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)); - - for (;;) { - - 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; - b = use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { - if (err == -EPERM) { - /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ + 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 (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; + goto fail; - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - continue; - } - } + } else { - 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); -- cgit