mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-10-29 05:40:23 -04:00 
			
		
		
		
	Merge branch 'jack_detection' into 'master'
Add message commands to enable/disable jack detection per port See merge request pulseaudio/pulseaudio!452
This commit is contained in:
		
						commit
						8dc3837d1e
					
				
					 10 changed files with 364 additions and 75 deletions
				
			
		|  | @ -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, ...}} | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -67,12 +67,14 @@ struct userdata { | |||
|     bool restore_bluetooth_profile; | ||||
| }; | ||||
| 
 | ||||
| #define ENTRY_VERSION 5 | ||||
| #define ENTRY_VERSION 6 | ||||
| 
 | ||||
| struct port_info { | ||||
|     char *name; | ||||
|     int64_t offset; | ||||
|     char *profile; | ||||
|     bool jack_detection; | ||||
|     pa_available_t available; | ||||
| }; | ||||
| 
 | ||||
| struct entry { | ||||
|  | @ -126,6 +128,8 @@ static struct port_info *port_info_new(pa_device_port *port) { | |||
|         p_info = pa_xnew0(struct port_info, 1); | ||||
|         p_info->name = pa_xstrdup(port->name); | ||||
|         p_info->offset = port->latency_offset; | ||||
|         p_info->jack_detection = port->jack_detection; | ||||
|         p_info->available = port->available; | ||||
|         if (port->preferred_profile) | ||||
|             p_info->profile = pa_xstrdup(port->preferred_profile); | ||||
|     } else | ||||
|  | @ -184,7 +188,11 @@ static bool entrys_equal(struct entry *a, struct entry *b) { | |||
| 
 | ||||
|     PA_HASHMAP_FOREACH(Ap_info, a->ports, state) { | ||||
|         if ((Bp_info = pa_hashmap_get(b->ports, Ap_info->name))) { | ||||
|             if (Ap_info->offset != Bp_info->offset) | ||||
|             if (Ap_info->offset != Bp_info->offset || | ||||
|                 Ap_info->jack_detection != Bp_info->jack_detection) | ||||
|                 return false; | ||||
|             /* Availability only matters if jack detection is off */ | ||||
|             if (!Ap_info->jack_detection && Ap_info->available != Bp_info->available) | ||||
|                 return false; | ||||
|         } else | ||||
|             return false; | ||||
|  | @ -222,6 +230,8 @@ static bool entry_write(struct userdata *u, const char *name, const struct entry | |||
|         pa_tagstruct_puts(t, p_info->name); | ||||
|         pa_tagstruct_puts64(t, p_info->offset); | ||||
|         pa_tagstruct_puts(t, p_info->profile); | ||||
|         pa_tagstruct_put_boolean(t, p_info->jack_detection); | ||||
|         pa_tagstruct_putu32(t, (uint32_t)p_info->available); | ||||
|     } | ||||
| 
 | ||||
|     pa_tagstruct_puts(t, e->preferred_input_port); | ||||
|  | @ -319,6 +329,8 @@ static struct entry* entry_read(struct userdata *u, const char *name) { | |||
|         int64_t port_offset = 0; | ||||
|         struct port_info *p_info; | ||||
|         unsigned i; | ||||
|         uint32_t available = PA_AVAILABLE_UNKNOWN; | ||||
|         bool jack_detection = true; | ||||
| 
 | ||||
|         if (pa_tagstruct_getu32(t, &port_count) < 0) | ||||
|             goto fail; | ||||
|  | @ -331,12 +343,19 @@ static struct entry* entry_read(struct userdata *u, const char *name) { | |||
|                 goto fail; | ||||
|             if (version >= 3 && pa_tagstruct_gets(t, &profile_name) < 0) | ||||
|                 goto fail; | ||||
|             if (version >= 6) { | ||||
|                 if (pa_tagstruct_get_boolean(t, &jack_detection) < 0 || | ||||
|                     pa_tagstruct_getu32(t, &available) < 0) | ||||
|                     goto fail; | ||||
|             } | ||||
| 
 | ||||
|             p_info = port_info_new(NULL); | ||||
|             p_info->name = pa_xstrdup(port_name); | ||||
|             p_info->offset = port_offset; | ||||
|             if (profile_name) | ||||
|                 p_info->profile = pa_xstrdup(profile_name); | ||||
|             p_info->jack_detection = jack_detection; | ||||
|             p_info->available = (pa_available_t)available; | ||||
| 
 | ||||
|             pa_assert_se(pa_hashmap_put(e->ports, p_info->name, p_info) >= 0); | ||||
|         } | ||||
|  | @ -399,9 +418,9 @@ static void show_full_info(pa_card *card) { | |||
|     pa_assert(card); | ||||
| 
 | ||||
|     if (card->save_profile) | ||||
|         pa_log_info("Storing profile and port latency offsets for card %s.", card->name); | ||||
|         pa_log_info("Storing profile, port latency offsets, jack detection and port availability for card %s.", card->name); | ||||
|     else | ||||
|         pa_log_info("Storing port latency offsets for card %s.", card->name); | ||||
|         pa_log_info("Storing port latency offsets, jack detection and port availability for card %s.", card->name); | ||||
| } | ||||
| 
 | ||||
| static pa_hook_result_t card_put_hook_callback(pa_core *c, pa_card *card, struct userdata *u) { | ||||
|  | @ -534,6 +553,76 @@ static pa_hook_result_t port_offset_change_callback(pa_core *c, pa_device_port * | |||
|     return PA_HOOK_OK; | ||||
| } | ||||
| 
 | ||||
| static pa_hook_result_t port_available_change_callback(pa_core *c, pa_device_port *port, struct userdata *u) { | ||||
|     struct entry *entry; | ||||
|     pa_card *card; | ||||
| 
 | ||||
|     pa_assert(port); | ||||
| 
 | ||||
|     /* If jack detection is enabled, the availability change needs not be saved */ | ||||
|     if (port->jack_detection) | ||||
|         return PA_HOOK_OK; | ||||
| 
 | ||||
|     card = port->card; | ||||
| 
 | ||||
|     if ((entry = entry_read(u, card->name))) { | ||||
|         struct port_info *p_info; | ||||
| 
 | ||||
|         if ((p_info = pa_hashmap_get(entry->ports, port->name))) | ||||
|             p_info->available = port->available; | ||||
|         else { | ||||
|             p_info = port_info_new(port); | ||||
|             pa_assert_se(pa_hashmap_put(entry->ports, p_info->name, p_info) >= 0); | ||||
|         } | ||||
| 
 | ||||
|         pa_log_info("Storing availability for port %s on card %s.", port->name, card->name); | ||||
| 
 | ||||
|     } else { | ||||
|         entry = entry_from_card(card); | ||||
|         show_full_info(card); | ||||
|     } | ||||
| 
 | ||||
|     if (entry_write(u, card->name, entry)) | ||||
|         trigger_save(u); | ||||
| 
 | ||||
|     entry_free(entry); | ||||
|     return PA_HOOK_OK; | ||||
| } | ||||
| 
 | ||||
| static pa_hook_result_t port_jack_detection_change_callback(pa_core *c, pa_device_port *port, struct userdata *u) { | ||||
|     struct entry *entry; | ||||
|     pa_card *card; | ||||
| 
 | ||||
|     pa_assert(port); | ||||
| 
 | ||||
|     card = port->card; | ||||
| 
 | ||||
|     if ((entry = entry_read(u, card->name))) { | ||||
|         struct port_info *p_info; | ||||
| 
 | ||||
|         if ((p_info = pa_hashmap_get(entry->ports, port->name))) { | ||||
|             p_info->jack_detection = port->jack_detection; | ||||
|             if (!p_info->jack_detection) | ||||
|                 p_info->available = port->available; | ||||
|         } else { | ||||
|             p_info = port_info_new(port); | ||||
|             pa_assert_se(pa_hashmap_put(entry->ports, p_info->name, p_info) >= 0); | ||||
|         } | ||||
| 
 | ||||
|         pa_log_info("Storing jack detection for port %s on card %s.", port->name, card->name); | ||||
| 
 | ||||
|     } else { | ||||
|         entry = entry_from_card(card); | ||||
|         show_full_info(card); | ||||
|     } | ||||
| 
 | ||||
|     if (entry_write(u, card->name, entry)) | ||||
|         trigger_save(u); | ||||
| 
 | ||||
|     entry_free(entry); | ||||
|     return PA_HOOK_OK; | ||||
| } | ||||
| 
 | ||||
| static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new_data, struct userdata *u) { | ||||
|     struct entry *e; | ||||
|     void *state; | ||||
|  | @ -548,13 +637,19 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new | |||
|     /* Always restore the latency offsets because their
 | ||||
|      * initial value is always 0 */ | ||||
| 
 | ||||
|     pa_log_info("Restoring port latency offsets for card %s.", new_data->name); | ||||
|     pa_log_info("Restoring port latency offsets and jack detection for card %s.", new_data->name); | ||||
| 
 | ||||
|     PA_HASHMAP_FOREACH(p_info, e->ports, state) | ||||
|         if ((p = pa_hashmap_get(new_data->ports, p_info->name))) { | ||||
|             p->latency_offset = p_info->offset; | ||||
|             if (!p->preferred_profile && p_info->profile) | ||||
|                 pa_device_port_set_preferred_profile(p, p_info->profile); | ||||
| 
 | ||||
|             /* Restore availability and jack detection only if jack detction was off */ | ||||
|             if (!p_info->jack_detection) { | ||||
|                 p->jack_detection = p_info->jack_detection; | ||||
|                 p->available = p_info->available; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     if (e->preferred_input_port) { | ||||
|  | @ -674,6 +769,8 @@ int pa__init(pa_module*m) { | |||
|     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u); | ||||
|     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_ADDED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_added_callback, u); | ||||
|     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) port_offset_change_callback, u); | ||||
|     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) port_available_change_callback, u); | ||||
|     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_JACK_DETECTION_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) port_jack_detection_change_callback, u); | ||||
| 
 | ||||
|     if (!(state_path = pa_state_path(NULL, true))) | ||||
|         goto fail; | ||||
|  |  | |||
|  | @ -38,8 +38,6 @@ | |||
| 
 | ||||
| #include "card.h" | ||||
| 
 | ||||
| static int card_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata); | ||||
| 
 | ||||
| static char* make_message_handler_path(const char *name) { | ||||
|     return pa_sprintf_malloc("/card/%s", name); | ||||
| } | ||||
|  | @ -142,6 +140,215 @@ void pa_card_new_data_done(pa_card_new_data *data) { | |||
|     pa_xfree(data->name); | ||||
| } | ||||
| 
 | ||||
| static int card_set_profile_is_sticky(pa_card *c, bool profile_is_sticky) { | ||||
|     pa_assert(c); | ||||
| 
 | ||||
|     if (c->profile_is_sticky == profile_is_sticky) | ||||
|         return 0; | ||||
| 
 | ||||
|     pa_log_debug("%s: profile_is_sticky: %s -> %s", | ||||
|             c->name, pa_yes_no(c->profile_is_sticky), pa_yes_no(profile_is_sticky)); | ||||
| 
 | ||||
|     c->profile_is_sticky = profile_is_sticky; | ||||
| 
 | ||||
|     if (c->linked) { | ||||
|         pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c); | ||||
|         pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static void set_jack_detection(pa_device_port *port, bool jack_detection, pa_available_t avail) { | ||||
| 
 | ||||
|     /* If jack detection was enabled, set the port state
 | ||||
|      * to the hardware state. */ | ||||
|     if (jack_detection) | ||||
|         avail = port->hw_available; | ||||
| 
 | ||||
|     if (port->jack_detection != jack_detection) { | ||||
|         port->jack_detection = jack_detection; | ||||
|         pa_hook_fire(&port->core->hooks[PA_CORE_HOOK_PORT_JACK_DETECTION_CHANGED], port); | ||||
|     } | ||||
| 
 | ||||
|     pa_device_port_set_available(port, avail, true); | ||||
| } | ||||
| 
 | ||||
| static int card_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) { | ||||
|     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; | ||||
|     char *message_handler_path; | ||||
| 
 | ||||
|     pa_assert(c); | ||||
|     pa_assert(message); | ||||
|     pa_assert(response); | ||||
| 
 | ||||
|     message_handler_path = make_message_handler_path(c->name); | ||||
| 
 | ||||
|     if (!object_path || !pa_streq(object_path, message_handler_path)) { | ||||
|         pa_xfree(message_handler_path); | ||||
|         return -PA_ERR_NOENTITY; | ||||
|     } | ||||
| 
 | ||||
|     pa_xfree(message_handler_path); | ||||
| 
 | ||||
|     /* Sticky profile operations */ | ||||
| 
 | ||||
|     if (pa_streq(message, "get-profile-sticky")) { | ||||
|         pa_json_encoder *encoder; | ||||
|         encoder = pa_json_encoder_new(); | ||||
| 
 | ||||
|         pa_json_encoder_add_element_bool(encoder, c->profile_is_sticky); | ||||
| 
 | ||||
|         *response = pa_json_encoder_to_string_free(encoder); | ||||
| 
 | ||||
|         return PA_OK; | ||||
|     } else if (pa_streq(message, "set-profile-sticky")) { | ||||
| 
 | ||||
|         if (!parameters || pa_json_object_get_type(parameters) != PA_JSON_TYPE_BOOL) { | ||||
|             pa_log_info("Card operation set-profile-sticky requires argument: \"true\" or \"false\""); | ||||
|             return -PA_ERR_INVALID; | ||||
|         } | ||||
| 
 | ||||
|         card_set_profile_is_sticky(c, pa_json_object_get_bool(parameters)); | ||||
| 
 | ||||
|         return PA_OK; | ||||
|     } | ||||
| 
 | ||||
|     /* Jack detection operations */ | ||||
| 
 | ||||
|     if (!parameters) { | ||||
|         pa_log_info("Card jack detection operations require at least one parameter"); | ||||
|         return -PA_ERR_INVALID; | ||||
|     } | ||||
| 
 | ||||
|     /* Get the arguments of the message */ | ||||
|     if (pa_json_object_get_type(parameters) == PA_JSON_TYPE_STRING) | ||||
|        port_name = pa_json_object_get_string(parameters); | ||||
| 
 | ||||
|     else if (pa_json_object_get_type(parameters) == PA_JSON_TYPE_OBJECT) { | ||||
|         const pa_hashmap *h; | ||||
| 
 | ||||
|         h = pa_json_object_get_object_member_hashmap(parameters); | ||||
|         if (pa_hashmap_size(h) > 1) { | ||||
|             pa_log_info("Too many parameters"); | ||||
|             return -PA_ERR_INVALID; | ||||
|         } | ||||
|         o = pa_hashmap_iterate(h, &state, (const void **) &port_name); | ||||
|         if (!o || (pa_json_object_get_type(o) != PA_JSON_TYPE_BOOL && pa_json_object_get_type(o) != PA_JSON_TYPE_INT)) { | ||||
|             pa_log_info("Parameters must contain a valid JSON object"); | ||||
|             return -PA_ERR_INVALID; | ||||
|         } | ||||
|         if (pa_json_object_get_type(o) == PA_JSON_TYPE_BOOL) { | ||||
|             if (!pa_streq(message, "set-jack-detection")) { | ||||
|                 pa_log_info("Parameters type does not match message command"); | ||||
|                 return -PA_ERR_INVALID; | ||||
|             } | ||||
|             jack_detection = pa_json_object_get_bool(o); | ||||
|         } else { | ||||
|             if (!pa_streq(message, "set-port-state")) { | ||||
|                 pa_log_info("Parameters type does not match message command"); | ||||
|                 return -PA_ERR_INVALID; | ||||
|             } | ||||
|             port_state = pa_json_object_get_int(o); | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|         pa_log_info("Parameters must be a valid JSON object"); | ||||
|         return -PA_ERR_INVALID; | ||||
|     } | ||||
| 
 | ||||
|     /* If the port argument is not "all", retrieve the port */ | ||||
|     if (!pa_streq(port_name, "all")) { | ||||
|         if (!(port = pa_hashmap_get(c->ports, port_name))) { | ||||
|             pa_log_info("Parameters do not contain a valid port name"); | ||||
|             return -PA_ERR_INVALID; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     state = NULL; | ||||
| 
 | ||||
|     if (pa_streq(message, "set-jack-detection")) { | ||||
| 
 | ||||
|         if (!port) { | ||||
|             PA_HASHMAP_FOREACH(port, c->ports, state) | ||||
|                 set_jack_detection(port, jack_detection, PA_AVAILABLE_UNKNOWN); | ||||
| 
 | ||||
|         } else | ||||
|             set_jack_detection(port, jack_detection, PA_AVAILABLE_UNKNOWN); | ||||
| 
 | ||||
|         return PA_OK; | ||||
| 
 | ||||
|     } else if (pa_streq(message, "get-jack-detection")) { | ||||
|         pa_json_encoder *encoder; | ||||
| 
 | ||||
|         encoder = pa_json_encoder_new(); | ||||
|         pa_json_encoder_begin_element_object(encoder); | ||||
|         if (!port) { | ||||
|             pa_json_encoder_add_member_string(encoder, "Card name", c->name); | ||||
| 
 | ||||
|             pa_json_encoder_begin_member_object(encoder, "Detection states"); | ||||
|             PA_HASHMAP_FOREACH(port, c->ports, state) | ||||
|                 pa_json_encoder_add_member_bool(encoder, port->name, port->jack_detection); | ||||
|             pa_json_encoder_end_object(encoder); | ||||
| 
 | ||||
|        } else | ||||
|             pa_json_encoder_add_member_bool(encoder, port->name, port->jack_detection); | ||||
| 
 | ||||
|        pa_json_encoder_end_object(encoder); | ||||
| 
 | ||||
|         *response = pa_json_encoder_to_string_free(encoder); | ||||
|         return PA_OK; | ||||
| 
 | ||||
|     } else if (pa_streq(message, "set-port-state")) { | ||||
| 
 | ||||
|         /* 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) | ||||
|                 set_jack_detection(port, false, (pa_available_t) port_state); | ||||
| 
 | ||||
|         } else | ||||
|             set_jack_detection(port, false, (pa_available_t) port_state); | ||||
| 
 | ||||
|         return PA_OK; | ||||
| 
 | ||||
|     } else if (pa_streq(message, "get-port-state")) { | ||||
|         pa_json_encoder *encoder; | ||||
| 
 | ||||
|         encoder = pa_json_encoder_new(); | ||||
|         pa_json_encoder_begin_element_object(encoder); | ||||
|         if (!port) { | ||||
|             pa_json_encoder_add_member_string(encoder, "Card name", c->name); | ||||
| 
 | ||||
|             pa_json_encoder_begin_member_object(encoder, "Port states"); | ||||
|             PA_HASHMAP_FOREACH(port, c->ports, state) { | ||||
|                 port_state = port->available; | ||||
|                 pa_json_encoder_add_member_int(encoder, port->name, port_state); | ||||
|             } | ||||
|             pa_json_encoder_end_object(encoder); | ||||
| 
 | ||||
|        } else { | ||||
|             port_state = port->available; | ||||
|             pa_json_encoder_add_member_int(encoder, port->name, port_state); | ||||
|        } | ||||
|        pa_json_encoder_end_object(encoder); | ||||
| 
 | ||||
|         *response = pa_json_encoder_to_string_free(encoder); | ||||
|         return PA_OK; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     return -PA_ERR_NOTIMPLEMENTED; | ||||
| } | ||||
| 
 | ||||
| pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) { | ||||
|     pa_card *c; | ||||
|     const char *name, *tmp; | ||||
|  | @ -328,25 +535,6 @@ static void update_port_preferred_profile(pa_card *c) { | |||
|             pa_device_port_set_preferred_profile(source->active_port, profile_name_for_dir(c->active_profile, PA_DIRECTION_INPUT)); | ||||
| } | ||||
| 
 | ||||
| static int card_set_profile_is_sticky(pa_card *c, bool profile_is_sticky) { | ||||
|     pa_assert(c); | ||||
| 
 | ||||
|     if (c->profile_is_sticky == profile_is_sticky) | ||||
|         return 0; | ||||
| 
 | ||||
|     pa_log_debug("%s: profile_is_sticky: %s -> %s", | ||||
|             c->name, pa_yes_no(c->profile_is_sticky), pa_yes_no(profile_is_sticky)); | ||||
| 
 | ||||
|     c->profile_is_sticky = profile_is_sticky; | ||||
| 
 | ||||
|     if (c->linked) { | ||||
|         pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c); | ||||
|         pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) { | ||||
|     int r; | ||||
| 
 | ||||
|  | @ -465,44 +653,3 @@ int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause) { | |||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int card_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) { | ||||
|     pa_card *c = userdata; | ||||
|     char *message_handler_path; | ||||
| 
 | ||||
|     pa_assert(c); | ||||
|     pa_assert(message); | ||||
|     pa_assert(response); | ||||
| 
 | ||||
|     message_handler_path = make_message_handler_path(c->name); | ||||
| 
 | ||||
|     if (!object_path || !pa_streq(object_path, message_handler_path)) { | ||||
|         pa_xfree(message_handler_path); | ||||
|         return -PA_ERR_NOENTITY; | ||||
|     } | ||||
| 
 | ||||
|     pa_xfree(message_handler_path); | ||||
| 
 | ||||
|     if (pa_streq(message, "get-profile-sticky")) { | ||||
|         pa_json_encoder *encoder; | ||||
|         encoder = pa_json_encoder_new(); | ||||
| 
 | ||||
|         pa_json_encoder_add_element_bool(encoder, c->profile_is_sticky); | ||||
| 
 | ||||
|         *response = pa_json_encoder_to_string_free(encoder); | ||||
| 
 | ||||
|         return PA_OK; | ||||
|     } else if (pa_streq(message, "set-profile-sticky")) { | ||||
| 
 | ||||
|         if (!parameters || pa_json_object_get_type(parameters) != PA_JSON_TYPE_BOOL) { | ||||
|             pa_log_info("Card operation set-profile-sticky requires argument: \"true\" or \"false\""); | ||||
|             return -PA_ERR_INVALID; | ||||
|         } | ||||
| 
 | ||||
|         card_set_profile_is_sticky(c, pa_json_object_get_bool(parameters)); | ||||
| 
 | ||||
|         return PA_OK; | ||||
|     } | ||||
| 
 | ||||
|     return -PA_ERR_NOTIMPLEMENTED; | ||||
| } | ||||
|  |  | |||
|  | @ -106,6 +106,8 @@ typedef struct pa_card_new_data { | |||
|     pa_device_port *preferred_input_port; | ||||
|     pa_device_port *preferred_output_port; | ||||
| 
 | ||||
|     bool jack_detection; | ||||
| 
 | ||||
|     bool namereg_fail:1; | ||||
| } pa_card_new_data; | ||||
| 
 | ||||
|  |  | |||
|  | @ -136,6 +136,7 @@ typedef enum pa_core_hook { | |||
|     PA_CORE_HOOK_CARD_SUSPEND_CHANGED, | ||||
|     PA_CORE_HOOK_PORT_AVAILABLE_CHANGED, | ||||
|     PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED, | ||||
|     PA_CORE_HOOK_PORT_JACK_DETECTION_CHANGED, | ||||
|     PA_CORE_HOOK_DEFAULT_SINK_CHANGED, | ||||
|     PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED, | ||||
|     PA_CORE_HOOK_MODULE_NEW, | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -200,6 +213,7 @@ pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, si | |||
|     p->type = data->type; | ||||
| 
 | ||||
|     p->latency_offset = 0; | ||||
|     p->jack_detection = true; | ||||
|     p->proplist = pa_proplist_new(); | ||||
| 
 | ||||
|     return p; | ||||
|  |  | |||
|  | @ -45,9 +45,12 @@ struct pa_device_port { | |||
|     char *preferred_profile; | ||||
|     pa_device_port_type_t type; | ||||
| 
 | ||||
|     bool jack_detection; | ||||
| 
 | ||||
|     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 */ | ||||
|  | @ -86,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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Georg Chini
						Georg Chini