[pulseaudio-commits] [Git][pulseaudio/pulseaudio][master] 8 commits: device-port: introduce available_group member

Tanu Kaskinen gitlab at gitlab.freedesktop.org
Wed Jun 17 06:10:46 UTC 2020



Tanu Kaskinen pushed to branch master at PulseAudio / pulseaudio


Commits:
861836c5 by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
device-port: introduce available_group member

In some cases, the I/O connector functionality can be shared
and we cannot determine the proper purpose automatically.
We just know that something was inserted to the jack.

Introduce a group identifier (a simple string - unique
per group) which helps to determine the proper ports
for the application. The user interface may be used
to set the wanted behaviour.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
feee531c by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
device-port: add type member

The clients might wanna to know for which purpose is the port.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
64eae8d8 by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
protocol: describe v34 (available_group, port type)

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
1fb44921 by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
alsa-ucm: set available_group (use jack name)

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
66185274 by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
alsa: legacy card - set available_group

Create automatically the groups per paths where
the similar jacks are used.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
0333c2ba by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
alsa: legacy card - implement device port type parser and assignment

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
80b993cf by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
alsa ucm: set device port type

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
b2d33997 by Jaroslav Kysela at 2020-06-17T06:06:12+00:00
pactl: print device port type and available group

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -


16 changed files:

- PROTOCOL
- configure.ac
- src/modules/alsa/alsa-mixer.c
- src/modules/alsa/alsa-mixer.h
- src/modules/alsa/alsa-ucm.c
- src/modules/alsa/alsa-ucm.h
- src/modules/bluetooth/module-bluez5-device.c
- src/modules/module-tunnel.c
- src/modules/raop/raop-sink.c
- src/pulse/def.h
- src/pulse/introspect.c
- src/pulse/introspect.h
- src/pulsecore/device-port.c
- src/pulsecore/device-port.h
- src/pulsecore/protocol-native.c
- src/utils/pactl.c


Changes:

=====================================
PROTOCOL
=====================================
@@ -427,6 +427,10 @@ Added two values to the pa_encoding_t enum:
     PA_ENCODING_TRUEHD_IEC61937 := 7
     PA_ENCODING_DTSHD_IEC61937 := 8
 
+## v34, implemented by >= 14.0
+
+Added available_group and type fields to the device port info.
+
 #### If you just changed the protocol, read this
 ## module-tunnel depends on the sink/source/sink-input/source-input protocol
 ## internals, so if you changed these, you might have broken module-tunnel.


=====================================
configure.ac
=====================================
@@ -42,7 +42,7 @@ AC_SUBST(PA_MINOR, pa_minor)
 AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
 
 AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 33)
+AC_SUBST(PA_PROTOCOL_VERSION, 34)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold x=z


=====================================
src/modules/alsa/alsa-mixer.c
=====================================
@@ -107,6 +107,12 @@ struct description_map {
     const char *description;
 };
 
+struct description2_map {
+    const char *key;
+    const char *description;
+    pa_device_port_type_t type;
+};
+
 static char *alsa_id_str(char *dst, size_t dst_len, pa_alsa_mixer_id *id) {
     if (id->index > 0) {
         snprintf(dst, dst_len, "'%s',%d", id->name, id->index);
@@ -288,6 +294,19 @@ static const char *lookup_description(const char *key, const struct description_
     return NULL;
 }
 
+static const struct description2_map *lookup_description2(const char *key, const struct description2_map dm[], unsigned n) {
+    unsigned i;
+
+    if (!key)
+        return NULL;
+
+    for (i = 0; i < n; i++)
+        if (pa_streq(dm[i].key, key))
+            return &dm[i];
+
+    return NULL;
+}
+
 struct pa_alsa_fdlist {
     unsigned num_fds;
     struct pollfd *fds;
@@ -739,6 +758,7 @@ void pa_alsa_path_free(pa_alsa_path *p) {
     }
 
     pa_proplist_free(p->proplist);
+    pa_xfree(p->available_group);
     pa_xfree(p->name);
     pa_xfree(p->description);
     pa_xfree(p->description_key);
@@ -2159,6 +2179,50 @@ static int element_parse_enumeration(pa_config_parser_state *state) {
     return 0;
 }
 
+static int parse_type(pa_config_parser_state *state) {
+    struct device_port_types {
+        const char *name;
+        pa_device_port_type_t type;
+    } device_port_types[] = {
+        { "unknown",      PA_DEVICE_PORT_TYPE_UNKNOWN },
+        { "aux",          PA_DEVICE_PORT_TYPE_AUX },
+        { "speaker",      PA_DEVICE_PORT_TYPE_SPEAKER },
+        { "headphones",   PA_DEVICE_PORT_TYPE_HEADPHONES },
+        { "line",         PA_DEVICE_PORT_TYPE_LINE },
+        { "mic",          PA_DEVICE_PORT_TYPE_MIC },
+        { "headset",      PA_DEVICE_PORT_TYPE_HEADSET },
+        { "handset",      PA_DEVICE_PORT_TYPE_HANDSET },
+        { "earpiece",     PA_DEVICE_PORT_TYPE_EARPIECE },
+        { "spdif",        PA_DEVICE_PORT_TYPE_SPDIF },
+        { "hdmi",         PA_DEVICE_PORT_TYPE_HDMI },
+        { "tv",           PA_DEVICE_PORT_TYPE_TV },
+        { "radio",        PA_DEVICE_PORT_TYPE_RADIO },
+        { "video",        PA_DEVICE_PORT_TYPE_VIDEO },
+        { "usb",          PA_DEVICE_PORT_TYPE_USB },
+        { "bluetooth",    PA_DEVICE_PORT_TYPE_BLUETOOTH },
+        { "portable",     PA_DEVICE_PORT_TYPE_PORTABLE },
+        { "handsfree",    PA_DEVICE_PORT_TYPE_HANDSFREE },
+        { "car",          PA_DEVICE_PORT_TYPE_CAR },
+        { "hifi",         PA_DEVICE_PORT_TYPE_HIFI },
+        { "phone",        PA_DEVICE_PORT_TYPE_PHONE },
+        { "network",      PA_DEVICE_PORT_TYPE_NETWORK },
+        { "analog",       PA_DEVICE_PORT_TYPE_ANALOG },
+    };
+    pa_alsa_path *path;
+    unsigned int idx;
+
+    path = state->userdata;
+
+    for (idx = 0; idx < PA_ELEMENTSOF(device_port_types); idx++)
+        if (pa_streq(state->rvalue, device_port_types[idx].name)) {
+            path->device_port_type = device_port_types[idx].type;
+            return 0;
+        }
+
+    pa_log("[%s:%u] Invalid value for option 'type': %s", state->filename, state->lineno, state->rvalue);
+    return -1;
+}
+
 static int parse_eld_device(pa_config_parser_state *state) {
     pa_alsa_path *path;
     uint32_t eld_device;
@@ -2641,35 +2705,38 @@ static int element_verify(pa_alsa_element *e) {
 }
 
 static int path_verify(pa_alsa_path *p) {
-    static const struct description_map well_known_descriptions[] = {
-        { "analog-input",               N_("Analog Input") },
-        { "analog-input-microphone",    N_("Microphone") },
-        { "analog-input-microphone-front",    N_("Front Microphone") },
-        { "analog-input-microphone-rear",     N_("Rear Microphone") },
-        { "analog-input-microphone-dock",     N_("Dock Microphone") },
-        { "analog-input-microphone-internal", N_("Internal Microphone") },
-        { "analog-input-microphone-headset",  N_("Headset Microphone") },
-        { "analog-input-linein",        N_("Line In") },
-        { "analog-input-radio",         N_("Radio") },
-        { "analog-input-video",         N_("Video") },
-        { "analog-output",              N_("Analog Output") },
-        { "analog-output-headphones",   N_("Headphones") },
-        { "analog-output-headphones-mono",    N_("Headphones Mono Output") },
-        { "analog-output-lfe-on-mono",  N_("LFE on Separate Mono Output") },
-        { "analog-output-lineout",      N_("Line Out") },
-        { "analog-output-mono",         N_("Analog Mono Output") },
-        { "analog-output-speaker",      N_("Speakers") },
-        { "hdmi-output",                N_("HDMI / DisplayPort") },
-        { "iec958-stereo-output",       N_("Digital Output (S/PDIF)") },
-        { "iec958-stereo-input",        N_("Digital Input (S/PDIF)") },
-        { "iec958-passthrough-output",  N_("Digital Passthrough (S/PDIF)") },
-        { "multichannel-input",         N_("Multichannel Input") },
-        { "multichannel-output",        N_("Multichannel Output") },
-        { "steelseries-arctis-5-output-game", N_("Game Output") },
-        { "steelseries-arctis-5-output-chat", N_("Chat Output") },
+    static const struct description2_map well_known_descriptions[] = {
+        { "analog-input",                     N_("Analog Input"),                 PA_DEVICE_PORT_TYPE_ANALOG },
+        { "analog-input-microphone",          N_("Microphone"),                   PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-microphone-front",    N_("Front Microphone"),             PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-microphone-rear",     N_("Rear Microphone"),              PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-microphone-dock",     N_("Dock Microphone"),              PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-microphone-internal", N_("Internal Microphone"),          PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-microphone-headset",  N_("Headset Microphone"),           PA_DEVICE_PORT_TYPE_MIC },
+        { "analog-input-linein",              N_("Line In"),                      PA_DEVICE_PORT_TYPE_LINE },
+        { "analog-input-radio",               N_("Radio"),                        PA_DEVICE_PORT_TYPE_RADIO },
+        { "analog-input-video",               N_("Video"),                        PA_DEVICE_PORT_TYPE_VIDEO },
+        { "analog-output",                    N_("Analog Output"),                PA_DEVICE_PORT_TYPE_ANALOG },
+        { "analog-output-headphones",         N_("Headphones"),                   PA_DEVICE_PORT_TYPE_HEADPHONES },
+        { "analog-output-headphones-mono",    N_("Headphones Mono Output"),       PA_DEVICE_PORT_TYPE_HEADPHONES },
+        { "analog-output-lineout",            N_("Line Out"),                     PA_DEVICE_PORT_TYPE_LINE },
+        { "analog-output-mono",               N_("Analog Mono Output"),           PA_DEVICE_PORT_TYPE_ANALOG },
+        { "analog-output-speaker",            N_("Speakers"),                     PA_DEVICE_PORT_TYPE_SPEAKER },
+        { "hdmi-output",                      N_("HDMI / DisplayPort"),           PA_DEVICE_PORT_TYPE_HDMI },
+        { "iec958-stereo-output",             N_("Digital Output (S/PDIF)"),      PA_DEVICE_PORT_TYPE_SPDIF },
+        { "iec958-stereo-input",              N_("Digital Input (S/PDIF)"),       PA_DEVICE_PORT_TYPE_SPDIF },
+        { "iec958-passthrough-output",        N_("Digital Passthrough (S/PDIF)"), PA_DEVICE_PORT_TYPE_SPDIF },
+        { "multichannel-input",               N_("Multichannel Input"),           PA_DEVICE_PORT_TYPE_LINE },
+        { "multichannel-output",              N_("Multichannel Output"),          PA_DEVICE_PORT_TYPE_LINE },
+        { "steelseries-arctis-5-output-game", N_("Game Output"),                  PA_DEVICE_PORT_TYPE_HEADSET },
+        { "steelseries-arctis-5-output-chat", N_("Chat Output"),                  PA_DEVICE_PORT_TYPE_HEADSET },
     };
 
     pa_alsa_element *e;
+    const char *key = p->description_key ? p->description_key : p->name;
+    const struct description2_map *map = lookup_description2(key,
+                                                             well_known_descriptions,
+                                                             PA_ELEMENTSOF(well_known_descriptions));
 
     pa_assert(p);
 
@@ -2677,10 +2744,12 @@ static int path_verify(pa_alsa_path *p) {
         if (element_verify(e) < 0)
             return -1;
 
-    if (!p->description)
-        p->description = pa_xstrdup(lookup_description(p->description_key ? p->description_key : p->name,
-                                                       well_known_descriptions,
-                                                       PA_ELEMENTSOF(well_known_descriptions)));
+    if (map) {
+        if (p->device_port_type == PA_DEVICE_PORT_TYPE_UNKNOWN)
+            p->device_port_type = map->type;
+        if (!p->description)
+            p->description = pa_xstrdup(map->description);
+    }
 
     if (!p->description) {
         if (p->description_key)
@@ -2713,6 +2782,7 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa
         { "priority",            pa_config_parse_unsigned,          NULL, "General" },
         { "description-key",     pa_config_parse_string,            NULL, "General" },
         { "description",         pa_config_parse_string,            NULL, "General" },
+        { "type",                parse_type,                        NULL, "General" },
         { "mute-during-activation", pa_config_parse_bool,           NULL, "General" },
         { "eld-device",          parse_eld_device,                  NULL, "General" },
 
@@ -4180,6 +4250,51 @@ fail:
     return -1;
 }
 
+/* the logic is simple: if we see the jack in multiple paths */
+/* assign all those jacks to one available_group */
+static void mapping_group_available(pa_hashmap *paths)
+{
+    void *state, *state2;
+    pa_alsa_path *p, *p2;
+    pa_alsa_jack *j, *j2;
+    uint32_t num = 1;
+
+    PA_HASHMAP_FOREACH(p, paths, state) {
+        const char *found = NULL;
+        bool has_control = false;
+        PA_LLIST_FOREACH(j, p->jacks) {
+           if (!j->has_control || j->state_plugged == PA_AVAILABLE_NO)
+               continue;
+           has_control = true;
+           j->state_plugged = PA_AVAILABLE_UNKNOWN;
+           PA_HASHMAP_FOREACH(p2, paths, state2) {
+               if (p2 == p)
+                   break;
+               PA_LLIST_FOREACH(j2, p->jacks) {
+                   if (!j2->has_control || j->state_plugged == PA_AVAILABLE_NO)
+                       continue;
+                   if (pa_streq(j->name, j2->name)) {
+                       j2->state_plugged = PA_AVAILABLE_UNKNOWN;
+                       found = p2->available_group;
+                       break;
+                   }
+               }
+           }
+           if (found)
+               break;
+       }
+       if (!has_control)
+           continue;
+       if (!found) {
+           p->available_group = pa_sprintf_malloc("Legacy %d", num);
+       } else {
+           p->available_group = pa_xstrdup(found);
+       }
+       if (!found)
+            num++;
+    }
+}
+
 static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
                                 pa_alsa_direction_t direction, pa_hashmap *used_paths,
                                 pa_hashmap *mixers) {
@@ -4228,6 +4343,8 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
     PA_HASHMAP_FOREACH(p, ps->paths, state)
         pa_hashmap_put(used_paths, p, p);
 
+    mapping_group_available(ps->paths);
+
     pa_log_debug("Available mixer paths (after tidying):");
     pa_alsa_path_set_dump(ps);
 }
@@ -5026,6 +5143,8 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
         pa_device_port_new_data_set_name(&port_data, name);
         pa_device_port_new_data_set_description(&port_data, description);
         pa_device_port_new_data_set_direction(&port_data, path->direction == PA_ALSA_DIRECTION_OUTPUT ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
+        pa_device_port_new_data_set_type(&port_data, path->device_port_type);
+        pa_device_port_new_data_set_available_group(&port_data, path->available_group);
 
         p = pa_device_port_new(core, &port_data, sizeof(pa_alsa_port_data));
         pa_device_port_new_data_done(&port_data);


=====================================
src/modules/alsa/alsa-mixer.h
=====================================
@@ -211,6 +211,8 @@ struct pa_alsa_path {
     char *name;
     char *description_key;
     char *description;
+    char *available_group;
+    pa_device_port_type_t device_port_type;
     unsigned priority;
     bool autodetect_eld_device;
     pa_alsa_mixer *eld_mixer_handle;


=====================================
src/modules/alsa/alsa-ucm.c
=====================================
@@ -66,6 +66,11 @@
 
 #ifdef HAVE_ALSA_UCM
 
+struct ucm_type {
+    const char *prefix;
+    pa_device_port_type_t type;
+};
+
 struct ucm_items {
     const char *id;
     const char *property;
@@ -76,6 +81,7 @@ struct ucm_info {
     unsigned priority;
 };
 
+static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *device);
 static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
 static void device_add_hw_mute_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
 
@@ -87,6 +93,21 @@ static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *
 static void ucm_port_data_free(pa_device_port *port);
 static void ucm_port_update_available(pa_alsa_ucm_port_data *port);
 
+static struct ucm_type types[] = {
+    {"None", PA_DEVICE_PORT_TYPE_UNKNOWN},
+    {"Speaker", PA_DEVICE_PORT_TYPE_SPEAKER},
+    {"Line", PA_DEVICE_PORT_TYPE_LINE},
+    {"Mic", PA_DEVICE_PORT_TYPE_MIC},
+    {"Headphones", PA_DEVICE_PORT_TYPE_HEADPHONES},
+    {"Headset", PA_DEVICE_PORT_TYPE_HEADSET},
+    {"Handset", PA_DEVICE_PORT_TYPE_HANDSET},
+    {"Bluetooth", PA_DEVICE_PORT_TYPE_BLUETOOTH},
+    {"Earpiece", PA_DEVICE_PORT_TYPE_EARPIECE},
+    {"SPDIF", PA_DEVICE_PORT_TYPE_SPDIF},
+    {"HDMI", PA_DEVICE_PORT_TYPE_HDMI},
+    {NULL, 0}
+};
+
 static struct ucm_items item[] = {
     {"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
     {"CapturePCM", PA_ALSA_PROP_UCM_SOURCE},
@@ -343,13 +364,27 @@ static int ucm_get_device_property(
 
     const char *value;
     const char **devices;
-    char *id;
+    char *id, *s;
     int i;
     int err;
     uint32_t ui;
     int n_confdev, n_suppdev;
     pa_alsa_ucm_volume *vol;
 
+    /* determine the device type */
+    device->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
+    id = s = pa_xstrdup(device_name);
+    while (s && *s && isalpha(*s)) s++;
+    if (s)
+        *s = '\0';
+    for (i = 0; types[i].prefix; i++)
+        if (pa_streq(id, types[i].prefix)) {
+            device->type = types[i].type;
+            break;
+        }
+    pa_xfree(id);
+
+    /* set properties */
     for (i = 0; item[i].id; i++) {
         id = pa_sprintf_malloc("%s/%s", item[i].id, device_name);
         err = snd_use_case_get(uc_mgr, id, &value);
@@ -955,6 +990,8 @@ static void ucm_add_port_combination(
     pa_alsa_ucm_device *sorted[num], *dev;
     pa_alsa_ucm_port_data *data;
     pa_alsa_ucm_volume *vol;
+    pa_alsa_jack *jack, *jack2;
+    pa_device_port_type_t type, type2;
     void *state;
 
     for (i = 0; i < num; i++)
@@ -973,6 +1010,8 @@ static void ucm_add_port_combination(
 
     priority = is_sink ? dev->playback_priority : dev->capture_priority;
     prio2 = (priority == 0 ? 0 : 1.0/priority);
+    jack = ucm_get_jack(context->ucm, dev);
+    type = dev->type;
 
     for (i = 1; i < num; i++) {
         char *tmp;
@@ -991,6 +1030,20 @@ static void ucm_add_port_combination(
         priority = is_sink ? dev->playback_priority : dev->capture_priority;
         if (priority != 0 && prio2 > 0)
             prio2 += 1.0/priority;
+
+        jack2 = ucm_get_jack(context->ucm, dev);
+        if (jack2) {
+            if (jack && jack != jack2)
+                pa_log_warn("Multiple jacks per combined device '%s': '%s' '%s'", name, jack->name, jack2->name);
+            jack = jack2;
+        }
+
+        type2 = dev->type;
+        if (type2 != PA_DEVICE_PORT_TYPE_UNKNOWN) {
+            if (type != PA_DEVICE_PORT_TYPE_UNKNOWN && type != type2)
+                pa_log_warn("Multiple device types per combined device '%s': %d %d", name, type, type2);
+            type = type2;
+        }
     }
 
     /* Make combination ports always have lower priority, and use the formula
@@ -1008,7 +1061,10 @@ static void ucm_add_port_combination(
         pa_device_port_new_data_init(&port_data);
         pa_device_port_new_data_set_name(&port_data, name);
         pa_device_port_new_data_set_description(&port_data, desc);
+        pa_device_port_new_data_set_type(&port_data, type);
         pa_device_port_new_data_set_direction(&port_data, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
+        if (jack)
+            pa_device_port_new_data_set_available_group(&port_data, jack->name);
 
         port = pa_device_port_new(core, &port_data, sizeof(pa_alsa_ucm_port_data));
         pa_device_port_new_data_done(&port_data);


=====================================
src/modules/alsa/alsa-ucm.h
=====================================
@@ -179,6 +179,8 @@ struct pa_alsa_ucm_device {
 
     pa_proplist *proplist;
 
+    pa_device_port_type_t type;
+
     unsigned playback_priority;
     unsigned capture_priority;
 


=====================================
src/modules/bluetooth/module-bluez5-device.c
=====================================
@@ -1762,6 +1762,7 @@ static pa_available_t transport_state_to_availability(pa_bluetooth_transport_sta
 static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     pa_device_port *port;
     pa_device_port_new_data port_data;
+    pa_device_port_type_t input_type, output_type;
     const char *name_prefix, *input_description, *output_description;
 
     pa_assert(u);
@@ -1771,60 +1772,67 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     name_prefix = "unknown";
     input_description = _("Bluetooth Input");
     output_description = _("Bluetooth Output");
+    input_type = output_type = PA_DEVICE_PORT_TYPE_BLUETOOTH;
 
     switch (form_factor_from_class(u->device->class_of_device)) {
         case PA_BLUETOOTH_FORM_FACTOR_HEADSET:
             name_prefix = "headset";
             input_description = output_description = _("Headset");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_HEADSET;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE:
             name_prefix = "handsfree";
             input_description = output_description = _("Handsfree");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_HANDSFREE;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE:
             name_prefix = "microphone";
             input_description = _("Microphone");
             output_description = _("Bluetooth Output");
+            input_type = PA_DEVICE_PORT_TYPE_MIC;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_SPEAKER:
             name_prefix = "speaker";
             input_description = _("Bluetooth Input");
             output_description = _("Speaker");
+            output_type = PA_DEVICE_PORT_TYPE_SPEAKER;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE:
             name_prefix = "headphone";
             input_description = _("Bluetooth Input");
             output_description = _("Headphone");
+            output_type = PA_DEVICE_PORT_TYPE_HEADPHONES;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_PORTABLE:
             name_prefix = "portable";
             input_description = output_description = _("Portable");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_PORTABLE;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_CAR:
             name_prefix = "car";
             input_description = output_description = _("Car");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_CAR;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_HIFI:
             name_prefix = "hifi";
             input_description = output_description = _("HiFi");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_HIFI;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_PHONE:
             name_prefix = "phone";
             input_description = output_description = _("Phone");
+            input_type = output_type = PA_DEVICE_PORT_TYPE_PHONE;
             break;
 
         case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN:
-            name_prefix = "unknown";
-            input_description = _("Bluetooth Input");
-            output_description = _("Bluetooth Output");
             break;
     }
 
@@ -1833,6 +1841,7 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     pa_device_port_new_data_set_name(&port_data, u->output_port_name);
     pa_device_port_new_data_set_description(&port_data, output_description);
     pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_OUTPUT);
+    pa_device_port_new_data_set_type(&port_data, output_type);
     pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_OUTPUT));
     pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
     pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
@@ -1843,6 +1852,7 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     pa_device_port_new_data_set_name(&port_data, u->input_port_name);
     pa_device_port_new_data_set_description(&port_data, input_description);
     pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_INPUT);
+    pa_device_port_new_data_set_type(&port_data, input_type);
     pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_INPUT));
     pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
     pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);


=====================================
src/modules/module-tunnel.c
=====================================
@@ -1034,9 +1034,17 @@ static int read_ports(struct userdata *u, pa_tagstruct *t) {
                 pa_log("Parse failure");
                 return -PA_ERR_PROTOCOL;
             }
-            if (u->version >= 24 && pa_tagstruct_getu32(t, &priority) < 0) { /* available */
-                pa_log("Parse failure");
-                return -PA_ERR_PROTOCOL;
+            if (u->version >= 24) {
+                if (pa_tagstruct_getu32(t, &priority) < 0) { /* available */
+                    pa_log("Parse failure");
+                    return -PA_ERR_PROTOCOL;
+                }
+                if (u->version >= 34 &&
+                    (pa_tagstruct_gets(t, &s) < 0 || /* available_group */
+                     pa_tagstruct_getu32(t, &priority) < 0)) { /* device port type */
+                    pa_log("Parse failure");
+                    return -PA_ERR_PROTOCOL;
+                }
             }
         }
 


=====================================
src/modules/raop/raop-sink.c
=====================================
@@ -635,6 +635,7 @@ static pa_device_port *raop_create_port(struct userdata *u, const char *server)
     pa_device_port_new_data_set_name(&data, "network-output");
     pa_device_port_new_data_set_description(&data, server);
     pa_device_port_new_data_set_direction(&data, PA_DIRECTION_OUTPUT);
+    pa_device_port_new_data_set_type(&data, PA_DEVICE_PORT_TYPE_NETWORK);
 
     port = pa_device_port_new(u->core, &data, 0);
 


=====================================
src/pulse/def.h
=====================================
@@ -1070,6 +1070,33 @@ typedef enum pa_port_available {
 /** \endcond */
 #endif
 
+/** Port type. \since 14.0 */
+typedef enum pa_device_port_type {
+    PA_DEVICE_PORT_TYPE_UNKNOWN = 0,
+    PA_DEVICE_PORT_TYPE_AUX = 1,
+    PA_DEVICE_PORT_TYPE_SPEAKER = 2,
+    PA_DEVICE_PORT_TYPE_HEADPHONES = 3,
+    PA_DEVICE_PORT_TYPE_LINE = 4,
+    PA_DEVICE_PORT_TYPE_MIC = 5,
+    PA_DEVICE_PORT_TYPE_HEADSET = 6,
+    PA_DEVICE_PORT_TYPE_HANDSET = 7,
+    PA_DEVICE_PORT_TYPE_EARPIECE = 8,
+    PA_DEVICE_PORT_TYPE_SPDIF = 9,
+    PA_DEVICE_PORT_TYPE_HDMI = 10,
+    PA_DEVICE_PORT_TYPE_TV = 11,
+    PA_DEVICE_PORT_TYPE_RADIO = 12,
+    PA_DEVICE_PORT_TYPE_VIDEO = 13,
+    PA_DEVICE_PORT_TYPE_USB = 14,
+    PA_DEVICE_PORT_TYPE_BLUETOOTH = 15,
+    PA_DEVICE_PORT_TYPE_PORTABLE = 16,
+    PA_DEVICE_PORT_TYPE_HANDSFREE = 17,
+    PA_DEVICE_PORT_TYPE_CAR = 18,
+    PA_DEVICE_PORT_TYPE_HIFI = 19,
+    PA_DEVICE_PORT_TYPE_PHONE = 20,
+    PA_DEVICE_PORT_TYPE_NETWORK = 21,
+    PA_DEVICE_PORT_TYPE_ANALOG = 22,
+} pa_device_port_type_t;
+
 PA_C_DECL_END
 
 #endif


=====================================
src/pulse/introspect.c
=====================================
@@ -219,6 +219,13 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
                                 goto fail;
                             i.ports[j]->available = av;
                         }
+                        i.ports[j]->available_group = NULL;
+                        i.ports[j]->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
+                        if (o->context->version >= 34) {
+                            if (pa_tagstruct_gets(t, &i.ports[j]->available_group) < 0 ||
+                                pa_tagstruct_getu32(t, &i.ports[j]->type) < 0)
+                                goto fail;
+                        }
                     }
 
                     i.ports[j] = NULL;
@@ -492,11 +499,17 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
                                 goto fail;
                             i.ports[j]->available = av;
                         }
+                        i.ports[j]->available_group = NULL;
+                        i.ports[j]->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
+                        if (o->context->version >= 34) {
+                            if (pa_tagstruct_gets(t, &i.ports[j]->available_group) < 0 ||
+                                pa_tagstruct_getu32(t, &i.ports[j]->type))
+                                goto fail;
+                        }
                     }
 
                     i.ports[j] = NULL;
                 }
-
                 if (pa_tagstruct_gets(t, &ap) < 0)
                     goto fail;
 
@@ -863,6 +876,14 @@ static int fill_card_port_info(pa_context *context, pa_tagstruct* t, pa_card_inf
                 return -PA_ERR_PROTOCOL;
         } else
             port->latency_offset = 0;
+
+        port->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
+        if (context->version >= 34) {
+            if (pa_tagstruct_gets(t, &port->available_group) < 0 ||
+                pa_tagstruct_getu32(t, &port->type) < 0)
+                return -PA_ERR_PROTOCOL;
+        } else
+            port->available_group = NULL;
     }
 
     return 0;


=====================================
src/pulse/introspect.h
=====================================
@@ -229,6 +229,8 @@ typedef struct pa_sink_port_info {
     const char *description;            /**< Description of this port */
     uint32_t priority;                  /**< The higher this value is, the more useful this port is as a default. */
     int available;                      /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */
+    const char *available_group;        /**< A string indentifier which determine the group of devices handling the available state simultaneously. \since 14.0 */
+    uint32_t type;			/**< Port device type (PA_PORT_DEVICE_TYPE). \since 14.0 */
 } pa_sink_port_info;
 
 /** Stores information about sinks. Please note that this structure
@@ -309,6 +311,8 @@ typedef struct pa_source_port_info {
     const char *description;            /**< Description of this port */
     uint32_t priority;                  /**< The higher this value is, the more useful this port is as a default. */
     int available;                      /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */
+    const char *available_group;        /**< A string indentifier which determine the group of devices handling the available state simultaneously. \since 14.0 */
+    uint32_t type;			/**< Port device type (PA_PORT_DEVICE_TYPE). \since 14.0 */
 } pa_source_port_info;
 
 /** Stores information about sources. Please note that this structure
@@ -509,6 +513,8 @@ typedef struct pa_card_port_info {
     pa_proplist *proplist;              /**< Property list */
     int64_t latency_offset;             /**< Latency offset of the port that gets added to the sink/source latency when the port is active. \since 3.0 */
     pa_card_profile_info2** profiles2;  /**< Array of pointers to available profiles, or NULL. Array is terminated by an entry set to NULL. \since 5.0 */
+    const char *available_group;        /**< A string indentifier which determine the group of devices handling the available state simultaneously. \since 14.0 */
+    uint32_t type;			/**< Port device type (PA_PORT_DEVICE_TYPE). \since 14.0 */
 } pa_card_port_info;
 
 /** Stores information about cards. Please note that this structure


=====================================
src/pulsecore/device-port.c
=====================================
@@ -29,6 +29,7 @@ pa_device_port_new_data *pa_device_port_new_data_init(pa_device_port_new_data *d
     pa_assert(data);
 
     pa_zero(*data);
+    data->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
     data->available = PA_AVAILABLE_UNKNOWN;
     return data;
 }
@@ -53,17 +54,31 @@ void pa_device_port_new_data_set_available(pa_device_port_new_data *data, pa_ava
     data->available = available;
 }
 
+void pa_device_port_new_data_set_available_group(pa_device_port_new_data *data, const char *group) {
+    pa_assert(data);
+
+    pa_xfree(data->available_group);
+    data->available_group = pa_xstrdup(group);
+}
+
 void pa_device_port_new_data_set_direction(pa_device_port_new_data *data, pa_direction_t direction) {
     pa_assert(data);
 
     data->direction = direction;
 }
 
+void pa_device_port_new_data_set_type(pa_device_port_new_data *data, pa_device_port_type_t type) {
+    pa_assert(data);
+
+    data->type = type;
+}
+
 void pa_device_port_new_data_done(pa_device_port_new_data *data) {
     pa_assert(data);
 
     pa_xfree(data->name);
     pa_xfree(data->description);
+    pa_xfree(data->available_group);
 }
 
 void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp) {
@@ -144,6 +159,7 @@ static void device_port_free(pa_object *o) {
     if (p->profiles)
         pa_hashmap_free(p->profiles);
 
+    pa_xfree(p->available_group);
     pa_xfree(p->preferred_profile);
     pa_xfree(p->name);
     pa_xfree(p->description);
@@ -169,8 +185,11 @@ pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, si
     p->card = NULL;
     p->priority = 0;
     p->available = data->available;
+    p->available_group = data->available_group;
+    data->available_group = NULL;
     p->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     p->direction = data->direction;
+    p->type = data->type;
 
     p->latency_offset = 0;
     p->proplist = pa_proplist_new();


=====================================
src/pulsecore/device-port.h
=====================================
@@ -43,9 +43,11 @@ struct pa_device_port {
     char *name;
     char *description;
     char *preferred_profile;
+    pa_device_port_type_t type;
 
     unsigned priority;
     pa_available_t available;         /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */
+    char *available_group;	      /* a string indentifier which determine the group of devices handling the available state simulteneously */
 
     pa_proplist *proplist;
     pa_hashmap *profiles; /* Does not own the profiles */
@@ -67,14 +69,18 @@ typedef struct pa_device_port_new_data {
     char *name;
     char *description;
     pa_available_t available;
+    char *available_group;
     pa_direction_t direction;
+    pa_device_port_type_t type;
 } pa_device_port_new_data;
 
 pa_device_port_new_data *pa_device_port_new_data_init(pa_device_port_new_data *data);
 void pa_device_port_new_data_set_name(pa_device_port_new_data *data, const char *name);
 void pa_device_port_new_data_set_description(pa_device_port_new_data *data, const char *description);
 void pa_device_port_new_data_set_available(pa_device_port_new_data *data, pa_available_t available);
+void pa_device_port_new_data_set_available_group(pa_device_port_new_data *data, const char *group);
 void pa_device_port_new_data_set_direction(pa_device_port_new_data *data, pa_direction_t direction);
+void pa_device_port_new_data_set_type(pa_device_port_new_data *data, pa_device_port_type_t type);
 void pa_device_port_new_data_done(pa_device_port_new_data *data);
 
 pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, size_t extra);


=====================================
src/pulsecore/protocol-native.c
=====================================
@@ -3205,8 +3205,13 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
             pa_tagstruct_puts(t, p->name);
             pa_tagstruct_puts(t, p->description);
             pa_tagstruct_putu32(t, p->priority);
-            if (c->version >= 24)
+            if (c->version >= 24) {
                 pa_tagstruct_putu32(t, p->available);
+                if (c->version >= 34) {
+                    pa_tagstruct_puts(t, p->available_group);
+                    pa_tagstruct_putu32(t, p->type);
+                }
+            }
         }
 
         pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
@@ -3275,8 +3280,13 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
             pa_tagstruct_puts(t, p->name);
             pa_tagstruct_puts(t, p->description);
             pa_tagstruct_putu32(t, p->priority);
-            if (c->version >= 24)
+            if (c->version >= 24) {
                 pa_tagstruct_putu32(t, p->available);
+                if (c->version >= 34) {
+                    pa_tagstruct_puts(t, p->available_group);
+                    pa_tagstruct_putu32(t, p->type);
+                }
+            }
         }
 
         pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
@@ -3358,8 +3368,13 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
         PA_HASHMAP_FOREACH(p, port->profiles, state2)
             pa_tagstruct_puts(t, p->name);
 
-        if (c->version >= 27)
+        if (c->version >= 27) {
             pa_tagstruct_puts64(t, port->latency_offset);
+            if (c->version >= 34) {
+                pa_tagstruct_puts(t, port->available_group);
+                pa_tagstruct_putu32(t, port->type);
+            }
+        }
     }
 }
 


=====================================
src/utils/pactl.c
=====================================
@@ -234,12 +234,43 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi
 
 static const char* get_available_str_ynonly(int available) {
     switch (available) {
-        case PA_PORT_AVAILABLE_YES: return ", available";
-        case PA_PORT_AVAILABLE_NO: return ", not available";
+        case PA_PORT_AVAILABLE_YES: return _(", available");
+        case PA_PORT_AVAILABLE_NO: return _(", not available");
     }
     return "";
 }
 
+static const char* get_device_port_type(unsigned int type) {
+    static char buf[32];
+    switch (type) {
+    case PA_DEVICE_PORT_TYPE_UNKNOWN: return _("Unknown");
+    case PA_DEVICE_PORT_TYPE_AUX: return _("Aux");
+    case PA_DEVICE_PORT_TYPE_SPEAKER: return _("Speaker");
+    case PA_DEVICE_PORT_TYPE_HEADPHONES: return _("Headphones");
+    case PA_DEVICE_PORT_TYPE_LINE: return _("Line");
+    case PA_DEVICE_PORT_TYPE_MIC: return _("Mic");
+    case PA_DEVICE_PORT_TYPE_HEADSET: return _("Headset");
+    case PA_DEVICE_PORT_TYPE_HANDSET: return _("Handset");
+    case PA_DEVICE_PORT_TYPE_EARPIECE: return _("Earpiece");
+    case PA_DEVICE_PORT_TYPE_SPDIF: return _("SPDIF");
+    case PA_DEVICE_PORT_TYPE_HDMI: return _("HDMI");
+    case PA_DEVICE_PORT_TYPE_TV: return _("TV");
+    case PA_DEVICE_PORT_TYPE_RADIO: return _("Radio");
+    case PA_DEVICE_PORT_TYPE_VIDEO: return _("Video");
+    case PA_DEVICE_PORT_TYPE_USB: return _("USB");
+    case PA_DEVICE_PORT_TYPE_BLUETOOTH: return _("Bluetooth");
+    case PA_DEVICE_PORT_TYPE_PORTABLE: return _("Portable");
+    case PA_DEVICE_PORT_TYPE_HANDSFREE: return _("Handsfree");
+    case PA_DEVICE_PORT_TYPE_CAR: return _("Car");
+    case PA_DEVICE_PORT_TYPE_HIFI: return _("HiFi");
+    case PA_DEVICE_PORT_TYPE_PHONE: return _("Phone");
+    case PA_DEVICE_PORT_TYPE_NETWORK: return _("Network");
+    case PA_DEVICE_PORT_TYPE_ANALOG: return _("Analog");
+    }
+    snprintf(buf, sizeof(buf), "%s-%u", _("Unknown"), type);
+    return buf;
+}
+
 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
 
     static const char *state_table[] = {
@@ -330,8 +361,10 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
 
         printf(_("\tPorts:\n"));
         for (p = i->ports; *p; p++)
-            printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
-                    (*p)->priority, get_available_str_ynonly((*p)->available));
+            printf(_("\t\t%s: %s (type: %s, priority: %u%s%s%s)\n"),
+                    (*p)->name, (*p)->description, get_device_port_type((*p)->type),
+                    (*p)->priority, (*p)->available_group ? _(", available group: ") : "",
+                    (*p)->available_group ?: "", get_available_str_ynonly((*p)->available));
     }
 
     if (i->active_port)
@@ -436,8 +469,10 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
 
         printf(_("\tPorts:\n"));
         for (p = i->ports; *p; p++)
-            printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
-                    (*p)->priority, get_available_str_ynonly((*p)->available));
+            printf(_("\t\t%s: %s (type: %s, priority: %u%s%s%s)\n"),
+                    (*p)->name, (*p)->description, get_device_port_type((*p)->type),
+                    (*p)->priority, (*p)->available_group ? _(", available group: ") : "",
+                    (*p)->available_group ?: "", get_available_str_ynonly((*p)->available));
     }
 
     if (i->active_port)
@@ -598,8 +633,9 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
         printf(_("\tPorts:\n"));
         for (p = i->ports; *p; p++) {
             pa_card_profile_info **pr = (*p)->profiles;
-            printf("\t\t%s: %s (priority: %u, latency offset: %" PRId64 " usec%s)\n", (*p)->name,
-                (*p)->description, (*p)->priority, (*p)->latency_offset,
+            printf(_("\t\t%s: %s (type: %s, priority: %u, latency offset: %" PRId64 " usec%s%s%s)\n"), (*p)->name,
+                (*p)->description, get_device_port_type((*p)->type), (*p)->priority, (*p)->latency_offset,
+                (*p)->available_group ? _(", available group: ") : "", (*p)->available_group ?: "",
                 get_available_str_ynonly((*p)->available));
 
             if (!pa_proplist_isempty((*p)->proplist)) {



View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/compare/9315bbdfe5c2987bc1501653f9672f79a6f9ee6d...b2d33997930da473aa7ebd70076ac5e9d2ae01e8

-- 
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/compare/9315bbdfe5c2987bc1501653f9672f79a6f9ee6d...b2d33997930da473aa7ebd70076ac5e9d2ae01e8
You're receiving this email because of your account on gitlab.freedesktop.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-commits/attachments/20200617/a2d84fbf/attachment-0001.htm>


More information about the pulseaudio-commits mailing list