Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/connectivity/bluetooth/shell/audio/ccp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ to :code:`0` which is the GTBS bearer.
init : Initialize CCP Call Control Server
set_bearer_name : Set bearer name [index] <name>
get_bearer_name : Get bearer name [index]
get_bearer_name : Get bearer UCI [index]


Example Usage
Expand Down Expand Up @@ -58,6 +59,15 @@ Setting and getting the bearer name
uart:~$ ccp_call_control_server get_bearer_name 1
Bearer[1] name: New TBS name

Getting the bearer UCI
----------------------

.. code-block:: console

uart:~$ ccp_call_control_server get_bearer_uci
Bearer[0] UCI: un999
uart:~$ ccp_call_control_server get_bearer_name 1
Bearer[1] UCI: skype

Call Control Client
*******************
Expand Down Expand Up @@ -90,3 +100,7 @@ Example Usage when connected
Bearer 0x20046254 name: Generic TBS
uart:~$ ccp_call_control_client read_bearer_name 1
Bearer 0x20046256 name: Telephone Bearer #1
uart:~$ ccp_call_control_client read_bearer_uci
Bearer 0x20046254 UCI: un999
uart:~$ ccp_call_control_client read_bearer_uci 1
Bearer 0x20046256 name: skype
45 changes: 45 additions & 0 deletions include/zephyr/bluetooth/audio/ccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ int bt_ccp_call_control_server_set_bearer_provider_name(
int bt_ccp_call_control_server_get_bearer_provider_name(
struct bt_ccp_call_control_server_bearer *bearer, const char **name);

/**
* @brief Get the bearer provider name.
*
* @param[in] bearer The bearer to get the name for.
* @param[out] uci Pointer that will be updated to be the bearer uci.
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p uci is NULL
* @retval -EFAULT @p bearer is not registered
*/
int bt_ccp_call_control_server_get_bearer_uci(struct bt_ccp_call_control_server_bearer *bearer,
const char **uci);

/** @} */ /* End of group bt_ccp_call_control_server */

/**
Expand Down Expand Up @@ -184,6 +197,21 @@ struct bt_ccp_call_control_client_cb {
const char *name);
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
/**
* @brief Callback function for bt_ccp_call_control_client_read_bearer_provider_name().
*
* This callback is called once the read bearer provider name procedure is completed.
*
* @param client Call Control Client instance pointer.
* @param err Error value. 0 on success, GATT error on positive
* value or errno on negative value.
* @param uci The UCI of the bearer. NULL if @p err is not 0.
*/
void (*bearer_uci)(struct bt_ccp_call_control_client_bearer *bearer, int err,
const char *uci);
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

/** @cond INTERNAL_HIDDEN */
/** Internally used field for list handling */
sys_snode_t _node;
Expand Down Expand Up @@ -262,6 +290,23 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
*/
int bt_ccp_call_control_client_read_bearer_provider_name(
struct bt_ccp_call_control_client_bearer *bearer);

/**
* @brief Read the bearer Unicorm Caller Identifier (UCI) of a remote TBS bearer.
*
* @kconfig_dep{CONFIG_BT_TBS_CLIENT_BEARER_UCI}
*
* @param bearer The bearer to read the UCI from
*
* @retval 0 Success
* @retval -EINVAL @p bearer is NULL
* @retval -EFAULT @p bearer has not been discovered
* @retval -EEXIST A @ref bt_ccp_call_control_client could not be identified for @p bearer
* @retval -EBUSY The @ref bt_ccp_call_control_client identified by @p bearer is busy, or the TBS
* instance of @p bearer is busy.
* @retval -ENOTCONN The @ref bt_ccp_call_control_client identified by @p bearer is not connected
*/
int bt_ccp_call_control_client_read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer);
/** @} */ /* End of group bt_ccp_call_control_client */
#ifdef __cplusplus
}
Expand Down
9 changes: 8 additions & 1 deletion include/zephyr/bluetooth/audio/tbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,14 @@ extern "C" {
* whenever the client should perform on action on the GTBS instance of the
* server, rather than any of the specific Telephone Bearer Service instances.
*/
#define BT_TBS_GTBS_INDEX 0xFF
#define BT_TBS_GTBS_INDEX 0xFF

/** Maximum size of bearer uniform caller identifier (UCI)
*
* Includes the NULL terminator.
* Allowed values are defined by Bluetooth Assigned Numbers.
*/
#define BT_TBS_MAX_UCI_SIZE 6

/** @brief Opaque Telephone Bearer Service instance. */
struct bt_tbs_instance;
Expand Down
1 change: 1 addition & 0 deletions samples/bluetooth/ccp_call_control_client/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CONFIG_BT_TBS_CLIENT_GTBS=y
CONFIG_BT_TBS_CLIENT_TBS=y
CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=1
CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME=y
CONFIG_BT_TBS_CLIENT_BEARER_UCI=y
CONFIG_UTF8=y

# TBS Client may require up to 12 buffers
Expand Down
82 changes: 67 additions & 15 deletions samples/bluetooth/ccp_call_control_client/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,22 @@ static void ccp_call_control_client_read_bearer_provider_name_cb(
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
static void
ccp_call_control_client_read_bearer_uci_cb(struct bt_ccp_call_control_client_bearer *bearer,
int err, const char *name)
{
if (err != 0) {
LOG_ERR("Failed to read bearer %p UCI: %d\n", (void *)bearer, err);
return;
}

LOG_INF("Bearer %p UCI: %s", (void *)bearer, name);

k_sem_give(&sem_ccp_action_completed);
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */

static int reset_ccp_call_control_client(void)
{
int err;
Expand Down Expand Up @@ -292,24 +308,62 @@ static int read_bearer_name(struct bt_ccp_call_control_client_bearer *bearer)
return 0;
}

static int read_bearer_names(void)
static int read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer)
{
int err;

#if defined(CONFIG_BT_TBS_CLIENT_GTBS)
err = read_bearer_name(client_bearers.gtbs_bearer);
err = bt_ccp_call_control_client_read_bearer_uci(bearer);
if (err != 0) {
LOG_ERR("Failed to read name for GTBS bearer: %d", err);
return err;
}

err = k_sem_take(&sem_ccp_action_completed, SEM_TIMEOUT);
if (err != 0) {
LOG_ERR("Failed to take sem_ccp_action_completed: %d", err);
return err;
}

return 0;
}

static int read_bearer_values(void)
{
int err;

#if defined(CONFIG_BT_TBS_CLIENT_GTBS)
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
err = read_bearer_name(client_bearers.gtbs_bearer);
if (err != 0) {
LOG_ERR("Failed to read name for GTBS bearer: %d", err);
return err;
}
}

if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_UCI)) {
err = read_bearer_uci(client_bearers.gtbs_bearer);
if (err != 0) {
LOG_ERR("Failed to read UCI for GTBS bearer: %d", err);
return err;
}
}
#endif /* CONFIG_BT_TBS_CLIENT_GTBS */

#if defined(CONFIG_BT_TBS_CLIENT_TBS)
for (size_t i = 0; i < client_bearers.tbs_count; i++) {
err = read_bearer_name(client_bearers.tbs_bearers[i]);
if (err != 0) {
LOG_ERR("Failed to read name for bearer[%zu]: %d", i, err);
return err;
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
err = read_bearer_name(client_bearers.tbs_bearers[i]);
if (err != 0) {
LOG_ERR("Failed to read name for bearer[%zu]: %d", i, err);
return err;
}
}

if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_UCI)) {
err = read_bearer_uci(client_bearers.tbs_bearers[i]);
if (err != 0) {
LOG_ERR("Failed to read UCI for bearer[%zu]: %d", i, err);
return err;
}
}
}
#endif /* CONFIG_BT_TBS_CLIENT_TBS */
Expand All @@ -322,8 +376,11 @@ static int init_ccp_call_control_client(void)
static struct bt_ccp_call_control_client_cb ccp_call_control_client_cbs = {
.discover = ccp_call_control_client_discover_cb,
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb
.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb,
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
.bearer_uci = ccp_call_control_client_read_bearer_uci_cb,
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
};
static struct bt_le_scan_cb scan_cbs = {
.recv = scan_recv_cb,
Expand Down Expand Up @@ -384,12 +441,7 @@ int main(void)
continue;
}

if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
err = read_bearer_names();
if (err != 0) {
continue;
}
}
read_bearer_values();

/* Reset if disconnected */
err = k_sem_take(&sem_conn_state_change, K_FOREVER);
Expand Down
112 changes: 87 additions & 25 deletions subsys/bluetooth/audio/ccp_call_control_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,31 +289,7 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
return 0;
}

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
static void tbs_client_read_bearer_provider_name_cb(struct bt_conn *conn, int err,
uint8_t inst_index, const char *name)
{
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
struct bt_ccp_call_control_client_cb *listener, *next;
struct bt_ccp_call_control_client_bearer *bearer;

atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);

bearer = get_bearer_by_tbs_index(client, inst_index);
if (bearer == NULL) {
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
inst_index);

return;
}

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
if (listener->bearer_provider_name != NULL) {
listener->bearer_provider_name(bearer, err, name);
}
}
}

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI) || defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
/**
* @brief Validates a bearer and provides a client with ownership of the busy flag
*
Expand Down Expand Up @@ -353,6 +329,32 @@ static int validate_bearer_and_get_client(const struct bt_ccp_call_control_clien

return 0;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI || CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
static void tbs_client_read_bearer_provider_name_cb(struct bt_conn *conn, int err,
uint8_t inst_index, const char *name)
{
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
struct bt_ccp_call_control_client_cb *listener, *next;
struct bt_ccp_call_control_client_bearer *bearer;

atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);

bearer = get_bearer_by_tbs_index(client, inst_index);
if (bearer == NULL) {
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
inst_index);

return;
}

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
if (listener->bearer_provider_name != NULL) {
listener->bearer_provider_name(bearer, err, name);
}
}
}

int bt_ccp_call_control_client_read_bearer_provider_name(
struct bt_ccp_call_control_client_bearer *bearer)
Expand Down Expand Up @@ -389,3 +391,63 @@ int bt_ccp_call_control_client_read_bearer_provider_name(
return 0;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
static void tbs_client_read_bearer_uci_cb(struct bt_conn *conn, int err, uint8_t inst_index,
const char *uci)
{
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
struct bt_ccp_call_control_client_cb *listener, *next;
struct bt_ccp_call_control_client_bearer *bearer;

atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);

bearer = get_bearer_by_tbs_index(client, inst_index);
if (bearer == NULL) {
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
inst_index);

return;
}

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
if (listener->bearer_uci != NULL) {
listener->bearer_uci(bearer, err, uci);
}
}
}

int bt_ccp_call_control_client_read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer)
{
struct bt_ccp_call_control_client *client;
int err;

err = validate_bearer_and_get_client(bearer, &client);
if (err != 0) {
return err;
}

tbs_client_cbs.bearer_uci = tbs_client_read_bearer_uci_cb;

err = bt_tbs_client_read_bearer_uci(client->conn, bearer->tbs_index);
if (err != 0) {
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);

/* Return expected return values directly */
if (err == -ENOTCONN || err == -EBUSY) {
LOG_DBG("bt_tbs_client_read_bearer_uci returned %d", err);

return err;
}

/* Assert if the return value is -EINVAL as that means we are missing a check */
__ASSERT(err != -EINVAL, "err shall not be -EINVAL");

LOG_DBG("Unexpected error from bt_tbs_client_read_bearer_uci: %d", err);

return -ENOEXEC;
}

return 0;
}
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
Loading