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 | Message: get-profile-sticky | ||||||
| Parameters: None | Parameters: None | ||||||
| Return value: JSON "true" or "false" | 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; |     device->available = available; | ||||||
| 
 | 
 | ||||||
|     PA_DYNARRAY_FOREACH(port, device->ucm_ports, idx) |     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) { | 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, |     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_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) { | 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++) |     for (tp = tports; tp->port; tp++) | ||||||
|         if (tp->avail != PA_AVAILABLE_NO) |         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++) |     for (tp = tports; tp->port; tp++) | ||||||
|         if (tp->avail == PA_AVAILABLE_NO) |         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++) { |     for (tp = tports; tp->port; tp++) { | ||||||
|         pa_alsa_port_data *data; |         pa_alsa_port_data *data; | ||||||
|  |  | ||||||
|  | @ -2340,9 +2340,9 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot | ||||||
| 
 | 
 | ||||||
|     /* Update port availability */ |     /* Update port availability */ | ||||||
|     pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name)); |     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_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 or release transport as needed */ | ||||||
|     acquire = (t->state == PA_BLUETOOTH_TRANSPORT_STATE_PLAYING && u->profile == t->profile); |     acquire = (t->state == PA_BLUETOOTH_TRANSPORT_STATE_PLAYING && u->profile == t->profile); | ||||||
|  |  | ||||||
|  | @ -67,12 +67,14 @@ struct userdata { | ||||||
|     bool restore_bluetooth_profile; |     bool restore_bluetooth_profile; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define ENTRY_VERSION 5 | #define ENTRY_VERSION 6 | ||||||
| 
 | 
 | ||||||
| struct port_info { | struct port_info { | ||||||
|     char *name; |     char *name; | ||||||
|     int64_t offset; |     int64_t offset; | ||||||
|     char *profile; |     char *profile; | ||||||
|  |     bool jack_detection; | ||||||
|  |     pa_available_t available; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct entry { | 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 = pa_xnew0(struct port_info, 1); | ||||||
|         p_info->name = pa_xstrdup(port->name); |         p_info->name = pa_xstrdup(port->name); | ||||||
|         p_info->offset = port->latency_offset; |         p_info->offset = port->latency_offset; | ||||||
|  |         p_info->jack_detection = port->jack_detection; | ||||||
|  |         p_info->available = port->available; | ||||||
|         if (port->preferred_profile) |         if (port->preferred_profile) | ||||||
|             p_info->profile = pa_xstrdup(port->preferred_profile); |             p_info->profile = pa_xstrdup(port->preferred_profile); | ||||||
|     } else |     } else | ||||||
|  | @ -184,7 +188,11 @@ static bool entrys_equal(struct entry *a, struct entry *b) { | ||||||
| 
 | 
 | ||||||
|     PA_HASHMAP_FOREACH(Ap_info, a->ports, state) { |     PA_HASHMAP_FOREACH(Ap_info, a->ports, state) { | ||||||
|         if ((Bp_info = pa_hashmap_get(b->ports, Ap_info->name))) { |         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; |                 return false; | ||||||
|         } else |         } else | ||||||
|             return false; |             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_puts(t, p_info->name); | ||||||
|         pa_tagstruct_puts64(t, p_info->offset); |         pa_tagstruct_puts64(t, p_info->offset); | ||||||
|         pa_tagstruct_puts(t, p_info->profile); |         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); |     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; |         int64_t port_offset = 0; | ||||||
|         struct port_info *p_info; |         struct port_info *p_info; | ||||||
|         unsigned i; |         unsigned i; | ||||||
|  |         uint32_t available = PA_AVAILABLE_UNKNOWN; | ||||||
|  |         bool jack_detection = true; | ||||||
| 
 | 
 | ||||||
|         if (pa_tagstruct_getu32(t, &port_count) < 0) |         if (pa_tagstruct_getu32(t, &port_count) < 0) | ||||||
|             goto fail; |             goto fail; | ||||||
|  | @ -331,12 +343,19 @@ static struct entry* entry_read(struct userdata *u, const char *name) { | ||||||
|                 goto fail; |                 goto fail; | ||||||
|             if (version >= 3 && pa_tagstruct_gets(t, &profile_name) < 0) |             if (version >= 3 && pa_tagstruct_gets(t, &profile_name) < 0) | ||||||
|                 goto fail; |                 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 = port_info_new(NULL); | ||||||
|             p_info->name = pa_xstrdup(port_name); |             p_info->name = pa_xstrdup(port_name); | ||||||
|             p_info->offset = port_offset; |             p_info->offset = port_offset; | ||||||
|             if (profile_name) |             if (profile_name) | ||||||
|                 p_info->profile = pa_xstrdup(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); |             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); |     pa_assert(card); | ||||||
| 
 | 
 | ||||||
|     if (card->save_profile) |     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 |     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) { | 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; |     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) { | static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new_data, struct userdata *u) { | ||||||
|     struct entry *e; |     struct entry *e; | ||||||
|     void *state; |     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
 |     /* Always restore the latency offsets because their
 | ||||||
|      * initial value is always 0 */ |      * 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) |     PA_HASHMAP_FOREACH(p_info, e->ports, state) | ||||||
|         if ((p = pa_hashmap_get(new_data->ports, p_info->name))) { |         if ((p = pa_hashmap_get(new_data->ports, p_info->name))) { | ||||||
|             p->latency_offset = p_info->offset; |             p->latency_offset = p_info->offset; | ||||||
|             if (!p->preferred_profile && p_info->profile) |             if (!p->preferred_profile && p_info->profile) | ||||||
|                 pa_device_port_set_preferred_profile(p, 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) { |     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_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_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_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))) |     if (!(state_path = pa_state_path(NULL, true))) | ||||||
|         goto fail; |         goto fail; | ||||||
|  |  | ||||||
|  | @ -38,8 +38,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "card.h" | #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) { | static char* make_message_handler_path(const char *name) { | ||||||
|     return pa_sprintf_malloc("/card/%s", 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); |     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 *pa_card_new(pa_core *core, pa_card_new_data *data) { | ||||||
|     pa_card *c; |     pa_card *c; | ||||||
|     const char *name, *tmp; |     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)); |             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 pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) { | ||||||
|     int r; |     int r; | ||||||
| 
 | 
 | ||||||
|  | @ -465,44 +653,3 @@ int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause) { | ||||||
| 
 | 
 | ||||||
|     return ret; |     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_input_port; | ||||||
|     pa_device_port *preferred_output_port; |     pa_device_port *preferred_output_port; | ||||||
| 
 | 
 | ||||||
|  |     bool jack_detection; | ||||||
|  | 
 | ||||||
|     bool namereg_fail:1; |     bool namereg_fail:1; | ||||||
| } pa_card_new_data; | } pa_card_new_data; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -136,6 +136,7 @@ typedef enum pa_core_hook { | ||||||
|     PA_CORE_HOOK_CARD_SUSPEND_CHANGED, |     PA_CORE_HOOK_CARD_SUSPEND_CHANGED, | ||||||
|     PA_CORE_HOOK_PORT_AVAILABLE_CHANGED, |     PA_CORE_HOOK_PORT_AVAILABLE_CHANGED, | ||||||
|     PA_CORE_HOOK_PORT_LATENCY_OFFSET_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_SINK_CHANGED, | ||||||
|     PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED, |     PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED, | ||||||
|     PA_CORE_HOOK_MODULE_NEW, |     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); |     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) |     if (p->available == status) | ||||||
|         return; |         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); */ | /*    pa_assert(status != PA_AVAILABLE_UNKNOWN); */ | ||||||
| 
 | 
 | ||||||
|     p->available = status; |     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->type = data->type; | ||||||
| 
 | 
 | ||||||
|     p->latency_offset = 0; |     p->latency_offset = 0; | ||||||
|  |     p->jack_detection = true; | ||||||
|     p->proplist = pa_proplist_new(); |     p->proplist = pa_proplist_new(); | ||||||
| 
 | 
 | ||||||
|     return p; |     return p; | ||||||
|  |  | ||||||
|  | @ -45,9 +45,12 @@ struct pa_device_port { | ||||||
|     char *preferred_profile; |     char *preferred_profile; | ||||||
|     pa_device_port_type_t type; |     pa_device_port_type_t type; | ||||||
| 
 | 
 | ||||||
|  |     bool jack_detection; | ||||||
|  | 
 | ||||||
|     unsigned priority; |     unsigned priority; | ||||||
|     pa_available_t available;         /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */ |     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 */ |     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_proplist *proplist; | ||||||
|     pa_hashmap *profiles; /* Does not own the profiles */ |     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); | 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 */ | /* 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_latency_offset(pa_device_port *p, int64_t offset); | ||||||
| void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp); | 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