Bluetooth: Audio: Make PACS location optional

Make the PACS location characteristic optional, and
also optionally writable.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2022-04-13 21:10:18 +02:00 committed by Carles Cufí
commit a796927961
7 changed files with 163 additions and 82 deletions

View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -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;

View file

@ -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 */

View file

@ -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 */

View file

@ -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));