mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	pulse-server: use transportCodec prop for bluez codec messages
This commit is contained in:
		
							parent
							
								
									a552655edc
								
							
						
					
					
						commit
						6b5b56bcc7
					
				
					 2 changed files with 134 additions and 121 deletions
				
			
		| 
						 | 
				
			
			@ -1,40 +1,29 @@
 | 
			
		|||
static int bluez_card_object_message_handler(struct pw_manager *m, struct pw_manager_object *o, const char *message, const char *params, char **response)
 | 
			
		||||
{
 | 
			
		||||
	struct card_info card_info = CARD_INFO_INIT;
 | 
			
		||||
	uint32_t n_profiles;
 | 
			
		||||
	struct profile_info *profile_info;
 | 
			
		||||
	const char *prefix;
 | 
			
		||||
	uint32_t prefix_len;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * XXX: We just list/switch profiles here, until codec is a separate
 | 
			
		||||
	 * XXX: device param.
 | 
			
		||||
	 */
 | 
			
		||||
	struct transport_codec_info codecs[64];
 | 
			
		||||
	uint32_t n_codecs, active;
 | 
			
		||||
 | 
			
		||||
	pw_log_debug(NAME "bluez-card %p object message:'%s' params:'%s'", o, message, params);
 | 
			
		||||
 | 
			
		||||
	collect_card_info(o, &card_info);
 | 
			
		||||
	profile_info = alloca(card_info.n_profiles * sizeof(*profile_info));
 | 
			
		||||
	n_profiles = collect_profile_info(o, &card_info, profile_info);
 | 
			
		||||
	n_codecs = collect_transport_codec_info(o, codecs, SPA_N_ELEMENTS(codecs), &active);
 | 
			
		||||
 | 
			
		||||
	if (card_info.active_profile_name && strstr(card_info.active_profile_name, "headset-head-unit") != NULL)
 | 
			
		||||
		prefix = "headset-head-unit-";
 | 
			
		||||
	else
 | 
			
		||||
		prefix = "a2dp-sink-";
 | 
			
		||||
	prefix_len = strlen(prefix);
 | 
			
		||||
	if (n_codecs == 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (strcmp(message, "switch-codec") == 0) {
 | 
			
		||||
		uint32_t i;
 | 
			
		||||
		uint32_t profile_id = SPA_ID_INVALID;
 | 
			
		||||
		regex_t re;
 | 
			
		||||
		regmatch_t matches[2];
 | 
			
		||||
		const char *str;
 | 
			
		||||
		uint32_t str_len;
 | 
			
		||||
		char *codec;
 | 
			
		||||
		char buf[1024];
 | 
			
		||||
		struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
 | 
			
		||||
		struct spa_pod_frame f[1];
 | 
			
		||||
		struct spa_pod *param;
 | 
			
		||||
		uint32_t codec_id = SPA_ID_INVALID;
 | 
			
		||||
 | 
			
		||||
		/* Parse args */
 | 
			
		||||
		if (params == NULL)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		if (regcomp(&re, "[:space:]*{\\(.*\\)}[:space:]*", 0) != 0)
 | 
			
		||||
		if (regcomp(&re, "[:space:]*{\\([0-9]*\\)}[:space:]*", 0) != 0)
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		if (regexec(&re, params, SPA_N_ELEMENTS(matches), matches, 0) != 0) {
 | 
			
		||||
			regfree(&re);
 | 
			
		||||
| 
						 | 
				
			
			@ -42,122 +31,45 @@ static int bluez_card_object_message_handler(struct pw_manager *m, struct pw_man
 | 
			
		|||
		}
 | 
			
		||||
		regfree(&re);
 | 
			
		||||
 | 
			
		||||
		str = params + matches[1].rm_so;
 | 
			
		||||
		str_len = matches[1].rm_eo - matches[1].rm_so;
 | 
			
		||||
 | 
			
		||||
		/* Find profile corresponding to selected codec */
 | 
			
		||||
		for (i = 0; i < n_profiles; ++i) {
 | 
			
		||||
			if (strncmp(profile_info[i].name, prefix, prefix_len) != 0)
 | 
			
		||||
				continue;
 | 
			
		||||
			if (strncmp(profile_info[i].name + prefix_len, str, str_len) == 0 &&
 | 
			
		||||
			    strlen(profile_info[i].name) == prefix_len + str_len) {
 | 
			
		||||
				profile_id = profile_info[i].id;
 | 
			
		||||
				goto found;
 | 
			
		||||
			}
 | 
			
		||||
		codec = strndup(params + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
 | 
			
		||||
		if (codec) {
 | 
			
		||||
			codec_id = atoi(codec);
 | 
			
		||||
			free(codec);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	found:
 | 
			
		||||
		if (profile_id != SPA_ID_INVALID) {
 | 
			
		||||
			char buf[1024];
 | 
			
		||||
			struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
 | 
			
		||||
		/* Switch codec */
 | 
			
		||||
		spa_pod_builder_push_object(&b, &f[0],
 | 
			
		||||
				SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
 | 
			
		||||
		spa_pod_builder_add(&b,
 | 
			
		||||
				SPA_PROP_bluetoothAudioCodec, SPA_POD_Id(codec_id), 0);
 | 
			
		||||
		param = spa_pod_builder_pop(&b, &f[0]);
 | 
			
		||||
 | 
			
		||||
			/* Switch profile */
 | 
			
		||||
			pw_device_set_param((struct pw_device*)o->proxy,
 | 
			
		||||
					SPA_PARAM_Profile, 0,
 | 
			
		||||
					spa_pod_builder_add_object(&b,
 | 
			
		||||
						SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
 | 
			
		||||
						SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_id),
 | 
			
		||||
						SPA_PARAM_PROFILE_save, SPA_POD_Bool(true)));
 | 
			
		||||
			return 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		pw_device_set_param((struct pw_device *)o->proxy,
 | 
			
		||||
				SPA_PARAM_Props, 0, param);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (strcmp(message, "list-codecs") == 0) {
 | 
			
		||||
		uint32_t i;
 | 
			
		||||
		const char *p;
 | 
			
		||||
		FILE *r;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		regex_t re;
 | 
			
		||||
		regmatch_t matches[2];
 | 
			
		||||
		bool found = false;
 | 
			
		||||
 | 
			
		||||
		r = open_memstream(response, &size);
 | 
			
		||||
		if (r == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		if (regcomp(&re, "codec \\(.*\\))", 0) != 0)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		fputc('{', r);
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < n_profiles; ++i) {
 | 
			
		||||
			if (strncmp(profile_info[i].name, prefix, prefix_len) != 0)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			found = true;
 | 
			
		||||
			fputc('{', r);
 | 
			
		||||
			fprintf(r, "{%s}", profile_info[i].name + prefix_len);
 | 
			
		||||
 | 
			
		||||
			/* Parse codec name from description */
 | 
			
		||||
			p = profile_info[i].description;
 | 
			
		||||
			if (regexec(&re, p, SPA_N_ELEMENTS(matches), matches, 0) == 0) {
 | 
			
		||||
				fputc('{', r);
 | 
			
		||||
				fwrite(p + matches[1].rm_so, 1, matches[1].rm_eo - matches[1].rm_so, r);
 | 
			
		||||
				fputc('}', r);
 | 
			
		||||
			} else {
 | 
			
		||||
				fprintf(r, "{%s}", p);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fputc('}', r);
 | 
			
		||||
		for (i = 0; i < n_codecs; ++i) {
 | 
			
		||||
			const char *desc = codecs[i].description;
 | 
			
		||||
			fprintf(r, "{{%d}{%s}}", (int)codecs[i].id, desc ? desc : "Unknown");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fputc('}', r);
 | 
			
		||||
 | 
			
		||||
		regfree(&re);
 | 
			
		||||
 | 
			
		||||
		if (!found) {
 | 
			
		||||
			fclose(r);
 | 
			
		||||
			free(*response);
 | 
			
		||||
			*response = NULL;
 | 
			
		||||
			return -ENOSYS;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return fclose(r) ? -errno : 0;
 | 
			
		||||
	} else if (strcmp(message, "get-codec") == 0) {
 | 
			
		||||
		const char *name = "none";
 | 
			
		||||
		FILE *r;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		struct pw_manager_object *obj;
 | 
			
		||||
 | 
			
		||||
		r = open_memstream(response, &size);
 | 
			
		||||
		if (r == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		/* Look up from nodes */
 | 
			
		||||
		spa_list_for_each(obj, &m->object_list, link) {
 | 
			
		||||
			const char *str;
 | 
			
		||||
			uint32_t card_id = SPA_ID_INVALID;
 | 
			
		||||
			struct pw_node_info *info;
 | 
			
		||||
 | 
			
		||||
			if (obj->creating || obj->removing)
 | 
			
		||||
				continue;
 | 
			
		||||
			if (!object_is_sink(obj) && !object_is_source_or_monitor(obj))
 | 
			
		||||
				continue;
 | 
			
		||||
			if ((info = obj->info) == NULL || info->props == NULL)
 | 
			
		||||
				continue;
 | 
			
		||||
			if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
 | 
			
		||||
				card_id = (uint32_t)atoi(str);
 | 
			
		||||
			if (card_id != o->id)
 | 
			
		||||
				continue;
 | 
			
		||||
			str = spa_dict_lookup(info->props, "api.bluez5.codec");
 | 
			
		||||
			if (str) {
 | 
			
		||||
				name = str;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fprintf(r, "{%s}", name);
 | 
			
		||||
		return fclose(r) ? -errno : 0;
 | 
			
		||||
		if (active == SPA_ID_INVALID)
 | 
			
		||||
			*response = strdup("{none}");
 | 
			
		||||
		else
 | 
			
		||||
			*response = spa_aprintf("{%d}", (int)codecs[active].id);
 | 
			
		||||
		return *response ? 0 : -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -ENOSYS;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue