diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index b328c6f67b7..c00949aed62 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -1070,6 +1070,7 @@ struct bt_audio_unicast_server_cb { int (*publish_capability)(struct bt_conn *conn, uint8_t type, uint8_t index, struct bt_codec *const codec); +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) /** @brief Publish location callback * * Publish location callback is called whenever a remote client @@ -1090,6 +1091,7 @@ struct bt_audio_unicast_server_cb { enum bt_audio_pac_type type, enum bt_audio_location *location); +#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) || defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE) /** @brief Write location callback * * Write location callback is called whenever a remote client @@ -1103,6 +1105,8 @@ struct bt_audio_unicast_server_cb { */ int (*write_location)(struct bt_conn *conn, enum bt_audio_pac_type type, enum bt_audio_location location); +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE || CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ }; /** Broadcast Audio Sink callback structure */ diff --git a/subsys/bluetooth/audio/Kconfig.pacs b/subsys/bluetooth/audio/Kconfig.pacs index 50a2413b79e..d8f10889ff1 100644 --- a/subsys/bluetooth/audio/Kconfig.pacs +++ b/subsys/bluetooth/audio/Kconfig.pacs @@ -37,6 +37,20 @@ config BT_PACS_SNK_CONTEXT 0x0100: Ringtone 0x0200: TV +config BT_PAC_SNK_LOC + bool "Sink PAC Location Support" + default y + help + This option enables support for Sink PAC Location Characteristic. + +config BT_PAC_SNK_LOC_WRITEABLE + bool "Sink PAC Location Writable Support" + default y + depends on BT_PAC_SNK_LOC + help + This option enables support for clients to write to the Sink PAC + Location Characteristic. + endif # BT_PACS_SNK config BT_PAC_SRC @@ -65,5 +79,19 @@ config BT_PACS_SRC_CONTEXT 0x0100: Ringtone 0x0200: TV +config BT_PAC_SRC_LOC + bool "Source PAC Location Support" + default y + help + This option enables support for Source PAC Location Characteristic. + +config BT_PAC_SRC_LOC_WRITEABLE + bool "Source PAC Location Writable Support" + default y + depends on BT_PAC_SRC_LOC + help + This option enables support for clients to write to the Source PAC + Location Characteristic. + endif # BT_PAC_SRC endif # BT_PACS diff --git a/subsys/bluetooth/audio/capabilities.c b/subsys/bluetooth/audio/capabilities.c index 5a571b246fa..790a07fb24e 100644 --- a/subsys/bluetooth/audio/capabilities.c +++ b/subsys/bluetooth/audio/capabilities.c @@ -28,9 +28,6 @@ static sys_slist_t snks; static sys_slist_t srcs; -static enum bt_audio_location sink_location; -static enum bt_audio_location source_location; - #if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) && defined(CONFIG_BT_ASCS) /* TODO: The unicast server callbacks uses `const` for many of the pointers, * wheras the capabilities callbacks do no. The latter should be updated to use @@ -261,14 +258,28 @@ static int publish_capability_cb(struct bt_conn *conn, uint8_t type, return -ENOENT; } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) + +#if defined(CONFIG_BT_PAC_SNK_LOC) +static enum bt_audio_location sink_location; +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#if defined(CONFIG_BT_PAC_SRC_LOC) +static enum bt_audio_location source_location; +#endif /* CONFIG_BT_PAC_SRC_LOC */ + static int publish_location_cb(struct bt_conn *conn, enum bt_audio_pac_type type, enum bt_audio_location *location) { - if (type == BT_AUDIO_SINK) { + if (0) { +#if defined(CONFIG_BT_PAC_SNK_LOC) + } else if (type == BT_AUDIO_SINK) { *location = sink_location; +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#if defined(CONFIG_BT_PAC_SRC_LOC) } else if (type == BT_AUDIO_SOURCE) { *location = source_location; +#endif /* CONFIG_BT_PAC_SRC_LOC */ } else { BT_ERR("Invalid endpoint type: %u", type); @@ -278,28 +289,14 @@ static int publish_location_cb(struct bt_conn *conn, return 0; } +#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) || defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE) static int write_location_cb(struct bt_conn *conn, enum bt_audio_pac_type type, enum bt_audio_location location) { - int err; - - if (type == BT_AUDIO_SINK) { - sink_location = location; - } else if (type == BT_AUDIO_SOURCE) { - source_location = location; - } else { - BT_ERR("Invalid endpoint type: %u", type); - - return -EINVAL; - } - - err = bt_audio_unicast_server_location_changed(type); - if (err) { - BT_DBG("Location for type %d wasn't notified: %d", type, err); - } - - return 0; + return bt_audio_capability_set_location(type, location); } +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE || CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ static struct bt_audio_unicast_server_cb unicast_server_cb = { .config = unicast_server_config_cb, @@ -312,8 +309,12 @@ static struct bt_audio_unicast_server_cb unicast_server_cb = { .stop = unicast_server_stop_cb, .release = unicast_server_release_cb, .publish_capability = publish_capability_cb, +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) .publish_location = publish_location_cb, +#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) || defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE) .write_location = write_location_cb +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE || CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ }; #endif /* CONFIG_BT_AUDIO_UNICAST_SERVER && CONFIG_BT_ASCS */ @@ -421,15 +422,21 @@ int bt_audio_capability_unregister(struct bt_audio_capability *cap) return 0; } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) int bt_audio_capability_set_location(enum bt_audio_pac_type type, enum bt_audio_location location) { int err; - if (type == BT_AUDIO_SINK) { + if (0) { +#if defined(CONFIG_BT_PAC_SNK_LOC) + } else if (type == BT_AUDIO_SINK) { sink_location = location; +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#if defined(CONFIG_BT_PAC_SRC_LOC) } else if (type == BT_AUDIO_SOURCE) { source_location = location; +#endif /* CONFIG_BT_PAC_SRC_LOC */ } else { BT_ERR("Invalid endpoint type: %u", type); @@ -446,3 +453,4 @@ int bt_audio_capability_set_location(enum bt_audio_pac_type type, return 0; } +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index 47f759322a9..401aed27989 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -598,17 +598,23 @@ static int has_init(const struct device *dev) has.features |= BT_HAS_FEAT_WRITABLE_PRESETS_SUPP; } - if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BANDED)) { - /* HAP_d1.0r00; 3.7 BAP Unicast Server role requirements - * A Banded Hearing Aid in the HA role shall set the Front Left and the Front - * Right bits to a value of 0b1 in the Sink Audio Locations characteristic value. - */ - bt_audio_capability_set_location(BT_AUDIO_SINK, BT_AUDIO_LOCATION_FRONT_LEFT | - BT_AUDIO_LOCATION_FRONT_RIGHT); - } else if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_LEFT)) { - bt_audio_capability_set_location(BT_AUDIO_SINK, BT_AUDIO_LOCATION_FRONT_LEFT); - } else { - bt_audio_capability_set_location(BT_AUDIO_SINK, BT_AUDIO_LOCATION_FRONT_RIGHT); + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { + if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BANDED)) { + /* HAP_d1.0r00; 3.7 BAP Unicast Server role requirements + * A Banded Hearing Aid in the HA role shall set the + * Front Left and the Front Right bits to a value of 0b1 + * in the Sink Audio Locations characteristic value. + */ + bt_audio_capability_set_location(BT_AUDIO_SINK, + (BT_AUDIO_LOCATION_FRONT_LEFT | + BT_AUDIO_LOCATION_FRONT_RIGHT)); + } else if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_LEFT)) { + bt_audio_capability_set_location(BT_AUDIO_SINK, + BT_AUDIO_LOCATION_FRONT_LEFT); + } else { + bt_audio_capability_set_location(BT_AUDIO_SINK, + BT_AUDIO_LOCATION_FRONT_RIGHT); + } } return 0; diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index b158a814ff9..2695130b3a4 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -172,6 +172,7 @@ static ssize_t supported_context_read(struct bt_conn *conn, sizeof(context)); } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) static int get_pac_loc(struct bt_conn *conn, enum bt_audio_pac_type type, enum bt_audio_location *location) { @@ -192,11 +193,11 @@ static int get_pac_loc(struct bt_conn *conn, enum bt_audio_pac_type type, return 0; } +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ #endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SNK) static struct k_work_delayable snks_work; -static struct k_work_delayable snks_loc_work; static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) @@ -207,6 +208,14 @@ static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return pac_read(conn, attr, buf, len, offset); } +static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + BT_DBG("attr %p value 0x%04x", attr, value); +} + +#if defined(CONFIG_BT_PAC_SNK_LOC) +static struct k_work_delayable snks_loc_work; + static ssize_t snk_loc_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) @@ -237,6 +246,7 @@ static ssize_t snk_loc_read(struct bt_conn *conn, &location_32_le, sizeof(location_32_le)); } +#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) static ssize_t snk_loc_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, uint16_t len, uint16_t offset, uint8_t flags) @@ -272,21 +282,18 @@ static ssize_t snk_loc_write(struct bt_conn *conn, return len; } - -static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) -{ - BT_DBG("attr %p value 0x%04x", attr, value); -} +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */ static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { BT_DBG("attr %p value 0x%04x", attr, value); } + +#endif /* CONFIG_BT_PAC_SNK_LOC */ #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) static struct k_work_delayable srcs_work; -static struct k_work_delayable srcs_loc_work; static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) @@ -297,6 +304,14 @@ static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return pac_read(conn, attr, buf, len, offset); } +static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + BT_DBG("attr %p value 0x%04x", attr, value); +} + +#if defined(CONFIG_BT_PAC_SRC_LOC) +static struct k_work_delayable srcs_loc_work; + static ssize_t src_loc_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) @@ -327,6 +342,7 @@ static ssize_t src_loc_read(struct bt_conn *conn, &location_32_le, sizeof(location_32_le)); } +#if defined(BT_PAC_SRC_LOC_WRITEABLE) static ssize_t src_loc_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, uint16_t len, uint16_t offset, uint8_t flags) @@ -363,16 +379,13 @@ static ssize_t src_loc_write(struct bt_conn *conn, return len; } - -static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) -{ - BT_DBG("attr %p value 0x%04x", attr, value); -} +#endif /* BT_PAC_SRC_LOC_WRITEABLE */ static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { BT_DBG("attr %p value 0x%04x", attr, value); } +#endif /* CONFIG_BT_PAC_SRC_LOC */ #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC) @@ -385,14 +398,22 @@ BT_GATT_SERVICE_DEFINE(pacs_svc, snk_read, NULL, NULL), BT_GATT_CCC(snk_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), +#if defined(CONFIG_BT_PAC_SNK_LOC) BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SNK_LOC, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, - snk_loc_read, snk_loc_write, NULL), + snk_loc_read, +#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) + snk_loc_write, +#else + NULL, +#endif /* BT_PAC_SRC_LOC_WRITEABLE */ + NULL), BT_GATT_CCC(snk_loc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), +#endif /* CONFIG_BT_PAC_SNK_LOC */ #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SRC, @@ -401,14 +422,22 @@ BT_GATT_SERVICE_DEFINE(pacs_svc, src_read, NULL, NULL), BT_GATT_CCC(src_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), +#if defined(CONFIG_BT_PAC_SRC_LOC) BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SRC_LOC, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, - src_loc_read, src_loc_write, NULL), + src_loc_read, +#if defined(BT_PAC_SRC_LOC_WRITEABLE) + src_loc_write, +#else + NULL, +#endif /* BT_PAC_SRC_LOC_WRITEABLE */ + NULL), BT_GATT_CCC(src_loc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), +#endif /* CONFIG_BT_PAC_SRC_LOC */ #endif /* CONFIG_BT_PAC_SNK */ BT_GATT_CHARACTERISTIC(BT_UUID_PACS_CONTEXT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, @@ -441,6 +470,7 @@ static struct k_work_delayable *bt_pacs_get_work(uint8_t type) return NULL; } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) static struct k_work_delayable *bt_pacs_get_loc_work(uint8_t type) { switch (type) { @@ -457,38 +487,6 @@ static struct k_work_delayable *bt_pacs_get_loc_work(uint8_t type) return NULL; } -static void pac_notify(struct k_work *work) -{ -#if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC) - struct bt_uuid *uuid; - uint8_t type; - int err; - -#if defined(CONFIG_BT_PAC_SNK) - if (work == &snks_work.work) { - type = BT_AUDIO_SINK; - uuid = BT_UUID_PACS_SNK; - } -#endif /* CONFIG_BT_PAC_SNK */ - -#if defined(CONFIG_BT_PAC_SRC) - if (work == &srcs_work.work) { - type = BT_AUDIO_SOURCE; - uuid = BT_UUID_PACS_SRC; - } -#endif /* CONFIG_BT_PAC_SRC */ - - /* TODO: We can skip this if we are not connected to any devices */ - get_pac_records(NULL, type, &read_buf); - - err = bt_gatt_notify_uuid(NULL, uuid, pacs_svc.attrs, read_buf.data, - read_buf.len); - if (err != 0) { - BT_WARN("PACS notify failed: %d", err); - } -#endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ -} - static void pac_notify_loc(struct k_work *work) { #if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC) @@ -526,6 +524,39 @@ static void pac_notify_loc(struct k_work *work) } #endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ } +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ + +static void pac_notify(struct k_work *work) +{ +#if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC) + struct bt_uuid *uuid; + uint8_t type; + int err; + +#if defined(CONFIG_BT_PAC_SNK) + if (work == &snks_work.work) { + type = BT_AUDIO_SINK; + uuid = BT_UUID_PACS_SNK; + } +#endif /* CONFIG_BT_PAC_SNK */ + +#if defined(CONFIG_BT_PAC_SRC) + if (work == &srcs_work.work) { + type = BT_AUDIO_SOURCE; + uuid = BT_UUID_PACS_SRC; + } +#endif /* CONFIG_BT_PAC_SRC */ + + /* TODO: We can skip this if we are not connected to any devices */ + get_pac_records(NULL, type, &read_buf); + + err = bt_gatt_notify_uuid(NULL, uuid, pacs_svc.attrs, read_buf.data, + read_buf.len); + if (err != 0) { + BT_WARN("PACS notify failed: %d", err); + } +#endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ +} void bt_pacs_add_capability(uint8_t type) { @@ -556,6 +587,7 @@ void bt_pacs_remove_capability(uint8_t type) k_work_reschedule(work, PAC_NOTIFY_TIMEOUT); } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) int bt_pacs_location_changed(enum bt_audio_pac_type type) { struct k_work_delayable *work; @@ -574,3 +606,4 @@ int bt_pacs_location_changed(enum bt_audio_pac_type type) return 0; } +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ diff --git a/subsys/bluetooth/audio/unicast_server.c b/subsys/bluetooth/audio/unicast_server.c index 58c7a0f8db6..f9e791251d5 100644 --- a/subsys/bluetooth/audio/unicast_server.c +++ b/subsys/bluetooth/audio/unicast_server.c @@ -52,7 +52,9 @@ int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_c return 0; } +#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC) int bt_audio_unicast_server_location_changed(enum bt_audio_pac_type type) { return bt_pacs_location_changed(type); } +#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */ 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 1c9d95d1101..4102c79db90 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 @@ -209,7 +209,7 @@ static void set_location(void) { int err; - if (IS_ENABLED(CONFIG_BT_PAC_SNK)) { + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { err = bt_audio_capability_set_location(BT_AUDIO_SINK, BT_AUDIO_LOCATION_FRONT_CENTER); if (err != 0) { @@ -218,7 +218,7 @@ static void set_location(void) } } - if (IS_ENABLED(CONFIG_BT_PAC_SRC)) { + if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) { err = bt_audio_capability_set_location(BT_AUDIO_SINK, (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT));