mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	bluez5: different icon for A2DP & HFP output routes
Set different icons for A2DP & HFP output routes, so that they look different (in Gnome). Don't call the non-HFP output route as "headset" or "handsfree" in this case, to be less ambiguous about microphone availability. Also set device.icon-name for the device too.
This commit is contained in:
		
							parent
							
								
									9586ef891e
								
							
						
					
					
						commit
						270eda63a9
					
				
					 3 changed files with 71 additions and 6 deletions
				
			
		|  | @ -1721,8 +1721,9 @@ static void emit_device_info(struct spa_bt_monitor *monitor, | ||||||
| { | { | ||||||
| 	struct spa_device_object_info info; | 	struct spa_device_object_info info; | ||||||
| 	char dev[32], name[128], class[16], vendor_id[64], product_id[64], product_id_tot[67]; | 	char dev[32], name[128], class[16], vendor_id[64], product_id[64], product_id_tot[67]; | ||||||
| 	struct spa_dict_item items[23]; | 	struct spa_dict_item items[24]; | ||||||
| 	uint32_t n_items = 0; | 	uint32_t n_items = 0; | ||||||
|  | 	enum spa_bt_form_factor ff; | ||||||
| 
 | 
 | ||||||
| 	info = SPA_DEVICE_OBJECT_INFO_INIT(); | 	info = SPA_DEVICE_OBJECT_INFO_INIT(); | ||||||
| 	info.type = SPA_TYPE_INTERFACE_Device; | 	info.type = SPA_TYPE_INTERFACE_Device; | ||||||
|  | @ -1731,6 +1732,8 @@ static void emit_device_info(struct spa_bt_monitor *monitor, | ||||||
| 		SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; | 		SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; | ||||||
| 	info.flags = 0; | 	info.flags = 0; | ||||||
| 
 | 
 | ||||||
|  | 	ff = spa_bt_form_factor_from_class(device->bluetooth_class); | ||||||
|  | 
 | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "bluez5"); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "bluez5"); | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, "bluetooth"); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, "bluetooth"); | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Device"); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Device"); | ||||||
|  | @ -1745,9 +1748,8 @@ static void emit_device_info(struct spa_bt_monitor *monitor, | ||||||
| 		items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, vendor_id); | 		items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, vendor_id); | ||||||
| 		items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, product_id_tot); | 		items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, product_id_tot); | ||||||
| 	} | 	} | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_FORM_FACTOR, | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_FORM_FACTOR, spa_bt_form_factor_name(ff)); | ||||||
| 			spa_bt_form_factor_name( | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ICON_NAME, spa_bt_form_factor_icon_name(ff)); | ||||||
| 				spa_bt_form_factor_from_class(device->bluetooth_class))); |  | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_STRING, device->address); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_STRING, device->address); | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ICON, device->icon); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ICON, device->icon); | ||||||
| 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PATH, device->path); | 	items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PATH, device->path); | ||||||
|  |  | ||||||
|  | @ -534,7 +534,7 @@ static void emit_device_set_node(struct impl *this, uint32_t id) | ||||||
| 	struct spa_bt_device *device = this->bt_dev; | 	struct spa_bt_device *device = this->bt_dev; | ||||||
| 	struct node *node = &this->nodes[id]; | 	struct node *node = &this->nodes[id]; | ||||||
| 	struct spa_device_object_info info; | 	struct spa_device_object_info info; | ||||||
| 	struct spa_dict_item items[8]; | 	struct spa_dict_item items[9]; | ||||||
| 	char str_id[32], members_json[8192], channels_json[512]; | 	char str_id[32], members_json[8192], channels_json[512]; | ||||||
| 	struct device_set_member *members; | 	struct device_set_member *members; | ||||||
| 	uint32_t n_members; | 	uint32_t n_members; | ||||||
|  | @ -2150,6 +2150,22 @@ static bool profile_has_route(uint32_t profile, uint32_t route) | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool device_has_route(struct impl *this, uint32_t route) | ||||||
|  | { | ||||||
|  | 	bool found = false; | ||||||
|  | 
 | ||||||
|  | 	if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_DUPLEX) | ||||||
|  | 		found = found || profile_has_route(DEVICE_PROFILE_A2DP, route); | ||||||
|  | 	if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_BAP_AUDIO) | ||||||
|  | 		found = found || profile_has_route(DEVICE_PROFILE_BAP, route); | ||||||
|  | 	if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) | ||||||
|  | 		found = found || profile_has_route(DEVICE_PROFILE_HSP_HFP, route); | ||||||
|  | 	if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_ASHA_SINK) | ||||||
|  | 		found = found || profile_has_route(DEVICE_PROFILE_ASHA, route); | ||||||
|  | 
 | ||||||
|  | 	return found; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | ||||||
| 		uint32_t id, uint32_t route, uint32_t profile) | 		uint32_t id, uint32_t route, uint32_t profile) | ||||||
| { | { | ||||||
|  | @ -2157,6 +2173,7 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | ||||||
| 	struct spa_pod_frame f[2]; | 	struct spa_pod_frame f[2]; | ||||||
| 	enum spa_direction direction; | 	enum spa_direction direction; | ||||||
| 	const char *name_prefix, *description, *hfp_description, *port_type; | 	const char *name_prefix, *description, *hfp_description, *port_type; | ||||||
|  | 	const char *port_icon_name = NULL; | ||||||
| 	enum spa_bt_form_factor ff; | 	enum spa_bt_form_factor ff; | ||||||
| 	enum spa_bluetooth_audio_codec codec; | 	enum spa_bluetooth_audio_codec codec; | ||||||
| 	enum spa_param_availability available; | 	enum spa_param_availability available; | ||||||
|  | @ -2250,6 +2267,20 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | ||||||
| 		dev = DEVICE_ID_SINK; | 		dev = DEVICE_ID_SINK; | ||||||
| 		available = this->device_set.sink_enabled ? | 		available = this->device_set.sink_enabled ? | ||||||
| 			SPA_PARAM_AVAILABILITY_no : SPA_PARAM_AVAILABILITY_yes; | 			SPA_PARAM_AVAILABILITY_no : SPA_PARAM_AVAILABILITY_yes; | ||||||
|  | 
 | ||||||
|  | 		if (device_has_route(this, ROUTE_HF_OUTPUT)) { | ||||||
|  | 			/* Distinguish A2DP vs. HFP output routes */ | ||||||
|  | 			switch (ff) { | ||||||
|  | 			case SPA_BT_FORM_FACTOR_HEADSET: | ||||||
|  | 			case SPA_BT_FORM_FACTOR_HANDSFREE: | ||||||
|  | 				port_icon_name = spa_bt_form_factor_icon_name(SPA_BT_FORM_FACTOR_HEADPHONE); | ||||||
|  | 				/* Don't call it "headset", the HF one has the mic */ | ||||||
|  | 				description = _("Headphone"); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case ROUTE_HF_OUTPUT: | 	case ROUTE_HF_OUTPUT: | ||||||
| 		direction = SPA_DIRECTION_OUTPUT; | 		direction = SPA_DIRECTION_OUTPUT; | ||||||
|  | @ -2257,6 +2288,8 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | ||||||
| 		description = hfp_description; | 		description = hfp_description; | ||||||
| 		dev = DEVICE_ID_SINK; | 		dev = DEVICE_ID_SINK; | ||||||
| 		available = SPA_PARAM_AVAILABILITY_yes; | 		available = SPA_PARAM_AVAILABILITY_yes; | ||||||
|  | 		if (device_has_route(this, ROUTE_OUTPUT)) | ||||||
|  | 			port_icon_name = spa_bt_form_factor_icon_name(SPA_BT_FORM_FACTOR_HEADSET); | ||||||
| 		break; | 		break; | ||||||
| 	case ROUTE_SET_INPUT: | 	case ROUTE_SET_INPUT: | ||||||
| 		if (!(this->device_set.source_enabled && this->device_set.leader)) | 		if (!(this->device_set.source_enabled && this->device_set.leader)) | ||||||
|  | @ -2292,11 +2325,16 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, | ||||||
| 		0); | 		0); | ||||||
| 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_info, 0); | 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_info, 0); | ||||||
| 	spa_pod_builder_push_struct(b, &f[1]); | 	spa_pod_builder_push_struct(b, &f[1]); | ||||||
| 	spa_pod_builder_int(b, 1); | 	spa_pod_builder_int(b, port_icon_name ? 2 : 1); | ||||||
| 	spa_pod_builder_add(b, | 	spa_pod_builder_add(b, | ||||||
| 			SPA_POD_String("port.type"), | 			SPA_POD_String("port.type"), | ||||||
| 			SPA_POD_String(port_type), | 			SPA_POD_String(port_type), | ||||||
| 			NULL); | 			NULL); | ||||||
|  | 	if (port_icon_name) | ||||||
|  | 		spa_pod_builder_add(b, | ||||||
|  | 				SPA_POD_String("device.icon-name"), | ||||||
|  | 				SPA_POD_String(port_icon_name), | ||||||
|  | 				NULL); | ||||||
| 	spa_pod_builder_pop(b, &f[1]); | 	spa_pod_builder_pop(b, &f[1]); | ||||||
| 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_profiles, 0); | 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_profiles, 0); | ||||||
| 	spa_pod_builder_push_array(b, &f[1]); | 	spa_pod_builder_push_array(b, &f[1]); | ||||||
|  |  | ||||||
|  | @ -427,6 +427,31 @@ static inline const char *spa_bt_form_factor_name(enum spa_bt_form_factor ff) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline const char *spa_bt_form_factor_icon_name(enum spa_bt_form_factor ff) | ||||||
|  | { | ||||||
|  | 	switch (ff) { | ||||||
|  | 	case SPA_BT_FORM_FACTOR_HEADSET: | ||||||
|  | 		return "audio-headset-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_HANDSFREE: | ||||||
|  | 		return "audio-handsfree-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_MICROPHONE: | ||||||
|  | 		return "audio-input-microphone-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_SPEAKER: | ||||||
|  | 		return "audio-speakers-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_HEADPHONE: | ||||||
|  | 		return "audio-headphones-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_PORTABLE: | ||||||
|  | 		return "multimedia-player-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_PHONE: | ||||||
|  | 		return "phone-bluetooth"; | ||||||
|  | 	case SPA_BT_FORM_FACTOR_CAR: | ||||||
|  | 	case SPA_BT_FORM_FACTOR_HIFI: | ||||||
|  | 	case SPA_BT_FORM_FACTOR_UNKNOWN: | ||||||
|  | 	default: | ||||||
|  | 		return "audio-card-bluetooth"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline enum spa_bt_form_factor spa_bt_form_factor_from_class(uint32_t bluetooth_class) | static inline enum spa_bt_form_factor spa_bt_form_factor_from_class(uint32_t bluetooth_class) | ||||||
| { | { | ||||||
| 	uint32_t major, minor; | 	uint32_t major, minor; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Pauli Virtanen
						Pauli Virtanen