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(-) 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); -- 2.14.1