From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 28 Apr 2009 23:58:18 +0000 (+0200)
Subject: alsa: allow configuration of fallback device strings in profiles
X-Git-Url: http://git.0pointer.de/?p=pulseaudio.git;a=commitdiff_plain;h=d8710711fb0c74b4ad83ac99c2501218155b502b

alsa: allow configuration of fallback device strings in profiles

This has the benefit that we can properly support ALSA devices where
only the raw 'hw' device exists but no 'front' although it's a proper
2ch stereo device.
---

diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 18d6880..a3a0450 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -528,7 +528,7 @@ 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",
+     "hw", NULL,
      N_("Analog Mono"),
      "analog-mono",
      1,
@@ -536,7 +536,7 @@ static const struct pa_alsa_profile_info device_table[] = {
      "Capture", "Mic" },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
-     "front",
+     "front", "hw",
      N_("Analog Stereo"),
      "analog-stereo",
      10,
@@ -544,7 +544,7 @@ static const struct pa_alsa_profile_info device_table[] = {
      "Capture", "Mic" },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
-     "iec958",
+     "iec958", NULL,
      N_("Digital Stereo (IEC958)"),
      "iec958-stereo",
      5,
@@ -552,7 +552,7 @@ static const struct pa_alsa_profile_info device_table[] = {
      "IEC958 In", NULL },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
-     "hdmi",
+     "hdmi", NULL,
      N_("Digital Stereo (HDMI)"),
      "hdmi-stereo",
      4,
@@ -561,7 +561,7 @@ static const struct pa_alsa_profile_info device_table[] = {
 
     {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
-     "surround40",
+     "surround40", NULL,
      N_("Analog Surround 4.0"),
      "analog-surround-40",
      7,
@@ -570,7 +570,7 @@ static const struct pa_alsa_profile_info device_table[] = {
 
     {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
-     "a52",
+     "a52", NULL,
      N_("Digital Surround 4.0 (IEC958/AC3)"),
      "iec958-ac3-surround-40",
      2,
@@ -580,7 +580,7 @@ static const struct pa_alsa_profile_info device_table[] = {
     {{ 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",
+     "surround41", NULL,
      N_("Analog Surround 4.1"),
      "analog-surround-41",
      7,
@@ -590,7 +590,7 @@ static const struct pa_alsa_profile_info device_table[] = {
     {{ 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",
+     "surround50", NULL,
      N_("Analog Surround 5.0"),
      "analog-surround-50",
      7,
@@ -600,7 +600,7 @@ static const struct pa_alsa_profile_info device_table[] = {
     {{ 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",
+     "surround51", NULL,
      N_("Analog Surround 5.1"),
      "analog-surround-51",
      8,
@@ -610,7 +610,7 @@ static const struct pa_alsa_profile_info device_table[] = {
     {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
             PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE}},
-     "a52",
+     "a52", NULL,
      N_("Digital Surround 5.1 (IEC958/AC3)"),
      "iec958-ac3-surround-51",
      3,
@@ -621,16 +621,72 @@ 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,
             PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }},
-     "surround71",
+     "surround71", NULL,
      N_("Analog Surround 7.1"),
      "analog-surround-71",
      7,
      "Master", "PCM",
      "Capture", "Mic" },
 
-    {{ 0, { 0 }}, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
+    {{ 0, { 0 }}, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
 };
 
+static snd_pcm_t *open_by_device_string_with_fallback(
+        const char *prefix,
+        const char *prefix_fallback,
+        const char *dev_id,
+        char **dev,
+        pa_sample_spec *ss,
+        pa_channel_map* map,
+        int mode,
+        uint32_t *nfrags,
+        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 require_exact_channel_number) {
+
+    snd_pcm_t *pcm_handle;
+    char *d;
+
+    d = pa_sprintf_malloc("%s:%s", prefix, dev_id);
+
+    pcm_handle = pa_alsa_open_by_device_string(
+            d,
+            dev,
+            ss,
+            map,
+            mode,
+            nfrags,
+            period_size,
+            tsched_size,
+            use_mmap,
+            use_tsched,
+            require_exact_channel_number);
+    pa_xfree(d);
+
+    if (!pcm_handle && prefix_fallback) {
+
+        d = pa_sprintf_malloc("%s:%s", prefix_fallback, dev_id);
+
+        pcm_handle = pa_alsa_open_by_device_string(
+                d,
+                dev,
+                ss,
+                map,
+                mode,
+                nfrags,
+                period_size,
+                tsched_size,
+                use_mmap,
+                use_tsched,
+                require_exact_channel_number);
+        pa_xfree(d);
+    }
+
+    return pcm_handle;
+}
+
 snd_pcm_t *pa_alsa_open_by_device_id_auto(
         const char *dev_id,
         char **dev,
@@ -671,14 +727,14 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 
             pa_log_debug("Checking for %s (%s)", device_table[i].name, device_table[i].alsa_name);
 
-            d = pa_sprintf_malloc("%s:%s", device_table[i].alsa_name, dev_id);
-
             try_ss.channels = device_table[i].map.channels;
             try_ss.rate = ss->rate;
             try_ss.format = ss->format;
 
-            pcm_handle = pa_alsa_open_by_device_string(
-                    d,
+            pcm_handle = open_by_device_string_with_fallback(
+                    device_table[i].alsa_name,
+                    device_table[i].alsa_name_fallback,
+                    dev_id,
                     dev,
                     &try_ss,
                     map,
@@ -690,8 +746,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
                     use_tsched,
                     TRUE);
 
-            pa_xfree(d);
-
             if (pcm_handle) {
 
                 *ss = try_ss;
@@ -703,6 +757,7 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 
                 return pcm_handle;
             }
+
         }
 
         if (direction > 0) {
@@ -775,7 +830,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_profile(
         pa_bool_t *use_tsched,
         const pa_alsa_profile_info *profile) {
 
-    char *d;
     snd_pcm_t *pcm_handle;
     pa_sample_spec try_ss;
 
@@ -787,14 +841,14 @@ snd_pcm_t *pa_alsa_open_by_device_id_profile(
     pa_assert(period_size);
     pa_assert(profile);
 
-    d = pa_sprintf_malloc("%s:%s", profile->alsa_name, dev_id);
-
     try_ss.channels = profile->map.channels;
     try_ss.rate = ss->rate;
     try_ss.format = ss->format;
 
-    pcm_handle = pa_alsa_open_by_device_string(
-            d,
+    pcm_handle = open_by_device_string_with_fallback(
+            profile->alsa_name,
+            profile->alsa_name_fallback,
+            dev_id,
             dev,
             &try_ss,
             map,
@@ -806,8 +860,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_profile(
             use_tsched,
             TRUE);
 
-    pa_xfree(d);
-
     if (!pcm_handle)
         return NULL;
 
@@ -860,6 +912,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
             goto fail;
         }
 
+        pa_log_debug("Managed to open %s", d);
+
         if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
 
             if (!reformat) {
@@ -928,26 +982,25 @@ int pa_alsa_probe_profiles(
         snd_pcm_t *pcm_i = NULL;
 
         if (i->alsa_name) {
-            char *id;
             pa_sample_spec try_ss;
             pa_channel_map try_map;
 
             pa_log_debug("Checking for playback on %s (%s)", i->name, i->alsa_name);
-            id = pa_sprintf_malloc("%s:%s", i->alsa_name, dev_id);
 
             try_ss = *ss;
             try_ss.channels = i->map.channels;
             try_map = i->map;
 
-            pcm_i = pa_alsa_open_by_device_string(
-                    id, NULL,
+            pcm_i = open_by_device_string_with_fallback(
+                    i->alsa_name,
+                    i->alsa_name_fallback,
+                    dev_id,
+                    NULL,
                     &try_ss, &try_map,
                     SND_PCM_STREAM_PLAYBACK,
                     NULL, NULL, 0, NULL, NULL,
                     TRUE);
 
-            pa_xfree(id);
-
             if (!pcm_i)
                 continue;
         }
@@ -956,26 +1009,25 @@ int pa_alsa_probe_profiles(
             snd_pcm_t *pcm_j = NULL;
 
             if (j->alsa_name) {
-                char *jd;
                 pa_sample_spec try_ss;
                 pa_channel_map try_map;
 
                 pa_log_debug("Checking for capture on %s (%s)", j->name, j->alsa_name);
-                jd = pa_sprintf_malloc("%s:%s", j->alsa_name, dev_id);
 
                 try_ss = *ss;
                 try_ss.channels = j->map.channels;
                 try_map = j->map;
 
-                pcm_j = pa_alsa_open_by_device_string(
-                        jd, NULL,
+                pcm_j = open_by_device_string_with_fallback(
+                        j->alsa_name,
+                        j->alsa_name_fallback,
+                        dev_id,
+                        NULL,
                         &try_ss, &try_map,
                         SND_PCM_STREAM_CAPTURE,
                         NULL, NULL, 0, NULL, NULL,
                         TRUE);
 
-                pa_xfree(jd);
-
                 if (!pcm_j)
                     continue;
             }
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index 77ac8a7..4c5d336 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -56,6 +56,7 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min);
 typedef struct pa_alsa_profile_info {
     pa_channel_map map;
     const char *alsa_name;
+    const char *alsa_name_fallback;
     const char *description; /* internationalized */
     const char *name;
     unsigned priority;
