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:
parent
fc6b100bc8
commit
18466530ab
10 changed files with 381 additions and 89 deletions
|
@ -197,6 +197,41 @@ struct bt_codec_data {
|
|||
BT_CODEC_META_CONTEXT_RINGTONE | \
|
||||
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. */
|
||||
struct bt_codec {
|
||||
/** Codec ID */
|
||||
|
@ -1014,6 +1049,40 @@ struct bt_audio_unicast_server_cb {
|
|||
*/
|
||||
int (*publish_capability)(struct bt_conn *conn, uint8_t type,
|
||||
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 */
|
||||
|
@ -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);
|
||||
|
||||
/** @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
|
||||
* @ingroup bt_audio
|
||||
|
|
|
@ -261,6 +261,15 @@ int bt_audio_capability_register(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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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_AUDIO_STREAM stream.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_BROADCAST_SOURCE broadcast_source.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_AUDIO_BROADCAST_SINK broadcast_sink.c)
|
||||
|
|
|
@ -200,7 +200,7 @@ config BT_AUDIO_DEBUG_STREAM
|
|||
|
||||
config BT_AUDIO_DEBUG_CAPABILITIES
|
||||
bool "Bluetooth Audio Capabilities debug"
|
||||
depends on BT_AUDIO_CAPABILITIES
|
||||
depends on BT_AUDIO_CAPABILITY
|
||||
help
|
||||
Use this option to enable Bluetooth Audio Capabilities debug logs for
|
||||
the Bluetooth Audio functionality.
|
||||
|
@ -247,7 +247,7 @@ config BT_AUDIO_STREAM
|
|||
default y if BT_ASCS || BT_AUDIO_UNICAST_CLIENT || \
|
||||
BT_AUDIO_BROADCAST_SOURCE || BT_AUDIO_BROADCAST_SINK
|
||||
|
||||
config BT_AUDIO_CAPABILITIES
|
||||
config BT_AUDIO_CAPABILITY
|
||||
# Virtual/hidden option
|
||||
bool
|
||||
default y if BT_ASCS || BT_AUDIO_BROADCAST_SINK
|
||||
|
|
|
@ -19,44 +19,6 @@ config BT_PAC_SNK
|
|||
This option enables support for Sink PAC Characteristic.
|
||||
|
||||
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
|
||||
hex "Supported Sink Contexts"
|
||||
default 0x03ff
|
||||
|
@ -85,44 +47,6 @@ config BT_PAC_SRC
|
|||
This option enables support for Source PAC Characteristic.
|
||||
|
||||
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
|
||||
hex "Supported Source Contexts"
|
||||
default 0x03ff
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
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
|
||||
|
@ -258,6 +261,46 @@ static int publish_capability_cb(struct bt_conn *conn, uint8_t type,
|
|||
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 = {
|
||||
.config = unicast_server_config_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,
|
||||
.release = unicast_server_release_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 */
|
||||
|
||||
|
@ -375,3 +420,29 @@ int bt_audio_capability_unregister(struct bt_audio_capability *cap)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
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 */
|
||||
|
||||
#if defined(CONFIG_BT_PAC_SNK)
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
offset);
|
||||
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &snk_loc,
|
||||
sizeof(snk_loc));
|
||||
err = get_pac_loc(NULL, BT_AUDIO_SINK, &location);
|
||||
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,
|
||||
const struct bt_gatt_attr *attr, const void *data,
|
||||
uint16_t len, uint16_t offset, uint8_t flags)
|
||||
{
|
||||
int err;
|
||||
enum bt_audio_location location;
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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)
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
offset);
|
||||
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &src_loc,
|
||||
sizeof(src_loc));
|
||||
err = get_pac_loc(NULL, BT_AUDIO_SOURCE, &location);
|
||||
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,
|
||||
const struct bt_gatt_attr *attr, const void *data,
|
||||
uint16_t len, uint16_t offset, uint8_t flags)
|
||||
{
|
||||
int err;
|
||||
uint32_t location;
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -343,6 +441,22 @@ static struct k_work_delayable *bt_pacs_get_work(uint8_t type)
|
|||
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)
|
||||
{
|
||||
#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 */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct k_work_delayable *work;
|
||||
|
@ -403,3 +555,22 @@ void bt_pacs_remove_capability(uint8_t type)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <bluetooth/audio/audio.h>
|
||||
|
||||
#define BT_AUDIO_LOCATION_MASK BIT_MASK(28)
|
||||
|
||||
struct bt_pac_codec {
|
||||
uint8_t id; /* Codec 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_remove_capability(uint8_t type);
|
||||
int bt_pacs_location_changed(enum bt_audio_pac_type type);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <bluetooth/audio/audio.h>
|
||||
|
||||
#include "pacs_internal.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_AUDIO_DEBUG_UNICAST_SERVER)
|
||||
#define LOG_MODULE_NAME bt_unicast_server
|
||||
#include "common/log.h"
|
||||
|
@ -49,3 +51,8 @@ int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_c
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_audio_unicast_server_location_changed(enum bt_audio_pac_type type)
|
||||
{
|
||||
return bt_pacs_location_changed(type);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
init();
|
||||
|
||||
set_location();
|
||||
|
||||
/* TODO: When babblesim supports ISO, wait for audio stream to pass */
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue