From 35bd427927a558df8f205d1141b80bdf1023bfb4 Mon Sep 17 00:00:00 2001 From: Szymon Czapracki Date: Thu, 24 Nov 2022 09:33:09 +0100 Subject: [PATCH] Bluetooth: audio: Add configurable PACS supported contexts Add the ability to change supported contexts in PACS. Enhance the context command in the shell module to make it configurable. Signed-off-by: Szymon Czapracki --- include/zephyr/bluetooth/audio/pacs.h | 8 ++ subsys/bluetooth/audio/pacs.c | 103 ++++++++++++++++-- subsys/bluetooth/shell/audio.c | 34 ++++-- .../bsim_test_audio/src/unicast_server_test.c | 15 +++ 4 files changed, 143 insertions(+), 17 deletions(-) diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index db8d903dfc8..64533abe8ed 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -96,6 +96,14 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, */ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir); +/** @brief Set the supported contexts for an endpoint type + * + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set. + */ +int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, + enum bt_audio_context contexts); + #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 8fbb87f9f07..188caed8185 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -55,20 +55,20 @@ struct pacs { sys_slist_t list; }; -#if defined(CONFIG_BT_PAC_SNK) +#if defined(CONTIG_BT_PAC_SNK) static uint16_t snk_available_contexts; -static const uint16_t snk_supported_contexts = CONFIG_BT_PACS_SNK_CONTEXT; +static uint16_t snk_supported_contexts; #else -static const uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static const uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) static uint16_t src_available_contexts; -static const uint16_t src_supported_contexts = CONFIG_BT_PACS_SRC_CONTEXT; +static uint16_t src_supported_contexts; #else -static const uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static const uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; #endif /* CONFIG_BT_PAC_SRC */ NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, CONFIG_BT_L2CAP_TX_MTU); @@ -231,10 +231,12 @@ static ssize_t supported_context_read(struct bt_conn *conn, } static void available_contexts_notify(struct k_work *work); +static void supported_contexts_notify(struct k_work *work); static K_WORK_DELAYABLE_DEFINE(available_contexts_work, available_contexts_notify); +static K_WORK_DELAYABLE_DEFINE(supported_contexts_work, supported_contexts_notify); static int set_available_contexts(uint16_t contexts, uint16_t *available, - const uint16_t supported) + uint16_t supported) { int err; @@ -246,13 +248,45 @@ static int set_available_contexts(uint16_t contexts, uint16_t *available, return 0; } - *available = contexts; - err = k_work_reschedule(&available_contexts_work, PAC_NOTIFY_TIMEOUT); if (err < 0) { return err; } + *available = contexts; + + return 0; +} + +static int set_supported_contexts(uint16_t contexts, uint16_t *supported, + uint16_t *available) +{ + int err; + + /* Ensure unspecified is always supported */ + contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + + if (*supported == contexts) { + return 0; + } + + err = k_work_reschedule(&supported_contexts_work, PAC_NOTIFY_TIMEOUT); + if (err < 0) { + return err; + } + + *supported = contexts; + + /* Update available contexts if needed*/ + if ((contexts & *available) != *available) { + *available = *available & contexts; + err = k_work_reschedule(&available_contexts_work, + PAC_NOTIFY_TIMEOUT); + if (err < 0) { + LOG_WRN("Update available contexts notify failed: %d", err); + } + } + return 0; } @@ -281,11 +315,22 @@ static inline int set_snk_available_contexts(uint16_t contexts) return set_available_contexts(contexts, &snk_available_contexts, snk_supported_contexts); } + +static inline int set_snk_supported_contexts(uint16_t contexts) +{ + return set_supported_contexts(contexts, &snk_supported_contexts, + &snk_available_contexts); +} #else static inline int set_snk_available_contexts(uint16_t contexts) { return -ENOTSUP; } + +static inline int set_snk_supported_contexts(uint16_t contexts) +{ + return -ENOTSUP; +} #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK_LOC) @@ -385,11 +430,22 @@ static inline int set_src_available_contexts(uint16_t contexts) return set_available_contexts(contexts, &src_available_contexts, src_supported_contexts); } + +static inline int set_src_supported_contexts(uint16_t contexts) +{ + return set_supported_contexts(contexts, &src_supported_contexts, + &snk_supported_contexts); +} #else static inline int set_src_available_contexts(uint16_t contexts) { return -ENOTSUP; } + +static inline int set_src_supported_contexts(uint16_t contexts) +{ + return -ENOTSUP; +} #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SRC_LOC) @@ -602,6 +658,21 @@ static void available_contexts_notify(struct k_work *work) } } +static void supported_contexts_notify(struct k_work *work) +{ + struct bt_pacs_context context = { + .snk = sys_cpu_to_le16(snk_supported_contexts), + .src = sys_cpu_to_le16(src_supported_contexts), + }; + int err; + + err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SUPPORTED_CONTEXT, pacs_svc.attrs, + &context, sizeof(context)); + if (err != 0 && err != -ENOTCONN) { + LOG_WRN("Supported Audio Contexts notify failed: %d", err); + } +} + bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context) { if (dir == BT_AUDIO_DIR_SOURCE) { @@ -722,6 +793,18 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context return -EINVAL; } +int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts) +{ + switch (dir) { + case BT_AUDIO_DIR_SINK: + return set_snk_supported_contexts(contexts); + case BT_AUDIO_DIR_SOURCE: + return set_src_supported_contexts(contexts); + } + + return -EINVAL; +} + enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) { switch (dir) { diff --git a/subsys/bluetooth/shell/audio.c b/subsys/bluetooth/shell/audio.c index 23a3c05b21b..123490970dd 100644 --- a/subsys/bluetooth/shell/audio.c +++ b/subsys/bluetooth/shell/audio.c @@ -1887,10 +1887,21 @@ static int cmd_context(const struct shell *sh, size_t argc, char *argv[]) return err; } - err = bt_pacs_set_available_contexts(dir, ctx); - if (err) { - shell_error(ctx_shell, "Set available contexts err %d", err); - return err; + if (!strcmp(argv[3], "supported")) { + err = bt_pacs_set_supported_contexts(dir, ctx); + if (err) { + shell_error(ctx_shell, "Set supported contexts err %d", err); + return err; + } + } else if (!strcmp(argv[3], "available")) { + err = bt_pacs_set_available_contexts(dir, ctx); + if (err) { + shell_error(ctx_shell, "Set available contexts err %d", err); + return err; + } + } else { + shell_error(sh, "Unsupported context type: %s", argv[3]); + return -ENOEXEC; } return 0; @@ -1924,6 +1935,10 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, LOCATION); __ASSERT(err == 0, "Failed to set sink location"); + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, + CONTEXT); + __ASSERT(err == 0, "Failed to set sink supported contexts"); + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, CONTEXT); __ASSERT(err == 0, "Failed to set sink available contexts"); @@ -1933,6 +1948,10 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, LOCATION); __ASSERT(err == 0, "Failed to set source location"); + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, + CONTEXT); + __ASSERT(err == 0, "Failed to set sink supported contexts"); + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, CONTEXT); __ASSERT(err == 0, "Failed to set source available contexts"); @@ -2084,9 +2103,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(audio_cmds, SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_location, NULL, " ", cmd_set_loc, 3, 0), - SHELL_COND_CMD_ARG(CONFIG_BT_PACS, add_context, NULL, - " ", - cmd_context, 3, 0), + SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_context, NULL, + "" + " ", + cmd_context, 4, 0), SHELL_SUBCMD_SET_END ); diff --git a/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_server_test.c b/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_server_test.c index d080a05471a..cfff7e73712 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_server_test.c +++ b/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_server_test.c @@ -296,6 +296,14 @@ static void set_available_contexts(void) { int err; + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, + BT_AUDIO_CONTEXT_TYPE_MEDIA | + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL); + if (IS_ENABLED(CONFIG_BT_PAC_SNK) && err != 0) { + FAIL("Failed to set sink supported contexts (err %d)\n", err); + return; + } + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_MEDIA | BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL); @@ -304,6 +312,13 @@ static void set_available_contexts(void) return; } + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, + BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS); + if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) { + FAIL("Failed to set source supported contexts (err %d)\n", err); + return; + } + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS); if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) {