Skip to content

Commit 5b01daa

Browse files
committed
Bluetooth: CCP: Client: Add support for get bearer uci
Add support for getting the remote bearer UCI. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 8495dd1 commit 5b01daa

File tree

12 files changed

+372
-47
lines changed

12 files changed

+372
-47
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ Example Usage when connected
100100
Bearer 0x20046254 name: Generic TBS
101101
uart:~$ ccp_call_control_client read_bearer_name 1
102102
Bearer 0x20046256 name: Telephone Bearer #1
103+
uart:~$ ccp_call_control_client read_bearer_uci
104+
Bearer 0x20046254 UCI: un999
105+
uart:~$ ccp_call_control_client read_bearer_uci 1
106+
Bearer 0x20046256 name: skype

include/zephyr/bluetooth/audio/ccp.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ struct bt_ccp_call_control_client_cb {
197197
const char *name);
198198
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
199199

200+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
201+
/**
202+
* @brief Callback function for bt_ccp_call_control_client_read_bearer_provider_name().
203+
*
204+
* This callback is called once the read bearer provider name procedure is completed.
205+
*
206+
* @param client Call Control Client instance pointer.
207+
* @param err Error value. 0 on success, GATT error on positive
208+
* value or errno on negative value.
209+
* @param uci The UCI of the bearer. NULL if @p err is not 0.
210+
*/
211+
void (*bearer_uci)(struct bt_ccp_call_control_client_bearer *bearer, int err,
212+
const char *uci);
213+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
214+
200215
/** @cond INTERNAL_HIDDEN */
201216
/** Internally used field for list handling */
202217
sys_snode_t _node;
@@ -275,6 +290,23 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
275290
*/
276291
int bt_ccp_call_control_client_read_bearer_provider_name(
277292
struct bt_ccp_call_control_client_bearer *bearer);
293+
294+
/**
295+
* @brief Read the bearer Unicorm Caller Identifier (UCI) of a remote TBS bearer.
296+
*
297+
* @kconfig_dep{CONFIG_BT_TBS_CLIENT_BEARER_UCI}
298+
*
299+
* @param bearer The bearer to read the UCI from
300+
*
301+
* @retval 0 Success
302+
* @retval -EINVAL @p bearer is NULL
303+
* @retval -EFAULT @p bearer has not been discovered
304+
* @retval -EEXIST A @ref bt_ccp_call_control_client could not be identified for @p bearer
305+
* @retval -EBUSY The @ref bt_ccp_call_control_client identified by @p bearer is busy, or the TBS
306+
* instance of @p bearer is busy.
307+
* @retval -ENOTCONN The @ref bt_ccp_call_control_client identified by @p bearer is not connected
308+
*/
309+
int bt_ccp_call_control_client_read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer);
278310
/** @} */ /* End of group bt_ccp_call_control_client */
279311
#ifdef __cplusplus
280312
}

samples/bluetooth/ccp_call_control_client/prj.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ CONFIG_BT_TBS_CLIENT_GTBS=y
1717
CONFIG_BT_TBS_CLIENT_TBS=y
1818
CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=1
1919
CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME=y
20+
CONFIG_BT_TBS_CLIENT_BEARER_UCI=y
2021
CONFIG_UTF8=y
2122

2223
# TBS Client may require up to 12 buffers

samples/bluetooth/ccp_call_control_client/src/main.c

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,22 @@ static void ccp_call_control_client_read_bearer_provider_name_cb(
222222
}
223223
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
224224

225+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
226+
static void
227+
ccp_call_control_client_read_bearer_uci_cb(struct bt_ccp_call_control_client_bearer *bearer,
228+
int err, const char *name)
229+
{
230+
if (err != 0) {
231+
LOG_ERR("Failed to read bearer %p UCI: %d\n", (void *)bearer, err);
232+
return;
233+
}
234+
235+
LOG_INF("Bearer %p UCI: %s", (void *)bearer, name);
236+
237+
k_sem_give(&sem_ccp_action_completed);
238+
}
239+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
240+
225241
static int reset_ccp_call_control_client(void)
226242
{
227243
int err;
@@ -292,24 +308,62 @@ static int read_bearer_name(struct bt_ccp_call_control_client_bearer *bearer)
292308
return 0;
293309
}
294310

295-
static int read_bearer_names(void)
311+
static int read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer)
296312
{
297313
int err;
298314

299-
#if defined(CONFIG_BT_TBS_CLIENT_GTBS)
300-
err = read_bearer_name(client_bearers.gtbs_bearer);
315+
err = bt_ccp_call_control_client_read_bearer_uci(bearer);
301316
if (err != 0) {
302-
LOG_ERR("Failed to read name for GTBS bearer: %d", err);
303317
return err;
304318
}
319+
320+
err = k_sem_take(&sem_ccp_action_completed, SEM_TIMEOUT);
321+
if (err != 0) {
322+
LOG_ERR("Failed to take sem_ccp_action_completed: %d", err);
323+
return err;
324+
}
325+
326+
return 0;
327+
}
328+
329+
static int read_bearer_values(void)
330+
{
331+
int err;
332+
333+
#if defined(CONFIG_BT_TBS_CLIENT_GTBS)
334+
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
335+
err = read_bearer_name(client_bearers.gtbs_bearer);
336+
if (err != 0) {
337+
LOG_ERR("Failed to read name for GTBS bearer: %d", err);
338+
return err;
339+
}
340+
}
341+
342+
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_UCI)) {
343+
err = read_bearer_uci(client_bearers.gtbs_bearer);
344+
if (err != 0) {
345+
LOG_ERR("Failed to read UCI for GTBS bearer: %d", err);
346+
return err;
347+
}
348+
}
305349
#endif /* CONFIG_BT_TBS_CLIENT_GTBS */
306350

307351
#if defined(CONFIG_BT_TBS_CLIENT_TBS)
308352
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;
353+
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
354+
err = read_bearer_name(client_bearers.tbs_bearers[i]);
355+
if (err != 0) {
356+
LOG_ERR("Failed to read name for bearer[%zu]: %d", i, err);
357+
return err;
358+
}
359+
}
360+
361+
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_UCI)) {
362+
err = read_bearer_uci(client_bearers.tbs_bearers[i]);
363+
if (err != 0) {
364+
LOG_ERR("Failed to read UCI for bearer[%zu]: %d", i, err);
365+
return err;
366+
}
313367
}
314368
}
315369
#endif /* CONFIG_BT_TBS_CLIENT_TBS */
@@ -322,8 +376,11 @@ static int init_ccp_call_control_client(void)
322376
static struct bt_ccp_call_control_client_cb ccp_call_control_client_cbs = {
323377
.discover = ccp_call_control_client_discover_cb,
324378
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
325-
.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb
379+
.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb,
326380
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
381+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
382+
.bearer_uci = ccp_call_control_client_read_bearer_uci_cb,
383+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
327384
};
328385
static struct bt_le_scan_cb scan_cbs = {
329386
.recv = scan_recv_cb,
@@ -384,12 +441,7 @@ int main(void)
384441
continue;
385442
}
386443

387-
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
388-
err = read_bearer_names();
389-
if (err != 0) {
390-
continue;
391-
}
392-
}
444+
read_bearer_values();
393445

394446
/* Reset if disconnected */
395447
err = k_sem_take(&sem_conn_state_change, K_FOREVER);

subsys/bluetooth/audio/ccp_call_control_client.c

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -289,31 +289,7 @@ int bt_ccp_call_control_client_get_bearers(struct bt_ccp_call_control_client *cl
289289
return 0;
290290
}
291291

292-
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
293-
static void tbs_client_read_bearer_provider_name_cb(struct bt_conn *conn, int err,
294-
uint8_t inst_index, const char *name)
295-
{
296-
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
297-
struct bt_ccp_call_control_client_cb *listener, *next;
298-
struct bt_ccp_call_control_client_bearer *bearer;
299-
300-
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
301-
302-
bearer = get_bearer_by_tbs_index(client, inst_index);
303-
if (bearer == NULL) {
304-
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
305-
inst_index);
306-
307-
return;
308-
}
309-
310-
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
311-
if (listener->bearer_provider_name != NULL) {
312-
listener->bearer_provider_name(bearer, err, name);
313-
}
314-
}
315-
}
316-
292+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI) || defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
317293
/**
318294
* @brief Validates a bearer and provides a client with ownership of the busy flag
319295
*
@@ -353,6 +329,32 @@ static int validate_bearer_and_get_client(const struct bt_ccp_call_control_clien
353329

354330
return 0;
355331
}
332+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI || CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
333+
334+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
335+
static void tbs_client_read_bearer_provider_name_cb(struct bt_conn *conn, int err,
336+
uint8_t inst_index, const char *name)
337+
{
338+
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
339+
struct bt_ccp_call_control_client_cb *listener, *next;
340+
struct bt_ccp_call_control_client_bearer *bearer;
341+
342+
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
343+
344+
bearer = get_bearer_by_tbs_index(client, inst_index);
345+
if (bearer == NULL) {
346+
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
347+
inst_index);
348+
349+
return;
350+
}
351+
352+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
353+
if (listener->bearer_provider_name != NULL) {
354+
listener->bearer_provider_name(bearer, err, name);
355+
}
356+
}
357+
}
356358

357359
int bt_ccp_call_control_client_read_bearer_provider_name(
358360
struct bt_ccp_call_control_client_bearer *bearer)
@@ -389,3 +391,63 @@ int bt_ccp_call_control_client_read_bearer_provider_name(
389391
return 0;
390392
}
391393
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
394+
395+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
396+
static void tbs_client_read_bearer_uci_cb(struct bt_conn *conn, int err, uint8_t inst_index,
397+
const char *uci)
398+
{
399+
struct bt_ccp_call_control_client *client = get_client_by_conn(conn);
400+
struct bt_ccp_call_control_client_cb *listener, *next;
401+
struct bt_ccp_call_control_client_bearer *bearer;
402+
403+
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
404+
405+
bearer = get_bearer_by_tbs_index(client, inst_index);
406+
if (bearer == NULL) {
407+
LOG_DBG("Could not lookup bearer for client %p and index 0x%02X", client,
408+
inst_index);
409+
410+
return;
411+
}
412+
413+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ccp_call_control_client_cbs, listener, next, _node) {
414+
if (listener->bearer_uci != NULL) {
415+
listener->bearer_uci(bearer, err, uci);
416+
}
417+
}
418+
}
419+
420+
int bt_ccp_call_control_client_read_bearer_uci(struct bt_ccp_call_control_client_bearer *bearer)
421+
{
422+
struct bt_ccp_call_control_client *client;
423+
int err;
424+
425+
err = validate_bearer_and_get_client(bearer, &client);
426+
if (err != 0) {
427+
return err;
428+
}
429+
430+
tbs_client_cbs.bearer_uci = tbs_client_read_bearer_uci_cb;
431+
432+
err = bt_tbs_client_read_bearer_uci(client->conn, bearer->tbs_index);
433+
if (err != 0) {
434+
atomic_clear_bit(client->flags, CCP_CALL_CONTROL_CLIENT_FLAG_BUSY);
435+
436+
/* Return expected return values directly */
437+
if (err == -ENOTCONN || err == -EBUSY) {
438+
LOG_DBG("bt_tbs_client_read_bearer_uci returned %d", err);
439+
440+
return err;
441+
}
442+
443+
/* Assert if the return value is -EINVAL as that means we are missing a check */
444+
__ASSERT(err != -EINVAL, "err shall not be -EINVAL");
445+
446+
LOG_DBG("Unexpected error from bt_tbs_client_read_bearer_uci: %d", err);
447+
448+
return -ENOEXEC;
449+
}
450+
451+
return 0;
452+
}
453+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */

subsys/bluetooth/audio/shell/ccp_call_control_client.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,27 @@ ccp_call_control_client_bearer_provider_name_cb(struct bt_ccp_call_control_clien
6565
}
6666
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
6767

68+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
69+
static void ccp_call_control_client_bearer_uci_cb(struct bt_ccp_call_control_client_bearer *bearer,
70+
int err, const char *name)
71+
{
72+
if (err != 0) {
73+
bt_shell_error("Failed to read bearer %p UCI: %d", (void *)bearer, err);
74+
return;
75+
}
76+
77+
bt_shell_info("Bearer %p UCI: %s", (void *)bearer, name);
78+
}
79+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
80+
6881
static struct bt_ccp_call_control_client_cb ccp_call_control_client_cbs = {
6982
.discover = ccp_call_control_client_discover_cb,
7083
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
7184
.bearer_provider_name = ccp_call_control_client_bearer_provider_name_cb,
7285
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
86+
#if defined(CONFIG_BT_TBS_CLIENT_BEARER_UCI)
87+
.bearer_uci = ccp_call_control_client_bearer_uci_cb,
88+
#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */
7389
};
7490

7591
static int cmd_ccp_call_control_client_discover(const struct shell *sh, size_t argc, char *argv[])
@@ -187,6 +203,37 @@ static int cmd_ccp_call_control_client_read_bearer_name(const struct shell *sh,
187203
return 0;
188204
}
189205

206+
static int cmd_ccp_call_control_client_read_bearer_uci(const struct shell *sh, size_t argc,
207+
char *argv[])
208+
{
209+
struct bt_ccp_call_control_client_bearer *bearer;
210+
unsigned long index = 0;
211+
int err;
212+
213+
if (argc > 1) {
214+
index = validate_and_get_index(sh, argv[1]);
215+
if (index < 0) {
216+
return index;
217+
}
218+
}
219+
220+
bearer = get_bearer_by_index(index);
221+
if (bearer == NULL) {
222+
shell_error(sh, "Failed to get bearer for index %lu", index);
223+
224+
return -ENOEXEC;
225+
}
226+
227+
err = bt_ccp_call_control_client_read_bearer_uci(bearer);
228+
if (err != 0) {
229+
shell_error(sh, "Failed to read bearer[%lu] UCI: %d", index, err);
230+
231+
return -ENOEXEC;
232+
}
233+
234+
return 0;
235+
}
236+
190237
static int cmd_ccp_call_control_client(const struct shell *sh, size_t argc, char **argv)
191238
{
192239
if (argc > 1) {
@@ -204,6 +251,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(ccp_call_control_client_cmds,
204251
cmd_ccp_call_control_client_discover, 1, 0),
205252
SHELL_CMD_ARG(read_bearer_name, NULL, "Get bearer name [index]",
206253
cmd_ccp_call_control_client_read_bearer_name, 1, 1),
254+
SHELL_CMD_ARG(read_bearer_name, NULL, "Get bearer UCI [index]",
255+
cmd_ccp_call_control_client_read_bearer_uci, 1, 1),
207256
SHELL_SUBCMD_SET_END);
208257

209258
SHELL_CMD_ARG_REGISTER(ccp_call_control_client, &ccp_call_control_client_cmds,

tests/bluetooth/audio/ccp_call_control_client/include/ccp_call_control_client.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ DECLARE_FAKE_VOID_FUNC(mock_ccp_call_control_client_discover_cb,
2121
struct bt_ccp_call_control_client_bearers *);
2222
DECLARE_FAKE_VOID_FUNC(mock_ccp_call_control_client_bearer_provider_name_cb,
2323
struct bt_ccp_call_control_client_bearer *, int, const char *);
24+
DECLARE_FAKE_VOID_FUNC(mock_ccp_call_control_client_bearer_uci_cb,
25+
struct bt_ccp_call_control_client_bearer *, int, const char *);
2426

2527
#endif /* MOCKS_CCP_CALL_CONTROL_CLIENT_H_ */

0 commit comments

Comments
 (0)