From 4d4956ea2f8df5f770f2137d8576afc6e5f161dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jan 2009 23:46:42 +0100 Subject: Add SPDIF/HDMI ALSA devices and device descriptions to device search table --- src/modules/alsa/alsa-util.c | 223 +++++++++++++++++++++++----------- src/modules/alsa/alsa-util.h | 4 +- src/modules/alsa/module-alsa-sink.c | 11 +- src/modules/alsa/module-alsa-source.c | 11 +- src/pulse/proplist.h | 8 +- 5 files changed, 184 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index ff3af19d..871471f1 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -474,33 +474,81 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min) { struct device_info { pa_channel_map map; + const char *alsa_name; + const char *description; const char *name; }; static const struct device_info device_table[] = { - {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, "front" }, + {{ 1, { PA_CHANNEL_POSITION_MONO }}, + "hw", + "Analog Mono", + "analog-mono" }, + + {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, + "front", + "Analog Stereo", + "analog-stereo" }, + + {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, + "iec958", + "IEC958 Digital Stereo", + "iec958-stereo" }, + + {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, + "hdmi", + "HDMI Digital Stereo", + "hdmi-stereo"}, {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "surround40" }, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, + "surround40", + "Analog Surround 4.0", + "analog-surround-40" }, + + {{ 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", + "iec958-ac3-surround-40" }, {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_LFE }}, "surround41" }, + PA_CHANNEL_POSITION_LFE }}, + "surround41", + "Analog Surround 4.1", + "analog-surround-41"}, {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_CENTER }}, "surround50" }, + PA_CHANNEL_POSITION_CENTER }}, + "surround50", + "Analog Surround 5.0", + "analog-surround-50" }, {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }}, "surround51" }, + PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }}, + "surround51", + "Analog Surround 5.1", + "analog-surround-51" }, + + {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_CENTER, + 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", + "iec958-ac3-surround-51" }, {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }} , "surround71" }, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }}, + "surround71", + "Analog Surround 7.1", + "analog-surround-71" }, - {{ 0, { 0 }}, NULL } + {{ 0, { 0 }}, NULL, NULL, NULL } }; static pa_bool_t channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { @@ -532,7 +580,9 @@ snd_pcm_t *pa_alsa_open_by_device_id( snd_pcm_uframes_t *period_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, - pa_bool_t *use_tsched) { + pa_bool_t *use_tsched, + const char**config_description, + const char **config_name) { int i; int direction = 1; @@ -554,90 +604,122 @@ snd_pcm_t *pa_alsa_open_by_device_id( * way, we iterate backwards, and check all devices that do not * provide a superset of the requested channel map.*/ - for (i = 0;; i += direction) { + i = 0; + for (;;) { pa_sample_spec try_ss; pa_bool_t reformat; - if (i < 0) { - pa_assert(direction == -1); - - /* OK, so we iterated backwards, and now are at the - * beginning of our list. */ + if ((direction > 0) == channel_map_superset(&device_table[i].map, map)) { + pa_log_debug("Checking for %s (%s)", device_table[i].name, device_table[i].alsa_name); - break; + d = pa_sprintf_malloc("%s:%s", device_table[i].alsa_name, dev_id); - } else if (!device_table[i].name) { - pa_assert(direction == 1); + reformat = FALSE; + for (;;) { + pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with"); - /* OK, so we are at the end of our list. at iterated - * forwards. */ + /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <= + * 1.0.17a would then ignore the SND_PCM_NO_xxx + * flags. Instead we enable nonblock mode afterwards via + * snd_pcm_nonblock(). Also see + * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */ - i--; - direction = -1; - } + if ((err = snd_pcm_open(&pcm_handle, d, mode, + /* SND_PCM_NONBLOCK| */ + SND_PCM_NO_AUTO_RESAMPLE| + SND_PCM_NO_AUTO_CHANNELS| + (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) { + pa_log_info("Couldn't open PCM device %s: %s", d, snd_strerror(err)); + break; + } - if ((direction > 0) == !channel_map_superset(&device_table[i].map, map)) - continue; + try_ss.channels = device_table[i].map.channels; + try_ss.rate = ss->rate; + try_ss.format = ss->format; - d = pa_sprintf_malloc("%s:%s", device_table[i].name, dev_id); + if ((err = pa_alsa_set_hw_params(pcm_handle, &try_ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, TRUE)) < 0) { - reformat = FALSE; - for (;;) { - pa_log_debug("Trying %s %s SND_PCM_NO_AUTO_FORMAT ...", d, reformat ? "without" : "with"); + if (!reformat) { + reformat = TRUE; + snd_pcm_close(pcm_handle); + continue; + } - /* We don't pass SND_PCM_NONBLOCK here, since alsa-lib <= - * 1.0.17a would then ignore the SND_PCM_NO_xxx - * flags. Instead we enable nonblock mode afterwards via - * snd_pcm_nonblock(). Also see - * http://mailman.alsa-project.org/pipermail/alsa-devel/2008-August/010258.html */ + if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) { + char *t; - if ((err = snd_pcm_open(&pcm_handle, d, mode, - /* SND_PCM_NONBLOCK| */ - SND_PCM_NO_AUTO_RESAMPLE| - SND_PCM_NO_AUTO_CHANNELS| - (reformat ? 0 : SND_PCM_NO_AUTO_FORMAT))) < 0) { - pa_log_info("Couldn't open PCM device %s: %s", d, snd_strerror(err)); - break; - } + t = pa_sprintf_malloc("plug:%s", d); + pa_xfree(d); + d = t; - try_ss.channels = device_table[i].map.channels; - try_ss.rate = ss->rate; - try_ss.format = ss->format; + reformat = FALSE; - if ((err = pa_alsa_set_hw_params(pcm_handle, &try_ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, TRUE)) < 0) { + snd_pcm_close(pcm_handle); + continue; + } - if (!reformat) { - reformat = TRUE; + pa_log_info("PCM device %s refused our hw parameters: %s", d, snd_strerror(err)); snd_pcm_close(pcm_handle); - continue; + break; } - if (!pa_startswith(d, "plug:") && !pa_startswith(d, "plughw:")) { - char *t; - - t = pa_sprintf_malloc("plug:%s", d); - pa_xfree(d); - d = t; + *ss = try_ss; + *map = device_table[i].map; + pa_assert(map->channels == ss->channels); + *dev = d; + if (config_description) + *config_description = device_table[i].description; + if (config_name) + *config_name = device_table[i].name; - reformat = FALSE; + return pcm_handle; + } - snd_pcm_close(pcm_handle); - continue; - } + pa_xfree(d); + } - pa_log_info("PCM device %s refused our hw parameters: %s", d, snd_strerror(err)); - snd_pcm_close(pcm_handle); - break; + if (direction > 0) { + if (!device_table[i+1].alsa_name) { + /* OK, so we are at the end of our list. Let's turn + * back. */ + direction = -1; + } else { + /* We are not at the end of the list, so let's simply + * try the next entry */ + i++; } - - *ss = try_ss; - *map = device_table[i].map; - pa_assert(map->channels == ss->channels); - *dev = d; - return pcm_handle; } - pa_xfree(d); + if (direction < 0) { + + if (device_table[i+1].alsa_name && + device_table[i].map.channels == device_table[i+1].map.channels) { + + /* OK, the next entry has the same number of channels, + * let's try it */ + i++; + + } else { + /* Hmm, so the next entry does not have the same + * number of channels, so let's go backwards until we + * find the next entry with a differnt number of + * channels */ + + for (i--; i >= 0; i--) + if (device_table[i].map.channels != device_table[i+1].map.channels) + break; + + /* Hmm, there is no entry with a different number of + * entries, then we're done */ + if (i < 0) + break; + + /* OK, now lets find go back as long as we have the same number of channels */ + for (; i > 0; i--) + if (device_table[i].map.channels != device_table[i-1].map.channels) + break; + } + } } /* OK, we didn't find any good device, so let's try the raw plughw: stuff */ @@ -647,6 +729,11 @@ snd_pcm_t *pa_alsa_open_by_device_id( pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched); pa_xfree(d); + if (pcm_handle) { + *config_description = NULL; + *config_name = NULL; + } + return pcm_handle; } diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 95bb983a..ce5f0eb6 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -64,7 +64,9 @@ snd_pcm_t *pa_alsa_open_by_device_id( snd_pcm_uframes_t *period_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, - pa_bool_t *use_tsched); + pa_bool_t *use_tsched, + const char **config_name, + const char **config_description); snd_pcm_t *pa_alsa_open_by_device_string( const char *device, diff --git a/src/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c index a3e818dd..dfa20557 100644 --- a/src/modules/alsa/module-alsa-sink.c +++ b/src/modules/alsa/module-alsa-sink.c @@ -1253,6 +1253,7 @@ int pa__init(pa_module*m) { pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d; pa_usec_t usec; pa_sink_new_data data; + const char *profile_description = NULL, *profile_name = NULL; snd_pcm_info_alloca(&pcm_info); @@ -1338,7 +1339,7 @@ int pa__init(pa_module*m) { &ss, &map, SND_PCM_STREAM_PLAYBACK, &nfrags, &period_frames, tsched_frames, - &b, &d))) + &b, &d, &profile_description, &profile_name))) goto fail; @@ -1358,6 +1359,9 @@ int pa__init(pa_module*m) { pa_assert(u->device_name); pa_log_info("Successfully opened device %s.", u->device_name); + if (profile_description) + pa_log_info("Selected configuration '%s' (%s).", profile_description, profile_name); + if (use_mmap && !b) { pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); u->use_mmap = use_mmap = FALSE; @@ -1441,6 +1445,11 @@ int pa__init(pa_module*m) { pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); + if (profile_name) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_NAME, profile_name); + if (profile_description) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, profile_description); + u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY); pa_sink_new_data_done(&data); pa_xfree(name_buf); diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c index 901db01f..f89b6e2e 100644 --- a/src/modules/alsa/module-alsa-source.c +++ b/src/modules/alsa/module-alsa-source.c @@ -1087,6 +1087,7 @@ int pa__init(pa_module*m) { pa_bool_t namereg_fail; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d; pa_source_new_data data; + const char *profile_description = NULL, *profile_name = NULL; snd_pcm_info_alloca(&pcm_info); @@ -1167,7 +1168,7 @@ int pa__init(pa_module*m) { &ss, &map, SND_PCM_STREAM_CAPTURE, &nfrags, &period_frames, tsched_frames, - &b, &d))) + &b, &d, &profile_description, &profile_name))) goto fail; } else { @@ -1185,6 +1186,9 @@ int pa__init(pa_module*m) { pa_assert(u->device_name); pa_log_info("Successfully opened device %s.", u->device_name); + if (profile_description) + pa_log_info("Selected configuration '%s' (%s).", profile_description, profile_name); + if (use_mmap && !b) { pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); u->use_mmap = use_mmap = FALSE; @@ -1268,6 +1272,11 @@ int pa__init(pa_module*m) { pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); + if (profile_name) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_NAME, profile_name); + if (profile_description) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, profile_description); + u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); pa_source_new_data_done(&data); pa_xfree(name_buf); diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index 5d65ff3c..77f0399c 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -75,8 +75,10 @@ PA_C_DECL_BEGIN * device.connector isa, pci, usb, firewire, bluetooth * device.access_mode mmap, mmap_rewrite, serial * device.master_device - * device.bufferin.buffer_size - * device.bufferin.fragment_size + * device.buffering.buffer_size + * device.buffering.fragment_size + * device.profile.name analog-stereo, analog-surround-40, iec958-stereo, ... + * device.profile.description "Analog Stereo", ... */ #define PA_PROP_MEDIA_NAME "media.name" #define PA_PROP_MEDIA_TITLE "media.title" @@ -124,6 +126,8 @@ PA_C_DECL_BEGIN #define PA_PROP_DEVICE_MASTER_DEVICE "device.master_device" #define PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE "device.buffering.buffer_size" #define PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE "device.buffering.fragment_size" +#define PA_PROP_DEVICE_PROFILE_NAME "device.profile.name" +#define PA_PROP_DEVICE_PROFILE_DESCRIPTION "device.profile.description" /** A property list object. Basically a dictionary with UTF-8 strings * as keys and arbitrary data as values. \since 0.9.11 */ -- cgit