Bluetooth: PACS: Refactor PAC location read/write

Refactor the PAC location read and write. Instead
of storing the location in the service, the
location is now stored in the application, and
is retrieved by the service via callbacks.

Similarly, if a client writes the location, this
request is being sent to the application.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2022-02-08 14:43:43 +01:00 committed by Marti Bolivar
commit 18466530ab
10 changed files with 381 additions and 89 deletions

View file

@ -197,6 +197,41 @@ struct bt_codec_data {
BT_CODEC_META_CONTEXT_RINGTONE | \ BT_CODEC_META_CONTEXT_RINGTONE | \
BT_CODEC_META_CONTEXT_TV) BT_CODEC_META_CONTEXT_TV)
/** Location values for BT Audio.
*
* These values are defined by the Generic Audio Assigned Numbers
*/
enum bt_audio_location {
BT_AUDIO_LOCATION_FRONT_LEFT = BIT(0),
BT_AUDIO_LOCATION_FRONT_RIGHT = BIT(1),
BT_AUDIO_LOCATION_FRONT_CENTER = BIT(2),
BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 = BIT(3),
BT_AUDIO_LOCATION_BACK_LEFT = BIT(4),
BT_AUDIO_LOCATION_BACK_RIGHT = BIT(5),
BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER = BIT(6),
BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER = BIT(7),
BT_AUDIO_LOCATION_BACK_CENTER = BIT(8),
BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 = BIT(9),
BT_AUDIO_LOCATION_SIDE_LEFT = BIT(10),
BT_AUDIO_LOCATION_SIDE_RIGHT = BIT(11),
BT_AUDIO_LOCATION_TOP_FRONT_LEFT = BIT(12),
BT_AUDIO_LOCATION_TOP_FRONT_RIGHT = BIT(13),
BT_AUDIO_LOCATION_TOP_FRONT_CENTER = BIT(14),
BT_AUDIO_LOCATION_TOP_CENTER = BIT(15),
BT_AUDIO_LOCATION_TOP_BACK_LEFT = BIT(16),
BT_AUDIO_LOCATION_TOP_BECK_RIGHT = BIT(17),
BT_AUDIO_LOCATION_TOP_SIDE_LEFT = BIT(18),
BT_AUDIO_LOCATION_TOP_SIDE_RIGHT = BIT(19),
BT_AUDIO_LOCATION_TOP_BACK_CENTER = BIT(20),
BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER = BIT(21),
BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT = BIT(22),
BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT = BIT(23),
BT_AUDIO_LOCATION_FRONT_LEFT_WIDE = BIT(24),
BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE = BIT(25),
BT_AUDIO_LOCATION_LEFT_SURROUND = BIT(26),
BT_AUDIO_LOCATION_RIGHT_SURROUND = BIT(27),
};
/** @brief Codec structure. */ /** @brief Codec structure. */
struct bt_codec { struct bt_codec {
/** Codec ID */ /** Codec ID */
@ -1014,6 +1049,40 @@ struct bt_audio_unicast_server_cb {
*/ */
int (*publish_capability)(struct bt_conn *conn, uint8_t type, int (*publish_capability)(struct bt_conn *conn, uint8_t type,
uint8_t index, struct bt_codec *const codec); uint8_t index, struct bt_codec *const codec);
/** @brief Publish location callback
*
* Publish location callback is called whenever a remote client
* requests to read the Published Audio Capabilities (PAC) location,
* or if the location needs to be notified.
*
* @param[in] conn The connection that requests the location.
* Will be NULL if the location is requested
* for sending a notification, as a result of
* callling
* bt_audio_unicast_server_location_changed().
* @param[in] type Type of the endpoint.
* @param[out] location Pointer to the location that needs to be set.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*publish_location)(struct bt_conn *conn,
enum bt_audio_pac_type type,
enum bt_audio_location *location);
/** @brief Write location callback
*
* Write location callback is called whenever a remote client
* requests to write the Published Audio Capabilities (PAC) location.
*
* @param conn The connection that requests the write.
* @param type Type of the endpoint.
* @param location The location being written.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*write_location)(struct bt_conn *conn, enum bt_audio_pac_type type,
enum bt_audio_location location);
}; };
/** Broadcast Audio Sink callback structure */ /** Broadcast Audio Sink callback structure */
@ -1238,6 +1307,14 @@ int bt_audio_unicast_server_register_cb(const struct bt_audio_unicast_server_cb
*/ */
int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_cb *cb); int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_cb *cb);
/** @brief Notify location changed
*
* Notify connected clients that the location has changed
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_audio_unicast_server_location_changed(enum bt_audio_pac_type type);
/** /**
* @defgroup bt_audio_client Audio Client APIs * @defgroup bt_audio_client Audio Client APIs
* @ingroup bt_audio * @ingroup bt_audio

View file

@ -261,6 +261,15 @@ int bt_audio_capability_register(struct bt_audio_capability *cap);
*/ */
int bt_audio_capability_unregister(struct bt_audio_capability *cap); int bt_audio_capability_unregister(struct bt_audio_capability *cap);
/** @brief Set the location for an endpoint type
*
* @param type Type of the endpoint.
* @param location The location to be set.
*
*/
int bt_audio_capability_set_location(enum bt_audio_pac_type type,
enum bt_audio_location location);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -44,7 +44,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_ASCS ascs.c)
zephyr_library_sources_ifdef(CONFIG_BT_PACS pacs.c) zephyr_library_sources_ifdef(CONFIG_BT_PACS pacs.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_STREAM stream.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_STREAM stream.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_UNICAST_SERVER unicast_server.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_UNICAST_SERVER unicast_server.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_CAPABILITIES capabilities.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_CAPABILITY capabilities.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_UNICAST_CLIENT unicast_client.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_UNICAST_CLIENT unicast_client.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_BROADCAST_SOURCE broadcast_source.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_BROADCAST_SOURCE broadcast_source.c)
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_BROADCAST_SINK broadcast_sink.c) zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_BROADCAST_SINK broadcast_sink.c)

View file

@ -200,7 +200,7 @@ config BT_AUDIO_DEBUG_STREAM
config BT_AUDIO_DEBUG_CAPABILITIES config BT_AUDIO_DEBUG_CAPABILITIES
bool "Bluetooth Audio Capabilities debug" bool "Bluetooth Audio Capabilities debug"
depends on BT_AUDIO_CAPABILITIES depends on BT_AUDIO_CAPABILITY
help help
Use this option to enable Bluetooth Audio Capabilities debug logs for Use this option to enable Bluetooth Audio Capabilities debug logs for
the Bluetooth Audio functionality. the Bluetooth Audio functionality.
@ -247,7 +247,7 @@ config BT_AUDIO_STREAM
default y if BT_ASCS || BT_AUDIO_UNICAST_CLIENT || \ default y if BT_ASCS || BT_AUDIO_UNICAST_CLIENT || \
BT_AUDIO_BROADCAST_SOURCE || BT_AUDIO_BROADCAST_SINK BT_AUDIO_BROADCAST_SOURCE || BT_AUDIO_BROADCAST_SINK
config BT_AUDIO_CAPABILITIES config BT_AUDIO_CAPABILITY
# Virtual/hidden option # Virtual/hidden option
bool bool
default y if BT_ASCS || BT_AUDIO_BROADCAST_SINK default y if BT_ASCS || BT_AUDIO_BROADCAST_SINK

View file

@ -19,44 +19,6 @@ config BT_PAC_SNK
This option enables support for Sink PAC Characteristic. This option enables support for Sink PAC Characteristic.
if BT_PAC_SNK if BT_PAC_SNK
config BT_PAC_SNK_LOC
hex "Sink PAC Locations Characteristic Support"
default 0x00000000
range 0x00000000 0x0ffffff
help
This option enables support for Sink PAC Locations Characteristic.
Bitmap of Audio Location values for PAC records where the server acts
as an Audio Sink:
0x00000000: Mono/Unespecified
0x00000001: Front Left
0x00000002: Front Right
0x00000004: Front Center
0x00000008: Low Frequency Effects 1
0x00000010: Back Left
0x00000020: Back Right
0x00000040: Front Left of Center
0x00000080: Front Right of Center
0x00000100: Back Center
0x00000200: Low Frequency Effects 2
0x00000400: Side Left
0x00000800: Side Right
0x00001000: Top Front Left
0x00002000: Top Front Right
0x00004000: Top Front Center
0x00008000: Top Center
0x00010000: Top Back Left
0x00020000: Top Back Right
0x00040000: Top Side Left
0x00080000: Top Side Right
0x00100000: Top Back Center
0x00200000: Bottom Front Center
0x00400000: Bottom Front Left
0x00800000: Bottom Front Right
0x01000000: Front Left Wide
0x02000000: Front Right Wide
0x01000000: Left Surround
0x02000000: Right Surround
config BT_PACS_SNK_CONTEXT config BT_PACS_SNK_CONTEXT
hex "Supported Sink Contexts" hex "Supported Sink Contexts"
default 0x03ff default 0x03ff
@ -85,44 +47,6 @@ config BT_PAC_SRC
This option enables support for Source PAC Characteristic. This option enables support for Source PAC Characteristic.
if BT_PAC_SRC if BT_PAC_SRC
config BT_PAC_SRC_LOC
hex "Source PAC Locations Characteristic Support"
default 0x00000000
range 0x00000000 0x0ffffff
help
This option enables support for Source PAC Locations Characteristic.
Bitmap of Audio Location values for PAC records where the server acts
as an Audio Source:
0x00000000: Mono/Unespecified
0x00000001: Front Left
0x00000002: Front Right
0x00000004: Front Center
0x00000008: Low Frequency Effects 1
0x00000010: Back Left
0x00000020: Back Right
0x00000040: Front Left of Center
0x00000080: Front Right of Center
0x00000100: Back Center
0x00000200: Low Frequency Effects 2
0x00000400: Side Left
0x00000800: Side Right
0x00001000: Top Front Left
0x00002000: Top Front Right
0x00004000: Top Front Center
0x00008000: Top Center
0x00010000: Top Back Left
0x00020000: Top Back Right
0x00040000: Top Side Left
0x00080000: Top Side Right
0x00100000: Top Back Center
0x00200000: Bottom Front Center
0x00400000: Bottom Front Left
0x00800000: Bottom Front Right
0x01000000: Front Left Wide
0x02000000: Front Right Wide
0x01000000: Left Surround
0x02000000: Right Surround
config BT_PACS_SRC_CONTEXT config BT_PACS_SRC_CONTEXT
hex "Supported Source Contexts" hex "Supported Source Contexts"
default 0x03ff default 0x03ff

View file

@ -28,6 +28,9 @@
static sys_slist_t snks; static sys_slist_t snks;
static sys_slist_t srcs; 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) #if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) && defined(CONFIG_BT_ASCS)
/* TODO: The unicast server callbacks uses `const` for many of the pointers, /* 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 * wheras the capabilities callbacks do no. The latter should be updated to use
@ -258,6 +261,46 @@ static int publish_capability_cb(struct bt_conn *conn, uint8_t type,
return -ENOENT; return -ENOENT;
} }
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) {
*location = sink_location;
} else if (type == BT_AUDIO_SOURCE) {
*location = source_location;
} else {
BT_ERR("Invalid endpoint type: %u", type);
return -EINVAL;
}
return 0;
}
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;
}
static struct bt_audio_unicast_server_cb unicast_server_cb = { static struct bt_audio_unicast_server_cb unicast_server_cb = {
.config = unicast_server_config_cb, .config = unicast_server_config_cb,
.reconfig = unicast_server_reconfig_cb, .reconfig = unicast_server_reconfig_cb,
@ -269,6 +312,8 @@ static struct bt_audio_unicast_server_cb unicast_server_cb = {
.stop = unicast_server_stop_cb, .stop = unicast_server_stop_cb,
.release = unicast_server_release_cb, .release = unicast_server_release_cb,
.publish_capability = publish_capability_cb, .publish_capability = publish_capability_cb,
.publish_location = publish_location_cb,
.write_location = write_location_cb
}; };
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER && CONFIG_BT_ASCS */ #endif /* CONFIG_BT_AUDIO_UNICAST_SERVER && CONFIG_BT_ASCS */
@ -375,3 +420,29 @@ int bt_audio_capability_unregister(struct bt_audio_capability *cap)
return 0; return 0;
} }
int bt_audio_capability_set_location(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;
}
if (IS_ENABLED(CONFIG_BT_AUDIO_UNICAST_SERVER)) {
err = bt_audio_unicast_server_location_changed(type);
if (err) {
BT_DBG("Location for type %d wasn't notified: %d",
type, err);
}
}
return 0;
}

View file

@ -171,11 +171,32 @@ static ssize_t supported_context_read(struct bt_conn *conn,
return bt_gatt_attr_read(conn, attr, buf, len, offset, &context, return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
sizeof(context)); sizeof(context));
} }
static int get_pac_loc(struct bt_conn *conn, enum bt_audio_pac_type type,
enum bt_audio_location *location)
{
int err;
if (unicast_server_cb == NULL ||
unicast_server_cb->publish_location == NULL) {
BT_WARN("No callback for publish_location");
return -ENODATA;
}
err = unicast_server_cb->publish_location(conn, type, location);
if (err != 0 || *location == 0) {
BT_DBG("err (%d) or invalid location value (%u)",
err, *location);
return -ENODATA;
}
return 0;
}
#endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ #endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */
#if defined(CONFIG_BT_PAC_SNK) #if defined(CONFIG_BT_PAC_SNK)
static struct k_work_delayable snks_work; static struct k_work_delayable snks_work;
static uint32_t snk_loc = CONFIG_BT_PAC_SNK_LOC; static struct k_work_delayable snks_loc_work;
static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
@ -190,26 +211,64 @@ static ssize_t snk_loc_read(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
int err;
enum bt_audio_location location;
uint32_t location_32;
uint32_t location_32_le;
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
offset); offset);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &snk_loc, err = get_pac_loc(NULL, BT_AUDIO_SINK, &location);
sizeof(snk_loc)); if (err != 0) {
BT_DBG("get_pac_loc returned %d", err);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location_32 = (uint32_t)location;
if (location_32 > BT_AUDIO_LOCATION_MASK || location_32 == 0) {
BT_ERR("Invalid location value: 0x%08X", location_32);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location_32_le = sys_cpu_to_le32(location_32);
return bt_gatt_attr_read(conn, attr, buf, len, offset,
&location_32_le, sizeof(location_32_le));
} }
static ssize_t snk_loc_write(struct bt_conn *conn, static ssize_t snk_loc_write(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const void *data, const struct bt_gatt_attr *attr, const void *data,
uint16_t len, uint16_t offset, uint8_t flags) uint16_t len, uint16_t offset, uint8_t flags)
{ {
int err;
enum bt_audio_location location;
if (offset) { if (offset) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
if (len != sizeof(snk_loc)) { if (len != sizeof(location)) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
snk_loc = sys_get_le32(data); if (unicast_server_cb == NULL ||
unicast_server_cb->write_location == NULL) {
BT_WARN("No callback for write_location");
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location = (enum bt_audio_location)sys_get_le32(data);
if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
BT_DBG("Invalid location value: 0x%08X", location);
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
}
err = unicast_server_cb->write_location(conn, BT_AUDIO_SINK, location);
if (err != 0) {
BT_DBG("write_location returned %d", err);
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
}
return len; return len;
} }
@ -227,7 +286,7 @@ static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
#if defined(CONFIG_BT_PAC_SRC) #if defined(CONFIG_BT_PAC_SRC)
static struct k_work_delayable srcs_work; static struct k_work_delayable srcs_work;
static uint32_t src_loc = CONFIG_BT_PAC_SRC_LOC; static struct k_work_delayable srcs_loc_work;
static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
@ -242,26 +301,65 @@ static ssize_t src_loc_read(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
int err;
enum bt_audio_location location;
uint32_t location_32;
uint32_t location_32_le;
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
offset); offset);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &src_loc, err = get_pac_loc(NULL, BT_AUDIO_SOURCE, &location);
sizeof(src_loc)); if (err != 0) {
BT_DBG("get_pac_loc returned %d", err);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location_32 = (uint32_t)location;
if (location_32 > BT_AUDIO_LOCATION_MASK || location_32 == 0) {
BT_ERR("Invalid location value: 0x%08X", location_32);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location_32_le = sys_cpu_to_le32(location_32);
return bt_gatt_attr_read(conn, attr, buf, len, offset,
&location_32_le, sizeof(location_32_le));
} }
static ssize_t src_loc_write(struct bt_conn *conn, static ssize_t src_loc_write(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const void *data, const struct bt_gatt_attr *attr, const void *data,
uint16_t len, uint16_t offset, uint8_t flags) uint16_t len, uint16_t offset, uint8_t flags)
{ {
int err;
uint32_t location;
if (offset) { if (offset) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
if (len != sizeof(src_loc)) { if (len != sizeof(location)) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
src_loc = sys_get_le32(data); if (unicast_server_cb == NULL ||
unicast_server_cb->write_location == NULL) {
BT_WARN("No callback for write_location");
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
location = (enum bt_audio_location)sys_get_le32(data);
if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
BT_DBG("Invalid location value: 0x%08X", location);
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
}
err = unicast_server_cb->write_location(conn, BT_AUDIO_SOURCE,
location);
if (err != 0) {
BT_DBG("write_location returned %d", err);
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
}
return len; return len;
} }
@ -343,6 +441,22 @@ static struct k_work_delayable *bt_pacs_get_work(uint8_t type)
return NULL; return NULL;
} }
static struct k_work_delayable *bt_pacs_get_loc_work(uint8_t type)
{
switch (type) {
#if defined(CONFIG_BT_PAC_SNK)
case BT_AUDIO_SINK:
return &snks_loc_work;
#endif /* CONFIG_BT_PAC_SNK */
#if defined(CONFIG_BT_PAC_SRC)
case BT_AUDIO_SOURCE:
return &srcs_loc_work;
#endif /* CONFIG_BT_PAC_SNK */
}
return NULL;
}
static void pac_notify(struct k_work *work) static void pac_notify(struct k_work *work)
{ {
#if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC) #if defined(CONFIG_BT_PAC_SNK) || defined(CONFIG_BT_PAC_SRC)
@ -375,6 +489,44 @@ static void pac_notify(struct k_work *work)
#endif /* CONFIG_BT_PAC_SNK || CONFIG_BT_PAC_SRC */ #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)
uint32_t location;
struct bt_uuid *uuid;
enum bt_audio_pac_type type;
int err;
#if defined(CONFIG_BT_PAC_SNK)
if (work == &snks_loc_work.work) {
type = BT_AUDIO_SINK;
uuid = BT_UUID_PACS_SNK_LOC;
}
#endif /* CONFIG_BT_PAC_SNK */
#if defined(CONFIG_BT_PAC_SRC)
if (work == &srcs_loc_work.work) {
type = BT_AUDIO_SOURCE;
uuid = BT_UUID_PACS_SRC_LOC;
}
#endif /* CONFIG_BT_PAC_SRC */
/* TODO: We can skip this if we are not connected to any devices */
err = get_pac_loc(NULL, type, &location);
if (err != 0) {
BT_DBG("get_pac_loc returned %d, won't notify", err);
return;
}
err = bt_gatt_notify_uuid(NULL, uuid, pacs_svc.attrs,
&sys_cpu_to_le32(location),
sizeof(location));
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) void bt_pacs_add_capability(uint8_t type)
{ {
struct k_work_delayable *work; struct k_work_delayable *work;
@ -403,3 +555,22 @@ void bt_pacs_remove_capability(uint8_t type)
k_work_reschedule(work, PAC_NOTIFY_TIMEOUT); k_work_reschedule(work, PAC_NOTIFY_TIMEOUT);
} }
int bt_pacs_location_changed(enum bt_audio_pac_type type)
{
struct k_work_delayable *work;
work = bt_pacs_get_loc_work(type);
if (!work) {
return -EINVAL;
}
/* Initialize handler if it hasn't been initialized */
if (!work->work.handler) {
k_work_init_delayable(work, pac_notify_loc);
}
k_work_reschedule(work, PAC_NOTIFY_TIMEOUT);
return 0;
}

View file

@ -7,6 +7,10 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <bluetooth/audio/audio.h>
#define BT_AUDIO_LOCATION_MASK BIT_MASK(28)
struct bt_pac_codec { struct bt_pac_codec {
uint8_t id; /* Codec ID */ uint8_t id; /* Codec ID */
uint16_t cid; /* Company ID */ uint16_t cid; /* Company ID */
@ -48,3 +52,4 @@ struct bt_pacs_context {
void bt_pacs_add_capability(uint8_t type); void bt_pacs_add_capability(uint8_t type);
void bt_pacs_remove_capability(uint8_t type); void bt_pacs_remove_capability(uint8_t type);
int bt_pacs_location_changed(enum bt_audio_pac_type type);

View file

@ -10,6 +10,8 @@
#include <bluetooth/audio/audio.h> #include <bluetooth/audio/audio.h>
#include "pacs_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_AUDIO_DEBUG_UNICAST_SERVER) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_AUDIO_DEBUG_UNICAST_SERVER)
#define LOG_MODULE_NAME bt_unicast_server #define LOG_MODULE_NAME bt_unicast_server
#include "common/log.h" #include "common/log.h"
@ -49,3 +51,8 @@ int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_c
return 0; return 0;
} }
int bt_audio_unicast_server_location_changed(enum bt_audio_pac_type type)
{
return bt_pacs_location_changed(type);
}

View file

@ -205,10 +205,38 @@ static void init(void)
} }
} }
static void set_location(void)
{
int err;
if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
err = bt_audio_capability_set_location(BT_AUDIO_SINK,
BT_AUDIO_LOCATION_FRONT_CENTER);
if (err != 0) {
FAIL("Failed to set sink location (err %d)\n", err);
return;
}
}
if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
err = bt_audio_capability_set_location(BT_AUDIO_SINK,
(BT_AUDIO_LOCATION_FRONT_LEFT |
BT_AUDIO_LOCATION_FRONT_RIGHT));
if (err != 0) {
FAIL("Failed to set source location (err %d)\n", err);
return;
}
}
printk("Location successfully set\n");
}
static void test_main(void) static void test_main(void)
{ {
init(); init();
set_location();
/* TODO: When babblesim supports ISO, wait for audio stream to pass */ /* TODO: When babblesim supports ISO, wait for audio stream to pass */
WAIT_FOR_FLAG(flag_connected); WAIT_FOR_FLAG(flag_connected);