Skip to content

Commit da281c6

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 81c70c1 commit da281c6

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
@@ -168,6 +168,21 @@ struct bt_ccp_call_control_client_cb {
168168
void (*discover)(struct bt_ccp_call_control_client *client, int err,
169169
struct bt_ccp_call_control_client_bearers *bearers);
170170

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

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

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
@@ -27,6 +27,7 @@ LOG_MODULE_REGISTER(bt_ccp_call_control_client, CONFIG_BT_CCP_CALL_CONTROL_CLIEN
2727

2828
static sys_slist_t ccp_call_control_client_cbs =
2929
SYS_SLIST_STATIC_INIT(&ccp_call_control_client_cbs);
30+
static struct bt_tbs_client_cb tbs_client_cbs;
3031

3132
static struct bt_tbs_client_cb tbs_client_cbs;
3233

@@ -52,6 +53,32 @@ struct bt_ccp_call_control_client {
5253

5354
static struct bt_ccp_call_control_client clients[CONFIG_BT_MAX_CONN];
5455

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

@@ -251,3 +280,104 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
251280

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

0 commit comments

Comments
 (0)