diff mbox series

[v1] bluetoothctl: CCP client interface for bluetoothctl

Message ID 20240423232622.1142256-1-ajay.k.v@intel.com
State New
Headers show
Series [v1] bluetoothctl: CCP client interface for bluetoothctl | expand

Commit Message

Ajay KV April 23, 2024, 11:26 p.m. UTC
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

Comments

Paul Menzel April 23, 2024, 8:07 p.m. UTC | #1
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);
diff mbox series

Patch

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