[pulseaudio-commits] 5 commits - configure.ac PROTOCOL src/Makefile.am src/modules src/pulse src/pulsecore

Tanu Kaskinen tanuk at kemper.freedesktop.org
Sat Nov 26 07:02:32 PST 2011


 PROTOCOL                        |   15 +++++
 configure.ac                    |    2 
 src/Makefile.am                 |    1 
 src/modules/alsa/alsa-mixer.c   |    9 +--
 src/modules/alsa/alsa-mixer.h   |    2 
 src/modules/alsa/alsa-sink.c    |    2 
 src/modules/alsa/alsa-source.c  |    2 
 src/modules/module-tunnel.c     |   91 ++++++++++++++-------------------
 src/pulse/def.h                 |   15 +++++
 src/pulse/introspect.c          |   16 +++++
 src/pulse/introspect.h          |    2 
 src/pulsecore/card.c            |   10 +++
 src/pulsecore/card.h            |    4 +
 src/pulsecore/cli-text.c        |   48 +++++++++++------
 src/pulsecore/core.h            |    1 
 src/pulsecore/device-port.c     |  110 ++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/device-port.h     |   75 +++++++++++++++++++++++++++
 src/pulsecore/protocol-native.c |    4 +
 src/pulsecore/sink.c            |   41 +-------------
 src/pulsecore/sink.h            |   16 -----
 src/pulsecore/source.c          |   20 +------
 src/pulsecore/source.h          |    1 
 22 files changed, 341 insertions(+), 146 deletions(-)

New commits:
commit 7e5a741dd17a69792c8d850bdb79612c6e82b2c8
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:15 2011 +0100

    cli: Show card ports and jack detection status
    
    Expose the new stuff through pacmd.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 5498744..2253635 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -102,6 +102,33 @@ char *pa_client_list_to_string(pa_core *c) {
     return pa_strbuf_tostring_free(s);
 }
 
+static const char *port_available_to_string(pa_port_available_t a) {
+    switch (a) {
+        case PA_PORT_AVAILABLE_UNKNOWN:
+            return "unknown";
+        case PA_PORT_AVAILABLE_NO:
+            return "no";
+        case PA_PORT_AVAILABLE_YES:
+            return "yes";
+        default:
+            return "invalid"; /* Should never happen! */
+    }
+}
+
+static void append_port_list(pa_strbuf *s, pa_hashmap *ports)
+{
+    pa_device_port *p;
+    void *state;
+
+    if (!ports)
+        return;
+
+    pa_strbuf_puts(s, "\tports:\n");
+    PA_HASHMAP_FOREACH(p, ports, state)
+        pa_strbuf_printf(s, "\t\t%s: %s (priority %u, available: %s)\n",
+            p->name, p->description, p->priority, port_available_to_string(p->available));
+}
+
 char *pa_card_list_to_string(pa_core *c) {
     pa_strbuf *s;
     pa_card *card;
@@ -160,6 +187,8 @@ char *pa_card_list_to_string(pa_core *c) {
             for (source = pa_idxset_first(card->sources, &sidx); source; source = pa_idxset_next(card->sources, &sidx))
                 pa_strbuf_printf(s, "\t\t%s/#%u: %s\n", source->name, source->index, pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
         }
+
+        append_port_list(s, card->ports);
     }
 
     return pa_strbuf_tostring_free(s);
@@ -306,15 +335,7 @@ char *pa_sink_list_to_string(pa_core *c) {
         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
         pa_xfree(t);
 
-        if (sink->ports) {
-            pa_device_port *p;
-            void *state;
-
-            pa_strbuf_puts(s, "\tports:\n");
-            PA_HASHMAP_FOREACH(p, sink->ports, state)
-                pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
-        }
-
+        append_port_list(s, sink->ports);
 
         if (sink->active_port)
             pa_strbuf_printf(
@@ -429,14 +450,7 @@ char *pa_source_list_to_string(pa_core *c) {
         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
         pa_xfree(t);
 
-        if (source->ports) {
-            pa_device_port *p;
-            void *state;
-
-            pa_strbuf_puts(s, "\tports:\n");
-            PA_HASHMAP_FOREACH(p, source->ports, state)
-                pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
-        }
+        append_port_list(s, source->ports);
 
         if (source->active_port)
             pa_strbuf_printf(

commit 47f28a584399b3a83602d5015fb734d52e58d808
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:14 2011 +0100

    Notify port available status changes, and update protocol version
    
    The recommended way of setting available status is to call
    pa_device_port_set_available, which will send a subscription event
    to the relevant card. It will also fire a hook.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/PROTOCOL b/PROTOCOL
index 8b2f81f..7468cd4 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -288,6 +288,11 @@ PA_COMMAND_GET_(SOURCE|SINK)_OUTPUT_INFO_LIST):
 
 The field is added once for every port.
 
+## v25, implemented by >= 2.0
+
+When port availability changes, send a subscription event for the
+owning card.
+
 #### 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.
diff --git a/configure.ac b/configure.ac
index fa126f8..60ecd0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,7 +36,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, 24)
+AC_SUBST(PA_PROTOCOL_VERSION, 25)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold y=z
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 151eef5..a28cb74 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -4286,9 +4286,10 @@ void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) {
         pa_alsa_decibel_fix_dump(db_fix);
 }
 
-void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
+void pa_alsa_add_ports(pa_core *c, pa_hashmap **p, pa_alsa_path_set *ps) {
     pa_alsa_path *path;
 
+    pa_assert(c);
     pa_assert(p);
     pa_assert(!*p);
     pa_assert(ps);
@@ -4313,7 +4314,7 @@ void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
             pa_device_port *port;
             pa_alsa_port_data *data;
 
-            port = pa_device_port_new(s->name, s->description, sizeof(pa_alsa_port_data));
+            port = pa_device_port_new(c, s->name, s->description, sizeof(pa_alsa_port_data));
             port->priority = s->priority;
 
             data = PA_DEVICE_PORT_DATA(port);
@@ -4338,7 +4339,7 @@ void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
                 /* If there is no or just one setting we only need a
                  * single entry */
 
-                port = pa_device_port_new(path->name, path->description, sizeof(pa_alsa_port_data));
+                port = pa_device_port_new(c, path->name, path->description, sizeof(pa_alsa_port_data));
                 port->priority = path->priority * 100;
 
 
@@ -4362,7 +4363,7 @@ void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
                     else
                         d = pa_xstrdup(path->description);
 
-                    port = pa_device_port_new(n, d, sizeof(pa_alsa_port_data));
+                    port = pa_device_port_new(c, n, d, sizeof(pa_alsa_port_data));
                     port->priority = path->priority * 100 + s->priority;
 
                     pa_xfree(n);
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 92ddac5..818e88a 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -323,6 +323,6 @@ struct pa_alsa_port_data {
     pa_alsa_setting *setting;
 };
 
-void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps);
+void pa_alsa_add_ports(pa_core *c, pa_hashmap **p, pa_alsa_path_set *ps);
 
 #endif
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 93ecb28..786aa20 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -2224,7 +2224,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     }
 
     if (u->mixer_path_set)
-        pa_alsa_add_ports(&data.ports, u->mixer_path_set);
+        pa_alsa_add_ports(u->core, &data.ports, u->mixer_path_set);
 
     u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE | PA_SINK_LATENCY | (u->use_tsched ? PA_SINK_DYNAMIC_LATENCY : 0) |
                           (set_formats ? PA_SINK_SET_FORMATS : 0));
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 255a61d..e311a34 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1950,7 +1950,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     }
 
     if (u->mixer_path_set)
-        pa_alsa_add_ports(&data.ports, u->mixer_path_set);
+        pa_alsa_add_ports(u->core, &data.ports, u->mixer_path_set);
 
     u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|(u->use_tsched ? PA_SOURCE_DYNAMIC_LATENCY : 0));
     pa_source_new_data_done(&data);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index d0641cf..ba21fa9 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -113,6 +113,7 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_CARD_PUT,
     PA_CORE_HOOK_CARD_UNLINK,
     PA_CORE_HOOK_CARD_PROFILE_CHANGED,
+    PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
     PA_CORE_HOOK_MAX
 } pa_core_hook_t;
 
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index 8aeb173..7988649 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -21,11 +21,49 @@
   USA.
 ***/
 
-
 #include "device-port.h"
+#include <pulsecore/card.h>
 
 PA_DEFINE_PUBLIC_CLASS(pa_device_port, pa_object);
 
+void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status)
+{
+    uint32_t state;
+    pa_card *card;
+/*    pa_source *source;
+    pa_sink *sink; */
+    pa_core *core;
+
+    pa_assert(p);
+
+    if (p->available == status)
+        return;
+
+    pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN);
+
+    p->available = status;
+    pa_log_debug("Setting port %s to status %s", p->name, status == PA_PORT_AVAILABLE_YES ? "yes" : "no");
+
+    /* Post subscriptions to the card which owns us */
+    pa_assert_se(core = p->core);
+    PA_IDXSET_FOREACH(card, core->cards, state)
+        if (p == pa_hashmap_get(card->ports, p->name))
+            pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, card->index);
+#if 0
+/* This stuff is temporarily commented out while figuring out whether to actually do this */
+    if (p->is_output)
+        PA_IDXSET_FOREACH(sink, core->sinks, state)
+            if (p == pa_hashmap_get(sink->ports, p->name))
+                pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index);
+    if (p->is_input)
+        PA_IDXSET_FOREACH(source, core->sources, state)
+            if (p == pa_hashmap_get(source->ports, p->name))
+                pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, source->index);
+#endif
+
+    pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
+}
+
 static void device_port_free(pa_object *o) {
     pa_device_port *p = PA_DEVICE_PORT(o);
 
@@ -40,7 +78,7 @@ static void device_port_free(pa_object *o) {
 }
 
 
-pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra) {
+pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra) {
     pa_device_port *p;
 
     pa_assert(name);
@@ -50,6 +88,7 @@ pa_device_port *pa_device_port_new(const char *name, const char *description, si
 
     p->name = pa_xstrdup(name);
     p->description = pa_xstrdup(description);
+    p->core = c;
     p->priority = 0;
     p->available = PA_PORT_AVAILABLE_UNKNOWN;
     p->profiles = NULL;
diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
index f997c77..f387021 100644
--- a/src/pulsecore/device-port.h
+++ b/src/pulsecore/device-port.h
@@ -35,10 +35,15 @@
 #include <pulsecore/object.h>
 #include <pulsecore/hashmap.h>
 
+/* Note: Including core.h here leads to circular references
+   (device-port.h -> core.h -> sink.h -> device-port.h), hence the line below instead */
+typedef struct pa_core pa_core;
+
 typedef struct pa_device_port pa_device_port;
 
 struct pa_device_port {
     pa_object parent; /* Needed for reference counting */
+    pa_core *core;
 
     char *name;
     char *description;
@@ -58,8 +63,13 @@ PA_DECLARE_PUBLIC_CLASS(pa_device_port);
 
 #define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
 
-pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
+pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra);
 
 void pa_device_port_hashmap_free(pa_hashmap *h);
 
+#include <pulsecore/core.h>
+
+/* The port's available status has changed */
+void pa_device_port_set_available(pa_device_port *p, pa_port_available_t available);
+
 #endif

commit 0dced7f2758970b672b8f0d0409c57cddaaaca43
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:13 2011 +0100

    Cards now has ports directly, and device port has list of profiles
    
    This forms the base for being able to expose all ports of all
    profiles (even inactive ones) to clients.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index feaa444..1f12aef 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -34,6 +34,7 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/namereg.h>
+#include <pulsecore/device-port.h>
 
 #include "card.h"
 
@@ -66,7 +67,7 @@ pa_card_new_data* pa_card_new_data_init(pa_card_new_data *data) {
 
     memset(data, 0, sizeof(*data));
     data->proplist = pa_proplist_new();
-
+    data->ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     return data;
 }
 
@@ -99,6 +100,9 @@ void pa_card_new_data_done(pa_card_new_data *data) {
         pa_hashmap_free(data->profiles, NULL, NULL);
     }
 
+    if (data->ports)
+        pa_device_port_hashmap_free(data->ports);
+
     pa_xfree(data->name);
     pa_xfree(data->active_profile);
 }
@@ -139,6 +143,8 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
      * copying it here */
     c->profiles = data->profiles;
     data->profiles = NULL;
+    c->ports = data->ports;
+    data->ports = NULL;
 
     c->active_profile = NULL;
     c->save_profile = FALSE;
@@ -195,6 +201,8 @@ void pa_card_free(pa_card *c) {
     pa_assert(pa_idxset_isempty(c->sources));
     pa_idxset_free(c->sources, NULL, NULL);
 
+    pa_device_port_hashmap_free(c->ports);
+
     if (c->profiles) {
         pa_card_profile *p;
 
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
index 2d691b6..6f942e8 100644
--- a/src/pulsecore/card.h
+++ b/src/pulsecore/card.h
@@ -63,6 +63,8 @@ struct pa_card {
     pa_hashmap *profiles;
     pa_card_profile *active_profile;
 
+    pa_hashmap *ports;
+
     pa_bool_t save_profile:1;
 
     void *userdata;
@@ -80,6 +82,8 @@ typedef struct pa_card_new_data {
     pa_hashmap *profiles;
     char *active_profile;
 
+    pa_hashmap *ports;
+
     pa_bool_t namereg_fail:1;
 
     pa_bool_t save_profile:1;
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index 09646ee..8aeb173 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -32,6 +32,8 @@ static void device_port_free(pa_object *o) {
     pa_assert(p);
     pa_assert(pa_device_port_refcnt(p) == 0);
 
+    if (p->profiles)
+        pa_hashmap_free(p->profiles, NULL, NULL);
     pa_xfree(p->name);
     pa_xfree(p->description);
     pa_xfree(p);
@@ -50,6 +52,9 @@ pa_device_port *pa_device_port_new(const char *name, const char *description, si
     p->description = pa_xstrdup(description);
     p->priority = 0;
     p->available = PA_PORT_AVAILABLE_UNKNOWN;
+    p->profiles = NULL;
+    p->is_input = FALSE;
+    p->is_output = FALSE;
 
     return p;
 }
diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
index dfe3fc1..f997c77 100644
--- a/src/pulsecore/device-port.h
+++ b/src/pulsecore/device-port.h
@@ -46,6 +46,10 @@ struct pa_device_port {
     unsigned priority;
     pa_port_available_t available;         /* PA_PORT_AVAILABLE_UNKNOWN, PA_PORT_AVAILABLE_NO or PA_PORT_AVAILABLE_YES */
 
+    pa_hashmap *profiles; /* Can be NULL. Does not own the profiles */
+    pa_bool_t is_input:1;
+    pa_bool_t is_output:1;
+
     /* .. followed by some implementation specific data */
 };
 

commit d9685ec85db3722bf3988a64dda4d8ee21c7777b
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:12 2011 +0100

    Turn device ports into reference counted objects
    
    Since both cards and sinks can hold references to a port, it makes
    sense to reference count them. Although no current implementation
    actually has sinks with ports but without a card, it felt wrong
    to make it harder to make such an implementation in the future.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index 5d63aec..17653ac 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -826,6 +826,7 @@ libpulsecore_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/shared.c pulsecore/shared.h \
 		pulsecore/sink-input.c pulsecore/sink-input.h \
 		pulsecore/sink.c pulsecore/sink.h \
+		pulsecore/device-port.c pulsecore/device-port.h \
 		pulsecore/sioman.c pulsecore/sioman.h \
 		pulsecore/sound-file-stream.c pulsecore/sound-file-stream.h \
 		pulsecore/sound-file.c pulsecore/sound-file.h \
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
new file mode 100644
index 0000000..09646ee
--- /dev/null
+++ b/src/pulsecore/device-port.c
@@ -0,0 +1,66 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+  Copyright 2011 David Henningsson, Canonical Ltd.
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+
+#include "device-port.h"
+
+PA_DEFINE_PUBLIC_CLASS(pa_device_port, pa_object);
+
+static void device_port_free(pa_object *o) {
+    pa_device_port *p = PA_DEVICE_PORT(o);
+
+    pa_assert(p);
+    pa_assert(pa_device_port_refcnt(p) == 0);
+
+    pa_xfree(p->name);
+    pa_xfree(p->description);
+    pa_xfree(p);
+}
+
+
+pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra) {
+    pa_device_port *p;
+
+    pa_assert(name);
+
+    p = PA_DEVICE_PORT(pa_object_new_internal(PA_ALIGN(sizeof(pa_device_port)) + extra, pa_device_port_type_id, pa_device_port_check_type));
+    p->parent.free = device_port_free;
+
+    p->name = pa_xstrdup(name);
+    p->description = pa_xstrdup(description);
+    p->priority = 0;
+    p->available = PA_PORT_AVAILABLE_UNKNOWN;
+
+    return p;
+}
+
+void pa_device_port_hashmap_free(pa_hashmap *h) {
+    pa_device_port *p;
+
+    pa_assert(h);
+
+    while ((p = pa_hashmap_steal_first(h)))
+        pa_device_port_unref(p);
+
+    pa_hashmap_free(h, NULL, NULL);
+}
diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
new file mode 100644
index 0000000..dfe3fc1
--- /dev/null
+++ b/src/pulsecore/device-port.h
@@ -0,0 +1,61 @@
+#ifndef foopulsedeviceporthfoo
+#define foopulsedeviceporthfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+  Copyright 2011 David Henningsson, Canonical Ltd.
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <inttypes.h>
+
+#include <pulse/def.h>
+#include <pulsecore/object.h>
+#include <pulsecore/hashmap.h>
+
+typedef struct pa_device_port pa_device_port;
+
+struct pa_device_port {
+    pa_object parent; /* Needed for reference counting */
+
+    char *name;
+    char *description;
+
+    unsigned priority;
+    pa_port_available_t available;         /* PA_PORT_AVAILABLE_UNKNOWN, PA_PORT_AVAILABLE_NO or PA_PORT_AVAILABLE_YES */
+
+    /* .. followed by some implementation specific data */
+};
+
+PA_DECLARE_PUBLIC_CLASS(pa_device_port);
+#define PA_DEVICE_PORT(s) (pa_device_port_cast(s))
+
+#define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
+
+pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
+
+void pa_device_port_hashmap_free(pa_hashmap *h);
+
+#endif
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 9cad937..aa547f9 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -139,40 +139,13 @@ void pa_sink_new_data_done(pa_sink_new_data *data) {
 
     pa_proplist_free(data->proplist);
 
-    if (data->ports) {
-        pa_device_port *p;
-
-        while ((p = pa_hashmap_steal_first(data->ports)))
-            pa_device_port_free(p);
-
-        pa_hashmap_free(data->ports, NULL, NULL);
-    }
+    if (data->ports)
+        pa_device_port_hashmap_free(data->ports);
 
     pa_xfree(data->name);
     pa_xfree(data->active_port);
 }
 
-pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra) {
-    pa_device_port *p;
-
-    pa_assert(name);
-
-    p = pa_xmalloc(PA_ALIGN(sizeof(pa_device_port)) + extra);
-    p->name = pa_xstrdup(name);
-    p->description = pa_xstrdup(description);
-
-    p->priority = 0;
-
-    return p;
-}
-
-void pa_device_port_free(pa_device_port *p) {
-    pa_assert(p);
-
-    pa_xfree(p->name);
-    pa_xfree(p->description);
-    pa_xfree(p);
-}
 
 /* Called from main context */
 static void reset_callbacks(pa_sink *s) {
@@ -762,14 +735,8 @@ static void sink_free(pa_object *o) {
     if (s->proplist)
         pa_proplist_free(s->proplist);
 
-    if (s->ports) {
-        pa_device_port *p;
-
-        while ((p = pa_hashmap_steal_first(s->ports)))
-            pa_device_port_free(p);
-
-        pa_hashmap_free(s->ports, NULL, NULL);
-    }
+    if (s->ports)
+        pa_device_port_hashmap_free(s->ports);
 
     pa_xfree(s);
 }
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 04fab19..56fa735 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -24,7 +24,6 @@
 ***/
 
 typedef struct pa_sink pa_sink;
-typedef struct pa_device_port pa_device_port;
 typedef struct pa_sink_volume_change pa_sink_volume_change;
 
 #include <inttypes.h>
@@ -43,6 +42,7 @@ typedef struct pa_sink_volume_change pa_sink_volume_change;
 #include <pulsecore/asyncmsgq.h>
 #include <pulsecore/msgobject.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/device-port.h>
 #include <pulsecore/card.h>
 #include <pulsecore/queue.h>
 #include <pulsecore/thread-mq.h>
@@ -55,18 +55,6 @@ static inline pa_bool_t PA_SINK_IS_LINKED(pa_sink_state_t x) {
     return x == PA_SINK_RUNNING || x == PA_SINK_IDLE || x == PA_SINK_SUSPENDED;
 }
 
-struct pa_device_port {
-    char *name;
-    char *description;
-
-    unsigned priority;
-    pa_port_available_t available;         /* PA_PORT_AVAILABLE_UNKNOWN, PA_PORT_AVAILABLE_NO or PA_PORT_AVAILABLE_YES */
-
-    /* .. followed by some implementation specific data */
-};
-
-#define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
-
 /* A generic definition for void callback functions */
 typedef void(*pa_sink_cb_t)(pa_sink *s);
 
@@ -500,9 +488,6 @@ void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic);
 
 pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
 
-pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
-void pa_device_port_free(pa_device_port *p);
-
 /* Verify that we called in IO context (aka 'thread context), or that
  * the sink is not yet set up, i.e. the thread not set up yet. See
  * pa_assert_io_context() in thread-mq.h for more information. */
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 33f4c73..d6b3b76 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -131,14 +131,8 @@ void pa_source_new_data_done(pa_source_new_data *data) {
 
     pa_proplist_free(data->proplist);
 
-    if (data->ports) {
-        pa_device_port *p;
-
-        while ((p = pa_hashmap_steal_first(data->ports)))
-            pa_device_port_free(p);
-
-        pa_hashmap_free(data->ports, NULL, NULL);
-    }
+    if (data->ports)
+        pa_device_port_hashmap_free(data->ports);
 
     pa_xfree(data->name);
     pa_xfree(data->active_port);
@@ -671,14 +665,8 @@ static void source_free(pa_object *o) {
     if (s->proplist)
         pa_proplist_free(s->proplist);
 
-    if (s->ports) {
-        pa_device_port *p;
-
-        while ((p = pa_hashmap_steal_first(s->ports)))
-            pa_device_port_free(p);
-
-        pa_hashmap_free(s->ports, NULL, NULL);
-    }
+    if (s->ports)
+        pa_device_port_hashmap_free(s->ports);
 
     pa_xfree(s);
 }
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index c5cfb39..e6f7028 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -43,6 +43,7 @@ typedef struct pa_source_volume_change pa_source_volume_change;
 #include <pulsecore/msgobject.h>
 #include <pulsecore/rtpoll.h>
 #include <pulsecore/card.h>
+#include <pulsecore/device-port.h>
 #include <pulsecore/queue.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/source-output.h>

commit 961ec210a676e768902956218ff50bfac26dae65
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:11 2011 +0100

    Introduce "available" concept for ports, and communicate that to clients. Bump protocol version to 24.
    
    Note: There is still no notification when status availability changes.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/PROTOCOL b/PROTOCOL
index 8c69190..8b2f81f 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -278,6 +278,16 @@ New field in PA_COMMAND_UNDERFLOW:
 
     int64_t index
 
+## v24, implemented by >= 2.0
+
+New field in all commands that send/receive port introspection data
+(PA_COMMAND_GET_(SOURCE|SINK)_OUTPUT_INFO,
+PA_COMMAND_GET_(SOURCE|SINK)_OUTPUT_INFO_LIST):
+
+    uint32_t available
+
+The field is added once for every port.
+
 #### 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.
diff --git a/configure.ac b/configure.ac
index 1f65dd5..fa126f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,7 +36,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, 23)
+AC_SUBST(PA_PROTOCOL_VERSION, 24)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold y=z
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index faee995..61ec35d 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -996,6 +996,41 @@ fail:
     pa_module_unload_request(u->module, TRUE);
 }
 
+static int read_ports(struct userdata *u, pa_tagstruct *t)
+{
+    if (u->version >= 16) {
+        uint32_t n_ports;
+        const char *s;
+
+        if (pa_tagstruct_getu32(t, &n_ports)) {
+            pa_log("Parse failure");
+            return -PA_ERR_PROTOCOL;
+        }
+
+        for (uint32_t j = 0; j < n_ports; j++) {
+            uint32_t priority;
+
+            if (pa_tagstruct_gets(t, &s) < 0 || /* name */
+                pa_tagstruct_gets(t, &s) < 0 || /* description */
+                pa_tagstruct_getu32(t, &priority) < 0) {
+
+                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 (pa_tagstruct_gets(t, &s) < 0) { /* active port */
+            pa_log("Parse failure");
+            return -PA_ERR_PROTOCOL;
+        }
+    }
+    return 0;
+}
+
 #ifdef TUNNEL_SINK
 
 /* Called from main context */
@@ -1066,32 +1101,8 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command,  uint32_t tag, pa_t
         }
     }
 
-    if (u->version >= 16) {
-        uint32_t n_ports;
-        const char *s;
-
-        if (pa_tagstruct_getu32(t, &n_ports)) {
-            pa_log("Parse failure");
-            goto fail;
-        }
-
-        for (uint32_t j = 0; j < n_ports; j++) {
-            uint32_t priority;
-
-            if (pa_tagstruct_gets(t, &s) < 0 || /* name */
-                pa_tagstruct_gets(t, &s) < 0 || /* description */
-                pa_tagstruct_getu32(t, &priority) < 0) {
-
-                pa_log("Parse failure");
-                goto fail;
-            }
-        }
-
-        if (pa_tagstruct_gets(t, &s) < 0) { /* active port */
-            pa_log("Parse failure");
-            goto fail;
-        }
-    }
+    if (read_ports(u, t) < 0)
+        goto fail;
 
     if (u->version >= 21) {
         uint8_t n_formats;
@@ -1318,32 +1329,8 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command,  uint32_t tag, pa
         }
     }
 
-    if (u->version >= 16) {
-        uint32_t n_ports;
-        const char *s;
-
-        if (pa_tagstruct_getu32(t, &n_ports)) {
-            pa_log("Parse failure");
-            goto fail;
-        }
-
-        for (uint32_t j = 0; j < n_ports; j++) {
-            uint32_t priority;
-
-            if (pa_tagstruct_gets(t, &s) < 0 || /* name */
-                pa_tagstruct_gets(t, &s) < 0 || /* description */
-                pa_tagstruct_getu32(t, &priority) < 0) {
-
-                pa_log("Parse failure");
-                goto fail;
-            }
-        }
-
-        if (pa_tagstruct_gets(t, &s) < 0) { /* active port */
-            pa_log("Parse failure");
-            goto fail;
-        }
-    }
+    if (read_ports(u, t) < 0)
+        goto fail;
 
     if (!pa_tagstruct_eof(t)) {
         pa_log("Packet too long");
diff --git a/src/pulse/def.h b/src/pulse/def.h
index 49e4fdc..ca74dfc 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -977,6 +977,21 @@ typedef void (*pa_free_cb_t)(void *p);
  * playback, \since 1.0 */
 #define PA_STREAM_EVENT_FORMAT_LOST "format-lost"
 
+/** Port availability / jack detection status
+ * \since 2.0 */
+typedef enum pa_port_available {
+    PA_PORT_AVAILABLE_UNKNOWN = 0, /**< This port does not support jack detection \since 2.0 */
+    PA_PORT_AVAILABLE_NO = 1,      /**< This port is not available, likely because the jack is not plugged in. \since 2.0 */
+    PA_PORT_AVAILABLE_YES = 2,     /**< This port is available, likely because the jack is plugged in. \since 2.0 */
+} pa_port_available_t;
+
+/** \cond fulldocs */
+#define PA_PORT_AVAILABLE_UNKNOWN PA_PORT_AVAILABLE_UNKNOWN
+#define PA_PORT_AVAILABLE_NO PA_PORT_AVAILABLE_NO
+#define PA_PORT_AVAILABLE_YES PA_PORT_AVAILABLE_YES
+
+/** \endcond */
+
 PA_C_DECL_END
 
 #endif
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 0d1d03f..c8bf7ca 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -211,6 +211,14 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
                             goto fail;
                         }
 
+                        i.ports[0][j].available = PA_PORT_AVAILABLE_UNKNOWN;
+                        if (o->context->version >= 24) {
+                            uint32_t av;
+                            if (pa_tagstruct_getu32(t, &av) < 0 || av > PA_PORT_AVAILABLE_YES)
+                                goto fail;
+                            i.ports[0][j].available = av;
+                        }
+
                         i.ports[j] = &i.ports[0][j];
                     }
 
@@ -476,6 +484,14 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
                             goto fail;
                         }
 
+                        i.ports[0][j].available = PA_PORT_AVAILABLE_UNKNOWN;
+                        if (o->context->version >= 24) {
+                            uint32_t av;
+                            if (pa_tagstruct_getu32(t, &av) < 0 || av > PA_PORT_AVAILABLE_YES)
+                                goto fail;
+                            i.ports[0][j].available = av;
+                        }
+
                         i.ports[j] = &i.ports[0][j];
                     }
 
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 1d77d45..afa4e8e 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -202,6 +202,7 @@ typedef struct pa_sink_port_info {
     const char *name;                   /**< Name of this port */
     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 \link pa_port_available_t, indicating availability status of this port. \since 2.0 */
 } pa_sink_port_info;
 
 /** Stores information about sinks. Please note that this structure
@@ -281,6 +282,7 @@ typedef struct pa_source_port_info {
     const char *name;                   /**< Name of this port */
     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 \link pa_port_available_t, indicating availability status of this port. \since 2.0 */
 } pa_source_port_info;
 
 /** Stores information about sources. Please note that this structure
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 951aff7..5d1d485 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -3124,6 +3124,8 @@ 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)
+                    pa_tagstruct_putu32(t, p->available);
             }
         }
 
@@ -3195,6 +3197,8 @@ 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)
+                    pa_tagstruct_putu32(t, p->available);
             }
         }
 
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index a88ac58..04fab19 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -60,6 +60,7 @@ struct pa_device_port {
     char *description;
 
     unsigned priority;
+    pa_port_available_t available;         /* PA_PORT_AVAILABLE_UNKNOWN, PA_PORT_AVAILABLE_NO or PA_PORT_AVAILABLE_YES */
 
     /* .. followed by some implementation specific data */
 };



More information about the pulseaudio-commits mailing list