Skip to content

Commit 875e209

Browse files
committed
Bluetooth: CCP: Client: Add support for get provider name
Add support for getting the remote bearer provider name. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 419a9d6 commit 875e209

File tree

16 files changed

+666
-26
lines changed

16 files changed

+666
-26
lines changed

doc/connectivity/bluetooth/shell/audio/ccp.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,10 @@ Example Usage when connected
8383
8484
uart:~$ ccp_call_control_client discover
8585
Discovery completed with GTBS and 1 TBS bearers
86+
87+
.. code-block:: console
88+
89+
uart:~$ ccp_call_control_client read_bearer_name
90+
Bearer 0x20046254 name: Generic TBS
91+
uart:~$ ccp_call_control_client read_bearer_name 1
92+
Bearer 0x20046256 name: Telephone Bearer #1

include/zephyr/bluetooth/audio/ccp.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,21 @@ struct bt_ccp_call_control_client_cb {
169169
void (*discover)(struct bt_ccp_call_control_client *client, int err,
170170
struct bt_ccp_call_control_client_bearers *bearers);
171171

172+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
173+
/**
174+
* @brief Callback function for bt_ccp_call_control_client_read_bearer_provider_name().
175+
*
176+
* This callback is called once the read bearer provider name procedure is completed.
177+
*
178+
* @param client Call Control Client instance pointer.
179+
* @param err Error value. 0 on success, GATT error on positive
180+
* value or errno on negative value.
181+
* @param name The bearer provider name. NULL if @p err is not 0.
182+
*/
183+
void (*bearer_provider_name)(struct bt_ccp_call_control_client_bearer *bearer, int err,
184+
const char *name);
185+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
186+
172187
/** @cond INTERNAL_HIDDEN */
173188
/** Internally used field for list handling */
174189
sys_snode_t _node;
@@ -230,6 +245,23 @@ int bt_ccp_call_control_client_unregister_cb(struct bt_ccp_call_control_client_c
230245
int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *client,
231246
struct bt_ccp_call_control_client_bearers *bearers);
232247

248+
/**
249+
* @brief Read the bearer provider name of a remote TBS bearer.
250+
*
251+
* @kconfig_dep{CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME}
252+
*
253+
* @param bearer The bearer to read the name from
254+
*
255+
* @retval 0 Success
256+
* @retval -EINVAL @p bearer is NULL
257+
* @retval -EFAULT @p bearer has not been discovered
258+
* @retval -EEXIST A @ref bt_ccp_call_control_client could not be identified for @p bearer
259+
* @retval -EBUSY The @ref bt_ccp_call_control_client identified by @p bearer is busy, or the TBS
260+
* instance of @p bearer is busy.
261+
* @retval -ENOTCONN The @ref bt_ccp_call_control_client identified by @p bearer is not connected
262+
*/
263+
int bt_ccp_call_control_client_read_bearer_provider_name(
264+
struct bt_ccp_call_control_client_bearer *bearer);
233265
/** @} */ /* End of group bt_ccp_call_control_client */
234266
#ifdef __cplusplus
235267
}

samples/bluetooth/ccp_call_control_client/prj.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ CONFIG_BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT=2
1616
CONFIG_BT_TBS_CLIENT_GTBS=y
1717
CONFIG_BT_TBS_CLIENT_TBS=y
1818
CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=1
19+
CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME=y
1920
CONFIG_UTF8=y
2021

2122
# TBS Client may require up to 12 buffers

samples/bluetooth/ccp_call_control_client/src/main.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,21 @@ static void ccp_call_control_client_discover_cb(struct bt_ccp_call_control_clien
207207
k_sem_give(&sem_ccp_action_completed);
208208
}
209209

210+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
211+
static void ccp_call_control_client_read_bearer_provider_name_cb(
212+
struct bt_ccp_call_control_client_bearer *bearer, int err, const char *name)
213+
{
214+
if (err != 0) {
215+
LOG_ERR("Failed to read bearer %p provider name: %d\n", (void *)bearer, err);
216+
return;
217+
}
218+
219+
LOG_INF("Bearer %p provider name: %s", (void *)bearer, name);
220+
221+
k_sem_give(&sem_ccp_action_completed);
222+
}
223+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
224+
210225
static int reset_ccp_call_control_client(void)
211226
{
212227
int err;
@@ -259,13 +274,59 @@ static int discover_services(void)
259274
return 0;
260275
}
261276

277+
static int read_bearer_name(struct bt_ccp_call_control_client_bearer *bearer)
278+
{
279+
int err;
280+
281+
err = bt_ccp_call_control_client_read_bearer_provider_name(bearer);
282+
if (err != 0) {
283+
return err;
284+
}
285+
286+
err = k_sem_take(&sem_ccp_action_completed, SEM_TIMEOUT);
287+
if (err != 0) {
288+
LOG_ERR("Failed to take sem_ccp_action_completed: %d", err);
289+
return err;
290+
}
291+
292+
return 0;
293+
}
294+
295+
static int read_bearer_names(void)
296+
{
297+
int err;
298+
299+
#if defined(CONFIG_BT_TBS_CLIENT_GTBS)
300+
err = read_bearer_name(client_bearers.gtbs_bearer);
301+
if (err != 0) {
302+
LOG_ERR("Failed to read name for GTBS bearer: %d", err);
303+
return err;
304+
}
305+
#endif /* CONFIG_BT_TBS_CLIENT_GTBS */
306+
307+
#if defined(CONFIG_BT_TBS_CLIENT_TBS)
308+
for (size_t i = 0; i < client_bearers.tbs_count; i++) {
309+
err = read_bearer_name(client_bearers.tbs_bearers[i]);
310+
if (err != 0) {
311+
LOG_ERR("Failed to read name for bearer[%zu]: %d", i, err);
312+
return err;
313+
}
314+
}
315+
#endif /* CONFIG_BT_TBS_CLIENT_TBS */
316+
317+
return 0;
318+
}
319+
262320
static int init_ccp_call_control_client(void)
263321
{
264-
static struct bt_le_scan_cb scan_cbs = {
265-
.recv = scan_recv_cb,
266-
};
267322
static struct bt_ccp_call_control_client_cb ccp_call_control_client_cbs = {
268323
.discover = ccp_call_control_client_discover_cb,
324+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
325+
.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb
326+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
327+
};
328+
static struct bt_le_scan_cb scan_cbs = {
329+
.recv = scan_recv_cb,
269330
};
270331
int err;
271332

@@ -323,6 +384,13 @@ int main(void)
323384
continue;
324385
}
325386

387+
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
388+
err = read_bearer_names();
389+
if (err != 0) {
390+
continue;
391+
}
392+
}
393+
326394
/* Reset if disconnected */
327395
err = k_sem_take(&sem_conn_state_change, K_FOREVER);
328396
if (err != 0) {

subsys/bluetooth/audio/ccp_call_control_client.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ LOG_MODULE_REGISTER(bt_ccp_call_control_client, CONFIG_BT_CCP_CALL_CONTROL_CLIEN
2828

2929
static sys_slist_t ccp_call_control_client_cbs =
3030
SYS_SLIST_STATIC_INIT(&ccp_call_control_client_cbs);
31+
static struct bt_tbs_client_cb tbs_client_cbs;
3132

3233
static struct bt_tbs_client_cb tbs_client_cbs;
3334

@@ -53,6 +54,32 @@ struct bt_ccp_call_control_client {
5354

5455
static struct bt_ccp_call_control_client clients[CONFIG_BT_MAX_CONN];
5556

57+
static struct bt_ccp_call_control_client_bearer *
58+
get_bearer_by_tbs_index(struct bt_ccp_call_control_client *client, uint8_t index)
59+
{
60+
for (size_t i = 0U; i < ARRAY_SIZE(client->bearers); i++) {
61+
struct bt_ccp_call_control_client_bearer *bearer = &client->bearers[i];
62+
63+
if (bearer->discovered && bearer->tbs_index == index) {
64+
return bearer;
65+
}
66+
}
67+
68+
return NULL;
69+
}
70+
71+
static struct bt_ccp_call_control_client *
72+
get_client_by_bearer(const struct bt_ccp_call_control_client_bearer *bearer)
73+
{
74+
for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
75+
if (IS_ARRAY_ELEMENT(clients[i].bearers, bearer)) {
76+
return &clients[i];
77+
}
78+
}
79+
80+
return NULL;
81+
}
82+
5683
static struct bt_ccp_call_control_client *get_client_by_conn(const struct bt_conn *conn)
5784
{
5885
return &clients[bt_conn_index(conn)];
@@ -84,6 +111,8 @@ static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
84111
if (client->conn == conn) {
85112
bt_conn_unref(client->conn);
86113
client->conn = NULL;
114+
115+
memset(client->bearers, 0, sizeof(client->bearers));
87116
}
88117
}
89118

@@ -252,3 +281,104 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
252281

253282
return 0;
254283
}
284+
285+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
286+
static void tbs_client_read_bearer_provider_name_cb(struct bt_conn *conn, int err,
287+
uint8_t inst_index, const char *name)
288+
{
289+
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
290+
struct bt_ccp_call_control_client_cb *listener, *next;
291+
struct bt_ccp_call_control_client_bearer *bearer;
292+
293+
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
294+
295+
bearer = get_bearer_by_tbs_index(client, inst_index);
296+
if (bearer == NULL) {
297+
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
298+
inst_index);
299+
300+
return;
301+
}
302+
303+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
304+
if (listener->bearer_provider_name != NULL) {
305+
listener->bearer_provider_name(bearer, err, name);
306+
}
307+
}
308+
}
309+
310+
/**
311+
* @brief Validates a bearer and provides a client with ownership of the busy flag
312+
*
313+
* @param[in] bearer The bearer to validate
314+
* @param[out] client A client identified by the @p bearer with the busy flag set if return
315+
* value is 0.
316+
*
317+
* @return 0 if the bearer is valid and the @p client has been populated, else an error.
318+
*/
319+
static int validate_bearer_and_get_client(const struct bt_ccp_call_control_client_bearer *bearer,
320+
struct bt_ccp_call_control_client **client)
321+
{
322+
CHECKIF(bearer == NULL) {
323+
LOG_DBG("bearer is NULL");
324+
325+
return -EINVAL;
326+
}
327+
328+
*client = get_client_by_bearer(bearer);
329+
if (*client == NULL) {
330+
LOG_DBG("Could not identify client from bearer %p", bearer);
331+
332+
return -EEXIST;
333+
}
334+
335+
if (!bearer->discovered) {
336+
LOG_DBG("bearer %p is not discovered", bearer);
337+
338+
return -EFAULT;
339+
}
340+
341+
if (atomic_test_and_set_bit((*client)->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY)) {
342+
LOG_DBG("Client %p identified by bearer %p is busy", *client, bearer);
343+
344+
return -EBUSY;
345+
}
346+
347+
return 0;
348+
}
349+
350+
int bt_ccp_call_control_client_read_bearer_provider_name(
351+
struct bt_ccp_call_control_client_bearer *bearer)
352+
{
353+
struct bt_ccp_call_control_client *client;
354+
int err;
355+
356+
err = validate_bearer_and_get_client(bearer, &client);
357+
if (err != 0) {
358+
return err;
359+
}
360+
361+
tbs_client_cbs.bearer_provider_name = tbs_client_read_bearer_provider_name_cb;
362+
363+
err = bt_tbs_client_read_bearer_provider_name(client->conn, bearer->tbs_index);
364+
if (err != 0) {
365+
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
366+
367+
/* Return expected return values directly */
368+
if (err == -ENOTCONN || err == -EBUSY) {
369+
LOG_DBG("bt_tbs_client_read_bearer_provider_name returned %d", err);
370+
371+
return err;
372+
}
373+
374+
/* Assert if the return value is -EINVAL as that means we are missing a check */
375+
__ASSERT(err != -EINVAL, "err shall not be -EINVAL");
376+
377+
LOG_DBG("Unexpected error from bt_tbs_client_read_bearer_provider_name: %d", err);
378+
379+
return -ENOEXEC;
380+
}
381+
382+
return 0;
383+
}
384+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */

0 commit comments

Comments
 (0)