card: Add messages to enable/disable jack detection

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.
This commit is contained in:
Georg Chini 2021-01-07 19:27:23 +01:00
parent 58521c05e8
commit f178a5b12e
7 changed files with 95 additions and 21 deletions

View file

@ -47,3 +47,28 @@ Object path: /card/<card_name>
Message: get-profile-sticky
Parameters: None
Return value: JSON "true" or "false"
Object path: /cards/<card_name>
Message: set-jack-detection
Parameters: {"port_name|all":true|false}
Return value: None
Object path: /cards/<card_name>
Message: get-jack-detection
Parameters: "port_name|all"
Return value: {"port_name":true|false}
If "all" is specified, the returned object looks different:
{"Card name":"card_name", "Detection states":{"port_name":true|false, ...}}
Object path: /cards/<card_name>
Message: set-port-state
Parameters: {"port_name|all":0|1|2}
Return value: None
0=unknown, 1=no, 2=yes
Object path: /cards/<card_name>
Message: get-port-state
Parameters: "port_name|all"
Return value: {"port_name":0|1|2}
If "all" is specified, the returned object looks different:
{"Card name":"card_name", "Port states":{"port_name":0|1|2, ...}}

View file

@ -2480,7 +2480,7 @@ static void device_set_available(pa_alsa_ucm_device *device, pa_available_t avai
device->available = available;
PA_DYNARRAY_FOREACH(port, device->ucm_ports, idx)
pa_device_port_set_available(port->core_port, port->device->available);
pa_device_port_set_available(port->core_port, port->device->available, false);
}
void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) {
@ -2519,7 +2519,7 @@ static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *
port->paths = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, pa_xfree,
(pa_free_cb_t) pa_alsa_path_free);
pa_device_port_set_available(port->core_port, port->device->available);
pa_device_port_set_available(port->core_port, port->device->available, false);
}
static void ucm_port_data_free(pa_device_port *port) {

View file

@ -435,10 +435,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;

View file

@ -2340,9 +2340,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);

View file

@ -163,10 +163,10 @@ static int card_message_handler(const char *object_path, const char *message, co
pa_card *c = userdata;
const char *port_name;
bool jack_detection;
int64_t port_state;
void *state = NULL;
pa_device_port *port = NULL;
const pa_json_object *o;
int64_t current_state;
char *message_handler_path;
pa_assert(c);
@ -240,7 +240,7 @@ static int card_message_handler(const char *object_path, const char *message, co
pa_log_info("Parameters type does not match message command");
return -PA_ERR_INVALID;
}
current_state = pa_json_object_get_int(o);
port_state = pa_json_object_get_int(o);
}
} else {
@ -256,15 +256,35 @@ static int card_message_handler(const char *object_path, const char *message, co
}
}
state = NULL;
if (pa_streq(message, "set-jack-detection")) {
if (!port) {
PA_HASHMAP_FOREACH(port, c->ports, state)
port->jack_detection = jack_detection;
PA_HASHMAP_FOREACH(port, c->ports, state) {
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;
port->jack_detection = 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;
@ -291,10 +311,25 @@ static int card_message_handler(const char *object_path, const char *message, co
} 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;
/* 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, state) {
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_json_encoder *encoder;
@ -306,14 +341,14 @@ static int card_message_handler(const char *object_path, const char *message, co
pa_json_encoder_begin_member_object(encoder, "Port states");
PA_HASHMAP_FOREACH(port, c->ports, state) {
current_state = port->available;
pa_json_encoder_add_member_int(encoder, port->name, current_state);
port_state = port->available;
pa_json_encoder_add_member_int(encoder, port->name, port_state);
}
pa_json_encoder_end_object(encoder);
} else {
current_state = port->available;
pa_json_encoder_add_member_int(encoder, port->name, current_state);
port_state = port->available;
pa_json_encoder_add_member_int(encoder, port->name, port_state);
}
pa_json_encoder_end_object(encoder);

View file

@ -90,12 +90,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;

View file

@ -50,6 +50,7 @@ struct pa_device_port {
unsigned priority;
pa_available_t available; /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */
char *availability_group; /* a string indentifier which determine the group of devices handling the available state simulteneously */
pa_available_t hw_available;
pa_proplist *proplist;
pa_hashmap *profiles; /* Does not own the profiles */
@ -88,7 +89,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);