Re: [PATCH BlueZ v2] bluetoothctl: Add submenu for Call control profile testing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ajay,

On Mon, May 6, 2024 at 2:30 PM Ajay KV <ajay.k.v@xxxxxxxxx> wrote:
>
> This adds submeu in bluetoothctl for CCP Testing with
> options like answer and reject the active call . This feature
> is tested with windows machnine as CCP server which uses Teams
> application to make calls
>
> Signed-off-by: Ajay KV <ajay.k.v@xxxxxxxxx>
> ---
>  Makefile.tools    |   4 +-
>  client/ccp_test.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++
>  client/ccp_test.h |  12 +++
>  client/main.c     |   5 +-
>  4 files changed, 231 insertions(+), 2 deletions(-)
>  create mode 100644 client/ccp_test.c
>  create mode 100644 client/ccp_test.h
>
> diff --git a/Makefile.tools b/Makefile.tools
> index 679c914bf8cd..a5587427f549 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -13,7 +13,9 @@ 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/ccp_test.c \
> +                                       client/ccp_test.h
>  client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \
>                         gdbus/libgdbus-internal.la src/libshared-glib.la \
>                         $(GLIB_LIBS) $(DBUS_LIBS) -lreadline
> diff --git a/client/ccp_test.c b/client/ccp_test.c
> new file mode 100644
> index 000000000000..d53fc2393c13
> --- /dev/null
> +++ b/client/ccp_test.c
> @@ -0,0 +1,212 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2024  Intel Corporation. All rights reserved.
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include "gdbus/gdbus.h"
> +#include "lib/bluetooth.h"
> +#include "src/shared/shell.h"
> +#include "print.h"
> +#include "ccp_test.h"
> +
> +/* String display constants */
> +#define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
> +#define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
> +
> +#define BLUEZ_CCP_TEST_INTERFACE "org.bluez.CCPTest1"

We probably need to start with the documentation of
org.bluez.CPPTest1, there is quite a few documentation under
doc/org.bluez*.rst.

> +
> +static DBusConnection *dbus_conn;
> +static GDBusProxy *default_call;
> +static GList *callList;
> +static GDBusClient *client;
> +
> +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_info(void *data, void *user_data)
> +{
> +       GDBusProxy *proxy = data;
> +       const char *description = user_data;
> +       char *str;
> +
> +       str = proxy_description(proxy, "CCPTest", description);
> +
> +       bt_shell_printf("%s%s\n", str,
> +                       default_call == proxy ? "[default]" : "");
> +
> +       g_free(str);
> +}
> +
> +static void call_reject_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 reject call: %s\n", error.name);
> +               dbus_error_free(&error);
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       bt_shell_printf("operation completed\n");
> +
> +       return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +}
> +
> +static void cmd_reject(int argc, char *argv[])
> +{
> +       if (!default_call) {
> +               bt_shell_printf("No active calls present\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       if (g_dbus_proxy_method_call(default_call, "reject", NULL,
> +                                    call_reject_reply, NULL, NULL) == FALSE) {
> +               bt_shell_printf("Failed to reject call\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +}
> +
> +static void call_answer_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 answer call: %s\n", error.name);
> +               dbus_error_free(&error);
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       bt_shell_printf("operation completed\n");
> +
> +       return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +}
> +
> +static void cmd_answer(int argc, char *argv[])
> +{
> +       if (!default_call)
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +
> +       if (g_dbus_proxy_method_call(default_call, "answer", NULL,
> +                                    call_answer_reply, NULL, NULL) == FALSE) {
> +               bt_shell_printf("Failed to answer the call\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +}
> +
> +static const struct bt_shell_menu call_menu = {
> +       .name = "ccp test",

I'd call it just ccp otherwise you may break autocomplete support by
adding spaces in between, in case you don't know bluetoothctl does
accept entering commands in a submenu.command format (e.g.
cpp.answer).

> +       .desc = "ccp test settings submenu",
> +       .entries = {
> +                   { "answer", NULL, cmd_answer, "answer the active call" },
> +                   { "reject", NULL, cmd_reject, "reject the active call" },
> +                  },

I guess we will need to add something like as "[call]" as parameter if
the intention is handle multiple calls simultaneously which if I
recall correctly is possible with CCP, btw I add as well command such
as list, to list current call objects and perhap a show command as
well to inspect the objects, but that can be done at a later stage if
you prefer that way.

> +};
> +
> +static void ccp_add_call(GDBusProxy *proxy)
> +{
> +       bt_shell_printf("[CHG] CCP Test caller added\n");
> +       callList = g_list_append(callList, proxy);
> +
> +       if (!default_call)
> +               default_call = proxy;
> +
> +       print_info(proxy, COLORED_NEW);
> +}
> +
> +static void ccp_remove_call(GDBusProxy *proxy)
> +{
> +       bt_shell_printf("[CHG] CCP Test caller removed\n");
> +
> +       if (default_call == proxy)
> +               default_call = NULL;
> +
> +       callList = g_list_remove(callList, proxy);
> +}
> +
> +static void proxy_added(GDBusProxy *proxy, void *user_data)
> +{
> +       const char *interface;
> +
> +       interface = g_dbus_proxy_get_interface(proxy);
> +
> +       if (!strcmp(interface, BLUEZ_CCP_TEST_INTERFACE))
> +               ccp_add_call(proxy);
> +}
> +
> +static void proxy_removed(GDBusProxy *proxy, void *user_data)
> +{
> +       const char *interface;
> +
> +       interface = g_dbus_proxy_get_interface(proxy);
> +
> +       if (!strcmp(interface, BLUEZ_CCP_TEST_INTERFACE))
> +               ccp_remove_call(proxy);
> +}
> +
> +static void ccptest_property_changed(GDBusProxy *proxy, const char *name,
> +                                    DBusMessageIter *iter)
> +{
> +       char *str;
> +
> +       str = proxy_description(proxy, "CCP Test", COLORED_CHG);
> +       print_iter(str, name, iter);
> +       g_free(str);
> +
> +       bt_shell_printf("[CHG] CCP Test property : %s\n", name);
> +}
> +
> +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, BLUEZ_CCP_TEST_INTERFACE))
> +               ccptest_property_changed(proxy, name, iter);
> +}
> +
> +void ccptest_add_submenu(void)
> +{
> +       bt_shell_add_submenu(&call_menu);
> +
> +       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, NULL, NULL);
> +}
> +
> +void ccptest_remove_submenu(void)
> +{
> +       g_dbus_client_unref(client);
> +}
> diff --git a/client/ccp_test.h b/client/ccp_test.h
> new file mode 100644
> index 000000000000..fc2ab2042bb8
> --- /dev/null
> +++ b/client/ccp_test.h
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2024 Intel Corporation. All rights reserved.
> + *
> + *
> + */
> +
> +void ccptest_add_submenu(void);
> +void ccptest_remove_submenu(void);
> diff --git a/client/main.c b/client/main.c
> index c8b0f7f1c2d8..dba6dea639d9 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -34,6 +34,7 @@
>  #include "admin.h"
>  #include "player.h"
>  #include "mgmt.h"
> +#include "ccp_test.h"
>
>  /* String display constants */
>  #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
> @@ -3060,7 +3061,7 @@ static const struct bt_shell_menu gatt_menu = {
>                                         "Unregister application service" },
>         { "register-includes", "<UUID> [handle]", cmd_register_includes,
>                                         "Register as Included service in." },
> -       { "unregister-includes", "<Service-UUID> <Inc-UUID>",
> +       { "unregister-includes", "<Service-UUID><Inc-UUID>",
>                         cmd_unregister_includes,
>                                  "Unregister Included service." },
>         { "register-characteristic",
> @@ -3199,6 +3200,7 @@ int main(int argc, char *argv[])
>
>         admin_add_submenu();
>         player_add_submenu();
> +       ccptest_add_submenu();
>         mgmt_add_submenu();
>
>         client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
> @@ -3216,6 +3218,7 @@ int main(int argc, char *argv[])
>
>         admin_remove_submenu();
>         player_remove_submenu();
> +       ccptest_remove_submenu();
>         mgmt_remove_submenu();
>
>         g_dbus_client_unref(client);
> --
> 2.34.1
>
>


-- 
Luiz Augusto von Dentz





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux