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 --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); -- 2.34.1