2024-04-23 18:05:11

by Ajay KV

[permalink] [raw]
Subject: [PATCH v1] bluetoothctl: CCP client interface for bluetoothctl

Allows bluetoothctl to send CCP client call control
commands like answer/reject call
---
Makefile.plugins | 3 +-
Makefile.tools | 4 +-
client/main.c | 4 +-
client/telephony_client.c | 213 +++++++++++++++++++++++++++++++
client/telephony_client.h | 12 ++
profiles/audio/ccp.c | 150 ++++++++++++++++++----
profiles/audio/telephony.c | 173 ++++++++++++++++++++++++++
profiles/audio/telephony.h | 65 ++++++++++
src/shared/ccp.c | 249 +++++++++++++++++++++++--------------
src/shared/ccp.h | 19 ++-
10 files changed, 765 insertions(+), 127 deletions(-)
create mode 100644 client/telephony_client.c
create mode 100644 client/telephony_client.h
create mode 100644 profiles/audio/telephony.c
create mode 100644 profiles/audio/telephony.h

diff --git a/Makefile.plugins b/Makefile.plugins
index 4aa2c9c92854..7c0e0bb23560 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -46,7 +46,8 @@ builtin_modules += avrcp
builtin_sources += profiles/audio/control.h profiles/audio/control.c \
profiles/audio/avctp.h profiles/audio/avctp.c \
profiles/audio/avrcp.h profiles/audio/avrcp.c \
- profiles/audio/player.h profiles/audio/player.c
+ profiles/audio/player.h profiles/audio/player.c\
+ profiles/audio/telephony.c profiles/audio/telephony.h
endif

if NETWORK
diff --git a/Makefile.tools b/Makefile.tools
index 27a753762d1c..e21f6e8e478e 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/telephony_client.c \
+ client/telephony_client.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/main.c b/client/main.c
index 51d08a67aa1a..438c45bb9c24 100644
--- a/client/main.c
+++ b/client/main.c
@@ -34,7 +34,7 @@
#include "admin.h"
#include "player.h"
#include "mgmt.h"
-
+#include "telephony_client.h"
/* String display constants */
#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
@@ -3199,6 +3199,7 @@ int main(int argc, char *argv[])

admin_add_submenu();
player_add_submenu();
+ telephony_add_submenu();
mgmt_add_submenu();

client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
@@ -3216,6 +3217,7 @@ int main(int argc, char *argv[])

admin_remove_submenu();
player_remove_submenu();
+ telephony_remove_submenu();
mgmt_remove_submenu();

g_dbus_client_unref(client);
diff --git a/client/telephony_client.c b/client/telephony_client.c
new file mode 100644
index 000000000000..121255920dd0
--- /dev/null
+++ b/client/telephony_client.c
@@ -0,0 +1,213 @@
+// 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 "telephony_client.h"
+
+/* String display constants */
+#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
+
+#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"
+
+static DBusConnection *dbus_conn;
+static GDBusProxy *default_call = NULL;
+static GList *callList = NULL;
+static GDBusClient *client = NULL;
+
+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, "Telephony", 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 = "telephony",
+ .desc = "telephony Settings Submenu",
+ .entries = {
+ { "answer", NULL, cmd_answer, "answer the active call" },
+ { "reject", NULL, cmd_reject, "reject the active call" },
+ {} },
+};
+
+static void call_added(GDBusProxy *proxy)
+{
+ bt_shell_printf("[CHG] Telephony caller Added\n");
+ callList = g_list_append(callList, proxy);
+
+ if (!default_call)
+ default_call = proxy;
+
+ print_info(proxy, COLORED_NEW);
+}
+
+static void call_removed(GDBusProxy *proxy)
+{
+ bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
+ call_added(proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (!strcmp(interface, BLUEZ_TELEPHONY_INTERFACE))
+ call_removed(proxy);
+}
+
+static void telephony_property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter)
+{
+ char *str;
+
+ str = proxy_description(proxy, "Telephony", COLORED_CHG);
+ print_iter(str, name, iter);
+ g_free(str);
+
+ bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
+ telephony_property_changed(proxy, name, iter);
+}
+
+void telephony_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 telephony_remove_submenu(void)
+{
+ g_dbus_client_unref(client);
+}
diff --git a/client/telephony_client.h b/client/telephony_client.h
new file mode 100644
index 000000000000..15c73f0051e0
--- /dev/null
+++ b/client/telephony_client.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 telephony_add_submenu(void);
+void telephony_remove_submenu(void);
diff --git a/profiles/audio/ccp.c b/profiles/audio/ccp.c
index fe678de9fede..21f98cfbcfb7 100644
--- a/profiles/audio/ccp.c
+++ b/profiles/audio/ccp.c
@@ -40,7 +40,6 @@
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-client.h"
#include "src/shared/gatt-server.h"
-#include "src/shared/ccp.h"

#include "btio/btio.h"
#include "src/plugin.h"
@@ -51,6 +50,8 @@
#include "src/service.h"
#include "src/log.h"
#include "src/error.h"
+#include "src/shared/ccp.h"
+#include "telephony.h"

#define GTBS_UUID_STR "0000184C-0000-1000-8000-00805f9b34fb"

@@ -58,9 +59,132 @@ struct ccp_data {
struct btd_device *device;
struct btd_service *service;
struct bt_ccp *ccp;
- unsigned int state_id;
+ unsigned int call_state_id;
+ struct telephony_ctrl *tc;
};

+static int ct_call_answer(struct telephony_ctrl *tc, void *user_data)
+{
+ struct bt_ccp *ccp = user_data;
+
+ DBG(" status %d index %d", tc->call_status, tc->call_index);
+
+ if (tc->call_status == CALL_DISCONNECTED)
+ return -1;
+
+ return bt_ccp_call_answer(ccp, tc->call_index);
+}
+
+static int ct_call_reject(struct telephony_ctrl *tc, void *user_data)
+{
+ struct bt_ccp *ccp = user_data;
+
+ DBG(" status %d index %d", tc->call_status, tc->call_index);
+
+ if (tc->call_status == CALL_DISCONNECTED)
+ return -1;
+
+ return bt_ccp_call_reject(ccp, tc->call_index);
+}
+
+static const struct telephony_control_callback ct_cbs = {
+ .call_answer = &ct_call_answer,
+ .call_reject = &ct_call_reject,
+};
+
+static void cb_call_list_update(struct bt_ccp *ccp, const uint8_t *buf,
+ uint16_t length)
+{
+ struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
+ struct ccp_call_list_evt *evt;
+
+ DBG("");
+
+ if (length < sizeof(struct ccp_call_list_evt))
+ return;
+
+ evt = (struct ccp_call_list_evt *)buf;
+ tc->call_index = evt->index;
+ tc->call_status = evt->state;
+
+ DBG(" status %d index %d", tc->call_status, tc->call_index);
+
+ telephony_update_call_Info(tc);
+}
+
+static void cb_incoming_call(struct bt_ccp *ccp, const uint8_t *buf,
+ uint16_t length)
+{
+ struct ccp_incoming_call_evt *evt;
+ struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
+
+ DBG("");
+
+ if (length < sizeof(struct ccp_incoming_call_evt))
+ return;
+
+ evt = (struct ccp_incoming_call_evt *)buf;
+ tc->call_index = evt->index;
+ tc->call_status = INCOMING_CALL;
+
+ DBG(" status %d index %d", tc->call_status, tc->call_index);
+
+ telephony_update_call_Info(tc);
+}
+
+static void cb_terminate_call(struct bt_ccp *ccp, const uint8_t *buf,
+ uint16_t length)
+{
+ struct ccp_call_terminate_evt *evt;
+ struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
+
+ DBG("");
+
+ if (length < sizeof(struct ccp_call_terminate_evt))
+ return;
+
+ evt = (struct ccp_call_terminate_evt *)buf;
+ tc->call_index = evt->index;
+ tc->call_status = CALL_DISCONNECTED;
+
+ DBG(" status %d index %d", tc->call_status, tc->call_index);
+
+ telephony_update_call_Info(tc);
+}
+
+static const struct bt_ccp_event_callback cbs = {
+ .incoming_call = cb_incoming_call,
+ .terminate_call = cb_terminate_call,
+ .call_list_update = cb_call_list_update
+};
+
+static int ccp_accept(struct btd_service *service)
+{
+ struct btd_device *device = btd_service_get_device(service);
+ struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+ struct ccp_data *data = btd_service_get_user_data(service);
+ char addr[18];
+
+ ba2str(device_get_address(device), addr);
+ DBG("%s", addr);
+
+ bt_ccp_attach(data->ccp, client);
+
+ data->tc = telephony_create_device(device_get_path(device), 0);
+ if (!data->tc) {
+ DBG("Unable to create telephony device object");
+ data->tc = NULL;
+ return -EINVAL;
+ }
+
+ telephony_set_callbacks(data->tc, &ct_cbs, data->ccp);
+ bt_ccp_set_user_data(data->ccp, data->tc);
+ bt_ccp_set_event_callbacks(data->ccp, &cbs, data->tc);
+ btd_service_connecting_complete(service, 0);
+
+ return 0;
+}
+
static void ccp_debug(const char *str, void *user_data)
{
DBG_IDX(0xffff, "%s", str);
@@ -140,28 +264,6 @@ static void ccp_remove(struct btd_service *service)
ccp_data_remove(data);
}

-static int ccp_accept(struct btd_service *service)
-{
- struct btd_device *device = btd_service_get_device(service);
- struct bt_gatt_client *client = btd_device_get_gatt_client(device);
- struct ccp_data *data = btd_service_get_user_data(service);
- char addr[18];
-
- ba2str(device_get_address(device), addr);
- DBG("%s", addr);
-
- if (!bt_ccp_attach(data->ccp, client)) {
- error("CCP unable to attach");
- return -EINVAL;
- }
-
- /* TODO: register telephony operations here */
-
- btd_service_connecting_complete(service, 0);
-
- return 0;
-}
-
static int ccp_connect(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
diff --git a/profiles/audio/telephony.c b/profiles/audio/telephony.c
new file mode 100644
index 000000000000..68f27b5471cc
--- /dev/null
+++ b/profiles/audio/telephony.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2024 Intel Corporation
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include "gdbus/gdbus.h"
+
+#include "src/log.h"
+#include "src/dbus-common.h"
+#include "src/error.h"
+#include "telephony.h"
+
+#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"
+
+struct call_callback {
+ const struct telephony_control_callback *cbs;
+ void *user_data;
+};
+
+void telephony_update_call_Info(struct telephony_ctrl *tc)
+{
+ DBG("");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), tc->path,
+ BLUEZ_TELEPHONY_INTERFACE, "call_state");
+}
+
+static DBusMessage *telephony_answer_call(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct telephony_ctrl *tc = data;
+ struct call_callback *cb = tc->cb;
+ int err;
+
+ DBG("");
+ if (!cb->cbs->call_answer)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->call_answer(tc, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *telephony_reject_call(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct telephony_ctrl *tc = data;
+ struct call_callback *cb = tc->cb;
+ int err;
+
+ DBG("");
+
+ if (!cb->cbs->call_reject)
+ return btd_error_not_supported(msg);
+
+ err = cb->cbs->call_reject(tc, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static gboolean ccp_get_index(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct telephony_ctrl *tc = data;
+ uint32_t index = tc->call_index;
+
+ DBG("");
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &index);
+
+ return TRUE;
+}
+
+static const GDBusSignalTable telephony_signals[] = {
+};
+
+/* methods exposed to client to perform call operations */
+static const GDBusMethodTable telephony_methods[] = {
+ { GDBUS_METHOD("answer", NULL, NULL, telephony_answer_call) },
+ { GDBUS_METHOD("reject", NULL, NULL, telephony_reject_call) },
+ { }
+};
+
+/*
+ * Inform registered clients on property changed events
+ * use g_dbus_emit_property_changed() API
+ */
+static const GDBusPropertyTable telephony_properties[] = {
+ { "call_state", "u", ccp_get_index, NULL, NULL },
+ { }
+};
+
+void telephony_destroy_device(struct telephony_ctrl *tc)
+{
+ DBG("%s", tc->path);
+
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ tc->path, BLUEZ_TELEPHONY_INTERFACE);
+
+ if (tc->path)
+ g_free(tc->cb);
+ if (tc->path)
+ g_free(tc->path);
+ if (tc->device)
+ g_free(tc->device);
+
+ if (tc)
+ g_free(tc);
+}
+
+struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id)
+{
+ struct telephony_ctrl *tc;
+
+ DBG("");
+ tc = g_new0(struct telephony_ctrl, 1);
+ tc->device = g_strdup(path);
+ tc->path = g_strdup_printf("%s/Caller%u", path, id);
+
+ if (!g_dbus_register_interface(btd_get_dbus_connection(),
+ tc->path, BLUEZ_TELEPHONY_INTERFACE,
+ telephony_methods,
+ telephony_signals,
+ telephony_properties, tc, NULL)) {
+ error("D-Bus failed to register %s path", tc->path);
+ telephony_destroy_device(tc);
+ return NULL;
+ }
+
+ DBG("%s", tc->path);
+
+ return tc;
+}
+
+void telephony_set_callbacks(struct telephony_ctrl *tp,
+ const struct telephony_control_callback *cbs,
+ void *user_data)
+{
+ struct call_callback *cb;
+
+ DBG("");
+
+ if (tp->cb)
+ g_free(tp->cb);
+
+ cb = g_new0(struct call_callback, 1);
+ cb->cbs = cbs;
+ cb->user_data = user_data;
+
+ tp->cb = cb;
+}
diff --git a/profiles/audio/telephony.h b/profiles/audio/telephony.h
new file mode 100644
index 000000000000..e321fb881beb
--- /dev/null
+++ b/profiles/audio/telephony.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2024 Intel Corporation
+ *
+ */
+
+struct telephony_ctrl {
+ char *device; /* Device path */
+ char *path; /* Telephony object path */
+ char *status;
+ uint8_t call_status; /* call status of active call*/
+ uint8_t call_index; /* call index of active call */
+ struct call_callback *cb;
+};
+
+struct telephony_control_callback {
+ int (*call_answer)(struct telephony_ctrl *tc, void *user_data);
+ int (*call_reject)(struct telephony_ctrl *tc, void *user_data);
+};
+
+struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id);
+
+void telephony_set_callbacks(struct telephony_ctrl *tc,
+ const struct telephony_control_callback *cbs,
+ void *user_data);
+
+void telephony_destroy_device(struct telephony_ctrl *tc);
+
+void telephony_set_incom_call_settings(struct telephony_ctrl *tc,
+ const char *key, void *data, size_t len);
+void telephony_set_call_termination(struct telephony_ctrl *tc,
+ const char *key, void *data, size_t len);
+
+void telephony_update_call_Info(struct telephony_ctrl *tc);
+
+struct ccp_call_list_evt {
+ uint8_t length;
+ uint8_t index;
+ uint8_t state;
+ uint8_t flag;
+};
+
+struct ccp_incoming_call_evt {
+ uint8_t length;
+ uint8_t index;
+};
+
+struct ccp_call_terminate_evt {
+ uint8_t length;
+ uint8_t index;
+ uint8_t reason;
+};
+
+enum call_state {
+ INCOMING_CALL = 0,
+ DIALLING_CALL,
+ ALERTING_CALL,
+ ACTIVE_CALL,
+ LOCAL_HOLD,
+ REMOTE_HOLD,
+ CALL_DISCONNECTED = 10
+};
diff --git a/src/shared/ccp.c b/src/shared/ccp.c
index 8e1b0b58f93b..25bb39713a13 100644
--- a/src/shared/ccp.c
+++ b/src/shared/ccp.c
@@ -3,7 +3,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2022 Intel Corporation. All rights reserved.
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
*
*/

@@ -112,6 +112,55 @@ struct bt_ccs {
};

static struct queue *ccp_db;
+static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
+{
+ if (!ccp)
+ return NULL;
+
+ if (ccp->rdb->ccs)
+ return ccp->rdb->ccs;
+
+ ccp->rdb->ccs = new0(struct bt_ccs, 1);
+ ccp->rdb->ccs->mdb = ccp->rdb;
+
+ return ccp->rdb->ccs;
+}
+
+static unsigned int ccp_send(struct bt_ccp *ccp, uint8_t index,
+ uint8_t operation)
+{
+ int ret;
+ uint16_t handle;
+ uint8_t cmd[2];
+ struct bt_ccs *ccs = ccp_get_ccs(ccp);
+
+ cmd[0] = operation;
+ cmd[1] = index;
+
+ if (!ccp->client)
+ return -1;
+
+ if (!gatt_db_attribute_get_char_data(ccs->call_ctrl_point, NULL,
+ &handle, NULL, NULL, NULL))
+ return -1;
+
+ ret = bt_gatt_client_write_without_response(ccp->client, handle, false,
+ cmd, 2);
+ if (!ret)
+ return -1;
+
+ return 0;
+}
+
+unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index)
+{
+ return ccp_send(ccp, index, 0);
+}
+
+unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index)
+{
+ return ccp_send(ccp, index, 1);
+}

static void ccp_debug(struct bt_ccp *ccp, const char *format, ...)
{
@@ -429,20 +478,6 @@ static struct bt_ccs *ccs_new(struct gatt_db *db)
return ccs;
}

-static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
-{
- if (!ccp)
- return NULL;
-
- if (ccp->rdb->ccs)
- return ccp->rdb->ccs;
-
- ccp->rdb->ccs = new0(struct bt_ccs, 1);
- ccp->rdb->ccs->mdb = ccp->rdb;
-
- return ccp->rdb->ccs;
-}
-
static void ccp_pending_destroy(void *data)
{
struct bt_ccp_pending *pending = data;
@@ -503,6 +538,8 @@ static void ccp_cb_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

+ DBG(ccp, "");
+
if (att_ecode)
DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);

@@ -515,27 +552,41 @@ static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
/* TODO: generic handler for non-mandatory CCP notifications */
}

-static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
+static void ccp_tc_update_call_list(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t length)
{
- struct bt_ccp *ccp = user_data;
+ struct event_callback *cb = ccp->cb;

- if (att_ecode)
- DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
+ DBG(ccp, " ");
+
+ if (cb && cb->cbs && cb->cbs->call_list_update)
+ cb->cbs->call_list_update(ccp, value, length);
}

-static void ccp_cb_status_flag_notify(uint16_t value_handle,
- const uint8_t *value,
- uint16_t length, void *user_data)
+static void ccp_tc_handle_incoming_call(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t length)
{
- struct bt_ccp *ccp = user_data;
+ struct event_callback *cb = ccp->cb;

- DBG(ccp, "");
+ DBG(ccp, " ");

- if (!length)
- return;
+ if (cb && cb->cbs && cb->cbs->incoming_call)
+ cb->cbs->incoming_call(ccp, value, length);
}

-static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
+static void ccp_tc_handle_terminate_call(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t length)
+{
+ struct event_callback *cb = ccp->cb;
+
+ DBG(ccp, " ");
+
+ if (cb && cb->cbs && cb->cbs->terminate_call)
+ cb->cbs->terminate_call(ccp, value, length);
+}
+
+/* callback registered function */
+static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

@@ -543,20 +594,15 @@ static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_terminate_notify(uint16_t value_handle, const uint8_t *value,
- uint16_t length, void *user_data)
+static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

- DBG(ccp, "");
-
- if (!length)
- return;
-
- /* TODO: update call state in Local context */
+ if (att_ecode)
+ DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
+static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

@@ -566,21 +612,17 @@ static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_bearer_name_notify(uint16_t value_handle,
- const uint8_t *value,
- uint16_t length, void *user_data)
+static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

DBG(ccp, "");

- if (!length)
- return;
-
- /* TODO: update call details in Local context */
+ if (att_ecode)
+ DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
+static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

@@ -590,51 +632,52 @@ static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
- uint16_t length, void *user_data)
+static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
{
struct bt_ccp *ccp = user_data;

DBG(ccp, "");

- if (!length)
- return;
-
- /* TODO: update call list in Local context */
+ if (att_ecode)
+ DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
}

-static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
+static void ccp_cb_status_flag_notify(uint16_t value_handle,
+ const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct bt_ccp *ccp = user_data;
+ DBG(ccp, "length %d", length);

- DBG(ccp, "");
-
- if (att_ecode)
- DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
+ if (!length)
+ return;
}

-static void ccp_cb_call_state_notify(uint16_t value_handle,
- const uint8_t *value,
- uint16_t length, void *user_data)
+static void ccp_cb_terminate_notify(uint16_t value_handle,
+ const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct bt_ccp *ccp = user_data;

- DBG(ccp, "");
+ DBG(ccp, "length %d", length);

if (!length)
return;

- /* TODO: update call state in Local context */
+ ccp_tc_handle_terminate_call(ccp, value, length);
}

-static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
+static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct bt_ccp *ccp = user_data;

- DBG(ccp, "");
+ DBG(ccp, "length %d", length);

- if (att_ecode)
- DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
+ if (!length)
+ return;
+
+ ccp_tc_update_call_list(ccp, value, length);
}

static void ccp_cb_incom_call_notify(uint16_t value_handle,
@@ -643,12 +686,12 @@ static void ccp_cb_incom_call_notify(uint16_t value_handle,
{
struct bt_ccp *ccp = user_data;

- DBG(ccp, "");
+ DBG(ccp, "length %d", length);

if (!length)
return;

- /* TODO: Handle incoming call notofiation, Answer/reject etc */
+ ccp_tc_handle_incoming_call(ccp, value, length);
}

static void bt_ccp_incom_call_attach(struct bt_ccp *ccp)
@@ -691,7 +734,7 @@ static void bt_ccp_call_state_attach(struct bt_ccp *ccp)
bt_gatt_client_register_notify(ccp->client,
value_handle,
ccp_cb_call_state_register,
- ccp_cb_call_state_notify, ccp,
+ NULL, ccp,
NULL);
}

@@ -735,7 +778,7 @@ static void bt_ccp_name_attach(struct bt_ccp *ccp)
bt_gatt_client_register_notify(ccp->client,
value_handle,
ccp_cb_bearer_name_register,
- ccp_cb_bearer_name_notify, ccp,
+ NULL, ccp,
NULL);
}

@@ -799,7 +842,7 @@ static void bt_ccp_uci_attach(struct bt_ccp *ccp)
ccp->bearer_uci_id = bt_gatt_client_register_notify(ccp->client,
value_handle,
ccp_cb_register,
- ccp_cb_notify, ccp,
+ NULL, ccp,
NULL);
}

@@ -820,7 +863,7 @@ static void bt_ccp_technology_attach(struct bt_ccp *ccp)
ccp->bearer_technology_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_strength_attach(struct bt_ccp *ccp)
@@ -839,7 +882,7 @@ static void bt_ccp_strength_attach(struct bt_ccp *ccp)

ccp->signal_strength_id =
bt_gatt_client_register_notify(ccp->client, value_handle,
- ccp_cb_register, ccp_cb_notify,
+ ccp_cb_register, NULL,
ccp, NULL);
}

@@ -859,7 +902,7 @@ static void bt_ccp_ccid_attach(struct bt_ccp *ccp)
ccp->ccid_id = bt_gatt_client_register_notify(ccp->client,
value_handle,
ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
@@ -879,7 +922,7 @@ static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
ccp->target_bearer_uri_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp,
+ NULL, ccp,
NULL);
}

@@ -900,7 +943,7 @@ static void bt_ccp_ctrl_point_attach(struct bt_ccp *ccp)
ccp->call_control_pt_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
@@ -920,7 +963,7 @@ static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
ccp->call_control_opt_opcode_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
@@ -940,7 +983,7 @@ static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
ccp->friendly_name_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
@@ -960,7 +1003,7 @@ static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
ccp->signal_reporting_intrvl_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
@@ -980,7 +1023,7 @@ static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
ccp->bearer_uri_schemes_list_id =
bt_gatt_client_register_notify(ccp->client,
value_handle, ccp_cb_register,
- ccp_cb_notify, ccp, NULL);
+ NULL, ccp, NULL);
}

static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
@@ -988,7 +1031,8 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
struct bt_ccp *ccp = user_data;
struct bt_ccs *ccs;
uint16_t value_handle;
- bt_uuid_t uuid;
+ bt_uuid_t uuid, uuid16;
+ uint16_t be16;

if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
NULL, NULL, &uuid))
@@ -998,105 +1042,122 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
if (!ccs || ccs->call_state)
return;

- if (bt_uuid16_cmp(&uuid, BEARER_PROVIDER_NAME_CHRC_UUID)) {
+ uuid16.type = uuid.type;
+
+ if (uuid.type == BT_UUID16) {
+ DBG(ccp, "uuid %x", uuid.value.u16);
+ uuid16.value.u16 = uuid.value.u16;
+ } else if (uuid.type == BT_UUID128) {
+ DBG(ccp, "uuid is u128 ");
+ uuid16.type = BT_UUID16;
+ memcpy(&be16, &uuid.value.u128.data[2], 2);
+ uuid16.value.u16 = htons(be16);
+ } else {
+ DBG(ccp, "unexpected uuid type %d", uuid16.type);
+ return;
+ }
+
+ DBG(ccp, "uuid read from gatt database %x", uuid16.value.u16);
+
+ if (bt_uuid16_cmp(&uuid16, BEARER_PROVIDER_NAME_CHRC_UUID)) {
DBG(ccp, "Found Bearer Name, handle 0x%04x", value_handle);

ccs->bearer_name = attr;
bt_ccp_name_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_UCI_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_UCI_CHRC_UUID)) {
DBG(ccp, "Found Bearer Uci, handle 0x%04x", value_handle);

ccs->bearer_uci = attr;
bt_ccp_uci_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_TECH_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_TECH_CHRC_UUID)) {
DBG(ccp, "Found Bearer Technology, handle %x", value_handle);

ccs->bearer_technology = attr;
bt_ccp_technology_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_STR_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_STR_CHRC_UUID)) {
DBG(ccp, "Found Signal Strength, handle 0x%04x", value_handle);

ccs->signal_strength = attr;
bt_ccp_strength_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
DBG(ccp, "Found Signal Interval, handle 0x%04x", value_handle);

ccs->signal_reporting_intrvl = attr;
bt_ccp_signal_intrvl_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, CALL_STATUS_FLAG_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, CALL_STATUS_FLAG_CHRC_UUID)) {
DBG(ccp, "Found Status Flag, handle 0x%04x", value_handle);

ccs->status_flag = attr;
bt_ccp_status_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_URI_SCHEME_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_URI_SCHEME_CHRC_UUID)) {
DBG(ccp, "Found URI Scheme, handle 0x%04x", value_handle);

ccs->bearer_uri_schemes_list = attr;
bt_ccp_uri_list_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, CURR_CALL_LIST_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, CURR_CALL_LIST_CHRC_UUID)) {
DBG(ccp, "Found Call List, handle 0x%04x", value_handle);

ccs->current_call_list = attr;
bt_ccp_call_list_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, BEARER_CCID_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, BEARER_CCID_CHRC_UUID)) {
DBG(ccp, "Found CCID, handle 0x%04x", value_handle);

ccs->ccid = attr;
bt_ccp_ccid_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
DBG(ccp, "Found Bearer Uri, handle 0x%04x", value_handle);

ccs->target_bearer_uri = attr;
bt_ccp_tar_uri_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_CHRC_UUID)) {
DBG(ccp, "Found Control Point, handle 0x%04x", value_handle);

ccs->call_ctrl_point = attr;
bt_ccp_ctrl_point_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
DBG(ccp, "Found Control opcode, handle 0x%04x", value_handle);

ccs->call_ctrl_opt_opcode = attr;
bt_ccp_ctrl_opcode_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, TERMINATION_REASON_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, TERMINATION_REASON_CHRC_UUID)) {
DBG(ccp, "Found Termination Reason, handle %x", value_handle);

ccs->termination_reason = attr;
bt_ccp_term_reason_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, INCOMING_CALL_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, INCOMING_CALL_CHRC_UUID)) {
DBG(ccp, "Found Incoming call, handle 0x%04x", value_handle);

ccs->incoming_call = attr;
bt_ccp_incom_call_attach(ccp);
}

- if (bt_uuid16_cmp(&uuid, CALL_FRIENDLY_NAME_CHRC_UUID)) {
+ if (bt_uuid16_cmp(&uuid16, CALL_FRIENDLY_NAME_CHRC_UUID)) {
DBG(ccp, "Found Friendly name, handle 0x%04x", value_handle);

ccs->friendly_name = attr;
diff --git a/src/shared/ccp.h b/src/shared/ccp.h
index 28b8b034ece3..3298abe9014c 100644
--- a/src/shared/ccp.h
+++ b/src/shared/ccp.h
@@ -3,7 +3,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2020 Intel Corporation. All rights reserved.
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
*
*/

@@ -18,14 +18,18 @@ struct bt_ccp;
struct bt_ccp_db;
struct bt_ccp_session_info;

-typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
-typedef void (*bt_ccp_destroy_func_t)(void *user_data);
-
struct bt_ccp_event_callback {
- void (*call_state)(struct bt_ccp *ccp, const uint8_t *value,
- uint16_t length);
+ void (*incoming_call)(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t len);
+ void (*terminate_call)(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t len);
+ void (*call_list_update)(struct bt_ccp *ccp,
+ const uint8_t *value, uint16_t len);
};

+typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
+typedef void (*bt_ccp_destroy_func_t)(void *user_data);
+
void bt_ccp_set_event_callbacks(struct bt_ccp *ccp,
const struct bt_ccp_event_callback *cbs,
void *user_data);
@@ -43,3 +47,6 @@ void bt_ccp_unref(struct bt_ccp *ccp);

bool bt_ccp_set_user_data(struct bt_ccp *ccp, void *user_data);
void *bt_ccp_get_user_data(struct bt_ccp *ccp);
+
+unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index);
+unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index);
--
2.34.1



2024-04-23 18:52:22

by bluez.test.bot

[permalink] [raw]
Subject: RE: [v1] bluetoothctl: CCP client interface for bluetoothctl

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=847132

---Test result---

Test Summary:
CheckPatch FAIL 1.41 seconds
GitLint PASS 0.32 seconds
BuildEll PASS 24.62 seconds
BluezMake FAIL 19.43 seconds
MakeCheck FAIL 36.99 seconds
MakeDistcheck PASS 177.53 seconds
CheckValgrind FAIL 16.26 seconds
CheckSmatch FAIL 24.48 seconds
bluezmakeextell FAIL 14.41 seconds
IncrementalBuild FAIL 19.79 seconds
ScanBuild FAIL 537.60 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v1] bluetoothctl: CCP client interface for bluetoothctl
ERROR:INITIALISED_STATIC: do not initialise statics to NULL
#188: FILE: client/telephony_client.c:30:
+static GDBusProxy *default_call = NULL;

ERROR:INITIALISED_STATIC: do not initialise statics to NULL
#189: FILE: client/telephony_client.c:31:
+static GList *callList = NULL;

ERROR:INITIALISED_STATIC: do not initialise statics to NULL
#190: FILE: client/telephony_client.c:32:
+static GDBusClient *client = NULL;

/github/workspace/src/src/13640519.patch total: 3 errors, 0 warnings, 1238 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13640519.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:

src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4660: all] Error 2
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:

src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8402: src/shared/libshared_glib_la-ccp.lo] Error 1
make: *** [Makefile:12216: check] Error 2
##############################
Test: CheckValgrind - FAIL
Desc: Run Bluez Make Check with Valgrind
Output:

src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:12216: check] Error 2
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:830:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1323:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1354:23: warning: Variable length array is used.
src/shared/gatt-server.c:278:25: warning: Variable length array is used.
src/shared/gatt-server.c:621:25: warning: Variable length array is used.
src/shared/gatt-server.c:720:25: warning: Variable length array is used.
src/shared/bap.c:282:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4660: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:

src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4660: all] Error 2
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:
[v1] bluetoothctl: CCP client interface for bluetoothctl

src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4660: all] Error 2
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:

src/shared/gatt-client.c:451:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:696:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:996:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1102:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1294:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1359:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1634:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1639:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2143:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2151:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3240:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3262:2: warning: Use of memory after it is freed
request_unref(req);
^~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/ccp.c:549:13: error: ‘ccp_cb_notify’ defined but not used [-Werror=unused-function]
549 | static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8640: src/shared/libshared_mainloop_la-ccp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4660: all] Error 2


---
Regards,
Linux Bluetooth

2024-04-23 20:07:55

by Paul Menzel

[permalink] [raw]
Subject: Re: [PATCH v1] bluetoothctl: CCP client interface for bluetoothctl

Dear Ajay,


Thank you for your patch.

I believe you should add BlueZ to the tag. It’d be also great if you
made the commit message summary a statement by adding a verb in
imperative mood. (The second bluetoothctl is also redundant.) Maybe:

bluetoothctl: Add CCP clien interface

Am 24.04.24 um 01:26 schrieb Ajay KV:
> Allows bluetoothctl to send CCP client call control
> commands like answer/reject call

For such a big diff, it’d be great if you elaborated. Where can the
specification be found? What is CCP, and give some example commands, and
state how you tested it.

> ---
> Makefile.plugins | 3 +-
> Makefile.tools | 4 +-
> client/main.c | 4 +-
> client/telephony_client.c | 213 +++++++++++++++++++++++++++++++
> client/telephony_client.h | 12 ++
> profiles/audio/ccp.c | 150 ++++++++++++++++++----
> profiles/audio/telephony.c | 173 ++++++++++++++++++++++++++
> profiles/audio/telephony.h | 65 ++++++++++
> src/shared/ccp.c | 249 +++++++++++++++++++++++--------------
> src/shared/ccp.h | 19 ++-
> 10 files changed, 765 insertions(+), 127 deletions(-)
> create mode 100644 client/telephony_client.c
> create mode 100644 client/telephony_client.h
> create mode 100644 profiles/audio/telephony.c
> create mode 100644 profiles/audio/telephony.h
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index 4aa2c9c92854..7c0e0bb23560 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -46,7 +46,8 @@ builtin_modules += avrcp
> builtin_sources += profiles/audio/control.h profiles/audio/control.c \
> profiles/audio/avctp.h profiles/audio/avctp.c \
> profiles/audio/avrcp.h profiles/audio/avrcp.c \
> - profiles/audio/player.h profiles/audio/player.c
> + profiles/audio/player.h profiles/audio/player.c\
> + profiles/audio/telephony.c profiles/audio/telephony.h
> endif
>
> if NETWORK
> diff --git a/Makefile.tools b/Makefile.tools
> index 27a753762d1c..e21f6e8e478e 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/telephony_client.c \
> + client/telephony_client.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/main.c b/client/main.c
> index 51d08a67aa1a..438c45bb9c24 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -34,7 +34,7 @@
> #include "admin.h"
> #include "player.h"
> #include "mgmt.h"
> -
> +#include "telephony_client.h"

Shoudl the blank line stay?

> /* String display constants */
> #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
> #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
> @@ -3199,6 +3199,7 @@ int main(int argc, char *argv[])
>
> admin_add_submenu();
> player_add_submenu();
> + telephony_add_submenu();
> mgmt_add_submenu();
>
> client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
> @@ -3216,6 +3217,7 @@ int main(int argc, char *argv[])
>
> admin_remove_submenu();
> player_remove_submenu();
> + telephony_remove_submenu();
> mgmt_remove_submenu();
>
> g_dbus_client_unref(client);
> diff --git a/client/telephony_client.c b/client/telephony_client.c
> new file mode 100644
> index 000000000000..121255920dd0
> --- /dev/null
> +++ b/client/telephony_client.c
> @@ -0,0 +1,213 @@
> +// 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 "telephony_client.h"
> +
> +/* String display constants */
> +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
> +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
> +
> +#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"
> +
> +static DBusConnection *dbus_conn;
> +static GDBusProxy *default_call = NULL;
> +static GList *callList = NULL;
> +static GDBusClient *client = NULL;
> +
> +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, "Telephony", 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 = "telephony",
> + .desc = "telephony Settings Submenu",
> + .entries = {
> + { "answer", NULL, cmd_answer, "answer the active call" },
> + { "reject", NULL, cmd_reject, "reject the active call" },

Should the elements be indented?

> + {} },
> +};
> +
> +static void call_added(GDBusProxy *proxy)

Why not `ccp_add_call()` or `add_call()`?

> +{
> + bt_shell_printf("[CHG] Telephony caller Added\n");

Lowercase: added. (Also below.)

> + callList = g_list_append(callList, proxy);
> +
> + if (!default_call)
> + default_call = proxy;
> +
> + print_info(proxy, COLORED_NEW);
> +}
> +
> +static void call_removed(GDBusProxy *proxy)
> +{
> + bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
> + call_added(proxy);
> +}
> +
> +static void proxy_removed(GDBusProxy *proxy, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, BLUEZ_TELEPHONY_INTERFACE))
> + call_removed(proxy);
> +}
> +
> +static void telephony_property_changed(GDBusProxy *proxy, const char *name,
> + DBusMessageIter *iter)
> +{
> + char *str;
> +
> + str = proxy_description(proxy, "Telephony", COLORED_CHG);
> + print_iter(str, name, iter);
> + g_free(str);
> +
> + bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
> + telephony_property_changed(proxy, name, iter);
> +}
> +
> +void telephony_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 telephony_remove_submenu(void)
> +{
> + g_dbus_client_unref(client);
> +}
> diff --git a/client/telephony_client.h b/client/telephony_client.h
> new file mode 100644
> index 000000000000..15c73f0051e0
> --- /dev/null
> +++ b/client/telephony_client.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 telephony_add_submenu(void);
> +void telephony_remove_submenu(void);
> diff --git a/profiles/audio/ccp.c b/profiles/audio/ccp.c
> index fe678de9fede..21f98cfbcfb7 100644
> --- a/profiles/audio/ccp.c
> +++ b/profiles/audio/ccp.c
> @@ -40,7 +40,6 @@
> #include "src/shared/gatt-db.h"
> #include "src/shared/gatt-client.h"
> #include "src/shared/gatt-server.h"
> -#include "src/shared/ccp.h"
>
> #include "btio/btio.h"
> #include "src/plugin.h"
> @@ -51,6 +50,8 @@
> #include "src/service.h"
> #include "src/log.h"
> #include "src/error.h"
> +#include "src/shared/ccp.h"
> +#include "telephony.h"
>
> #define GTBS_UUID_STR "0000184C-0000-1000-8000-00805f9b34fb"
>
> @@ -58,9 +59,132 @@ struct ccp_data {
> struct btd_device *device;
> struct btd_service *service;
> struct bt_ccp *ccp;
> - unsigned int state_id;
> + unsigned int call_state_id;
> + struct telephony_ctrl *tc;
> };
>
> +static int ct_call_answer(struct telephony_ctrl *tc, void *user_data)

What does ct mean?

> +{
> + struct bt_ccp *ccp = user_data;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + if (tc->call_status == CALL_DISCONNECTED)
> + return -1;
> +
> + return bt_ccp_call_answer(ccp, tc->call_index);
> +}
> +
> +static int ct_call_reject(struct telephony_ctrl *tc, void *user_data)
> +{
> + struct bt_ccp *ccp = user_data;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + if (tc->call_status == CALL_DISCONNECTED)
> + return -1;
> +
> + return bt_ccp_call_reject(ccp, tc->call_index);
> +}
> +
> +static const struct telephony_control_callback ct_cbs = {
> + .call_answer = &ct_call_answer,
> + .call_reject = &ct_call_reject,
> +};
> +
> +static void cb_call_list_update(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> + struct ccp_call_list_evt *evt;
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_call_list_evt))
> + return;
> +
> + evt = (struct ccp_call_list_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = evt->state;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static void cb_incoming_call(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct ccp_incoming_call_evt *evt;
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_incoming_call_evt))
> + return;
> +
> + evt = (struct ccp_incoming_call_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = INCOMING_CALL;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static void cb_terminate_call(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct ccp_call_terminate_evt *evt;
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_call_terminate_evt))
> + return;
> +
> + evt = (struct ccp_call_terminate_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = CALL_DISCONNECTED;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static const struct bt_ccp_event_callback cbs = {
> + .incoming_call = cb_incoming_call,
> + .terminate_call = cb_terminate_call,
> + .call_list_update = cb_call_list_update
> +};
> +
> +static int ccp_accept(struct btd_service *service)
> +{
> + struct btd_device *device = btd_service_get_device(service);
> + struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> + struct ccp_data *data = btd_service_get_user_data(service);
> + char addr[18];
> +
> + ba2str(device_get_address(device), addr);
> + DBG("%s", addr);
> +
> + bt_ccp_attach(data->ccp, client);
> +
> + data->tc = telephony_create_device(device_get_path(device), 0);
> + if (!data->tc) {
> + DBG("Unable to create telephony device object");
> + data->tc = NULL;
> + return -EINVAL;
> + }
> +
> + telephony_set_callbacks(data->tc, &ct_cbs, data->ccp);
> + bt_ccp_set_user_data(data->ccp, data->tc);
> + bt_ccp_set_event_callbacks(data->ccp, &cbs, data->tc);
> + btd_service_connecting_complete(service, 0);
> +
> + return 0;
> +}
> +
> static void ccp_debug(const char *str, void *user_data)
> {
> DBG_IDX(0xffff, "%s", str);
> @@ -140,28 +264,6 @@ static void ccp_remove(struct btd_service *service)
> ccp_data_remove(data);
> }
>
> -static int ccp_accept(struct btd_service *service)
> -{
> - struct btd_device *device = btd_service_get_device(service);
> - struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> - struct ccp_data *data = btd_service_get_user_data(service);
> - char addr[18];
> -
> - ba2str(device_get_address(device), addr);
> - DBG("%s", addr);
> -
> - if (!bt_ccp_attach(data->ccp, client)) {
> - error("CCP unable to attach");
> - return -EINVAL;
> - }
> -
> - /* TODO: register telephony operations here */
> -
> - btd_service_connecting_complete(service, 0);
> -
> - return 0;
> -}
> -
> static int ccp_connect(struct btd_service *service)
> {
> struct btd_device *device = btd_service_get_device(service);
> diff --git a/profiles/audio/telephony.c b/profiles/audio/telephony.c
> new file mode 100644
> index 000000000000..68f27b5471cc
> --- /dev/null
> +++ b/profiles/audio/telephony.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2024 Intel Corporation
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <glib.h>
> +#include <dbus/dbus.h>
> +#include "gdbus/gdbus.h"
> +
> +#include "src/log.h"
> +#include "src/dbus-common.h"
> +#include "src/error.h"
> +#include "telephony.h"
> +
> +#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"
> +
> +struct call_callback {
> + const struct telephony_control_callback *cbs;
> + void *user_data;
> +};
> +
> +void telephony_update_call_Info(struct telephony_ctrl *tc)
> +{
> + DBG("");
> + g_dbus_emit_property_changed(btd_get_dbus_connection(), tc->path,
> + BLUEZ_TELEPHONY_INTERFACE, "call_state");
> +}
> +
> +static DBusMessage *telephony_answer_call(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + struct call_callback *cb = tc->cb;
> + int err;
> +
> + DBG("");
> + if (!cb->cbs->call_answer)
> + return btd_error_not_supported(msg);
> +
> + err = cb->cbs->call_answer(tc, cb->user_data);
> + if (err < 0)
> + return btd_error_failed(msg, strerror(-err));
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static DBusMessage *telephony_reject_call(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + struct call_callback *cb = tc->cb;
> + int err;
> +
> + DBG("");
> +
> + if (!cb->cbs->call_reject)
> + return btd_error_not_supported(msg);
> +
> + err = cb->cbs->call_reject(tc, cb->user_data);
> + if (err < 0)
> + return btd_error_failed(msg, strerror(-err));
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static gboolean ccp_get_index(const GDBusPropertyTable *property,
> + DBusMessageIter *iter, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + uint32_t index = tc->call_index;
> +
> + DBG("");
> +
> + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &index);
> +
> + return TRUE;
> +}
> +
> +static const GDBusSignalTable telephony_signals[] = {
> +};
> +
> +/* methods exposed to client to perform call operations */
> +static const GDBusMethodTable telephony_methods[] = {
> + { GDBUS_METHOD("answer", NULL, NULL, telephony_answer_call) },
> + { GDBUS_METHOD("reject", NULL, NULL, telephony_reject_call) },
> + { }
> +};
> +
> +/*
> + * Inform registered clients on property changed events
> + * use g_dbus_emit_property_changed() API
> + */
> +static const GDBusPropertyTable telephony_properties[] = {
> + { "call_state", "u", ccp_get_index, NULL, NULL },
> + { }
> +};
> +
> +void telephony_destroy_device(struct telephony_ctrl *tc)
> +{
> + DBG("%s", tc->path);
> +
> + g_dbus_unregister_interface(btd_get_dbus_connection(),
> + tc->path, BLUEZ_TELEPHONY_INTERFACE);
> +
> + if (tc->path)
> + g_free(tc->cb);
> + if (tc->path)
> + g_free(tc->path);
> + if (tc->device)
> + g_free(tc->device);
> +
> + if (tc)
> + g_free(tc);
> +}
> +
> +struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id)
> +{
> + struct telephony_ctrl *tc;
> +
> + DBG("");
> + tc = g_new0(struct telephony_ctrl, 1);
> + tc->device = g_strdup(path);
> + tc->path = g_strdup_printf("%s/Caller%u", path, id);
> +
> + if (!g_dbus_register_interface(btd_get_dbus_connection(),
> + tc->path, BLUEZ_TELEPHONY_INTERFACE,
> + telephony_methods,
> + telephony_signals,
> + telephony_properties, tc, NULL)) {
> + error("D-Bus failed to register %s path", tc->path);
> + telephony_destroy_device(tc);
> + return NULL;
> + }
> +
> + DBG("%s", tc->path);
> +
> + return tc;
> +}
> +
> +void telephony_set_callbacks(struct telephony_ctrl *tp,
> + const struct telephony_control_callback *cbs,
> + void *user_data)
> +{
> + struct call_callback *cb;
> +
> + DBG("");
> +
> + if (tp->cb)
> + g_free(tp->cb);
> +
> + cb = g_new0(struct call_callback, 1);
> + cb->cbs = cbs;
> + cb->user_data = user_data;
> +
> + tp->cb = cb;
> +}
> diff --git a/profiles/audio/telephony.h b/profiles/audio/telephony.h
> new file mode 100644
> index 000000000000..e321fb881beb
> --- /dev/null
> +++ b/profiles/audio/telephony.h
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2024 Intel Corporation
> + *
> + */
> +
> +struct telephony_ctrl {
> + char *device; /* Device path */
> + char *path; /* Telephony object path */
> + char *status;
> + uint8_t call_status; /* call status of active call*/
> + uint8_t call_index; /* call index of active call */
> + struct call_callback *cb;
> +};
> +
> +struct telephony_control_callback {
> + int (*call_answer)(struct telephony_ctrl *tc, void *user_data);
> + int (*call_reject)(struct telephony_ctrl *tc, void *user_data);
> +};
> +
> +struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id);
> +
> +void telephony_set_callbacks(struct telephony_ctrl *tc,
> + const struct telephony_control_callback *cbs,
> + void *user_data);
> +
> +void telephony_destroy_device(struct telephony_ctrl *tc);
> +
> +void telephony_set_incom_call_settings(struct telephony_ctrl *tc,
> + const char *key, void *data, size_t len);
> +void telephony_set_call_termination(struct telephony_ctrl *tc,
> + const char *key, void *data, size_t len);
> +
> +void telephony_update_call_Info(struct telephony_ctrl *tc);
> +
> +struct ccp_call_list_evt {
> + uint8_t length;
> + uint8_t index;
> + uint8_t state;
> + uint8_t flag;
> +};
> +
> +struct ccp_incoming_call_evt {
> + uint8_t length;
> + uint8_t index;
> +};
> +
> +struct ccp_call_terminate_evt {
> + uint8_t length;
> + uint8_t index;
> + uint8_t reason;
> +};
> +
> +enum call_state {
> + INCOMING_CALL = 0,
> + DIALLING_CALL,
> + ALERTING_CALL,
> + ACTIVE_CALL,
> + LOCAL_HOLD,
> + REMOTE_HOLD,
> + CALL_DISCONNECTED = 10
> +};
> diff --git a/src/shared/ccp.c b/src/shared/ccp.c
> index 8e1b0b58f93b..25bb39713a13 100644
> --- a/src/shared/ccp.c
> +++ b/src/shared/ccp.c
> @@ -3,7 +3,7 @@
> *
> * BlueZ - Bluetooth protocol stack for Linux
> *
> - * Copyright (C) 2022 Intel Corporation. All rights reserved.
> + * Copyright (C) 2023 Intel Corporation. All rights reserved.
> *
> */
>
> @@ -112,6 +112,55 @@ struct bt_ccs {
> };
>
> static struct queue *ccp_db;
> +static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
> +{
> + if (!ccp)
> + return NULL;
> +
> + if (ccp->rdb->ccs)
> + return ccp->rdb->ccs;
> +
> + ccp->rdb->ccs = new0(struct bt_ccs, 1);
> + ccp->rdb->ccs->mdb = ccp->rdb;
> +
> + return ccp->rdb->ccs;
> +}
> +
> +static unsigned int ccp_send(struct bt_ccp *ccp, uint8_t index,
> + uint8_t operation)
> +{
> + int ret;
> + uint16_t handle;
> + uint8_t cmd[2];
> + struct bt_ccs *ccs = ccp_get_ccs(ccp);
> +
> + cmd[0] = operation;
> + cmd[1] = index;
> +
> + if (!ccp->client)
> + return -1;
> +
> + if (!gatt_db_attribute_get_char_data(ccs->call_ctrl_point, NULL,
> + &handle, NULL, NULL, NULL))
> + return -1;
> +
> + ret = bt_gatt_client_write_without_response(ccp->client, handle, false,
> + cmd, 2);
> + if (!ret)
> + return -1;
> +
> + return 0;
> +}
> +
> +unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index)
> +{
> + return ccp_send(ccp, index, 0);
> +}
> +
> +unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index)
> +{
> + return ccp_send(ccp, index, 1);
> +}
>
> static void ccp_debug(struct bt_ccp *ccp, const char *format, ...)
> {
> @@ -429,20 +478,6 @@ static struct bt_ccs *ccs_new(struct gatt_db *db)
> return ccs;
> }
>
> -static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
> -{
> - if (!ccp)
> - return NULL;
> -
> - if (ccp->rdb->ccs)
> - return ccp->rdb->ccs;
> -
> - ccp->rdb->ccs = new0(struct bt_ccs, 1);
> - ccp->rdb->ccs->mdb = ccp->rdb;
> -
> - return ccp->rdb->ccs;
> -}
> -
> static void ccp_pending_destroy(void *data)
> {
> struct bt_ccp_pending *pending = data;
> @@ -503,6 +538,8 @@ static void ccp_cb_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> + DBG(ccp, "");
> +
> if (att_ecode)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
>
> @@ -515,27 +552,41 @@ static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
> /* TODO: generic handler for non-mandatory CCP notifications */
> }
>
> -static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
> +static void ccp_tc_update_call_list(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> {
> - struct bt_ccp *ccp = user_data;
> + struct event_callback *cb = ccp->cb;
>
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + DBG(ccp, " ");
> +
> + if (cb && cb->cbs && cb->cbs->call_list_update)
> + cb->cbs->call_list_update(ccp, value, length);
> }
>
> -static void ccp_cb_status_flag_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_tc_handle_incoming_call(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> {
> - struct bt_ccp *ccp = user_data;
> + struct event_callback *cb = ccp->cb;
>
> - DBG(ccp, "");
> + DBG(ccp, " ");
>
> - if (!length)
> - return;
> + if (cb && cb->cbs && cb->cbs->incoming_call)
> + cb->cbs->incoming_call(ccp, value, length);
> }
>
> -static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> +static void ccp_tc_handle_terminate_call(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> +{
> + struct event_callback *cb = ccp->cb;
> +
> + DBG(ccp, " ");
> +
> + if (cb && cb->cbs && cb->cbs->terminate_call)
> + cb->cbs->terminate_call(ccp, value, length);
> +}
> +
> +/* callback registered function */
> +static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -543,20 +594,15 @@ static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_terminate_notify(uint16_t value_handle, const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> -
> - if (!length)
> - return;
> -
> - /* TODO: update call state in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -566,21 +612,17 @@ static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_bearer_name_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> DBG(ccp, "");
>
> - if (!length)
> - return;
> -
> - /* TODO: update call details in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -590,51 +632,52 @@ static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> DBG(ccp, "");
>
> - if (!length)
> - return;
> -
> - /* TODO: update call list in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_status_flag_notify(uint16_t value_handle,
> + const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
> + DBG(ccp, "length %d", length);
>
> - DBG(ccp, "");
> -
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + if (!length)
> + return;
> }
>
> -static void ccp_cb_call_state_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_terminate_notify(uint16_t value_handle,
> + const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> if (!length)
> return;
>
> - /* TODO: update call state in Local context */
> + ccp_tc_handle_terminate_call(ccp, value, length);
> }
>
> -static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + if (!length)
> + return;
> +
> + ccp_tc_update_call_list(ccp, value, length);
> }
>
> static void ccp_cb_incom_call_notify(uint16_t value_handle,
> @@ -643,12 +686,12 @@ static void ccp_cb_incom_call_notify(uint16_t value_handle,
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> if (!length)
> return;
>
> - /* TODO: Handle incoming call notofiation, Answer/reject etc */
> + ccp_tc_handle_incoming_call(ccp, value, length);
> }
>
> static void bt_ccp_incom_call_attach(struct bt_ccp *ccp)
> @@ -691,7 +734,7 @@ static void bt_ccp_call_state_attach(struct bt_ccp *ccp)
> bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_call_state_register,
> - ccp_cb_call_state_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -735,7 +778,7 @@ static void bt_ccp_name_attach(struct bt_ccp *ccp)
> bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_bearer_name_register,
> - ccp_cb_bearer_name_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -799,7 +842,7 @@ static void bt_ccp_uci_attach(struct bt_ccp *ccp)
> ccp->bearer_uci_id = bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_register,
> - ccp_cb_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -820,7 +863,7 @@ static void bt_ccp_technology_attach(struct bt_ccp *ccp)
> ccp->bearer_technology_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_strength_attach(struct bt_ccp *ccp)
> @@ -839,7 +882,7 @@ static void bt_ccp_strength_attach(struct bt_ccp *ccp)
>
> ccp->signal_strength_id =
> bt_gatt_client_register_notify(ccp->client, value_handle,
> - ccp_cb_register, ccp_cb_notify,
> + ccp_cb_register, NULL,
> ccp, NULL);
> }
>
> @@ -859,7 +902,7 @@ static void bt_ccp_ccid_attach(struct bt_ccp *ccp)
> ccp->ccid_id = bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
> @@ -879,7 +922,7 @@ static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
> ccp->target_bearer_uri_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -900,7 +943,7 @@ static void bt_ccp_ctrl_point_attach(struct bt_ccp *ccp)
> ccp->call_control_pt_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
> @@ -920,7 +963,7 @@ static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
> ccp->call_control_opt_opcode_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
> @@ -940,7 +983,7 @@ static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
> ccp->friendly_name_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
> @@ -960,7 +1003,7 @@ static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
> ccp->signal_reporting_intrvl_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
> @@ -980,7 +1023,7 @@ static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
> ccp->bearer_uri_schemes_list_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> @@ -988,7 +1031,8 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> struct bt_ccp *ccp = user_data;
> struct bt_ccs *ccs;
> uint16_t value_handle;
> - bt_uuid_t uuid;
> + bt_uuid_t uuid, uuid16;

Would be nice to make this a separate commit.


Kind regards,

Paul


> + uint16_t be16;
>
> if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
> NULL, NULL, &uuid))
> @@ -998,105 +1042,122 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> if (!ccs || ccs->call_state)
> return;
>
> - if (bt_uuid16_cmp(&uuid, BEARER_PROVIDER_NAME_CHRC_UUID)) {
> + uuid16.type = uuid.type;
> +
> + if (uuid.type == BT_UUID16) {
> + DBG(ccp, "uuid %x", uuid.value.u16);
> + uuid16.value.u16 = uuid.value.u16;
> + } else if (uuid.type == BT_UUID128) {
> + DBG(ccp, "uuid is u128 ");
> + uuid16.type = BT_UUID16;
> + memcpy(&be16, &uuid.value.u128.data[2], 2);
> + uuid16.value.u16 = htons(be16);
> + } else {
> + DBG(ccp, "unexpected uuid type %d", uuid16.type);
> + return;
> + }
> +
> + DBG(ccp, "uuid read from gatt database %x", uuid16.value.u16);
> +
> + if (bt_uuid16_cmp(&uuid16, BEARER_PROVIDER_NAME_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Name, handle 0x%04x", value_handle);
>
> ccs->bearer_name = attr;
> bt_ccp_name_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_UCI_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_UCI_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Uci, handle 0x%04x", value_handle);
>
> ccs->bearer_uci = attr;
> bt_ccp_uci_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_TECH_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_TECH_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Technology, handle %x", value_handle);
>
> ccs->bearer_technology = attr;
> bt_ccp_technology_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_STR_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_STR_CHRC_UUID)) {
> DBG(ccp, "Found Signal Strength, handle 0x%04x", value_handle);
>
> ccs->signal_strength = attr;
> bt_ccp_strength_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
> DBG(ccp, "Found Signal Interval, handle 0x%04x", value_handle);
>
> ccs->signal_reporting_intrvl = attr;
> bt_ccp_signal_intrvl_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_STATUS_FLAG_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_STATUS_FLAG_CHRC_UUID)) {
> DBG(ccp, "Found Status Flag, handle 0x%04x", value_handle);
>
> ccs->status_flag = attr;
> bt_ccp_status_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_URI_SCHEME_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_URI_SCHEME_CHRC_UUID)) {
> DBG(ccp, "Found URI Scheme, handle 0x%04x", value_handle);
>
> ccs->bearer_uri_schemes_list = attr;
> bt_ccp_uri_list_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CURR_CALL_LIST_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CURR_CALL_LIST_CHRC_UUID)) {
> DBG(ccp, "Found Call List, handle 0x%04x", value_handle);
>
> ccs->current_call_list = attr;
> bt_ccp_call_list_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_CCID_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_CCID_CHRC_UUID)) {
> DBG(ccp, "Found CCID, handle 0x%04x", value_handle);
>
> ccs->ccid = attr;
> bt_ccp_ccid_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Uri, handle 0x%04x", value_handle);
>
> ccs->target_bearer_uri = attr;
> bt_ccp_tar_uri_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_CHRC_UUID)) {
> DBG(ccp, "Found Control Point, handle 0x%04x", value_handle);
>
> ccs->call_ctrl_point = attr;
> bt_ccp_ctrl_point_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
> DBG(ccp, "Found Control opcode, handle 0x%04x", value_handle);
>
> ccs->call_ctrl_opt_opcode = attr;
> bt_ccp_ctrl_opcode_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, TERMINATION_REASON_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, TERMINATION_REASON_CHRC_UUID)) {
> DBG(ccp, "Found Termination Reason, handle %x", value_handle);
>
> ccs->termination_reason = attr;
> bt_ccp_term_reason_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, INCOMING_CALL_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, INCOMING_CALL_CHRC_UUID)) {
> DBG(ccp, "Found Incoming call, handle 0x%04x", value_handle);
>
> ccs->incoming_call = attr;
> bt_ccp_incom_call_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_FRIENDLY_NAME_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_FRIENDLY_NAME_CHRC_UUID)) {
> DBG(ccp, "Found Friendly name, handle 0x%04x", value_handle);
>
> ccs->friendly_name = attr;
> diff --git a/src/shared/ccp.h b/src/shared/ccp.h
> index 28b8b034ece3..3298abe9014c 100644
> --- a/src/shared/ccp.h
> +++ b/src/shared/ccp.h
> @@ -3,7 +3,7 @@
> *
> * BlueZ - Bluetooth protocol stack for Linux
> *
> - * Copyright (C) 2020 Intel Corporation. All rights reserved.
> + * Copyright (C) 2023 Intel Corporation. All rights reserved.
> *
> */
>
> @@ -18,14 +18,18 @@ struct bt_ccp;
> struct bt_ccp_db;
> struct bt_ccp_session_info;
>
> -typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
> -typedef void (*bt_ccp_destroy_func_t)(void *user_data);
> -
> struct bt_ccp_event_callback {
> - void (*call_state)(struct bt_ccp *ccp, const uint8_t *value,
> - uint16_t length);
> + void (*incoming_call)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> + void (*terminate_call)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> + void (*call_list_update)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> };
>
> +typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
> +typedef void (*bt_ccp_destroy_func_t)(void *user_data);
> +
> void bt_ccp_set_event_callbacks(struct bt_ccp *ccp,
> const struct bt_ccp_event_callback *cbs,
> void *user_data);
> @@ -43,3 +47,6 @@ void bt_ccp_unref(struct bt_ccp *ccp);
>
> bool bt_ccp_set_user_data(struct bt_ccp *ccp, void *user_data);
> void *bt_ccp_get_user_data(struct bt_ccp *ccp);
> +
> +unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index);
> +unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index);

2024-04-23 21:43:57

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v1] bluetoothctl: CCP client interface for bluetoothctl

Hi Ajay,

On Tue, Apr 23, 2024 at 2:04 PM Ajay KV <[email protected]> wrote:
>
> Allows bluetoothctl to send CCP client call control
> commands like answer/reject call
> ---
> Makefile.plugins | 3 +-
> Makefile.tools | 4 +-
> client/main.c | 4 +-
> client/telephony_client.c | 213 +++++++++++++++++++++++++++++++
> client/telephony_client.h | 12 ++
> profiles/audio/ccp.c | 150 ++++++++++++++++++----
> profiles/audio/telephony.c | 173 ++++++++++++++++++++++++++
> profiles/audio/telephony.h | 65 ++++++++++
> src/shared/ccp.c | 249 +++++++++++++++++++++++--------------
> src/shared/ccp.h | 19 ++-
> 10 files changed, 765 insertions(+), 127 deletions(-)
> create mode 100644 client/telephony_client.c
> create mode 100644 client/telephony_client.h
> create mode 100644 profiles/audio/telephony.c
> create mode 100644 profiles/audio/telephony.h
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index 4aa2c9c92854..7c0e0bb23560 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -46,7 +46,8 @@ builtin_modules += avrcp
> builtin_sources += profiles/audio/control.h profiles/audio/control.c \
> profiles/audio/avctp.h profiles/audio/avctp.c \
> profiles/audio/avrcp.h profiles/audio/avrcp.c \
> - profiles/audio/player.h profiles/audio/player.c
> + profiles/audio/player.h profiles/audio/player.c\
> + profiles/audio/telephony.c profiles/audio/telephony.h

It should be named ccp.c so we don't give the impression we are going
to write our own telefony stack, etc.

> endif
>
> if NETWORK
> diff --git a/Makefile.tools b/Makefile.tools
> index 27a753762d1c..e21f6e8e478e 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/telephony_client.c \
> + client/telephony_client.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/main.c b/client/main.c
> index 51d08a67aa1a..438c45bb9c24 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -34,7 +34,7 @@
> #include "admin.h"
> #include "player.h"
> #include "mgmt.h"
> -
> +#include "telephony_client.h"
> /* String display constants */
> #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
> #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
> @@ -3199,6 +3199,7 @@ int main(int argc, char *argv[])
>
> admin_add_submenu();
> player_add_submenu();
> + telephony_add_submenu();
> mgmt_add_submenu();
>
> client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
> @@ -3216,6 +3217,7 @@ int main(int argc, char *argv[])
>
> admin_remove_submenu();
> player_remove_submenu();
> + telephony_remove_submenu();
> mgmt_remove_submenu();
>
> g_dbus_client_unref(client);

Replace telephony term with ccp.

> diff --git a/client/telephony_client.c b/client/telephony_client.c
> new file mode 100644
> index 000000000000..121255920dd0
> --- /dev/null
> +++ b/client/telephony_client.c
> @@ -0,0 +1,213 @@
> +// 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 "telephony_client.h"
> +
> +/* String display constants */
> +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
> +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
> +
> +#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"
> +
> +static DBusConnection *dbus_conn;
> +static GDBusProxy *default_call = NULL;
> +static GList *callList = NULL;
> +static GDBusClient *client = NULL;
> +
> +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, "Telephony", 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 = "telephony",
> + .desc = "telephony Settings Submenu",
> + .entries = {
> + { "answer", NULL, cmd_answer, "answer the active call" },
> + { "reject", NULL, cmd_reject, "reject the active call" },
> + {} },
> +};
> +
> +static void call_added(GDBusProxy *proxy)
> +{
> + bt_shell_printf("[CHG] Telephony caller Added\n");
> + callList = g_list_append(callList, proxy);
> +
> + if (!default_call)
> + default_call = proxy;
> +
> + print_info(proxy, COLORED_NEW);
> +}
> +
> +static void call_removed(GDBusProxy *proxy)
> +{
> + bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
> + call_added(proxy);
> +}
> +
> +static void proxy_removed(GDBusProxy *proxy, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, BLUEZ_TELEPHONY_INTERFACE))
> + call_removed(proxy);
> +}
> +
> +static void telephony_property_changed(GDBusProxy *proxy, const char *name,
> + DBusMessageIter *iter)
> +{
> + char *str;
> +
> + str = proxy_description(proxy, "Telephony", COLORED_CHG);
> + print_iter(str, name, iter);
> + g_free(str);
> +
> + bt_shell_printf("[CHG] Telephony 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_TELEPHONY_INTERFACE))
> + telephony_property_changed(proxy, name, iter);
> +}
> +
> +void telephony_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 telephony_remove_submenu(void)
> +{
> + g_dbus_client_unref(client);
> +}
> diff --git a/client/telephony_client.h b/client/telephony_client.h
> new file mode 100644
> index 000000000000..15c73f0051e0
> --- /dev/null
> +++ b/client/telephony_client.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 telephony_add_submenu(void);
> +void telephony_remove_submenu(void);

client/ccp.c and client/ccp.h shall be made into its own set of patches.

> diff --git a/profiles/audio/ccp.c b/profiles/audio/ccp.c
> index fe678de9fede..21f98cfbcfb7 100644
> --- a/profiles/audio/ccp.c
> +++ b/profiles/audio/ccp.c
> @@ -40,7 +40,6 @@
> #include "src/shared/gatt-db.h"
> #include "src/shared/gatt-client.h"
> #include "src/shared/gatt-server.h"
> -#include "src/shared/ccp.h"
>
> #include "btio/btio.h"
> #include "src/plugin.h"
> @@ -51,6 +50,8 @@
> #include "src/service.h"
> #include "src/log.h"
> #include "src/error.h"
> +#include "src/shared/ccp.h"
> +#include "telephony.h"
>
> #define GTBS_UUID_STR "0000184C-0000-1000-8000-00805f9b34fb"
>
> @@ -58,9 +59,132 @@ struct ccp_data {
> struct btd_device *device;
> struct btd_service *service;
> struct bt_ccp *ccp;
> - unsigned int state_id;
> + unsigned int call_state_id;
> + struct telephony_ctrl *tc;
> };
>
> +static int ct_call_answer(struct telephony_ctrl *tc, void *user_data)
> +{
> + struct bt_ccp *ccp = user_data;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + if (tc->call_status == CALL_DISCONNECTED)
> + return -1;
> +
> + return bt_ccp_call_answer(ccp, tc->call_index);
> +}
> +
> +static int ct_call_reject(struct telephony_ctrl *tc, void *user_data)
> +{
> + struct bt_ccp *ccp = user_data;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + if (tc->call_status == CALL_DISCONNECTED)
> + return -1;
> +
> + return bt_ccp_call_reject(ccp, tc->call_index);
> +}
> +
> +static const struct telephony_control_callback ct_cbs = {
> + .call_answer = &ct_call_answer,
> + .call_reject = &ct_call_reject,
> +};
> +
> +static void cb_call_list_update(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> + struct ccp_call_list_evt *evt;
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_call_list_evt))
> + return;
> +
> + evt = (struct ccp_call_list_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = evt->state;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static void cb_incoming_call(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct ccp_incoming_call_evt *evt;
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_incoming_call_evt))
> + return;
> +
> + evt = (struct ccp_incoming_call_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = INCOMING_CALL;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static void cb_terminate_call(struct bt_ccp *ccp, const uint8_t *buf,
> + uint16_t length)
> +{
> + struct ccp_call_terminate_evt *evt;
> + struct telephony_ctrl *tc = bt_ccp_get_user_data(ccp);
> +
> + DBG("");
> +
> + if (length < sizeof(struct ccp_call_terminate_evt))
> + return;
> +
> + evt = (struct ccp_call_terminate_evt *)buf;
> + tc->call_index = evt->index;
> + tc->call_status = CALL_DISCONNECTED;
> +
> + DBG(" status %d index %d", tc->call_status, tc->call_index);
> +
> + telephony_update_call_Info(tc);
> +}
> +
> +static const struct bt_ccp_event_callback cbs = {
> + .incoming_call = cb_incoming_call,
> + .terminate_call = cb_terminate_call,
> + .call_list_update = cb_call_list_update
> +};
> +
> +static int ccp_accept(struct btd_service *service)
> +{
> + struct btd_device *device = btd_service_get_device(service);
> + struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> + struct ccp_data *data = btd_service_get_user_data(service);
> + char addr[18];
> +
> + ba2str(device_get_address(device), addr);
> + DBG("%s", addr);
> +
> + bt_ccp_attach(data->ccp, client);
> +
> + data->tc = telephony_create_device(device_get_path(device), 0);
> + if (!data->tc) {
> + DBG("Unable to create telephony device object");
> + data->tc = NULL;
> + return -EINVAL;
> + }
> +
> + telephony_set_callbacks(data->tc, &ct_cbs, data->ccp);
> + bt_ccp_set_user_data(data->ccp, data->tc);
> + bt_ccp_set_event_callbacks(data->ccp, &cbs, data->tc);
> + btd_service_connecting_complete(service, 0);
> +
> + return 0;
> +}
> +
> static void ccp_debug(const char *str, void *user_data)
> {
> DBG_IDX(0xffff, "%s", str);
> @@ -140,28 +264,6 @@ static void ccp_remove(struct btd_service *service)
> ccp_data_remove(data);
> }
>
> -static int ccp_accept(struct btd_service *service)
> -{
> - struct btd_device *device = btd_service_get_device(service);
> - struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> - struct ccp_data *data = btd_service_get_user_data(service);
> - char addr[18];
> -
> - ba2str(device_get_address(device), addr);
> - DBG("%s", addr);
> -
> - if (!bt_ccp_attach(data->ccp, client)) {
> - error("CCP unable to attach");
> - return -EINVAL;
> - }
> -
> - /* TODO: register telephony operations here */
> -
> - btd_service_connecting_complete(service, 0);
> -
> - return 0;
> -}
> -
> static int ccp_connect(struct btd_service *service)
> {
> struct btd_device *device = btd_service_get_device(service);
> diff --git a/profiles/audio/telephony.c b/profiles/audio/telephony.c
> new file mode 100644
> index 000000000000..68f27b5471cc
> --- /dev/null
> +++ b/profiles/audio/telephony.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2024 Intel Corporation
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <glib.h>
> +#include <dbus/dbus.h>
> +#include "gdbus/gdbus.h"
> +
> +#include "src/log.h"
> +#include "src/dbus-common.h"
> +#include "src/error.h"
> +#include "telephony.h"
> +
> +#define BLUEZ_TELEPHONY_INTERFACE "org.bluez.telephonyCtrl"

Don't thing we discussed about doing this sort of split of plugin just
to implement a D-Bus interface, don't see any reason for these changes
not to be part of ccp plugin, also the only reason for ccp plugin to
exist is probably to implement the D-Bus interface, which shall
document first under doc, and Id go with org.bluez.CCPTest1 as
interface and all properties and methods shall be marked as
experimental, in fact we may need a new tag for it since this
interface shall only be exposed when bluetoothd is set to something
like a test mode which can be used for validation purposes, and if
that is not enabled then the test interfaces shall not be enabled
either.

> +struct call_callback {
> + const struct telephony_control_callback *cbs;
> + void *user_data;
> +};
> +
> +void telephony_update_call_Info(struct telephony_ctrl *tc)
> +{
> + DBG("");
> + g_dbus_emit_property_changed(btd_get_dbus_connection(), tc->path,
> + BLUEZ_TELEPHONY_INTERFACE, "call_state");
> +}
> +
> +static DBusMessage *telephony_answer_call(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + struct call_callback *cb = tc->cb;
> + int err;
> +
> + DBG("");
> + if (!cb->cbs->call_answer)
> + return btd_error_not_supported(msg);
> +
> + err = cb->cbs->call_answer(tc, cb->user_data);
> + if (err < 0)
> + return btd_error_failed(msg, strerror(-err));
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static DBusMessage *telephony_reject_call(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + struct call_callback *cb = tc->cb;
> + int err;
> +
> + DBG("");
> +
> + if (!cb->cbs->call_reject)
> + return btd_error_not_supported(msg);
> +
> + err = cb->cbs->call_reject(tc, cb->user_data);
> + if (err < 0)
> + return btd_error_failed(msg, strerror(-err));
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static gboolean ccp_get_index(const GDBusPropertyTable *property,
> + DBusMessageIter *iter, void *data)
> +{
> + struct telephony_ctrl *tc = data;
> + uint32_t index = tc->call_index;
> +
> + DBG("");
> +
> + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &index);
> +
> + return TRUE;
> +}
> +
> +static const GDBusSignalTable telephony_signals[] = {
> +};
> +
> +/* methods exposed to client to perform call operations */
> +static const GDBusMethodTable telephony_methods[] = {
> + { GDBUS_METHOD("answer", NULL, NULL, telephony_answer_call) },
> + { GDBUS_METHOD("reject", NULL, NULL, telephony_reject_call) },
> + { }
> +};
> +
> +/*
> + * Inform registered clients on property changed events
> + * use g_dbus_emit_property_changed() API
> + */
> +static const GDBusPropertyTable telephony_properties[] = {
> + { "call_state", "u", ccp_get_index, NULL, NULL },
> + { }
> +};
> +
> +void telephony_destroy_device(struct telephony_ctrl *tc)
> +{
> + DBG("%s", tc->path);
> +
> + g_dbus_unregister_interface(btd_get_dbus_connection(),
> + tc->path, BLUEZ_TELEPHONY_INTERFACE);
> +
> + if (tc->path)
> + g_free(tc->cb);
> + if (tc->path)
> + g_free(tc->path);
> + if (tc->device)
> + g_free(tc->device);
> +
> + if (tc)
> + g_free(tc);
> +}
> +
> +struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id)
> +{
> + struct telephony_ctrl *tc;
> +
> + DBG("");
> + tc = g_new0(struct telephony_ctrl, 1);
> + tc->device = g_strdup(path);
> + tc->path = g_strdup_printf("%s/Caller%u", path, id);
> +
> + if (!g_dbus_register_interface(btd_get_dbus_connection(),
> + tc->path, BLUEZ_TELEPHONY_INTERFACE,
> + telephony_methods,
> + telephony_signals,
> + telephony_properties, tc, NULL)) {
> + error("D-Bus failed to register %s path", tc->path);
> + telephony_destroy_device(tc);
> + return NULL;
> + }
> +
> + DBG("%s", tc->path);
> +
> + return tc;
> +}
> +
> +void telephony_set_callbacks(struct telephony_ctrl *tp,
> + const struct telephony_control_callback *cbs,
> + void *user_data)
> +{
> + struct call_callback *cb;
> +
> + DBG("");
> +
> + if (tp->cb)
> + g_free(tp->cb);
> +
> + cb = g_new0(struct call_callback, 1);
> + cb->cbs = cbs;
> + cb->user_data = user_data;
> +
> + tp->cb = cb;
> +}
> diff --git a/profiles/audio/telephony.h b/profiles/audio/telephony.h
> new file mode 100644
> index 000000000000..e321fb881beb
> --- /dev/null
> +++ b/profiles/audio/telephony.h
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2024 Intel Corporation
> + *
> + */
> +
> +struct telephony_ctrl {
> + char *device; /* Device path */
> + char *path; /* Telephony object path */
> + char *status;
> + uint8_t call_status; /* call status of active call*/
> + uint8_t call_index; /* call index of active call */
> + struct call_callback *cb;
> +};
> +
> +struct telephony_control_callback {
> + int (*call_answer)(struct telephony_ctrl *tc, void *user_data);
> + int (*call_reject)(struct telephony_ctrl *tc, void *user_data);
> +};
> +
> +struct telephony_ctrl *telephony_create_device(const char *path, uint16_t id);
> +
> +void telephony_set_callbacks(struct telephony_ctrl *tc,
> + const struct telephony_control_callback *cbs,
> + void *user_data);
> +
> +void telephony_destroy_device(struct telephony_ctrl *tc);
> +
> +void telephony_set_incom_call_settings(struct telephony_ctrl *tc,
> + const char *key, void *data, size_t len);
> +void telephony_set_call_termination(struct telephony_ctrl *tc,
> + const char *key, void *data, size_t len);
> +
> +void telephony_update_call_Info(struct telephony_ctrl *tc);
> +
> +struct ccp_call_list_evt {
> + uint8_t length;
> + uint8_t index;
> + uint8_t state;
> + uint8_t flag;
> +};
> +
> +struct ccp_incoming_call_evt {
> + uint8_t length;
> + uint8_t index;
> +};
> +
> +struct ccp_call_terminate_evt {
> + uint8_t length;
> + uint8_t index;
> + uint8_t reason;
> +};
> +
> +enum call_state {
> + INCOMING_CALL = 0,
> + DIALLING_CALL,
> + ALERTING_CALL,
> + ACTIVE_CALL,
> + LOCAL_HOLD,
> + REMOTE_HOLD,
> + CALL_DISCONNECTED = 10
> +};

shared/ccp shall be on its own patch as well.

> diff --git a/src/shared/ccp.c b/src/shared/ccp.c
> index 8e1b0b58f93b..25bb39713a13 100644
> --- a/src/shared/ccp.c
> +++ b/src/shared/ccp.c
> @@ -3,7 +3,7 @@
> *
> * BlueZ - Bluetooth protocol stack for Linux
> *
> - * Copyright (C) 2022 Intel Corporation. All rights reserved.
> + * Copyright (C) 2023 Intel Corporation. All rights reserved.
> *
> */
>
> @@ -112,6 +112,55 @@ struct bt_ccs {
> };
>
> static struct queue *ccp_db;
> +static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
> +{
> + if (!ccp)
> + return NULL;
> +
> + if (ccp->rdb->ccs)
> + return ccp->rdb->ccs;
> +
> + ccp->rdb->ccs = new0(struct bt_ccs, 1);
> + ccp->rdb->ccs->mdb = ccp->rdb;
> +
> + return ccp->rdb->ccs;
> +}
> +
> +static unsigned int ccp_send(struct bt_ccp *ccp, uint8_t index,
> + uint8_t operation)
> +{
> + int ret;
> + uint16_t handle;
> + uint8_t cmd[2];
> + struct bt_ccs *ccs = ccp_get_ccs(ccp);
> +
> + cmd[0] = operation;
> + cmd[1] = index;
> +
> + if (!ccp->client)
> + return -1;
> +
> + if (!gatt_db_attribute_get_char_data(ccs->call_ctrl_point, NULL,
> + &handle, NULL, NULL, NULL))
> + return -1;
> +
> + ret = bt_gatt_client_write_without_response(ccp->client, handle, false,
> + cmd, 2);
> + if (!ret)
> + return -1;
> +
> + return 0;
> +}
> +
> +unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index)
> +{
> + return ccp_send(ccp, index, 0);
> +}
> +
> +unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index)
> +{
> + return ccp_send(ccp, index, 1);
> +}
>
> static void ccp_debug(struct bt_ccp *ccp, const char *format, ...)
> {
> @@ -429,20 +478,6 @@ static struct bt_ccs *ccs_new(struct gatt_db *db)
> return ccs;
> }
>
> -static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp)
> -{
> - if (!ccp)
> - return NULL;
> -
> - if (ccp->rdb->ccs)
> - return ccp->rdb->ccs;
> -
> - ccp->rdb->ccs = new0(struct bt_ccs, 1);
> - ccp->rdb->ccs->mdb = ccp->rdb;
> -
> - return ccp->rdb->ccs;
> -}
> -
> static void ccp_pending_destroy(void *data)
> {
> struct bt_ccp_pending *pending = data;
> @@ -503,6 +538,8 @@ static void ccp_cb_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> + DBG(ccp, "");
> +
> if (att_ecode)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
>
> @@ -515,27 +552,41 @@ static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value,
> /* TODO: generic handler for non-mandatory CCP notifications */
> }
>
> -static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
> +static void ccp_tc_update_call_list(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> {
> - struct bt_ccp *ccp = user_data;
> + struct event_callback *cb = ccp->cb;
>
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + DBG(ccp, " ");
> +
> + if (cb && cb->cbs && cb->cbs->call_list_update)
> + cb->cbs->call_list_update(ccp, value, length);
> }
>
> -static void ccp_cb_status_flag_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_tc_handle_incoming_call(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> {
> - struct bt_ccp *ccp = user_data;
> + struct event_callback *cb = ccp->cb;
>
> - DBG(ccp, "");
> + DBG(ccp, " ");
>
> - if (!length)
> - return;
> + if (cb && cb->cbs && cb->cbs->incoming_call)
> + cb->cbs->incoming_call(ccp, value, length);
> }
>
> -static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> +static void ccp_tc_handle_terminate_call(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t length)
> +{
> + struct event_callback *cb = ccp->cb;
> +
> + DBG(ccp, " ");
> +
> + if (cb && cb->cbs && cb->cbs->terminate_call)
> + cb->cbs->terminate_call(ccp, value, length);
> +}
> +
> +/* callback registered function */
> +static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -543,20 +594,15 @@ static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_terminate_notify(uint16_t value_handle, const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> -
> - if (!length)
> - return;
> -
> - /* TODO: update call state in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -566,21 +612,17 @@ static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_bearer_name_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> DBG(ccp, "");
>
> - if (!length)
> - return;
> -
> - /* TODO: update call details in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> @@ -590,51 +632,52 @@ static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data)
> DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> DBG(ccp, "");
>
> - if (!length)
> - return;
> -
> - /* TODO: update call list in Local context */
> + if (att_ecode)
> + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> }
>
> -static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_status_flag_notify(uint16_t value_handle,
> + const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
> + DBG(ccp, "length %d", length);
>
> - DBG(ccp, "");
> -
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + if (!length)
> + return;
> }
>
> -static void ccp_cb_call_state_notify(uint16_t value_handle,
> - const uint8_t *value,
> - uint16_t length, void *user_data)
> +static void ccp_cb_terminate_notify(uint16_t value_handle,
> + const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> if (!length)
> return;
>
> - /* TODO: update call state in Local context */
> + ccp_tc_handle_terminate_call(ccp, value, length);
> }
>
> -static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data)
> +static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value,
> + uint16_t length, void *user_data)
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> - if (att_ecode)
> - DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode);
> + if (!length)
> + return;
> +
> + ccp_tc_update_call_list(ccp, value, length);
> }
>
> static void ccp_cb_incom_call_notify(uint16_t value_handle,
> @@ -643,12 +686,12 @@ static void ccp_cb_incom_call_notify(uint16_t value_handle,
> {
> struct bt_ccp *ccp = user_data;
>
> - DBG(ccp, "");
> + DBG(ccp, "length %d", length);
>
> if (!length)
> return;
>
> - /* TODO: Handle incoming call notofiation, Answer/reject etc */
> + ccp_tc_handle_incoming_call(ccp, value, length);
> }
>
> static void bt_ccp_incom_call_attach(struct bt_ccp *ccp)
> @@ -691,7 +734,7 @@ static void bt_ccp_call_state_attach(struct bt_ccp *ccp)
> bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_call_state_register,
> - ccp_cb_call_state_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -735,7 +778,7 @@ static void bt_ccp_name_attach(struct bt_ccp *ccp)
> bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_bearer_name_register,
> - ccp_cb_bearer_name_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -799,7 +842,7 @@ static void bt_ccp_uci_attach(struct bt_ccp *ccp)
> ccp->bearer_uci_id = bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_register,
> - ccp_cb_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -820,7 +863,7 @@ static void bt_ccp_technology_attach(struct bt_ccp *ccp)
> ccp->bearer_technology_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_strength_attach(struct bt_ccp *ccp)
> @@ -839,7 +882,7 @@ static void bt_ccp_strength_attach(struct bt_ccp *ccp)
>
> ccp->signal_strength_id =
> bt_gatt_client_register_notify(ccp->client, value_handle,
> - ccp_cb_register, ccp_cb_notify,
> + ccp_cb_register, NULL,
> ccp, NULL);
> }
>
> @@ -859,7 +902,7 @@ static void bt_ccp_ccid_attach(struct bt_ccp *ccp)
> ccp->ccid_id = bt_gatt_client_register_notify(ccp->client,
> value_handle,
> ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
> @@ -879,7 +922,7 @@ static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp)
> ccp->target_bearer_uri_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp,
> + NULL, ccp,
> NULL);
> }
>
> @@ -900,7 +943,7 @@ static void bt_ccp_ctrl_point_attach(struct bt_ccp *ccp)
> ccp->call_control_pt_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
> @@ -920,7 +963,7 @@ static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp)
> ccp->call_control_opt_opcode_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
> @@ -940,7 +983,7 @@ static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp)
> ccp->friendly_name_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
> @@ -960,7 +1003,7 @@ static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp)
> ccp->signal_reporting_intrvl_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
> @@ -980,7 +1023,7 @@ static void bt_ccp_uri_list_attach(struct bt_ccp *ccp)
> ccp->bearer_uri_schemes_list_id =
> bt_gatt_client_register_notify(ccp->client,
> value_handle, ccp_cb_register,
> - ccp_cb_notify, ccp, NULL);
> + NULL, ccp, NULL);
> }
>
> static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> @@ -988,7 +1031,8 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> struct bt_ccp *ccp = user_data;
> struct bt_ccs *ccs;
> uint16_t value_handle;
> - bt_uuid_t uuid;
> + bt_uuid_t uuid, uuid16;
> + uint16_t be16;
>
> if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
> NULL, NULL, &uuid))
> @@ -998,105 +1042,122 @@ static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data)
> if (!ccs || ccs->call_state)
> return;
>
> - if (bt_uuid16_cmp(&uuid, BEARER_PROVIDER_NAME_CHRC_UUID)) {
> + uuid16.type = uuid.type;
> +
> + if (uuid.type == BT_UUID16) {
> + DBG(ccp, "uuid %x", uuid.value.u16);
> + uuid16.value.u16 = uuid.value.u16;
> + } else if (uuid.type == BT_UUID128) {
> + DBG(ccp, "uuid is u128 ");
> + uuid16.type = BT_UUID16;
> + memcpy(&be16, &uuid.value.u128.data[2], 2);
> + uuid16.value.u16 = htons(be16);
> + } else {
> + DBG(ccp, "unexpected uuid type %d", uuid16.type);
> + return;
> + }
> +
> + DBG(ccp, "uuid read from gatt database %x", uuid16.value.u16);
> +
> + if (bt_uuid16_cmp(&uuid16, BEARER_PROVIDER_NAME_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Name, handle 0x%04x", value_handle);
>
> ccs->bearer_name = attr;
> bt_ccp_name_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_UCI_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_UCI_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Uci, handle 0x%04x", value_handle);
>
> ccs->bearer_uci = attr;
> bt_ccp_uci_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_TECH_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_TECH_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Technology, handle %x", value_handle);
>
> ccs->bearer_technology = attr;
> bt_ccp_technology_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_STR_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_STR_CHRC_UUID)) {
> DBG(ccp, "Found Signal Strength, handle 0x%04x", value_handle);
>
> ccs->signal_strength = attr;
> bt_ccp_strength_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_SIGNAL_INTRVL_CHRC_UUID)) {
> DBG(ccp, "Found Signal Interval, handle 0x%04x", value_handle);
>
> ccs->signal_reporting_intrvl = attr;
> bt_ccp_signal_intrvl_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_STATUS_FLAG_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_STATUS_FLAG_CHRC_UUID)) {
> DBG(ccp, "Found Status Flag, handle 0x%04x", value_handle);
>
> ccs->status_flag = attr;
> bt_ccp_status_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_URI_SCHEME_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_URI_SCHEME_CHRC_UUID)) {
> DBG(ccp, "Found URI Scheme, handle 0x%04x", value_handle);
>
> ccs->bearer_uri_schemes_list = attr;
> bt_ccp_uri_list_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CURR_CALL_LIST_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CURR_CALL_LIST_CHRC_UUID)) {
> DBG(ccp, "Found Call List, handle 0x%04x", value_handle);
>
> ccs->current_call_list = attr;
> bt_ccp_call_list_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, BEARER_CCID_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, BEARER_CCID_CHRC_UUID)) {
> DBG(ccp, "Found CCID, handle 0x%04x", value_handle);
>
> ccs->ccid = attr;
> bt_ccp_ccid_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, INCOM_CALL_TARGET_URI_CHRC_UUID)) {
> DBG(ccp, "Found Bearer Uri, handle 0x%04x", value_handle);
>
> ccs->target_bearer_uri = attr;
> bt_ccp_tar_uri_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_CHRC_UUID)) {
> DBG(ccp, "Found Control Point, handle 0x%04x", value_handle);
>
> ccs->call_ctrl_point = attr;
> bt_ccp_ctrl_point_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) {
> DBG(ccp, "Found Control opcode, handle 0x%04x", value_handle);
>
> ccs->call_ctrl_opt_opcode = attr;
> bt_ccp_ctrl_opcode_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, TERMINATION_REASON_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, TERMINATION_REASON_CHRC_UUID)) {
> DBG(ccp, "Found Termination Reason, handle %x", value_handle);
>
> ccs->termination_reason = attr;
> bt_ccp_term_reason_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, INCOMING_CALL_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, INCOMING_CALL_CHRC_UUID)) {
> DBG(ccp, "Found Incoming call, handle 0x%04x", value_handle);
>
> ccs->incoming_call = attr;
> bt_ccp_incom_call_attach(ccp);
> }
>
> - if (bt_uuid16_cmp(&uuid, CALL_FRIENDLY_NAME_CHRC_UUID)) {
> + if (bt_uuid16_cmp(&uuid16, CALL_FRIENDLY_NAME_CHRC_UUID)) {
> DBG(ccp, "Found Friendly name, handle 0x%04x", value_handle);
>
> ccs->friendly_name = attr;
> diff --git a/src/shared/ccp.h b/src/shared/ccp.h
> index 28b8b034ece3..3298abe9014c 100644
> --- a/src/shared/ccp.h
> +++ b/src/shared/ccp.h
> @@ -3,7 +3,7 @@
> *
> * BlueZ - Bluetooth protocol stack for Linux
> *
> - * Copyright (C) 2020 Intel Corporation. All rights reserved.
> + * Copyright (C) 2023 Intel Corporation. All rights reserved.
> *
> */
>
> @@ -18,14 +18,18 @@ struct bt_ccp;
> struct bt_ccp_db;
> struct bt_ccp_session_info;
>
> -typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
> -typedef void (*bt_ccp_destroy_func_t)(void *user_data);
> -
> struct bt_ccp_event_callback {
> - void (*call_state)(struct bt_ccp *ccp, const uint8_t *value,
> - uint16_t length);
> + void (*incoming_call)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> + void (*terminate_call)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> + void (*call_list_update)(struct bt_ccp *ccp,
> + const uint8_t *value, uint16_t len);
> };
>
> +typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data);
> +typedef void (*bt_ccp_destroy_func_t)(void *user_data);
> +
> void bt_ccp_set_event_callbacks(struct bt_ccp *ccp,
> const struct bt_ccp_event_callback *cbs,
> void *user_data);
> @@ -43,3 +47,6 @@ void bt_ccp_unref(struct bt_ccp *ccp);
>
> bool bt_ccp_set_user_data(struct bt_ccp *ccp, void *user_data);
> void *bt_ccp_get_user_data(struct bt_ccp *ccp);
> +
> +unsigned int bt_ccp_call_answer(struct bt_ccp *ccp, uint8_t index);
> +unsigned int bt_ccp_call_reject(struct bt_ccp *ccp, uint8_t index);
> --
> 2.34.1
>
>


--
Luiz Augusto von Dentz