diff mbox series

[BlueZ,1/6] client/player: Add broadcast sink endpoint registration and configuration.

Message ID 20230712085900.5423-2-claudia.rosu@nxp.com
State New
Headers show
Series Add support for BAP broadcast sink | expand

Commit Message

Claudia Draghicescu July 12, 2023, 8:58 a.m. UTC
Added support for broadcast sink registration using the UUID for PAC sink.
Added support for broadcast source discovery.
Added in the endpoint configuration command a new parameter for
source address that triggers source synchronization and
stream configuration.
To test this feature use the following commands:

[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] Max Transports (auto/value): a
[/local/endpoint/ep0] unicast/broadcast (u/b): b
[/local/endpoint/ep0] BIG (auto/value): a
[/local/endpoint/ep0] BIS (auto/value): a

[bluetooth]# scan on
NOTE! in the list of scanned devices, the broadcast source will be
printed in green.
[bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0 
/local/endpoint/ep0 16_2_1 <source_address>

---
 client/player.c | 187 +++++++++++++++++++++++++++++++++++++++++++++---
 client/player.h |   3 +
 2 files changed, 181 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/client/player.c b/client/player.c
index e5084967a..fd2c89f0b 100644
--- a/client/player.c
+++ b/client/player.c
@@ -81,6 +81,7 @@  struct endpoint {
 	struct preset *preset;
 	bool broadcast;
 	struct iovec *bcode;
+	struct queue *bcast_sources;
 };
 
 static DBusConnection *dbus_conn;
@@ -94,6 +95,11 @@  static GList *local_endpoints = NULL;
 static GList *transports = NULL;
 static struct queue *ios = NULL;
 
+struct bcast_source {
+	GDBusProxy *proxy;
+	uint32_t bcast_id;
+};
+
 struct transport {
 	GDBusProxy *proxy;
 	int sk;
@@ -2285,6 +2291,9 @@  static void register_endpoint_setup(DBusMessageIter *iter, void *user_data)
 		bt_shell_hexdump(ep->meta->iov_base, ep->meta->iov_len);
 	}
 
+	g_dbus_dict_append_entry(&dict, "Broadcast", DBUS_TYPE_BOOLEAN,
+				&ep->broadcast);
+
 	dbus_message_iter_close_container(iter, &dict);
 }
 
@@ -2424,6 +2433,28 @@  static void endpoint_iso_group(const char *input, void *user_data)
 			endpoint_iso_stream, ep);
 }
 
+static void endpoint_iso_mode(const char *input, void *user_data)
+{
+	struct endpoint *ep = user_data;
+
+	if (!strcasecmp(input, "u") || !strcasecmp(input, "unicast")) {
+		ep->broadcast = false;
+	} else if (!strcasecmp(input, "b") || !strcasecmp(input, "broadcast")) {
+		ep->broadcast = true;
+		ep->bcast_sources = queue_new();
+	} else {
+		bt_shell_printf("Invalid input for Auto Accept\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	if (!ep->broadcast)
+		bt_shell_prompt_input(ep->path, "CIG (auto/value):",
+						endpoint_iso_group, ep);
+	else
+		bt_shell_prompt_input(ep->path, "BIG (auto/value):",
+						endpoint_iso_group, ep);
+}
+
 static void endpoint_max_transports(const char *input, void *user_data)
 {
 	struct endpoint *ep = user_data;
@@ -2445,7 +2476,10 @@  static void endpoint_max_transports(const char *input, void *user_data)
 
 	if (ep->broadcast)
 		bt_shell_prompt_input(ep->path, "BIG (auto/value):",
-			endpoint_iso_group, ep);
+					endpoint_iso_group, ep);
+	else if (!strcmp(ep->uuid, PAC_SINK_UUID))
+		bt_shell_prompt_input(ep->path, "unicast/broadcast (u/b):",
+					endpoint_iso_mode, ep);
 	else
 		bt_shell_prompt_input(ep->path, "CIG (auto/value):",
 			endpoint_iso_group, ep);
@@ -2472,13 +2506,6 @@  static void endpoint_auto_accept(const char *input, void *user_data)
 		bt_shell_printf("Invalid input for Auto Accept\n");
 		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
-
-	if (ep->broadcast)
-		bt_shell_prompt_input(ep->path, "BIG (auto/value):",
-					endpoint_iso_group, ep);
-	else
-		bt_shell_prompt_input(ep->path, "CIG (auto/value):",
-					endpoint_iso_group, ep);
 }
 
 static void endpoint_set_metadata(const char *input, void *user_data)
@@ -2714,6 +2741,103 @@  static void endpoint_set_config(struct endpoint_config *cfg)
 	}
 }
 
+static void sink_create_reply(DBusMessage *message, void *user_data)
+{
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, message) == TRUE) {
+		bt_shell_printf("Failed to create broadcast sink: %s\n",
+					error.name);
+		dbus_error_free(&error);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+
+struct bcast_sink {
+		uint8_t		bc_sid;
+		uint8_t		bc_num_bis;
+} bcast_sink = {
+		.bc_sid = 1,
+		.bc_num_bis = 1,
+};
+
+static bool match_bcast_source_by_address(
+			const void *data, const void *match_data)
+{
+	const struct bcast_source *source = data;
+	const char *addr = match_data;
+	char *source_addr;
+	DBusMessageIter iter;
+
+	if (!g_dbus_proxy_get_property(source->proxy, "Address", &iter))
+		return false;
+
+	dbus_message_iter_get_basic(&iter, &source_addr);
+
+	if (!strcasecmp(addr, source_addr))
+		return true;
+
+	return false;
+}
+static void sink_create_setup(DBusMessageIter *iter, void *user_data)
+{
+	struct bcast_source *bcast_source = user_data;
+	DBusMessageIter dict, source_iter;
+	const char *source_type, *source_address;
+
+	g_dbus_proxy_get_property(bcast_source->proxy, "Address", &source_iter);
+
+	dbus_message_iter_get_basic(&source_iter, &source_address);
+
+	g_dbus_proxy_get_property(bcast_source->proxy, "AddressType",
+					&source_iter);
+
+	dbus_message_iter_get_basic(&source_iter, &source_type);
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+	g_dbus_dict_append_entry(&dict, "SourceAddress", DBUS_TYPE_STRING,
+					&source_address);
+
+	g_dbus_dict_append_entry(&dict, "SourceAddressType", DBUS_TYPE_STRING,
+					&source_type);
+
+	g_dbus_dict_append_entry(&dict, "BIS", DBUS_TYPE_BYTE,
+					&bcast_sink.bc_sid);
+
+	g_dbus_dict_append_entry(&dict, "NumBis", DBUS_TYPE_BYTE,
+					&bcast_sink.bc_num_bis);
+
+	g_dbus_dict_append_entry(&dict, "BcastID", DBUS_TYPE_UINT32,
+					&bcast_source->bcast_id);
+
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+static void endpoint_bcast_sink_sync(struct endpoint_config *cfg, char *source)
+{
+	struct bcast_source *bcast_source = NULL;
+
+	bcast_source = queue_find(cfg->ep->bcast_sources,
+					match_bcast_source_by_address, source);
+
+	if (!bcast_source) {
+		bt_shell_printf("Source not found\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+
+	if (g_dbus_proxy_method_call(cfg->proxy, "BcastSinkCreate",
+			sink_create_setup, sink_create_reply,
+			bcast_source, NULL) == FALSE) {
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+}
+
 static void endpoint_config(const char *input, void *user_data)
 {
 	struct endpoint_config *cfg = user_data;
@@ -2771,6 +2895,10 @@  static void cmd_config_endpoint(int argc, char *argv[])
 		cfg->qos = &preset->qos;
 
 		endpoint_set_config(cfg);
+
+		if (argv[4])
+			endpoint_bcast_sink_sync(cfg, argv[4]);
+
 		return;
 	}
 
@@ -3172,7 +3300,7 @@  static const struct bt_shell_menu endpoint_menu = {
 	{ "unregister",   "<UUID/object>", cmd_unregister_endpoint,
 						"Register Endpoint",
 						local_endpoint_generator },
-	{ "config",       "<endpoint> <local endpoint> [preset]",
+	{ "config",       "<endpoint> <local endpoint> [preset] [source]",
 						cmd_config_endpoint,
 						"Configure Endpoint",
 						endpoint_generator },
@@ -4238,3 +4366,44 @@  void player_remove_submenu(void)
 	g_dbus_client_unref(client);
 	queue_destroy(ios, transport_free);
 }
+
+void player_add_bcast_source(GDBusProxy *proxy, uint8_t *service_data, int len)
+{
+	GList *l;
+
+	for (l = local_endpoints; l; l = g_list_next(l)) {
+		struct endpoint *ep = l->data;
+
+		if (ep->broadcast && ep->bcast_sources) {
+			struct bcast_source *bcast_source =
+				new0(struct bcast_source, 1);
+
+			bcast_source->proxy = proxy;
+			bcast_source->bcast_id = get_le24(service_data);
+			queue_push_tail(ep->bcast_sources, bcast_source);
+		}
+	}
+
+}
+static bool match_bcast_source_by_proxy(const void *data,
+			const void *user_data)
+{
+	const struct bcast_source *bcast_source = data;
+
+	if (bcast_source->proxy == user_data)
+		return true;
+
+	return false;
+}
+void player_remove_bcast_source(GDBusProxy *proxy)
+{
+	GList *l;
+
+	for (l = local_endpoints; l; l = g_list_next(l)) {
+		struct endpoint *ep = l->data;
+
+		if (ep->broadcast && ep->bcast_sources)
+			queue_remove_if(ep->bcast_sources,
+				match_bcast_source_by_proxy, proxy);
+	}
+}
diff --git a/client/player.h b/client/player.h
index e7778cb1e..21e73e8ed 100644
--- a/client/player.h
+++ b/client/player.h
@@ -10,3 +10,6 @@ 
 
 void player_add_submenu(void);
 void player_remove_submenu(void);
+void player_add_bcast_source(GDBusProxy *proxy,
+		uint8_t *service_data, int len);
+void player_remove_bcast_source(GDBusProxy *proxy);