1 /* Spa Bluez5 Device
2  *
3  * Copyright © 2018 Wim Taymans
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <poll.h>
31 #include <errno.h>
32 
33 #include <spa/support/log.h>
34 #include <spa/utils/type.h>
35 #include <spa/utils/keys.h>
36 #include <spa/utils/names.h>
37 #include <spa/utils/string.h>
38 #include <spa/node/node.h>
39 #include <spa/support/loop.h>
40 #include <spa/support/plugin.h>
41 #include <spa/support/i18n.h>
42 #include <spa/monitor/device.h>
43 #include <spa/monitor/utils.h>
44 #include <spa/monitor/event.h>
45 #include <spa/pod/filter.h>
46 #include <spa/pod/parser.h>
47 #include <spa/param/param.h>
48 #include <spa/param/audio/raw.h>
49 #include <spa/param/bluetooth/audio.h>
50 #include <spa/param/bluetooth/type-info.h>
51 #include <spa/debug/pod.h>
52 
53 #include "defs.h"
54 #include "a2dp-codecs.h"
55 
56 static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.device");
57 #undef SPA_LOG_TOPIC_DEFAULT
58 #define SPA_LOG_TOPIC_DEFAULT &log_topic
59 
60 #define MAX_DEVICES	64
61 
62 #define DEVICE_ID_SOURCE	0
63 #define DEVICE_ID_SINK		1
64 #define DYNAMIC_NODE_ID_FLAG	0x1000
65 
66 static struct spa_i18n *_i18n;
67 
68 #define _(_str)	 spa_i18n_text(_i18n,(_str))
69 #define N_(_str) (_str)
70 
71 enum {
72 	DEVICE_PROFILE_OFF = 0,
73 	DEVICE_PROFILE_AG = 1,
74 	DEVICE_PROFILE_A2DP = 2,
75 	DEVICE_PROFILE_HSP_HFP = 3,
76 };
77 
78 struct props {
79 	enum spa_bluetooth_audio_codec codec;
80 };
81 
reset_props(struct props * props)82 static void reset_props(struct props *props)
83 {
84 	props->codec = 0;
85 }
86 
87 struct impl;
88 
89 struct node {
90 	struct impl *impl;
91 	struct spa_bt_transport *transport;
92 	struct spa_hook transport_listener;
93 	uint32_t id;
94 	unsigned int active:1;
95 	unsigned int mute:1;
96 	unsigned int save:1;
97 	unsigned int a2dp_duplex:1;
98 	uint32_t n_channels;
99 	int64_t latency_offset;
100 	uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
101 	float volumes[SPA_AUDIO_MAX_CHANNELS];
102 	float soft_volumes[SPA_AUDIO_MAX_CHANNELS];
103 };
104 
105 struct dynamic_node
106 {
107 	struct impl *impl;
108 	struct spa_bt_transport *transport;
109 	struct spa_hook transport_listener;
110 	uint32_t id;
111 	const char *factory_name;
112 	bool a2dp_duplex;
113 };
114 
115 struct impl {
116 	struct spa_handle handle;
117 	struct spa_device device;
118 
119 	struct spa_log *log;
120 
121 	uint32_t info_all;
122 	struct spa_device_info info;
123 #define IDX_EnumProfile		0
124 #define IDX_Profile		1
125 #define IDX_EnumRoute		2
126 #define IDX_Route		3
127 #define IDX_PropInfo		4
128 #define IDX_Props		5
129 	struct spa_param_info params[6];
130 
131 	struct spa_hook_list hooks;
132 
133 	struct props props;
134 
135 	struct spa_bt_device *bt_dev;
136 	struct spa_hook bt_dev_listener;
137 
138 	uint32_t profile;
139 	unsigned int switching_codec:1;
140 	uint32_t prev_bt_connected_profiles;
141 
142 	const struct a2dp_codec **supported_codecs;
143 	size_t supported_codec_count;
144 
145 	struct dynamic_node dyn_a2dp_source;
146 	struct dynamic_node dyn_a2dp_sink;
147 	struct dynamic_node dyn_sco_source;
148 	struct dynamic_node dyn_sco_sink;
149 
150 #define MAX_SETTINGS 32
151 	struct spa_dict_item setting_items[MAX_SETTINGS];
152 	struct spa_dict setting_dict;
153 
154 	struct node nodes[2];
155 };
156 
init_node(struct impl * this,struct node * node,uint32_t id)157 static void init_node(struct impl *this, struct node *node, uint32_t id)
158 {
159 	uint32_t i;
160 
161 	spa_zero(*node);
162 	node->id = id;
163 	for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
164 		node->volumes[i] = 1.0f;
165 		node->soft_volumes[i] = 1.0f;
166 	}
167 }
168 
get_a2dp_codecs(struct impl * this,enum spa_bluetooth_audio_codec id,const struct a2dp_codec ** codecs,size_t size)169 static void get_a2dp_codecs(struct impl *this, enum spa_bluetooth_audio_codec id, const struct a2dp_codec **codecs, size_t size)
170 {
171 	const struct a2dp_codec * const *c;
172 
173 	spa_assert(size > 0);
174 	spa_assert(this->supported_codecs);
175 
176 	for (c = this->supported_codecs; *c && size > 1; ++c) {
177 		if ((*c)->id == id || id == 0) {
178 			*codecs++ = *c;
179 			--size;
180 		}
181 	}
182 
183 	*codecs = NULL;
184 }
185 
get_supported_a2dp_codec(struct impl * this,enum spa_bluetooth_audio_codec id,size_t * idx)186 static const struct a2dp_codec *get_supported_a2dp_codec(struct impl *this, enum spa_bluetooth_audio_codec id, size_t *idx)
187 {
188 	const struct a2dp_codec *a2dp_codec = NULL;
189 	size_t i;
190 	for (i = 0; i < this->supported_codec_count; ++i) {
191 		if (this->supported_codecs[i]->id == id) {
192 			a2dp_codec = this->supported_codecs[i];
193 			if (idx)
194 				*idx = i;
195 		}
196 	}
197 	return a2dp_codec;
198 }
199 
get_hfp_codec(enum spa_bluetooth_audio_codec id)200 static unsigned int get_hfp_codec(enum spa_bluetooth_audio_codec id)
201 {
202 	switch (id) {
203 	case SPA_BLUETOOTH_AUDIO_CODEC_CVSD:
204 		return HFP_AUDIO_CODEC_CVSD;
205 	case SPA_BLUETOOTH_AUDIO_CODEC_MSBC:
206 		return HFP_AUDIO_CODEC_MSBC;
207 	default:
208 		return 0;
209 	}
210 }
211 
get_hfp_codec_id(unsigned int codec)212 static enum spa_bluetooth_audio_codec get_hfp_codec_id(unsigned int codec)
213 {
214 	switch (codec) {
215 	case HFP_AUDIO_CODEC_MSBC:
216 		return SPA_BLUETOOTH_AUDIO_CODEC_MSBC;
217 	case HFP_AUDIO_CODEC_CVSD:
218 		return SPA_BLUETOOTH_AUDIO_CODEC_CVSD;
219 	}
220 	return SPA_ID_INVALID;
221 }
222 
get_hfp_codec_description(unsigned int codec)223 static const char *get_hfp_codec_description(unsigned int codec)
224 {
225 	switch (codec) {
226 	case HFP_AUDIO_CODEC_MSBC:
227 		return "mSBC";
228 	case HFP_AUDIO_CODEC_CVSD:
229 		return "CVSD";
230 	}
231 	return "unknown";
232 }
233 
get_hfp_codec_name(unsigned int codec)234 static const char *get_hfp_codec_name(unsigned int codec)
235 {
236 	switch (codec) {
237 	case HFP_AUDIO_CODEC_MSBC:
238 		return "msbc";
239 	case HFP_AUDIO_CODEC_CVSD:
240 		return "cvsd";
241 	}
242 	return "unknown";
243 }
244 
get_codec_name(struct spa_bt_transport * t,bool a2dp_duplex)245 static const char *get_codec_name(struct spa_bt_transport *t, bool a2dp_duplex)
246 {
247 	if (t->a2dp_codec != NULL) {
248 		if (a2dp_duplex && t->a2dp_codec->duplex_codec)
249 			return t->a2dp_codec->duplex_codec->name;
250 		return t->a2dp_codec->name;
251 	}
252 	return get_hfp_codec_name(t->codec);
253 }
254 
transport_destroy(void * userdata)255 static void transport_destroy(void *userdata)
256 {
257 	struct node *node = userdata;
258 	node->transport = NULL;
259 }
260 
emit_node_props(struct impl * this,struct node * node,bool full)261 static void emit_node_props(struct impl *this, struct node *node, bool full)
262 {
263 	struct spa_event *event;
264 	uint8_t buffer[4096];
265 	struct spa_pod_builder b = { 0 };
266 	struct spa_pod_frame f[1];
267 
268 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
269 	spa_pod_builder_push_object(&b, &f[0],
270 			SPA_TYPE_EVENT_Device, SPA_DEVICE_EVENT_ObjectConfig);
271 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Object, 0);
272 	spa_pod_builder_int(&b, node->id);
273 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Props, 0);
274 	spa_pod_builder_add_object(&b,
275 			SPA_TYPE_OBJECT_Props, SPA_EVENT_DEVICE_Props,
276 			SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float),
277 				SPA_TYPE_Float, node->n_channels, node->volumes),
278 			SPA_PROP_softVolumes, SPA_POD_Array(sizeof(float),
279 				SPA_TYPE_Float, node->n_channels, node->soft_volumes),
280 			SPA_PROP_channelMap, SPA_POD_Array(sizeof(uint32_t),
281 				SPA_TYPE_Id, node->n_channels, node->channels));
282 	if (full) {
283 		spa_pod_builder_add(&b,
284 			SPA_PROP_mute, SPA_POD_Bool(node->mute),
285 			SPA_PROP_softMute, SPA_POD_Bool(node->mute),
286 			SPA_PROP_latencyOffsetNsec, SPA_POD_Long(node->latency_offset),
287 			0);
288 	}
289 	event = spa_pod_builder_pop(&b, &f[0]);
290 
291 	spa_device_emit_event(&this->hooks, event);
292 }
293 
emit_volume(struct impl * this,struct node * node)294 static void emit_volume(struct impl *this, struct node *node)
295 {
296 	emit_node_props(this, node, false);
297 }
298 
299 static void emit_info(struct impl *this, bool full);
300 
get_soft_volume_boost(struct node * node)301 static float get_soft_volume_boost(struct node *node)
302 {
303 	/*
304 	 * For A2DP duplex, the duplex microphone channel sometimes does not appear
305 	 * to have hardware gain, and input volume is very low.
306 	 *
307 	 * Work around this by boosting the software volume level, i.e. adjust
308 	 * the scale on the user-visible volume control to something more sensible.
309 	 * If this causes clipping, the user can just reduce the mic volume to
310 	 * bring SW gain below 1.
311 	 */
312 	if (node->a2dp_duplex && node->transport &&
313 			node->id == DEVICE_ID_SOURCE &&
314 			!node->transport->volumes[SPA_BT_VOLUME_ID_RX].active)
315 		return 10.0f;	/* 20 dB boost */
316 
317 	/* In all other cases, no boost */
318 	return 1.0f;
319 }
320 
node_get_hw_volume(struct node * node)321 static float node_get_hw_volume(struct node *node)
322 {
323 	uint32_t i;
324 	float hw_volume = 0.0f;
325 	for (i = 0; i < node->n_channels; i++)
326 		hw_volume = SPA_MAX(node->volumes[i], hw_volume);
327 	return SPA_MIN(hw_volume, 1.0f);
328 }
329 
node_update_soft_volumes(struct node * node,float hw_volume)330 static void node_update_soft_volumes(struct node *node, float hw_volume)
331 {
332 	for (uint32_t i = 0; i < node->n_channels; ++i) {
333 		node->soft_volumes[i] = hw_volume > 0.0f
334 			? node->volumes[i] / hw_volume
335 			: 0.0f;
336 	}
337 }
338 
volume_changed(void * userdata)339 static void volume_changed(void *userdata)
340 {
341 	struct node *node = userdata;
342 	struct impl *impl = node->impl;
343 	struct spa_bt_transport_volume *t_volume;
344 	float prev_hw_volume;
345 
346 	if (!node->transport || !spa_bt_transport_volume_enabled(node->transport))
347 		return;
348 
349 	/* PW is the controller for remote device. */
350 	if (impl->profile != DEVICE_PROFILE_A2DP
351 	    && impl->profile !=  DEVICE_PROFILE_HSP_HFP)
352 		return;
353 
354 	t_volume = &node->transport->volumes[node->id];
355 
356 	if (!t_volume->active)
357 		return;
358 
359 	prev_hw_volume = node_get_hw_volume(node);
360 	for (uint32_t i = 0; i < node->n_channels; ++i) {
361 		node->volumes[i] = prev_hw_volume > 0.0f
362 			? node->volumes[i] * t_volume->volume / prev_hw_volume
363 			: t_volume->volume;
364 	}
365 
366 	node_update_soft_volumes(node, t_volume->volume);
367 
368 	emit_volume(impl, node);
369 
370 	impl->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
371 	impl->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
372 	emit_info(impl, false);
373 }
374 
375 static const struct spa_bt_transport_events transport_events = {
376 	SPA_VERSION_BT_DEVICE_EVENTS,
377 	.destroy = transport_destroy,
378 	.volume_changed = volume_changed,
379 };
380 
get_channels(struct spa_bt_transport * t,bool a2dp_duplex,uint32_t * n_channels,uint32_t * channels)381 static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t *n_channels, uint32_t *channels)
382 {
383 	const struct a2dp_codec *codec;
384 	struct spa_audio_info info = { 0 };
385 
386 	if (!a2dp_duplex || !t->a2dp_codec || !t->a2dp_codec->duplex_codec) {
387 		*n_channels = t->n_channels;
388 		memcpy(channels, t->channels, t->n_channels * sizeof(uint32_t));
389 		return;
390 	}
391 
392 	codec = t->a2dp_codec->duplex_codec;
393 
394 	if (!codec->validate_config ||
395 			codec->validate_config(codec, 0,
396 					t->configuration, t->configuration_len,
397 					&info) < 0) {
398 		*n_channels = 1;
399 		channels[0] = SPA_AUDIO_CHANNEL_MONO;
400 		return;
401 	}
402 
403 	*n_channels = info.info.raw.channels;
404 	memcpy(channels, info.info.raw.position,
405 			info.info.raw.channels * sizeof(uint32_t));
406 }
407 
emit_node(struct impl * this,struct spa_bt_transport * t,uint32_t id,const char * factory_name,bool a2dp_duplex)408 static void emit_node(struct impl *this, struct spa_bt_transport *t,
409 		uint32_t id, const char *factory_name, bool a2dp_duplex)
410 {
411 	struct spa_bt_device *device = this->bt_dev;
412 	struct spa_device_object_info info;
413 	struct spa_dict_item items[8];
414 	uint32_t n_items = 0;
415 	char transport[32], str_id[32];
416 	bool is_dyn_node = SPA_FLAG_IS_SET(id, DYNAMIC_NODE_ID_FLAG);
417 
418 	snprintf(transport, sizeof(transport), "pointer:%p", t);
419 	items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_TRANSPORT, transport);
420 	items[1] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PROFILE, spa_bt_profile_name(t->profile));
421 	items[2] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_CODEC, get_codec_name(t, a2dp_duplex));
422 	items[3] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ADDRESS, device->address);
423 	items[4] = SPA_DICT_ITEM_INIT("device.routes", "1");
424 	n_items = 5;
425 	if (!is_dyn_node) {
426 		snprintf(str_id, sizeof(str_id), "%d", id);
427 		items[5] = SPA_DICT_ITEM_INIT("card.profile.device", str_id);
428 		n_items++;
429 	}
430 	if (spa_streq(spa_bt_profile_name(t->profile), "headset-head-unit")) {
431 		items[n_items] = SPA_DICT_ITEM_INIT("device.intended-roles", "Communication");
432 		n_items++;
433 	}
434 	if (a2dp_duplex) {
435 		items[n_items] = SPA_DICT_ITEM_INIT("api.bluez5.a2dp-duplex", "true");
436 		n_items++;
437 	}
438 
439 	info = SPA_DEVICE_OBJECT_INFO_INIT();
440 	info.type = SPA_TYPE_INTERFACE_Node;
441 	info.factory_name = factory_name;
442 	info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
443 	info.props = &SPA_DICT_INIT(items, n_items);
444 
445 	SPA_FLAG_CLEAR(id, DYNAMIC_NODE_ID_FLAG);
446 	spa_device_emit_object_info(&this->hooks, id, &info);
447 
448 	if (!is_dyn_node) {
449 		uint32_t prev_channels = this->nodes[id].n_channels;
450 		float boost;
451 
452 		this->nodes[id].impl = this;
453 		this->nodes[id].active = true;
454 		this->nodes[id].a2dp_duplex = a2dp_duplex;
455 		get_channels(t, a2dp_duplex, &this->nodes[id].n_channels, this->nodes[id].channels);
456 		if (this->nodes[id].transport)
457 			spa_hook_remove(&this->nodes[id].transport_listener);
458 		this->nodes[id].transport = t;
459 		spa_bt_transport_add_listener(t, &this->nodes[id].transport_listener, &transport_events, &this->nodes[id]);
460 
461 		if (prev_channels > 0) {
462 			size_t i;
463 			/*
464 			 * Spread mono volume to all channels, if we had switched HFP -> A2DP.
465 			 * XXX: we should also use different route for hfp and a2dp
466 			 */
467 			for (i = prev_channels; i < this->nodes[id].n_channels; ++i)
468 				this->nodes[id].volumes[i] = this->nodes[id].volumes[i % prev_channels];
469 		}
470 
471 		boost = get_soft_volume_boost(&this->nodes[id]);
472 		if (boost != 1.0f) {
473 			size_t i;
474 			for (i = 0; i < this->nodes[id].n_channels; ++i)
475 				this->nodes[id].soft_volumes[i] = this->nodes[id].volumes[i] * boost;
476 		}
477 
478 		emit_node_props(this, &this->nodes[id], true);
479 	}
480 }
481 
find_transport(struct impl * this,int profile,enum spa_bluetooth_audio_codec codec)482 static struct spa_bt_transport *find_transport(struct impl *this, int profile, enum spa_bluetooth_audio_codec codec)
483 {
484 	struct spa_bt_device *device = this->bt_dev;
485 	struct spa_bt_transport *t;
486 
487 	spa_list_for_each(t, &device->transport_list, device_link) {
488 		bool codec_ok = codec == 0 ||
489 			(t->a2dp_codec != NULL && t->a2dp_codec->id == codec) ||
490 			get_hfp_codec_id(t->codec) == codec;
491 
492 		if ((t->profile & device->connected_profiles) &&
493 				(t->profile & profile) == t->profile &&
494 				codec_ok)
495 			return t;
496 	}
497 
498 	return NULL;
499 }
500 
dynamic_node_transport_destroy(void * data)501 static void dynamic_node_transport_destroy(void *data)
502 {
503 	struct dynamic_node *this = data;
504 	spa_log_debug(this->impl->log, "transport %p destroy", this->transport);
505 	this->transport = NULL;
506 }
507 
dynamic_node_transport_state_changed(void * data,enum spa_bt_transport_state old,enum spa_bt_transport_state state)508 static void dynamic_node_transport_state_changed(void *data,
509 	enum spa_bt_transport_state old,
510 	enum spa_bt_transport_state state)
511 {
512 	struct dynamic_node *this = data;
513 	struct impl *impl = this->impl;
514 	struct spa_bt_transport *t = this->transport;
515 
516 	spa_log_debug(impl->log, "transport %p state %d->%d", t, old, state);
517 
518 	if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING) {
519 		if (!SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) {
520 			SPA_FLAG_SET(this->id, DYNAMIC_NODE_ID_FLAG);
521 			emit_node(impl, t, this->id, this->factory_name, this->a2dp_duplex);
522 		}
523 	} else if (state < SPA_BT_TRANSPORT_STATE_PENDING && old >= SPA_BT_TRANSPORT_STATE_PENDING) {
524 		if (SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) {
525 			SPA_FLAG_CLEAR(this->id, DYNAMIC_NODE_ID_FLAG);
526 			spa_device_emit_object_info(&impl->hooks, this->id, NULL);
527 		}
528 	}
529 }
530 
dynamic_node_volume_changed(void * data)531 static void dynamic_node_volume_changed(void *data)
532 {
533 	struct dynamic_node *node = data;
534 	struct impl *impl = node->impl;
535 	struct spa_event *event;
536 	uint8_t buffer[4096];
537 	struct spa_pod_builder b = { 0 };
538 	struct spa_pod_frame f[1];
539 	struct spa_bt_transport_volume *t_volume;
540 	int id = node->id, volume_id;
541 
542 	SPA_FLAG_CLEAR(id, DYNAMIC_NODE_ID_FLAG);
543 
544 	/* Remote device is the controller */
545 	if (!node->transport || impl->profile != DEVICE_PROFILE_AG
546 	    || !spa_bt_transport_volume_enabled(node->transport))
547 		return;
548 
549 	if (id == 0 || id == 2)
550 		volume_id = SPA_BT_VOLUME_ID_RX;
551 	else if (id == 1)
552 		volume_id = SPA_BT_VOLUME_ID_TX;
553 	else
554 		return;
555 
556 	t_volume = &node->transport->volumes[volume_id];
557 	if (!t_volume->active)
558 		return;
559 
560 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
561 	spa_pod_builder_push_object(&b, &f[0],
562 			SPA_TYPE_EVENT_Device, SPA_DEVICE_EVENT_ObjectConfig);
563 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Object, 0);
564 	spa_pod_builder_int(&b, id);
565 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Props, 0);
566 	spa_pod_builder_add_object(&b,
567 			SPA_TYPE_OBJECT_Props, SPA_EVENT_DEVICE_Props,
568 			SPA_PROP_volume, SPA_POD_Float(t_volume->volume));
569 	event = spa_pod_builder_pop(&b, &f[0]);
570 
571 	spa_log_debug(impl->log, "dynamic node %p: volume %d changed %f, profile %d",
572 		node, volume_id, t_volume->volume, node->transport->profile);
573 
574 	/* Dynamic node doesn't has route, we can only set volume on adaptar node. */
575 	spa_device_emit_event(&impl->hooks, event);
576 }
577 
578 static const struct spa_bt_transport_events dynamic_node_transport_events = {
579 	SPA_VERSION_BT_TRANSPORT_EVENTS,
580 	.destroy = dynamic_node_transport_destroy,
581 	.state_changed = dynamic_node_transport_state_changed,
582 	.volume_changed = dynamic_node_volume_changed,
583 };
584 
emit_dynamic_node(struct dynamic_node * this,struct impl * impl,struct spa_bt_transport * t,uint32_t id,const char * factory_name,bool a2dp_duplex)585 static void emit_dynamic_node(struct dynamic_node *this, struct impl *impl,
586 	struct spa_bt_transport *t, uint32_t id, const char *factory_name, bool a2dp_duplex)
587 {
588 	spa_log_debug(impl->log, "dynamic node, transport: %p->%p id: %08x->%08x",
589 		this->transport, t, this->id, id);
590 
591 	if (this->transport) {
592 		/* Session manager don't really handles transport ptr changing. */
593 		spa_assert(this->transport == t);
594 		spa_hook_remove(&this->transport_listener);
595 	}
596 
597 	this->impl = impl;
598 	this->transport = t;
599 	this->id = id;
600 	this->factory_name = factory_name;
601 	this->a2dp_duplex = a2dp_duplex;
602 
603 	spa_bt_transport_add_listener(this->transport,
604 		&this->transport_listener, &dynamic_node_transport_events, this);
605 
606 	/* emits the node if the state is already pending */
607 	dynamic_node_transport_state_changed (this, SPA_BT_TRANSPORT_STATE_IDLE, t->state);
608 }
609 
remove_dynamic_node(struct dynamic_node * this)610 static void remove_dynamic_node(struct dynamic_node *this)
611 {
612 	if (this->transport == NULL)
613 		return;
614 
615 	/* destroy the node, if it exists */
616 	dynamic_node_transport_state_changed (this, this->transport->state,
617 		SPA_BT_TRANSPORT_STATE_IDLE);
618 
619 	spa_hook_remove(&this->transport_listener);
620 	this->impl = NULL;
621 	this->transport = NULL;
622 	this->id = 0;
623 	this->factory_name = NULL;
624 }
625 
emit_nodes(struct impl * this)626 static int emit_nodes(struct impl *this)
627 {
628 	struct spa_bt_transport *t;
629 
630 	switch (this->profile) {
631 	case DEVICE_PROFILE_OFF:
632 		break;
633 	case DEVICE_PROFILE_AG:
634 		if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY) {
635 			t = find_transport(this, SPA_BT_PROFILE_HFP_AG, 0);
636 			if (!t)
637 				t = find_transport(this, SPA_BT_PROFILE_HSP_AG, 0);
638 			if (t) {
639 				if (t->profile == SPA_BT_PROFILE_HSP_AG)
640 					this->props.codec = 0;
641 				else
642 					this->props.codec = get_hfp_codec_id(t->codec);
643 				emit_dynamic_node(&this->dyn_sco_source, this, t,
644 						0, SPA_NAME_API_BLUEZ5_SCO_SOURCE, false);
645 				emit_dynamic_node(&this->dyn_sco_sink, this, t,
646 						1, SPA_NAME_API_BLUEZ5_SCO_SINK, false);
647 			}
648 		}
649 		if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE) {
650 			t = find_transport(this, SPA_BT_PROFILE_A2DP_SOURCE, 0);
651 			if (t) {
652 				this->props.codec = t->a2dp_codec->id;
653 				emit_dynamic_node(&this->dyn_a2dp_source, this, t,
654 						2, SPA_NAME_API_BLUEZ5_A2DP_SOURCE, false);
655 
656 				if (t->a2dp_codec->duplex_codec) {
657 					emit_dynamic_node(&this->dyn_a2dp_sink, this, t,
658 						3, SPA_NAME_API_BLUEZ5_A2DP_SINK, true);
659 				}
660 			}
661 		}
662 		break;
663 	case DEVICE_PROFILE_A2DP:
664 		if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE) {
665 			t = find_transport(this, SPA_BT_PROFILE_A2DP_SOURCE, 0);
666 			if (t) {
667 				this->props.codec = t->a2dp_codec->id;
668 				emit_dynamic_node(&this->dyn_a2dp_source, this, t,
669 					DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_A2DP_SOURCE, false);
670 
671 				if (t->a2dp_codec->duplex_codec) {
672 					emit_node(this, t,
673 						DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_A2DP_SINK, true);
674 				}
675 			}
676 		}
677 
678 		if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) {
679 			t = find_transport(this, SPA_BT_PROFILE_A2DP_SINK, this->props.codec);
680 			if (t) {
681 				this->props.codec = t->a2dp_codec->id;
682 				emit_node(this, t, DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_A2DP_SINK, false);
683 
684 				if (t->a2dp_codec->duplex_codec) {
685 					emit_node(this, t,
686 						DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_A2DP_SOURCE, true);
687 				}
688 			}
689 		}
690 
691 		if (get_supported_a2dp_codec(this, this->props.codec, NULL) == NULL)
692 			this->props.codec = 0;
693 		break;
694 	case DEVICE_PROFILE_HSP_HFP:
695 		if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) {
696 			t = find_transport(this, SPA_BT_PROFILE_HFP_HF, this->props.codec);
697 			if (!t)
698 				t = find_transport(this, SPA_BT_PROFILE_HSP_HS, 0);
699 			if (t) {
700 				if (t->profile == SPA_BT_PROFILE_HSP_HS)
701 					this->props.codec = 0;
702 				else
703 					this->props.codec = get_hfp_codec_id(t->codec);
704 				emit_node(this, t, DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_SCO_SOURCE, false);
705 				emit_node(this, t, DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_SCO_SINK, false);
706 			}
707 		}
708 
709 		if (spa_bt_device_supports_hfp_codec(this->bt_dev, get_hfp_codec(this->props.codec)) != 1)
710 			this->props.codec = 0;
711 		break;
712 	default:
713 		return -EINVAL;
714 	}
715 	return 0;
716 }
717 
718 static const struct spa_dict_item info_items[] = {
719 	{ SPA_KEY_DEVICE_API, "bluez5" },
720 	{ SPA_KEY_DEVICE_BUS, "bluetooth" },
721 	{ SPA_KEY_MEDIA_CLASS, "Audio/Device" },
722 };
723 
emit_info(struct impl * this,bool full)724 static void emit_info(struct impl *this, bool full)
725 {
726 	uint64_t old = full ? this->info.change_mask : 0;
727 	if (full)
728 		this->info.change_mask = this->info_all;
729 	if (this->info.change_mask) {
730 		this->info.props = &SPA_DICT_INIT_ARRAY(info_items);
731 
732 		spa_device_emit_info(&this->hooks, &this->info);
733 		this->info.change_mask = old;
734 	}
735 }
736 
emit_remove_nodes(struct impl * this)737 static void emit_remove_nodes(struct impl *this)
738 {
739 	remove_dynamic_node (&this->dyn_a2dp_source);
740 	remove_dynamic_node (&this->dyn_a2dp_sink);
741 	remove_dynamic_node (&this->dyn_sco_source);
742 	remove_dynamic_node (&this->dyn_sco_sink);
743 
744 	for (uint32_t i = 0; i < 2; i++) {
745 		struct node * node = &this->nodes[i];
746 		if (node->transport) {
747 			spa_hook_remove(&node->transport_listener);
748 			node->transport = NULL;
749 		}
750 		if (node->active) {
751 			spa_device_emit_object_info(&this->hooks, i, NULL);
752 			node->active = false;
753 		}
754 	}
755 }
756 
757 static bool validate_profile(struct impl *this, uint32_t profile,
758 		enum spa_bluetooth_audio_codec codec);
759 
set_profile(struct impl * this,uint32_t profile,enum spa_bluetooth_audio_codec codec)760 static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec)
761 {
762 	if (!validate_profile(this, profile, codec)) {
763 		spa_log_warn(this->log, "trying to set invalid profile %d, codec %d, %08x %08x",
764 			    profile, codec,
765 			    this->bt_dev->profiles, this->bt_dev->connected_profiles);
766 		return -EINVAL;
767 	}
768 
769 	if (this->profile == profile &&
770 	    (this->profile != DEVICE_PROFILE_A2DP || codec == this->props.codec) &&
771 	    (this->profile != DEVICE_PROFILE_HSP_HFP || codec == this->props.codec))
772 		return 0;
773 
774 	emit_remove_nodes(this);
775 
776 	spa_bt_device_release_transports(this->bt_dev);
777 
778 	this->profile = profile;
779 	this->prev_bt_connected_profiles = this->bt_dev->connected_profiles;
780 	this->props.codec = codec;
781 
782 	/*
783 	 * A2DP: ensure there's a transport with the selected codec (0 means any).
784 	 * Don't try to switch codecs when the device is in the A2DP source role, since
785 	 * devices do not appear to like that.
786 	 */
787 	if (profile == DEVICE_PROFILE_A2DP && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) {
788 		int ret;
789 		const struct a2dp_codec *codecs[64];
790 
791 		get_a2dp_codecs(this, codec, codecs, SPA_N_ELEMENTS(codecs));
792 
793 		this->switching_codec = true;
794 
795 		ret = spa_bt_device_ensure_a2dp_codec(this->bt_dev, codecs);
796 		if (ret < 0) {
797 			if (ret != -ENOTSUP)
798 				spa_log_error(this->log, "failed to switch codec (%d), setting basic profile", ret);
799 		} else {
800 			return 0;
801 		}
802 	} else if (profile == DEVICE_PROFILE_HSP_HFP && get_hfp_codec(codec) && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_HFP_AG)) {
803 		int ret;
804 
805 		this->switching_codec = true;
806 
807 		ret = spa_bt_device_ensure_hfp_codec(this->bt_dev, get_hfp_codec(codec));
808 		if (ret < 0) {
809 			if (ret != -ENOTSUP)
810 				spa_log_error(this->log, "failed to switch codec (%d), setting basic profile", ret);
811 		} else {
812 			return 0;
813 		}
814 	}
815 
816 	this->switching_codec = false;
817 	this->props.codec = 0;
818 	emit_nodes(this);
819 
820 	this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
821 	this->params[IDX_Profile].flags ^= SPA_PARAM_INFO_SERIAL;
822 	this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
823 	this->params[IDX_EnumRoute].flags ^= SPA_PARAM_INFO_SERIAL;
824 	this->params[IDX_Props].flags ^= SPA_PARAM_INFO_SERIAL;
825 	this->params[IDX_PropInfo].flags ^= SPA_PARAM_INFO_SERIAL;
826 	emit_info(this, false);
827 
828 	return 0;
829 }
830 
codec_switched(void * userdata,int status)831 static void codec_switched(void *userdata, int status)
832 {
833 	struct impl *this = userdata;
834 
835 	spa_log_debug(this->log, "codec switched (status %d)", status);
836 
837 	this->switching_codec = false;
838 
839 	if (status < 0) {
840 		/* Failed to switch: return to a fallback profile */
841 		spa_log_error(this->log, "failed to switch codec (%d), setting fallback profile", status);
842 		if (this->profile == DEVICE_PROFILE_A2DP && this->props.codec != 0) {
843 			this->props.codec = 0;
844 		} else if (this->profile == DEVICE_PROFILE_HSP_HFP && this->props.codec != 0) {
845 			this->props.codec = 0;
846 		} else {
847 			this->profile = DEVICE_PROFILE_OFF;
848 		}
849 	}
850 
851 	emit_remove_nodes(this);
852 	emit_nodes(this);
853 
854 	this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
855 	if (this->prev_bt_connected_profiles != this->bt_dev->connected_profiles)
856 		this->params[IDX_EnumProfile].flags ^= SPA_PARAM_INFO_SERIAL;
857 	this->params[IDX_Profile].flags ^= SPA_PARAM_INFO_SERIAL;
858 	this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
859 	this->params[IDX_EnumRoute].flags ^= SPA_PARAM_INFO_SERIAL;
860 	this->params[IDX_Props].flags ^= SPA_PARAM_INFO_SERIAL;
861 	this->params[IDX_PropInfo].flags ^= SPA_PARAM_INFO_SERIAL;
862 	emit_info(this, false);
863 }
864 
profiles_changed(void * userdata,uint32_t prev_profiles,uint32_t prev_connected_profiles)865 static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t prev_connected_profiles)
866 {
867 	struct impl *this = userdata;
868 	uint32_t connected_change;
869 	bool nodes_changed = false;
870 
871 	connected_change = (this->bt_dev->connected_profiles ^ prev_connected_profiles);
872 
873 	/* Profiles changed. We have to re-emit device information. */
874 	spa_log_info(this->log, "profiles changed to  %08x %08x (prev %08x %08x, change %08x)"
875 		     " switching_codec:%d",
876 		     this->bt_dev->profiles, this->bt_dev->connected_profiles,
877 		     prev_profiles, prev_connected_profiles, connected_change,
878 		     this->switching_codec);
879 
880 	if (this->switching_codec)
881 		return;
882 
883 	if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) {
884 		free(this->supported_codecs);
885 		this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs(
886 			this->bt_dev, &this->supported_codec_count);
887 	}
888 
889 	switch (this->profile) {
890 	case DEVICE_PROFILE_OFF:
891 		/* Noop */
892 		nodes_changed = false;
893 		break;
894 	case DEVICE_PROFILE_AG:
895 		nodes_changed = (connected_change & (SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY |
896 						     SPA_BT_PROFILE_A2DP_SOURCE));
897 		spa_log_debug(this->log, "profiles changed: AG nodes changed: %d",
898 			      nodes_changed);
899 		break;
900 	case DEVICE_PROFILE_A2DP:
901 		if (get_supported_a2dp_codec(this, this->props.codec, NULL) == NULL)
902 			this->props.codec = 0;
903 		nodes_changed = (connected_change & (SPA_BT_PROFILE_A2DP_SINK |
904 						     SPA_BT_PROFILE_A2DP_SOURCE));
905 		spa_log_debug(this->log, "profiles changed: A2DP nodes changed: %d",
906 			      nodes_changed);
907 		break;
908 	case DEVICE_PROFILE_HSP_HFP:
909 		if (spa_bt_device_supports_hfp_codec(this->bt_dev, get_hfp_codec(this->props.codec)) != 1)
910 			this->props.codec = 0;
911 		nodes_changed = (connected_change & SPA_BT_PROFILE_HEADSET_HEAD_UNIT);
912 		spa_log_debug(this->log, "profiles changed: HSP/HFP nodes changed: %d",
913 			      nodes_changed);
914 		break;
915 	}
916 
917 	if (nodes_changed) {
918 		emit_remove_nodes(this);
919 		emit_nodes(this);
920 	}
921 
922 	this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
923 	this->params[IDX_Profile].flags ^= SPA_PARAM_INFO_SERIAL;
924 	this->params[IDX_EnumProfile].flags ^= SPA_PARAM_INFO_SERIAL;
925 	this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;  /* Profile changes may affect routes */
926 	this->params[IDX_EnumRoute].flags ^= SPA_PARAM_INFO_SERIAL;
927 	this->params[IDX_Props].flags ^= SPA_PARAM_INFO_SERIAL;
928 	this->params[IDX_PropInfo].flags ^= SPA_PARAM_INFO_SERIAL;
929 	emit_info(this, false);
930 }
931 
932 static void set_initial_profile(struct impl *this);
933 
device_connected(void * userdata,bool connected)934 static void device_connected(void *userdata, bool connected) {
935 	struct impl *this = userdata;
936 
937 	spa_log_debug(this->log, "connected: %d", connected);
938 
939 	if (connected ^ (this->profile != DEVICE_PROFILE_OFF))
940 		set_initial_profile(this);
941 }
942 
943 static const struct spa_bt_device_events bt_dev_events = {
944 	SPA_VERSION_BT_DEVICE_EVENTS,
945 	.connected = device_connected,
946 	.codec_switched = codec_switched,
947 	.profiles_changed = profiles_changed,
948 };
949 
impl_add_listener(void * object,struct spa_hook * listener,const struct spa_device_events * events,void * data)950 static int impl_add_listener(void *object,
951 			struct spa_hook *listener,
952 			const struct spa_device_events *events,
953 			void *data)
954 {
955 	struct impl *this = object;
956 	struct spa_hook_list save;
957 
958 	spa_return_val_if_fail(this != NULL, -EINVAL);
959 	spa_return_val_if_fail(events != NULL, -EINVAL);
960 
961 	spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
962 
963 	if (events->info)
964 		emit_info(this, true);
965 
966 	if (events->object_info)
967 		emit_nodes(this);
968 
969 	spa_hook_list_join(&this->hooks, &save);
970 
971 	return 0;
972 }
973 
impl_sync(void * object,int seq)974 static int impl_sync(void *object, int seq)
975 {
976 	struct impl *this = object;
977 
978 	spa_return_val_if_fail(this != NULL, -EINVAL);
979 
980 	spa_device_emit_result(&this->hooks, seq, 0, 0, NULL);
981 
982 	return 0;
983 }
984 
profile_direction_mask(struct impl * this,uint32_t index,enum spa_bluetooth_audio_codec codec)985 static uint32_t profile_direction_mask(struct impl *this, uint32_t index, enum spa_bluetooth_audio_codec codec)
986 {
987 	struct spa_bt_device *device = this->bt_dev;
988 	uint32_t mask;
989 	bool have_output = false, have_input = false;
990 	const struct a2dp_codec *a2dp_codec;
991 
992 	switch (index) {
993 	case DEVICE_PROFILE_A2DP:
994 		if (device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK)
995 			have_output = true;
996 
997 		a2dp_codec = get_supported_a2dp_codec(this, codec, NULL);
998 		if (a2dp_codec && a2dp_codec->duplex_codec)
999 			have_input = true;
1000 		break;
1001 	case DEVICE_PROFILE_HSP_HFP:
1002 		if (device->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT)
1003 			have_output = have_input = true;
1004 		break;
1005 	default:
1006 		break;
1007 	}
1008 
1009 	mask = 0;
1010 	if (have_output)
1011 		mask |= 1 << SPA_DIRECTION_OUTPUT;
1012 	if (have_input)
1013 		mask |= 1 << SPA_DIRECTION_INPUT;
1014 	return mask;
1015 }
1016 
get_profile_from_index(struct impl * this,uint32_t index,uint32_t * next,enum spa_bluetooth_audio_codec * codec)1017 static uint32_t get_profile_from_index(struct impl *this, uint32_t index, uint32_t *next, enum spa_bluetooth_audio_codec *codec)
1018 {
1019 	/*
1020 	 * XXX: The codecs should probably become a separate param, and not have
1021 	 * XXX: separate profiles for each one.
1022 	 */
1023 
1024 	*codec = 0;
1025 	*next = index + 1;
1026 
1027 	if (index <= 3) {
1028 		return index;
1029 	} else if (index != SPA_ID_INVALID) {
1030 		const struct spa_type_info *info;
1031 
1032 		*codec = index - 3;
1033 		*next = SPA_ID_INVALID;
1034 
1035 		for (info = spa_type_bluetooth_audio_codec; info->type; ++info)
1036 			if (info->type > *codec)
1037 				*next = SPA_MIN(info->type + 3, *next);
1038 
1039 		return get_hfp_codec(*codec) ? DEVICE_PROFILE_HSP_HFP : DEVICE_PROFILE_A2DP;
1040 	}
1041 
1042 	*next = SPA_ID_INVALID;
1043 	return SPA_ID_INVALID;
1044 }
1045 
get_index_from_profile(struct impl * this,uint32_t profile,enum spa_bluetooth_audio_codec codec)1046 static uint32_t get_index_from_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec)
1047 {
1048 	if (profile == DEVICE_PROFILE_OFF || profile == DEVICE_PROFILE_AG)
1049 		return profile;
1050 
1051 	if (profile == DEVICE_PROFILE_A2DP) {
1052 		if (codec == 0 || (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE))
1053 			return profile;
1054 
1055 		return codec + 3;
1056 	}
1057 
1058 	if (profile == DEVICE_PROFILE_HSP_HFP) {
1059 		if (codec == 0 || (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HFP_AG))
1060 			return profile;
1061 
1062 		return codec + 3;
1063 	}
1064 
1065 	return SPA_ID_INVALID;
1066 }
1067 
set_initial_hsp_hfp_profile(struct impl * this)1068 static bool set_initial_hsp_hfp_profile(struct impl *this)
1069 {
1070 	struct spa_bt_transport *t;
1071 	int i;
1072 
1073 	for (i = SPA_BT_PROFILE_HSP_HS; i <= SPA_BT_PROFILE_HFP_AG; i <<= 1) {
1074 		if (!(this->bt_dev->connected_profiles & i))
1075 			continue;
1076 
1077 		t = find_transport(this, i, 0);
1078 		if (t) {
1079 			this->profile = (i & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY) ?
1080 				DEVICE_PROFILE_AG : DEVICE_PROFILE_HSP_HFP;
1081 			this->props.codec = get_hfp_codec_id(t->codec);
1082 
1083 			spa_log_debug(this->log, "initial profile HSP/HFP profile:%d codec:%d",
1084 					this->profile, this->props.codec);
1085 			return true;
1086 		}
1087 	}
1088 	return false;
1089 }
1090 
set_initial_profile(struct impl * this)1091 static void set_initial_profile(struct impl *this)
1092 {
1093 	struct spa_bt_transport *t;
1094 	int i;
1095 
1096 	if (this->supported_codecs)
1097 		free(this->supported_codecs);
1098 	this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs(
1099 					this->bt_dev, &this->supported_codec_count);
1100 
1101 	/* Prefer A2DP, then HFP, then null, but select AG if the device
1102 	   appears not to have A2DP_SINK or any HEAD_UNIT profile */
1103 
1104 	/* If default profile is set to HSP/HFP, first try those and exit if found. */
1105 	if (this->bt_dev->settings != NULL) {
1106 		const char *str = spa_dict_lookup(this->bt_dev->settings, "bluez5.profile");
1107 		if (spa_streq(str, "headset-head-unit") && set_initial_hsp_hfp_profile(this))
1108 			return;
1109 	}
1110 
1111 	for (i = SPA_BT_PROFILE_A2DP_SINK; i <= SPA_BT_PROFILE_A2DP_SOURCE; i <<= 1) {
1112 		if (!(this->bt_dev->connected_profiles & i))
1113 			continue;
1114 
1115 		t = find_transport(this, i, 0);
1116 		if (t) {
1117 			this->profile = (i == SPA_BT_PROFILE_A2DP_SOURCE) ?
1118 				DEVICE_PROFILE_AG : DEVICE_PROFILE_A2DP;
1119 			this->props.codec = t->a2dp_codec->id;
1120 			spa_log_debug(this->log, "initial profile A2DP profile:%d codec:%d",
1121 					this->profile, this->props.codec);
1122 			return;
1123 		}
1124 	}
1125 
1126 	if (set_initial_hsp_hfp_profile(this))
1127 		return;
1128 
1129 	spa_log_debug(this->log, "initial profile off");
1130 
1131 	this->profile = DEVICE_PROFILE_OFF;
1132 	this->props.codec = 0;
1133 }
1134 
build_profile(struct impl * this,struct spa_pod_builder * b,uint32_t id,uint32_t index,uint32_t profile_index,enum spa_bluetooth_audio_codec codec)1135 static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *b,
1136 		uint32_t id, uint32_t index, uint32_t profile_index, enum spa_bluetooth_audio_codec codec)
1137 {
1138 	struct spa_bt_device *device = this->bt_dev;
1139 	struct spa_pod_frame f[2];
1140 	const char *name, *desc;
1141 	char *name_and_codec = NULL;
1142 	char *desc_and_codec = NULL;
1143 	uint32_t n_source = 0, n_sink = 0;
1144 	uint32_t capture[1] = { DEVICE_ID_SOURCE }, playback[1] = { DEVICE_ID_SINK };
1145 	int priority;
1146 
1147 	switch (profile_index) {
1148 	case DEVICE_PROFILE_OFF:
1149 		name = "off";
1150 		desc = _("Off");
1151 		priority = 0;
1152 		break;
1153 	case DEVICE_PROFILE_AG:
1154 	{
1155 		uint32_t profile = device->connected_profiles &
1156 		      (SPA_BT_PROFILE_A2DP_SOURCE | SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY);
1157 		if (profile == 0) {
1158 			return NULL;
1159 		} else {
1160 			name = "audio-gateway";
1161 			desc = _("Audio Gateway (A2DP Source & HSP/HFP AG)");
1162 		}
1163 		priority = 256;
1164 		break;
1165 	}
1166 	case DEVICE_PROFILE_A2DP:
1167 	{
1168 		/* make this device profile visible only if there is an A2DP sink */
1169 		uint32_t profile = device->connected_profiles &
1170 		      (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE);
1171 		if (!(profile & SPA_BT_PROFILE_A2DP_SINK)) {
1172 			return NULL;
1173 		}
1174 		name = spa_bt_profile_name(profile);
1175 		n_sink++;
1176 		if (codec) {
1177 			size_t idx;
1178 			const struct a2dp_codec *a2dp_codec = get_supported_a2dp_codec(this, codec, &idx);
1179 			if (a2dp_codec == NULL) {
1180 				errno = EINVAL;
1181 				return NULL;
1182 			}
1183 			name_and_codec = spa_aprintf("%s-%s", name, a2dp_codec->name);
1184 			name = name_and_codec;
1185 			if (profile == SPA_BT_PROFILE_A2DP_SINK && !a2dp_codec->duplex_codec) {
1186 				desc_and_codec = spa_aprintf(_("High Fidelity Playback (A2DP Sink, codec %s)"),
1187 							     a2dp_codec->description);
1188 			} else {
1189 				desc_and_codec = spa_aprintf(_("High Fidelity Duplex (A2DP Source/Sink, codec %s)"),
1190 							     a2dp_codec->description);
1191 
1192 			}
1193 			desc = desc_and_codec;
1194 			priority = 16 + this->supported_codec_count - idx;  /* order as in codec list */
1195 		} else {
1196 			if (profile == SPA_BT_PROFILE_A2DP_SINK) {
1197 				desc = _("High Fidelity Playback (A2DP Sink)");
1198 			} else {
1199 				desc = _("High Fidelity Duplex (A2DP Source/Sink)");
1200 			}
1201 			priority = 16;
1202 		}
1203 		break;
1204 	}
1205 	case DEVICE_PROFILE_HSP_HFP:
1206 	{
1207 		/* make this device profile visible only if there is a head unit */
1208 		uint32_t profile = device->connected_profiles &
1209 		      SPA_BT_PROFILE_HEADSET_HEAD_UNIT;
1210 		if (profile == 0) {
1211 			return NULL;
1212 		}
1213 		name = spa_bt_profile_name(profile);
1214 		n_source++;
1215 		n_sink++;
1216 		if (codec) {
1217 			bool codec_ok = !(profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY);
1218 			unsigned int hfp_codec = get_hfp_codec(codec);
1219 			if (spa_bt_device_supports_hfp_codec(this->bt_dev, hfp_codec) != 1)
1220 				codec_ok = false;
1221 			if (!codec_ok) {
1222 				errno = EINVAL;
1223 				return NULL;
1224 			}
1225 			name_and_codec = spa_aprintf("%s-%s", name, get_hfp_codec_name(hfp_codec));
1226 			name = name_and_codec;
1227 			desc_and_codec = spa_aprintf(_("Headset Head Unit (HSP/HFP, codec %s)"),
1228 						get_hfp_codec_description(hfp_codec));
1229 			desc = desc_and_codec;
1230 			priority = 1 + hfp_codec;  /* prefer msbc over cvsd */
1231 		} else {
1232 			desc = _("Headset Head Unit (HSP/HFP)");
1233 			priority = 1;
1234 		}
1235 		break;
1236 	}
1237 	default:
1238 		errno = EINVAL;
1239 		return NULL;
1240 	}
1241 
1242 	spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_ParamProfile, id);
1243 	spa_pod_builder_add(b,
1244 		SPA_PARAM_PROFILE_index,   SPA_POD_Int(index),
1245 		SPA_PARAM_PROFILE_name, SPA_POD_String(name),
1246 		SPA_PARAM_PROFILE_description, SPA_POD_String(desc),
1247 		SPA_PARAM_PROFILE_available, SPA_POD_Id(SPA_PARAM_AVAILABILITY_yes),
1248 		SPA_PARAM_PROFILE_priority, SPA_POD_Int(priority),
1249 		0);
1250 	if (n_source > 0 || n_sink > 0) {
1251 		spa_pod_builder_prop(b, SPA_PARAM_PROFILE_classes, 0);
1252 		spa_pod_builder_push_struct(b, &f[1]);
1253 		if (n_source > 0) {
1254 			spa_pod_builder_add_struct(b,
1255 				SPA_POD_String("Audio/Source"),
1256 				SPA_POD_Int(n_source),
1257 				SPA_POD_String("card.profile.devices"),
1258 				SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Int, 1, capture));
1259 		}
1260 		if (n_sink > 0) {
1261 			spa_pod_builder_add_struct(b,
1262 				SPA_POD_String("Audio/Sink"),
1263 				SPA_POD_Int(n_sink),
1264 				SPA_POD_String("card.profile.devices"),
1265 				SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Int, 1, playback));
1266 		}
1267 		spa_pod_builder_pop(b, &f[1]);
1268 	}
1269 
1270 	if (name_and_codec)
1271 		free(name_and_codec);
1272 	if (desc_and_codec)
1273 		free(desc_and_codec);
1274 
1275 	return spa_pod_builder_pop(b, &f[0]);
1276 }
1277 
validate_profile(struct impl * this,uint32_t profile,enum spa_bluetooth_audio_codec codec)1278 static bool validate_profile(struct impl *this, uint32_t profile,
1279 		enum spa_bluetooth_audio_codec codec)
1280 {
1281 	struct spa_pod_builder b = { 0 };
1282 	uint8_t buffer[1024];
1283 
1284 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
1285 	return (build_profile(this, &b, 0, 0, profile, codec) != NULL);
1286 }
1287 
build_route(struct impl * this,struct spa_pod_builder * b,uint32_t id,uint32_t port,uint32_t dev,uint32_t profile)1288 static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
1289 		uint32_t id, uint32_t port, uint32_t dev, uint32_t profile)
1290 {
1291 	struct spa_bt_device *device = this->bt_dev;
1292 	struct spa_pod_frame f[2];
1293 	enum spa_direction direction;
1294 	const char *name_prefix, *description, *port_type;
1295 	enum spa_bt_form_factor ff;
1296 	enum spa_bluetooth_audio_codec codec;
1297 	char name[128];
1298 	uint32_t i, j, mask, next;
1299 
1300 	ff = spa_bt_form_factor_from_class(device->bluetooth_class);
1301 
1302 	switch (ff) {
1303 	case SPA_BT_FORM_FACTOR_HEADSET:
1304 		name_prefix = "headset";
1305 		description = _("Headset");
1306 		port_type = "headset";
1307 		break;
1308 	case SPA_BT_FORM_FACTOR_HANDSFREE:
1309 		name_prefix = "handsfree";
1310 		description = _("Handsfree");
1311 		port_type = "handsfree";
1312 		break;
1313 	case SPA_BT_FORM_FACTOR_MICROPHONE:
1314 		name_prefix = "microphone";
1315 		description = _("Microphone");
1316 		port_type = "mic";
1317 		break;
1318 	case SPA_BT_FORM_FACTOR_SPEAKER:
1319 		name_prefix = "speaker";
1320 		description = _("Speaker");
1321 		port_type = "speaker";
1322 		break;
1323 	case SPA_BT_FORM_FACTOR_HEADPHONE:
1324 		name_prefix = "headphone";
1325 		description = _("Headphone");
1326 		port_type = "headphones";
1327 		break;
1328 	case SPA_BT_FORM_FACTOR_PORTABLE:
1329 		name_prefix = "portable";
1330 		description = _("Portable");
1331 		port_type = "portable";
1332 		break;
1333 	case SPA_BT_FORM_FACTOR_CAR:
1334 		name_prefix = "car";
1335 		description = _("Car");
1336 		port_type = "car";
1337 		break;
1338 	case SPA_BT_FORM_FACTOR_HIFI:
1339 		name_prefix = "hifi";
1340 		description = _("HiFi");
1341 		port_type = "hifi";
1342 		break;
1343 	case SPA_BT_FORM_FACTOR_PHONE:
1344 		name_prefix = "phone";
1345 		description = _("Phone");
1346 		port_type = "phone";
1347 		break;
1348 	case SPA_BT_FORM_FACTOR_UNKNOWN:
1349 	default:
1350 		name_prefix = "bluetooth";
1351 		description = _("Bluetooth");
1352 		port_type = "bluetooth";
1353 		break;
1354 	}
1355 
1356 	switch (port) {
1357 	case 0:
1358 		direction = SPA_DIRECTION_INPUT;
1359 		snprintf(name, sizeof(name), "%s-input", name_prefix);
1360 		break;
1361 	case 1:
1362 		direction = SPA_DIRECTION_OUTPUT;
1363 		snprintf(name, sizeof(name), "%s-output", name_prefix);
1364 		break;
1365 	default:
1366 		errno = EINVAL;
1367 		return NULL;
1368 	}
1369 
1370 	spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_ParamRoute, id);
1371 	spa_pod_builder_add(b,
1372 		SPA_PARAM_ROUTE_index, SPA_POD_Int(port),
1373 		SPA_PARAM_ROUTE_direction,  SPA_POD_Id(direction),
1374 		SPA_PARAM_ROUTE_name,  SPA_POD_String(name),
1375 		SPA_PARAM_ROUTE_description,  SPA_POD_String(description),
1376 		SPA_PARAM_ROUTE_priority,  SPA_POD_Int(0),
1377 		SPA_PARAM_ROUTE_available,  SPA_POD_Id(SPA_PARAM_AVAILABILITY_yes),
1378 		0);
1379 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_info, 0);
1380 	spa_pod_builder_push_struct(b, &f[1]);
1381 	spa_pod_builder_int(b, 1);
1382 	spa_pod_builder_add(b,
1383 			SPA_POD_String("port.type"),
1384 			SPA_POD_String(port_type),
1385 			NULL);
1386 	spa_pod_builder_pop(b, &f[1]);
1387 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_profiles, 0);
1388 	spa_pod_builder_push_array(b, &f[1]);
1389 
1390 	mask = 0;
1391 	for (i = 1; (j = get_profile_from_index(this, i, &next, &codec)) != SPA_ID_INVALID; i = next) {
1392 		uint32_t profile_mask;
1393 
1394 		profile_mask = profile_direction_mask(this, j, codec);
1395 		if (!(profile_mask & (1 << direction)))
1396 			continue;
1397 
1398 		/* Check the profile actually exists */
1399 		if (!validate_profile(this, j, codec))
1400 			continue;
1401 
1402 		mask |= profile_mask;
1403 		spa_pod_builder_int(b, i);
1404 	}
1405 	spa_pod_builder_pop(b, &f[1]);
1406 
1407 	if (!(mask & (1 << direction))) {
1408 		/* No profile has route direction */
1409 		return NULL;
1410 	}
1411 
1412 	if (dev != SPA_ID_INVALID) {
1413 		struct node *node = &this->nodes[dev];
1414 		struct spa_bt_transport_volume *t_volume;
1415 
1416 		mask = profile_direction_mask(this, this->profile, this->props.codec);
1417 		if (!(mask & (1 << direction)))
1418 			return NULL;
1419 
1420 		t_volume = node->transport
1421 			? &node->transport->volumes[node->id]
1422 			: NULL;
1423 
1424 		spa_pod_builder_prop(b, SPA_PARAM_ROUTE_device, 0);
1425 		spa_pod_builder_int(b, dev);
1426 
1427 		spa_pod_builder_prop(b, SPA_PARAM_ROUTE_props, 0);
1428 		spa_pod_builder_push_object(b, &f[1], SPA_TYPE_OBJECT_Props, id);
1429 
1430 		spa_pod_builder_prop(b, SPA_PROP_mute, 0);
1431 		spa_pod_builder_bool(b, node->mute);
1432 
1433 		spa_pod_builder_prop(b, SPA_PROP_channelVolumes,
1434 			(t_volume && t_volume->active) ? SPA_POD_PROP_FLAG_HARDWARE : 0);
1435 		spa_pod_builder_array(b, sizeof(float), SPA_TYPE_Float,
1436 				node->n_channels, node->volumes);
1437 
1438 		if (t_volume && t_volume->active) {
1439 			spa_pod_builder_prop(b, SPA_PROP_volumeStep, SPA_POD_PROP_FLAG_READONLY);
1440 			spa_pod_builder_float(b, 1.0f / (t_volume->hw_volume_max + 1));
1441 		}
1442 
1443 		spa_pod_builder_prop(b, SPA_PROP_channelMap, 0);
1444 		spa_pod_builder_array(b, sizeof(uint32_t), SPA_TYPE_Id,
1445 				node->n_channels, node->channels);
1446 
1447 		if (this->profile == DEVICE_PROFILE_A2DP && dev == DEVICE_ID_SINK) {
1448 			spa_pod_builder_prop(b, SPA_PROP_latencyOffsetNsec, 0);
1449 			spa_pod_builder_long(b, node->latency_offset);
1450 		}
1451 
1452 		spa_pod_builder_pop(b, &f[1]);
1453 
1454 		spa_pod_builder_prop(b, SPA_PARAM_ROUTE_save, 0);
1455 		spa_pod_builder_bool(b, node->save);
1456 	}
1457 
1458 	spa_pod_builder_prop(b, SPA_PARAM_ROUTE_devices, 0);
1459 	spa_pod_builder_push_array(b, &f[1]);
1460 	/* port and device indexes are the same, 0=source, 1=sink */
1461 	spa_pod_builder_int(b, port);
1462 	spa_pod_builder_pop(b, &f[1]);
1463 
1464 	if (profile != SPA_ID_INVALID) {
1465 		spa_pod_builder_prop(b, SPA_PARAM_ROUTE_profile, 0);
1466 		spa_pod_builder_int(b, profile);
1467 	}
1468 	return spa_pod_builder_pop(b, &f[0]);
1469 }
1470 
iterate_supported_a2dp_codecs(struct impl * this,int * j,const struct a2dp_codec ** codec)1471 static bool iterate_supported_a2dp_codecs(struct impl *this, int *j, const struct a2dp_codec **codec)
1472 {
1473 	int i;
1474 
1475 next:
1476 	*j = *j + 1;
1477 	spa_assert(*j >= 0);
1478 	if ((size_t)*j >= this->supported_codec_count)
1479 		return false;
1480 
1481 	for (i = 0; i < *j; ++i)
1482 		if (this->supported_codecs[i]->id == this->supported_codecs[*j]->id)
1483 			goto next;
1484 
1485 	*codec = this->supported_codecs[*j];
1486 	return true;
1487 }
1488 
build_prop_info(struct impl * this,struct spa_pod_builder * b,uint32_t id)1489 static struct spa_pod *build_prop_info(struct impl *this, struct spa_pod_builder *b, uint32_t id)
1490 {
1491 	struct spa_pod_frame f[2];
1492 	struct spa_pod_choice *choice;
1493 	const struct a2dp_codec *codec;
1494 	size_t n;
1495 	int j;
1496 
1497 #define FOR_EACH_A2DP_CODEC(j, codec) \
1498 		for (j = -1; iterate_supported_a2dp_codecs(this, &j, &codec);)
1499 #define FOR_EACH_HFP_CODEC(j) \
1500 		for (j = HFP_AUDIO_CODEC_MSBC; j >= HFP_AUDIO_CODEC_CVSD; --j) \
1501 			if (spa_bt_device_supports_hfp_codec(this->bt_dev, j) == 1)
1502 
1503 	spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
1504 
1505 	/*
1506 	 * XXX: the ids in principle should use builder_id, not builder_int,
1507 	 * XXX: but the type info for _type and _labels doesn't work quite right now.
1508 	 */
1509 
1510 	/* Transport codec */
1511 	spa_pod_builder_prop(b, SPA_PROP_INFO_id, 0);
1512 	spa_pod_builder_id(b, SPA_PROP_bluetoothAudioCodec);
1513 	spa_pod_builder_prop(b, SPA_PROP_INFO_name, 0);
1514 	spa_pod_builder_string(b, "Air codec");
1515 	spa_pod_builder_prop(b, SPA_PROP_INFO_type, 0);
1516 	spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0);
1517 	choice = (struct spa_pod_choice *)spa_pod_builder_frame(b, &f[1]);
1518 	n = 0;
1519 	if (this->profile == DEVICE_PROFILE_A2DP) {
1520 		FOR_EACH_A2DP_CODEC(j, codec) {
1521 			if (n == 0)
1522 				spa_pod_builder_int(b, codec->id);
1523 			spa_pod_builder_int(b, codec->id);
1524 			++n;
1525 		}
1526 	} else if (this->profile == DEVICE_PROFILE_HSP_HFP) {
1527 		FOR_EACH_HFP_CODEC(j) {
1528 			if (n == 0)
1529 				spa_pod_builder_int(b, get_hfp_codec_id(j));
1530 			spa_pod_builder_int(b, get_hfp_codec_id(j));
1531 			++n;
1532 		}
1533 	}
1534 	if (n == 0)
1535 		choice->body.type = SPA_CHOICE_None;
1536 	spa_pod_builder_pop(b, &f[1]);
1537 	spa_pod_builder_prop(b, SPA_PROP_INFO_labels, 0);
1538 	spa_pod_builder_push_struct(b, &f[1]);
1539 	if (this->profile == DEVICE_PROFILE_A2DP) {
1540 		FOR_EACH_A2DP_CODEC(j, codec) {
1541 			spa_pod_builder_int(b, codec->id);
1542 			spa_pod_builder_string(b, codec->description);
1543 		}
1544 	} else if (this->profile == DEVICE_PROFILE_HSP_HFP) {
1545 		FOR_EACH_HFP_CODEC(j) {
1546 			spa_pod_builder_int(b, get_hfp_codec_id(j));
1547 			spa_pod_builder_string(b, get_hfp_codec_description(j));
1548 		}
1549 	}
1550 	spa_pod_builder_pop(b, &f[1]);
1551 	return spa_pod_builder_pop(b, &f[0]);
1552 
1553 #undef FOR_EACH_A2DP_CODEC
1554 #undef FOR_EACH_HFP_CODEC
1555 }
1556 
build_props(struct impl * this,struct spa_pod_builder * b,uint32_t id)1557 static struct spa_pod *build_props(struct impl *this, struct spa_pod_builder *b, uint32_t id)
1558 {
1559 	struct props *p = &this->props;
1560 
1561 	return spa_pod_builder_add_object(b,
1562 			SPA_TYPE_OBJECT_Props, id,
1563 			SPA_PROP_bluetoothAudioCodec, SPA_POD_Id(p->codec));
1564 }
1565 
impl_enum_params(void * object,int seq,uint32_t id,uint32_t start,uint32_t num,const struct spa_pod * filter)1566 static int impl_enum_params(void *object, int seq,
1567 			    uint32_t id, uint32_t start, uint32_t num,
1568 			    const struct spa_pod *filter)
1569 {
1570 	struct impl *this = object;
1571 	struct spa_pod *param;
1572 	struct spa_pod_builder b = { 0 };
1573 	uint8_t buffer[2048];
1574 	struct spa_result_device_params result;
1575 	uint32_t count = 0;
1576 
1577 	spa_return_val_if_fail(this != NULL, -EINVAL);
1578 	spa_return_val_if_fail(num != 0, -EINVAL);
1579 
1580 	result.id = id;
1581 	result.next = start;
1582       next:
1583 	result.index = result.next++;
1584 
1585 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
1586 
1587 	switch (id) {
1588 	case SPA_PARAM_EnumProfile:
1589 	{
1590 		uint32_t profile;
1591 		enum spa_bluetooth_audio_codec codec;
1592 
1593 		profile = get_profile_from_index(this, result.index, &result.next, &codec);
1594 
1595 		switch (profile) {
1596 		case DEVICE_PROFILE_OFF:
1597 		case DEVICE_PROFILE_AG:
1598 		case DEVICE_PROFILE_A2DP:
1599 		case DEVICE_PROFILE_HSP_HFP:
1600 			param = build_profile(this, &b, id, result.index, profile, codec);
1601 			if (param == NULL)
1602 				goto next;
1603 			break;
1604 		default:
1605 			return 0;
1606 		}
1607 		break;
1608 	}
1609 	case SPA_PARAM_Profile:
1610 	{
1611 		uint32_t index;
1612 
1613 		switch (result.index) {
1614 		case 0:
1615 			index = get_index_from_profile(this, this->profile, this->props.codec);
1616 			param = build_profile(this, &b, id, index, this->profile, this->props.codec);
1617 			if (param == NULL)
1618 				return 0;
1619 			break;
1620 		default:
1621 			return 0;
1622 		}
1623 		break;
1624 	}
1625 	case SPA_PARAM_EnumRoute:
1626 	{
1627 		switch (result.index) {
1628 		case 0: case 1:
1629 			param = build_route(this, &b, id, result.index,
1630 					SPA_ID_INVALID, SPA_ID_INVALID);
1631 			if (param == NULL)
1632 				goto next;
1633 			break;
1634 		default:
1635 			return 0;
1636 		}
1637 		break;
1638 	}
1639 	case SPA_PARAM_Route:
1640 	{
1641 		switch (result.index) {
1642 		case 0: case 1:
1643 			param = build_route(this, &b, id, result.index,
1644 					result.index, this->profile);
1645 			if (param == NULL)
1646 				goto next;
1647 			break;
1648 		default:
1649 			return 0;
1650 		}
1651 		break;
1652 	}
1653 	case SPA_PARAM_PropInfo:
1654 	{
1655 		switch (result.index) {
1656 		case 0:
1657 			param = build_prop_info(this, &b, id);
1658 			break;
1659 		default:
1660 			return 0;
1661 		}
1662 		break;
1663 	}
1664 	case SPA_PARAM_Props:
1665 	{
1666 		switch (result.index) {
1667 		case 0:
1668 			param = build_props(this, &b, id);
1669 			break;
1670 		default:
1671 			return 0;
1672 		}
1673 		break;
1674 	}
1675 	default:
1676 		return -ENOENT;
1677 	}
1678 
1679 	if (spa_pod_filter(&b, &result.param, param, filter) < 0)
1680 		goto next;
1681 
1682 	spa_device_emit_result(&this->hooks, seq, 0,
1683 			SPA_RESULT_TYPE_DEVICE_PARAMS, &result);
1684 
1685 	if (++count != num)
1686 		goto next;
1687 
1688 	return 0;
1689 }
1690 
node_set_volume(struct impl * this,struct node * node,float volumes[],uint32_t n_volumes)1691 static int node_set_volume(struct impl *this, struct node *node, float volumes[], uint32_t n_volumes)
1692 {
1693 	uint32_t i;
1694 	int changed = 0;
1695 	struct spa_bt_transport_volume *t_volume;
1696 
1697 	if (n_volumes == 0)
1698 		return -EINVAL;
1699 
1700 	spa_log_info(this->log, "node %p volume %f", node, volumes[0]);
1701 
1702 	for (i = 0; i < node->n_channels; i++) {
1703 		if (node->volumes[i] == volumes[i % n_volumes])
1704 			continue;
1705 		++changed;
1706 		node->volumes[i] = volumes[i % n_volumes];
1707 	}
1708 
1709 	t_volume = node->transport ? &node->transport->volumes[node->id]: NULL;
1710 
1711 	if (t_volume && t_volume->active
1712 	    && spa_bt_transport_volume_enabled(node->transport)) {
1713 		float hw_volume = node_get_hw_volume(node);
1714 		spa_log_debug(this->log, "node %p hardware volume %f", node, hw_volume);
1715 
1716 		node_update_soft_volumes(node, hw_volume);
1717 		spa_bt_transport_set_volume(node->transport, node->id, hw_volume);
1718 	} else {
1719 		float boost = get_soft_volume_boost(node);
1720 		for (uint32_t i = 0; i < node->n_channels; ++i)
1721 			node->soft_volumes[i] = node->volumes[i] * boost;
1722 	}
1723 
1724 	emit_volume(this, node);
1725 
1726 	return changed;
1727 }
1728 
node_set_mute(struct impl * this,struct node * node,bool mute)1729 static int node_set_mute(struct impl *this, struct node *node, bool mute)
1730 {
1731 	struct spa_event *event;
1732 	uint8_t buffer[4096];
1733 	struct spa_pod_builder b = { 0 };
1734 	struct spa_pod_frame f[1];
1735 	int changed = 0;
1736 
1737 	spa_log_info(this->log, "node %p mute %d", node, mute);
1738 
1739 	changed = (node->mute != mute);
1740 	node->mute = mute;
1741 
1742 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
1743 	spa_pod_builder_push_object(&b, &f[0],
1744 			SPA_TYPE_EVENT_Device, SPA_DEVICE_EVENT_ObjectConfig);
1745 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Object, 0);
1746 	spa_pod_builder_int(&b, node->id);
1747 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Props, 0);
1748 
1749 	spa_pod_builder_add_object(&b,
1750 			SPA_TYPE_OBJECT_Props, SPA_EVENT_DEVICE_Props,
1751 			SPA_PROP_mute, SPA_POD_Bool(mute),
1752 			SPA_PROP_softMute, SPA_POD_Bool(mute));
1753 	event = spa_pod_builder_pop(&b, &f[0]);
1754 
1755 	spa_device_emit_event(&this->hooks, event);
1756 
1757 	return changed;
1758 }
1759 
node_set_latency_offset(struct impl * this,struct node * node,int64_t latency_offset)1760 static int node_set_latency_offset(struct impl *this, struct node *node, int64_t latency_offset)
1761 {
1762 	struct spa_event *event;
1763 	uint8_t buffer[4096];
1764 	struct spa_pod_builder b = { 0 };
1765 	struct spa_pod_frame f[1];
1766 	int changed = 0;
1767 
1768 	spa_log_info(this->log, "node %p latency offset %"PRIi64" nsec", node, latency_offset);
1769 
1770 	changed = (node->latency_offset != latency_offset);
1771 	node->latency_offset = latency_offset;
1772 
1773 	spa_pod_builder_init(&b, buffer, sizeof(buffer));
1774 	spa_pod_builder_push_object(&b, &f[0],
1775 			SPA_TYPE_EVENT_Device, SPA_DEVICE_EVENT_ObjectConfig);
1776 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Object, 0);
1777 	spa_pod_builder_int(&b, node->id);
1778 	spa_pod_builder_prop(&b, SPA_EVENT_DEVICE_Props, 0);
1779 
1780 	spa_pod_builder_add_object(&b,
1781 			SPA_TYPE_OBJECT_Props, SPA_EVENT_DEVICE_Props,
1782 			SPA_PROP_latencyOffsetNsec, SPA_POD_Long(latency_offset));
1783 	event = spa_pod_builder_pop(&b, &f[0]);
1784 
1785 	spa_device_emit_event(&this->hooks, event);
1786 
1787 	return changed;
1788 }
1789 
apply_device_props(struct impl * this,struct node * node,struct spa_pod * props)1790 static int apply_device_props(struct impl *this, struct node *node, struct spa_pod *props)
1791 {
1792 	float volume = 0;
1793 	bool mute = 0;
1794 	struct spa_pod_prop *prop;
1795 	struct spa_pod_object *obj = (struct spa_pod_object *) props;
1796 	int changed = 0;
1797 	float volumes[SPA_AUDIO_MAX_CHANNELS];
1798 	uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
1799 	uint32_t n_volumes = 0, SPA_UNUSED n_channels = 0;
1800 	int64_t latency_offset = 0;
1801 
1802 	if (!spa_pod_is_object_type(props, SPA_TYPE_OBJECT_Props))
1803 		return -EINVAL;
1804 
1805 	SPA_POD_OBJECT_FOREACH(obj, prop) {
1806 		switch (prop->key) {
1807 		case SPA_PROP_volume:
1808 			if (spa_pod_get_float(&prop->value, &volume) == 0) {
1809 				int res = node_set_volume(this, node, &volume, 1);
1810 				if (res > 0)
1811 					++changed;
1812 			}
1813 			break;
1814 		case SPA_PROP_mute:
1815 			if (spa_pod_get_bool(&prop->value, &mute) == 0) {
1816 				int res = node_set_mute(this, node, mute);
1817 				if (res > 0)
1818 					++changed;
1819 			}
1820 			break;
1821 		case SPA_PROP_channelVolumes:
1822 			n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
1823 					volumes, SPA_AUDIO_MAX_CHANNELS);
1824 			break;
1825 		case SPA_PROP_channelMap:
1826 			n_channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
1827 					channels, SPA_AUDIO_MAX_CHANNELS);
1828 			break;
1829 		case SPA_PROP_latencyOffsetNsec:
1830 			if (spa_pod_get_long(&prop->value, &latency_offset) == 0) {
1831 				int res = node_set_latency_offset(this, node, latency_offset);
1832 				if (res > 0)
1833 					++changed;
1834 			}
1835 		}
1836 	}
1837 	if (n_volumes > 0) {
1838 		int res = node_set_volume(this, node, volumes, n_volumes);
1839 		if (res > 0)
1840 			++changed;
1841 	}
1842 
1843 	return changed;
1844 }
1845 
impl_set_param(void * object,uint32_t id,uint32_t flags,const struct spa_pod * param)1846 static int impl_set_param(void *object,
1847 			  uint32_t id, uint32_t flags,
1848 			  const struct spa_pod *param)
1849 {
1850 	struct impl *this = object;
1851 	int res;
1852 
1853 	spa_return_val_if_fail(this != NULL, -EINVAL);
1854 
1855 	switch (id) {
1856 	case SPA_PARAM_Profile:
1857 	{
1858 		uint32_t idx, next;
1859 		uint32_t profile;
1860 		enum spa_bluetooth_audio_codec codec;
1861 
1862 		if (param == NULL)
1863 			return -EINVAL;
1864 
1865 		if ((res = spa_pod_parse_object(param,
1866 				SPA_TYPE_OBJECT_ParamProfile, NULL,
1867 				SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) {
1868 			spa_log_warn(this->log, "can't parse profile");
1869 			spa_debug_pod(0, NULL, param);
1870 			return res;
1871 		}
1872 
1873 		profile = get_profile_from_index(this, idx, &next, &codec);
1874 		if (profile == SPA_ID_INVALID)
1875 			return -EINVAL;
1876 
1877 		spa_log_debug(this->log, "setting profile %d codec:%d", profile, codec);
1878 		return set_profile(this, profile, codec);
1879 	}
1880 	case SPA_PARAM_Route:
1881 	{
1882 		uint32_t idx, device;
1883 		struct spa_pod *props = NULL;
1884 		struct node *node;
1885 		bool save = false;
1886 
1887 		if (param == NULL)
1888 			return -EINVAL;
1889 
1890 		if ((res = spa_pod_parse_object(param,
1891 				SPA_TYPE_OBJECT_ParamRoute, NULL,
1892 				SPA_PARAM_ROUTE_index, SPA_POD_Int(&idx),
1893 				SPA_PARAM_ROUTE_device, SPA_POD_Int(&device),
1894 				SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props),
1895 				SPA_PARAM_ROUTE_save, SPA_POD_OPT_Bool(&save))) < 0) {
1896 			spa_log_warn(this->log, "can't parse route");
1897 			spa_debug_pod(0, NULL, param);
1898 			return res;
1899 		}
1900 		if (device > 1 || !this->nodes[device].active)
1901 			return -EINVAL;
1902 
1903 		node = &this->nodes[device];
1904 		node->save = save;
1905 		if (props) {
1906 			int changed = apply_device_props(this, node, props);
1907 			if (changed > 0) {
1908 				this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
1909 				this->params[IDX_Route].flags ^= SPA_PARAM_INFO_SERIAL;
1910 			}
1911 			emit_info(this, false);
1912 		}
1913 		break;
1914 	}
1915 	case SPA_PARAM_Props:
1916 	{
1917 		uint32_t codec_id = SPA_ID_INVALID;
1918 
1919 		if (param == NULL)
1920 			return 0;
1921 
1922 		if ((res = spa_pod_parse_object(param,
1923 				SPA_TYPE_OBJECT_Props, NULL,
1924 				SPA_PROP_bluetoothAudioCodec, SPA_POD_OPT_Id(&codec_id))) < 0) {
1925 			spa_log_warn(this->log, "can't parse props");
1926 			spa_debug_pod(0, NULL, param);
1927 			return res;
1928 		}
1929 
1930 		if (codec_id == SPA_ID_INVALID)
1931 			return 0;
1932 
1933 		if (this->profile == DEVICE_PROFILE_A2DP) {
1934 			size_t j;
1935 			for (j = 0; j < this->supported_codec_count; ++j) {
1936 				if (this->supported_codecs[j]->id == codec_id) {
1937 					return set_profile(this, this->profile, codec_id);
1938 				}
1939 			}
1940 		} else if (this->profile == DEVICE_PROFILE_HSP_HFP) {
1941 			if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_CVSD &&
1942 					spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_CVSD) == 1) {
1943 				return set_profile(this, this->profile, codec_id);
1944 			} else if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_MSBC &&
1945 					spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_MSBC) == 1) {
1946 				return set_profile(this, this->profile, codec_id);
1947 			}
1948 		}
1949 		return -EINVAL;
1950 	}
1951 	default:
1952 		return -ENOENT;
1953 	}
1954 	return 0;
1955 }
1956 
1957 static const struct spa_device_methods impl_device = {
1958 	SPA_VERSION_DEVICE_METHODS,
1959 	.add_listener = impl_add_listener,
1960 	.sync = impl_sync,
1961 	.enum_params = impl_enum_params,
1962 	.set_param = impl_set_param,
1963 };
1964 
impl_get_interface(struct spa_handle * handle,const char * type,void ** interface)1965 static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
1966 {
1967 	struct impl *this;
1968 
1969 	spa_return_val_if_fail(handle != NULL, -EINVAL);
1970 	spa_return_val_if_fail(interface != NULL, -EINVAL);
1971 
1972 	this = (struct impl *) handle;
1973 
1974 	if (spa_streq(type, SPA_TYPE_INTERFACE_Device))
1975 		*interface = &this->device;
1976 	else
1977 		return -ENOENT;
1978 
1979 	return 0;
1980 }
1981 
impl_clear(struct spa_handle * handle)1982 static int impl_clear(struct spa_handle *handle)
1983 {
1984 	struct impl *this = (struct impl *) handle;
1985 	const struct spa_dict_item *it;
1986 
1987 	emit_remove_nodes(this);
1988 
1989 	free(this->supported_codecs);
1990 	if (this->bt_dev) {
1991 		this->bt_dev->settings = NULL;
1992 		spa_hook_remove(&this->bt_dev_listener);
1993 	}
1994 
1995 	spa_dict_for_each(it, &this->setting_dict) {
1996 		if(it->key)
1997 			free((void *)it->key);
1998 		if(it->value)
1999 			free((void *)it->value);
2000 	}
2001 
2002 	return 0;
2003 }
2004 
2005 static size_t
impl_get_size(const struct spa_handle_factory * factory,const struct spa_dict * params)2006 impl_get_size(const struct spa_handle_factory *factory,
2007 	      const struct spa_dict *params)
2008 {
2009 	return sizeof(struct impl);
2010 }
2011 
2012 static const struct spa_dict*
filter_bluez_device_setting(struct impl * this,const struct spa_dict * dict)2013 filter_bluez_device_setting(struct impl *this, const struct spa_dict *dict)
2014 {
2015 	uint32_t n_items = 0;
2016 	for (uint32_t i = 0
2017 		; i < dict->n_items && n_items < SPA_N_ELEMENTS(this->setting_items)
2018 		; i++)
2019 	{
2020 		const struct spa_dict_item *it = &dict->items[i];
2021 		if (it->key != NULL && strncmp(it->key, "bluez", 5) == 0 && it->value != NULL) {
2022 			this->setting_items[n_items++] =
2023 				SPA_DICT_ITEM_INIT(strdup(it->key), strdup(it->value));
2024 		}
2025 	}
2026 	this->setting_dict = SPA_DICT_INIT(this->setting_items, n_items);
2027 	return &this->setting_dict;
2028 }
2029 
2030 static int
impl_init(const struct spa_handle_factory * factory,struct spa_handle * handle,const struct spa_dict * info,const struct spa_support * support,uint32_t n_support)2031 impl_init(const struct spa_handle_factory *factory,
2032 	  struct spa_handle *handle,
2033 	  const struct spa_dict *info,
2034 	  const struct spa_support *support,
2035 	  uint32_t n_support)
2036 {
2037 	struct impl *this;
2038 	const char *str;
2039 
2040 	spa_return_val_if_fail(factory != NULL, -EINVAL);
2041 	spa_return_val_if_fail(handle != NULL, -EINVAL);
2042 
2043 	handle->get_interface = impl_get_interface;
2044 	handle->clear = impl_clear;
2045 
2046 	this = (struct impl *) handle;
2047 
2048 	this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
2049 	_i18n = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_I18N);
2050 
2051 	spa_log_topic_init(this->log, &log_topic);
2052 
2053 	if (info && (str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_DEVICE)))
2054 		sscanf(str, "pointer:%p", &this->bt_dev);
2055 
2056 	if (this->bt_dev == NULL) {
2057 		spa_log_error(this->log, "a device is needed");
2058 		return -EINVAL;
2059 	}
2060 
2061 	if (info) {
2062 		int profiles;
2063 		this->bt_dev->settings = filter_bluez_device_setting(this, info);
2064 
2065 		if ((str = spa_dict_lookup(info, "bluez5.auto-connect")) != NULL) {
2066 			if ((profiles = spa_bt_profiles_from_json_array(str)) >= 0)
2067 				this->bt_dev->reconnect_profiles = profiles;
2068 		}
2069 
2070 		if ((str = spa_dict_lookup(info, "bluez5.hw-volume")) != NULL) {
2071 			if ((profiles = spa_bt_profiles_from_json_array(str)) >= 0)
2072 				this->bt_dev->hw_volume_profiles = profiles;
2073 		}
2074 	}
2075 
2076 	this->device.iface = SPA_INTERFACE_INIT(
2077 			SPA_TYPE_INTERFACE_Device,
2078 			SPA_VERSION_DEVICE,
2079 			&impl_device, this);
2080 
2081 	spa_hook_list_init(&this->hooks);
2082 
2083 	reset_props(&this->props);
2084 
2085 	init_node(this, &this->nodes[0], 0);
2086 	init_node(this, &this->nodes[1], 1);
2087 
2088 	this->info = SPA_DEVICE_INFO_INIT();
2089 	this->info_all = SPA_DEVICE_CHANGE_MASK_PROPS |
2090 		SPA_DEVICE_CHANGE_MASK_PARAMS;
2091 
2092 	this->params[IDX_EnumProfile] = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ);
2093 	this->params[IDX_Profile] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_READWRITE);
2094 	this->params[IDX_EnumRoute] = SPA_PARAM_INFO(SPA_PARAM_EnumRoute, SPA_PARAM_INFO_READ);
2095 	this->params[IDX_Route] = SPA_PARAM_INFO(SPA_PARAM_Route, SPA_PARAM_INFO_READWRITE);
2096 	this->params[IDX_PropInfo] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
2097 	this->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
2098 	this->info.params = this->params;
2099 	this->info.n_params = 6;
2100 
2101 	spa_bt_device_add_listener(this->bt_dev, &this->bt_dev_listener, &bt_dev_events, this);
2102 
2103 	set_initial_profile(this);
2104 
2105 	return 0;
2106 }
2107 
2108 static const struct spa_interface_info impl_interfaces[] = {
2109 	{SPA_TYPE_INTERFACE_Device,},
2110 };
2111 
2112 static int
impl_enum_interface_info(const struct spa_handle_factory * factory,const struct spa_interface_info ** info,uint32_t * index)2113 impl_enum_interface_info(const struct spa_handle_factory *factory,
2114 			 const struct spa_interface_info **info,
2115 			 uint32_t *index)
2116 {
2117 	spa_return_val_if_fail(factory != NULL, -EINVAL);
2118 	spa_return_val_if_fail(info != NULL, -EINVAL);
2119 	spa_return_val_if_fail(index != NULL, -EINVAL);
2120 
2121 	if (*index >= SPA_N_ELEMENTS(impl_interfaces))
2122 		return 0;
2123 
2124 	*info = &impl_interfaces[(*index)++];
2125 	return 1;
2126 }
2127 
2128 static const struct spa_dict_item handle_info_items[] = {
2129 	{ SPA_KEY_FACTORY_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
2130 	{ SPA_KEY_FACTORY_DESCRIPTION, "A bluetooth device" },
2131 	{ SPA_KEY_FACTORY_USAGE, SPA_KEY_API_BLUEZ5_DEVICE"=<device>" },
2132 };
2133 
2134 static const struct spa_dict handle_info = SPA_DICT_INIT_ARRAY(handle_info_items);
2135 
2136 const struct spa_handle_factory spa_bluez5_device_factory = {
2137 	SPA_VERSION_HANDLE_FACTORY,
2138 	SPA_NAME_API_BLUEZ5_DEVICE,
2139 	&handle_info,
2140 	impl_get_size,
2141 	impl_init,
2142 	impl_enum_interface_info,
2143 };
2144