This adds the initial implementation for the assistant menu in bluetoothctl, to detect and print MediaAssistant objects. The current BAP Broadcast Assistant implementation can be tested by running bluetoothctl, connecting to a BASS Server, scanning a Broadcast Source that is streaming a number of BISes with audio capabilities matching the capabilities of the peer device, and noticing the MediaAssistant objects being created: client/bluetoothctl [bluetooth]# [CHG] Controller 00:60:37:31:7E:3F Pairable: yes [bluetooth]# AdvertisementMonitor path registered [bluetooth]# scan on [bluetooth]# [NEW] Device 00:60:37:94:A6:A3 00-60-37-94-A6-A3 [bluetooth]# connect 00:60:37:94:A6:A3 Attempting to connect to 00:60:37:94:A6:A3 [CHG] Device 00:60:37:94:A6:A3 Connected: yes [00-60-37-94-A6-A3]# Connection successful [00-60-37-94-A6-A3]# [NEW] Device 15:65:78:B6:52:F6 15-65-78-B6-52-F6 [00-60-37-94-A6-A3]# [NEW] Assistant /org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis1 [00-60-37-94-A6-A3]# [NEW] Assistant /org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis2 [00-60-37-94-A6-A3]# scan off [00-60-37-94-A6-A3]# Diovery stopped [00-60-37-94-A6-A3]# disconnect Attempting to disconnect from 00:60:37:94:A6:A3 [00-60-37-94-A6-A3]# Successful disconnected [CHG] Device 00:60:37:94:A6:A3 Connected: no [bluetooth]# [DEL] Assistant /org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis1 [bluetooth]# [DEL] Assistant /org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis2 --- Makefile.tools | 3 +- client/assistant.c | 164 +++++++++++++++++++++++++++++++++++++++++++++ client/assistant.h | 13 ++++ client/main.c | 5 +- 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 client/assistant.c create mode 100644 client/assistant.h diff --git a/Makefile.tools b/Makefile.tools index 679c914bf..f4f9e82dc 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -13,7 +13,8 @@ client_bluetoothctl_SOURCES = client/main.c \ client/gatt.h client/gatt.c \ client/admin.h client/admin.c \ client/player.h client/player.c \ - client/mgmt.h client/mgmt.c + client/mgmt.h client/mgmt.c \ + client/assistant.h client/assistant.c client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \ gdbus/libgdbus-internal.la src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline diff --git a/client/assistant.c b/client/assistant.c new file mode 100644 index 000000000..69a955c18 --- /dev/null +++ b/client/assistant.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdbool.h> +#include <inttypes.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/util.h" +#include "src/shared/shell.h" +#include "src/shared/io.h" +#include "src/shared/queue.h" +#include "print.h" +#include "assistant.h" + +/* String display constants */ +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF +#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF + +#define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1" + +static DBusConnection *dbus_conn; + +static GList *assistants; + +static char *proxy_description(GDBusProxy *proxy, const char *title, + const char *description) +{ + const char *path; + + path = g_dbus_proxy_get_path(proxy); + + return g_strdup_printf("%s%s%s%s %s ", + description ? "[" : "", + description ? : "", + description ? "] " : "", + title, path); +} + +static void print_assistant(GDBusProxy *proxy, const char *description) +{ + char *str; + + str = proxy_description(proxy, "Assistant", description); + + bt_shell_printf("%s\n", str); + + g_free(str); +} + +static void assistant_added(GDBusProxy *proxy) +{ + assistants = g_list_append(assistants, proxy); + + print_assistant(proxy, COLORED_NEW); +} + +static void proxy_added(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_added(proxy); +} + +static void assistant_removed(GDBusProxy *proxy) +{ + assistants = g_list_remove(assistants, proxy); + + print_assistant(proxy, COLORED_DEL); +} + +static void proxy_removed(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_removed(proxy); +} + +static void assistant_property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter) +{ + char *str; + + str = proxy_description(proxy, "Assistant", COLORED_CHG); + print_iter(str, name, iter); + g_free(str); +} + +static void property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_property_changed(proxy, name, iter); +} + +static void assistant_unregister(void *data) +{ + GDBusProxy *proxy = data; + + bt_shell_printf("Assistant %s unregistered\n", + g_dbus_proxy_get_path(proxy)); +} + +static void disconnect_handler(DBusConnection *connection, void *user_data) +{ + g_list_free_full(assistants, assistant_unregister); + assistants = NULL; +} + +static GDBusClient * client; + +void assistant_add_submenu(void) +{ + dbus_conn = bt_shell_get_env("DBUS_CONNECTION"); + if (!dbus_conn || client) + return; + + client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez"); + + g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed, + property_changed, NULL); + g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL); +} + +void assistant_remove_submenu(void) +{ + g_dbus_client_unref(client); + client = NULL; +} + diff --git a/client/assistant.h b/client/assistant.h new file mode 100644 index 000000000..418b0b840 --- /dev/null +++ b/client/assistant.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + * + */ + +void assistant_add_submenu(void); +void assistant_remove_submenu(void); + diff --git a/client/main.c b/client/main.c index f012ddd43..a96a42638 100644 --- a/client/main.c +++ b/client/main.c @@ -4,7 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Intel Corporation. All rights reserved. - * + * Copyright 2024 NXP * */ @@ -34,6 +34,7 @@ #include "admin.h" #include "player.h" #include "mgmt.h" +#include "assistant.h" /* String display constants */ #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF @@ -3205,6 +3206,7 @@ int main(int argc, char *argv[]) admin_add_submenu(); player_add_submenu(); mgmt_add_submenu(); + assistant_add_submenu(); client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez"); @@ -3222,6 +3224,7 @@ int main(int argc, char *argv[]) admin_remove_submenu(); player_remove_submenu(); mgmt_remove_submenu(); + assistant_remove_submenu(); g_dbus_client_unref(client); -- 2.39.2