[2/3] device-port: Add messages to enable/disable jack detection

Submitted by Georg Chini on April 9, 2018, 6:38 p.m.

Details

Message ID 20180409183826.18593-3-georg@chini.tk
State New
Headers show
Series "card: Add messages to control jack detection" ( rev: 1 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Georg Chini April 9, 2018, 6:38 p.m.
With this patch, messages can be sent to the cards to enable/disable
jack detection for the whole card or single ports, manually set a port
state and to retrieve the current state of jack detection and port
availability.
---
 doc/messaging_api.txt                        | 22 ++++++++++++
 src/modules/alsa/alsa-ucm.c                  |  2 +-
 src/modules/alsa/module-alsa-card.c          |  4 +--
 src/modules/bluetooth/module-bluez5-device.c |  4 +--
 src/pulsecore/card.c                         | 52 ++++++++++++++++++++++++----
 src/pulsecore/device-port.c                  | 15 +++++++-
 src/pulsecore/device-port.h                  |  3 +-
 7 files changed, 89 insertions(+), 13 deletions(-)

Patch hide | download patch | download mbox

diff --git a/doc/messaging_api.txt b/doc/messaging_api.txt
index 57a92f58..b3dfede0 100644
--- a/doc/messaging_api.txt
+++ b/doc/messaging_api.txt
@@ -70,3 +70,25 @@  Object path: /core
 Message: list-handlers
 Parameters: None
 Return value: {{{Handler name} {Description}} ...}
+
+Object path: /cards/<card_name>
+Message: set-jack-detection
+Parameters: {port_name|all}{0|1}
+Return value: None
+
+Object path: /cards/<card_name>
+Message: get-jack-detection
+Parameters: {port_name|all}
+Return value: {{port_name}{0|1}} ...
+If "all" is specified, the first value returned is the setting
+for the card.
+
+Object path: /cards/<card_name>
+Message: set-port-state
+Parameters: {port_name|all}{availability}
+Return value: None
+
+Object path: /cards/<card_name>
+Message: get-port-state
+Parameters: {port_name|all}
+Return value: {{port_name}{availability}} ...
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index b42c0407..03073a53 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -1880,7 +1880,7 @@  static void ucm_port_update_available(struct ucm_port *port) {
         }
     }
 
-    pa_device_port_set_available(port->core_port, available);
+    pa_device_port_set_available(port->core_port, available, false);
 }
 
 #else /* HAVE_ALSA_UCM */
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 385d61d2..104bb05d 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -421,10 +421,10 @@  static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
 
     for (tp = tports; tp->port; tp++)
         if (tp->avail != PA_AVAILABLE_NO)
-           pa_device_port_set_available(tp->port, tp->avail);
+           pa_device_port_set_available(tp->port, tp->avail, false);
     for (tp = tports; tp->port; tp++)
         if (tp->avail == PA_AVAILABLE_NO)
-           pa_device_port_set_available(tp->port, tp->avail);
+           pa_device_port_set_available(tp->port, tp->avail, false);
 
     for (tp = tports; tp->port; tp++) {
         pa_alsa_port_data *data;
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 935ee2ce..560de934 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -2253,9 +2253,9 @@  static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot
 
     /* Update port availability */
     pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name));
-    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_OUTPUT));
+    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_OUTPUT), false);
     pa_assert_se(port = pa_hashmap_get(u->card->ports, u->input_port_name));
-    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_INPUT));
+    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_INPUT), false);
 
     /* Acquire or release transport as needed */
     acquire = (t->state == PA_BLUETOOTH_TRANSPORT_STATE_PLAYING && u->profile == t->profile);
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index e91c034f..e056711c 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -127,6 +127,7 @@  static int card_message_handler(const char *object_path, const char *message, ch
     pa_card *c;
     char *port_name;
     bool jack_detection;
+    uint64_t port_state;
     void *state = NULL;
     void *state2;
     pa_device_port *port = NULL;
@@ -154,11 +155,29 @@  static int card_message_handler(const char *object_path, const char *message, ch
         if (!port) {
             c->jack_detection = jack_detection;
 
-            PA_HASHMAP_FOREACH(port, c->ports, state2)
+            PA_HASHMAP_FOREACH(port, c->ports, state2) {
+                pa_available_t avail = PA_AVAILABLE_UNKNOWN;
+
+                /* If jack detection was enabled, set the port state
+                 * to the hardware state. */
+                if (c->jack_detection)
+                    avail = port->hw_available;
+
                 port->jack_detection = c->jack_detection;
+                pa_device_port_set_available(port, avail, true);
+            }
+
+        } else {
+            pa_available_t avail = PA_AVAILABLE_UNKNOWN;
+
+            /* If jack detection was enabled, set the port state
+             * to the hardware state. */
+            if (jack_detection)
+                avail = port->hw_available;
 
-        } else
             port->jack_detection = jack_detection;
+            pa_device_port_set_available(port, avail, true);
+        }
 
         return PA_OK;
 
@@ -192,10 +211,29 @@  static int card_message_handler(const char *object_path, const char *message, ch
 
     } else if (pa_streq(message, "set-port-state")) {
 
-        /* Not implemented because jack_detection is still unused
-         * and manually setting a port state would require to disable
-         * jack detection */
-        return -PA_ERR_NOTIMPLEMENTED;
+        /* Get the requested port state */
+        if (pa_message_param_read_uint64(message_parameters, &port_state, &state) <= 0)
+            return -PA_ERR_INVALID;
+
+        /* Validate port state parameter */
+        if ((pa_available_t) port_state > PA_AVAILABLE_YES)
+            return -PA_ERR_INVALID;
+
+        if (!port) {
+
+            PA_HASHMAP_FOREACH(port, c->ports, state2) {
+
+                port->jack_detection = false;
+                pa_device_port_set_available(port, (pa_available_t) port_state, true);
+            }
+
+        } else {
+
+            port->jack_detection = false;
+            pa_device_port_set_available(port, (pa_available_t) port_state, true);
+        }
+
+        return PA_OK;
 
     } else if (pa_streq(message, "get-port-state")) {
         pa_message_param *param;
@@ -275,6 +313,8 @@  pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
     PA_HASHMAP_FOREACH(port, c->ports, state) {
         port->card = c;
         port->jack_detection = c->jack_detection;
+        if (!port->jack_detection)
+            pa_device_port_set_available(port, PA_AVAILABLE_UNKNOWN, true);
     }
 
     c->preferred_input_port = data->preferred_input_port;
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index 5cf4ac63..9735aa51 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -75,12 +75,25 @@  void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp)
     }
 }
 
-void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
+void pa_device_port_set_available(pa_device_port *p, pa_available_t status, bool force) {
     pa_assert(p);
 
+    /* If force is not set, status reflects the state of the port from a
+     * hardware perspective. We need to keep track of the real port state
+     * so that we can go back to it once jack detection is enabled for the
+     * port. If force is set, we are updating the port state manually, so
+     * the hardware state is unaffected. */
+    if (!force)
+        p->hw_available = status;
+
     if (p->available == status)
         return;
 
+    /* Do not set the port state if jack detection is disabled for the port
+     * unless we are setting the state manually. */
+    if (!force && !p->jack_detection)
+        return;
+
 /*    pa_assert(status != PA_AVAILABLE_UNKNOWN); */
 
     p->available = status;
diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
index 4787ff79..c71bd357 100644
--- a/src/pulsecore/device-port.h
+++ b/src/pulsecore/device-port.h
@@ -48,6 +48,7 @@  struct pa_device_port {
 
     unsigned priority;
     pa_available_t available;         /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */
+    pa_available_t hw_available;
 
     pa_proplist *proplist;
     pa_hashmap *profiles; /* Does not own the profiles */
@@ -82,7 +83,7 @@  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);
 
 /* The port's available status has changed */
-void pa_device_port_set_available(pa_device_port *p, pa_available_t available);
+void pa_device_port_set_available(pa_device_port *p, pa_available_t available, bool force);
 
 void pa_device_port_set_latency_offset(pa_device_port *p, int64_t offset);
 void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp);