Bluetooth: Audio: Add PACS for broadcast sink
Add support for using PACS and/or capabilities for the broadcast sink role. PACS and capabilities were originally only supported for the unicast server role, so the PACS callbacks were moved their own struct, as if a device supports both the unicast server role and the broadcast sink role, it will only have a single PACS instance. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
79fcb6ab43
commit
bb6c0866d8
11 changed files with 167 additions and 82 deletions
|
@ -1367,7 +1367,15 @@ struct bt_audio_unicast_server_cb {
|
||||||
* @return 0 in case of success or negative value in case of error.
|
* @return 0 in case of success or negative value in case of error.
|
||||||
*/
|
*/
|
||||||
int (*release)(struct bt_audio_stream *stream);
|
int (*release)(struct bt_audio_stream *stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Callback structure for the Public Audio Capabilities Service (PACS)
|
||||||
|
*
|
||||||
|
* This is used for the Unicast Server
|
||||||
|
* (@kconfig{CONFIG_BT_AUDIO_UNICAST_SERVER}) and Broadcast Sink
|
||||||
|
* (@kconfig{CONFIG_BT_AUDIO_BROADCAST_SINK}) roles.
|
||||||
|
*/
|
||||||
|
struct bt_audio_pacs_cb {
|
||||||
/** @brief Get available audio contexts callback
|
/** @brief Get available audio contexts callback
|
||||||
*
|
*
|
||||||
* Get available audio contexts callback is called whenever a remote client
|
* Get available audio contexts callback is called whenever a remote client
|
||||||
|
@ -1377,7 +1385,7 @@ struct bt_audio_unicast_server_cb {
|
||||||
* @param[in] conn The connection that requests the available audio
|
* @param[in] conn The connection that requests the available audio
|
||||||
* contexts. Will be NULL if requested for sending
|
* contexts. Will be NULL if requested for sending
|
||||||
* a notification, as a result of calling
|
* a notification, as a result of calling
|
||||||
* bt_audio_unicast_server_available_contexts_changed().
|
* bt_pacs_available_contexts_changed().
|
||||||
* @param[in] dir Direction of the endpoint.
|
* @param[in] dir Direction of the endpoint.
|
||||||
* @param[out] context Pointer to the contexts that needs to be set.
|
* @param[out] context Pointer to the contexts that needs to be set.
|
||||||
*
|
*
|
||||||
|
@ -1422,8 +1430,7 @@ struct bt_audio_unicast_server_cb {
|
||||||
* @param[in] conn The connection that requests the location.
|
* @param[in] conn The connection that requests the location.
|
||||||
* Will be NULL if the location is requested
|
* Will be NULL if the location is requested
|
||||||
* for sending a notification, as a result of
|
* for sending a notification, as a result of
|
||||||
* calling
|
* calling bt_audio_pacs_location_changed().
|
||||||
* bt_audio_unicast_server_location_changed().
|
|
||||||
* @param[in] dir Direction of the endpoint.
|
* @param[in] dir Direction of the endpoint.
|
||||||
* @param[out] location Pointer to the location that needs to be set.
|
* @param[out] location Pointer to the location that needs to be set.
|
||||||
*
|
*
|
||||||
|
@ -1662,6 +1669,40 @@ void bt_audio_stream_cb_register(struct bt_audio_stream *stream,
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @brief Register Published Audio Capabilities Service callbacks.
|
||||||
|
*
|
||||||
|
* Only one callback structure can be registered, and attempting to
|
||||||
|
* registering more than one will result in an error.
|
||||||
|
*
|
||||||
|
* This can only be done for the Unicast Server
|
||||||
|
* (@kconfig{CONFIG_BT_AUDIO_UNICAST_SERVER}) and Broadcast Sink
|
||||||
|
* (@kconfig{CONFIG_BT_AUDIO_BROADCAST_SINK}) roles.
|
||||||
|
*
|
||||||
|
* Calling bt_audio_capability_register() will implicitly register the
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* @param cb Unicast server callback structure.
|
||||||
|
*
|
||||||
|
* @return 0 in case of success or negative value in case of error.
|
||||||
|
*/
|
||||||
|
int bt_audio_pacs_register_cb(const struct bt_audio_pacs_cb *cb);
|
||||||
|
|
||||||
|
/** @brief Notify that the location has changed
|
||||||
|
*
|
||||||
|
* @param dir Direction of the location changed.
|
||||||
|
*
|
||||||
|
* @return 0 in case of success or negative value in case of error.
|
||||||
|
*/
|
||||||
|
int bt_audio_pacs_location_changed(enum bt_audio_dir dir);
|
||||||
|
|
||||||
|
/** @brief Notify available audio contexts changed
|
||||||
|
*
|
||||||
|
* Notify connected clients that the available audio contexts has changed
|
||||||
|
*
|
||||||
|
* @return 0 in case of success or negative value in case of error.
|
||||||
|
*/
|
||||||
|
int bt_pacs_available_contexts_changed(void);
|
||||||
|
|
||||||
/** @brief Register unicast server callbacks.
|
/** @brief Register unicast server callbacks.
|
||||||
*
|
*
|
||||||
* Only one callback structure can be registered, and attempting to
|
* Only one callback structure can be registered, and attempting to
|
||||||
|
@ -1684,24 +1725,6 @@ 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
|
|
||||||
*
|
|
||||||
* @param dir Direction of the endpoint.
|
|
||||||
*
|
|
||||||
* @return 0 in case of success or negative value in case of error.
|
|
||||||
*/
|
|
||||||
int bt_audio_unicast_server_location_changed(enum bt_audio_dir dir);
|
|
||||||
|
|
||||||
/** @brief Notify available audio contexts changed
|
|
||||||
*
|
|
||||||
* Notify connected clients that the available audio contexts has changed
|
|
||||||
*
|
|
||||||
* @return 0 in case of success or negative value in case of error.
|
|
||||||
*/
|
|
||||||
int bt_audio_unicast_server_available_contexts_changed(void);
|
|
||||||
|
|
||||||
/** @} */ /* End of group bt_audio_server */
|
/** @} */ /* End of group bt_audio_server */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -232,10 +232,12 @@ struct bt_audio_capability {
|
||||||
enum bt_audio_dir dir;
|
enum bt_audio_dir dir;
|
||||||
/** Capability codec reference */
|
/** Capability codec reference */
|
||||||
struct bt_codec *codec;
|
struct bt_codec *codec;
|
||||||
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER)
|
||||||
/** Capability preferences */
|
/** Capability preferences */
|
||||||
struct bt_audio_capability_pref pref;
|
struct bt_audio_capability_pref pref;
|
||||||
/** Capability operations reference */
|
/** Capability operations reference */
|
||||||
struct bt_audio_capability_ops *ops;
|
struct bt_audio_capability_ops *ops;
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER */
|
||||||
sys_snode_t node;
|
sys_snode_t node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
CONFIG_BT=y
|
CONFIG_BT=y
|
||||||
CONFIG_BT_DEBUG_LOG=y
|
CONFIG_BT_DEBUG_LOG=y
|
||||||
CONFIG_BT_AUDIO=y
|
CONFIG_BT_AUDIO=y
|
||||||
|
CONFIG_BT_SMP=y
|
||||||
|
CONFIG_BT_PAC_SNK=y
|
||||||
|
CONFIG_BT_PERIPHERAL=y
|
||||||
CONFIG_BT_AUDIO_BROADCAST_SINK=y
|
CONFIG_BT_AUDIO_BROADCAST_SINK=y
|
||||||
|
|
||||||
CONFIG_BT_DEVICE_NAME="Broadcast Audio Sink"
|
CONFIG_BT_DEVICE_NAME="Broadcast Audio Sink"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
#include <zephyr/bluetooth/bluetooth.h>
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
#include <zephyr/bluetooth/audio/audio.h>
|
#include <zephyr/bluetooth/audio/audio.h>
|
||||||
|
#include <zephyr/bluetooth/audio/capabilities.h>
|
||||||
|
|
||||||
#define SEM_TIMEOUT K_SECONDS(10)
|
#define SEM_TIMEOUT K_SECONDS(10)
|
||||||
|
|
||||||
|
@ -147,6 +148,11 @@ static struct bt_audio_broadcast_sink_cb broadcast_sink_cbs = {
|
||||||
.pa_sync_lost = pa_sync_lost_cb
|
.pa_sync_lost = pa_sync_lost_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct bt_audio_capability capabilities = {
|
||||||
|
.dir = BT_AUDIO_DIR_SINK,
|
||||||
|
.codec = &preset_16_2_1.codec,
|
||||||
|
};
|
||||||
|
|
||||||
static int init(void)
|
static int init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -159,6 +165,12 @@ static int init(void)
|
||||||
|
|
||||||
printk("Bluetooth initialized\n");
|
printk("Bluetooth initialized\n");
|
||||||
|
|
||||||
|
err = bt_audio_capability_register(&capabilities);
|
||||||
|
if (err) {
|
||||||
|
printk("Capability register failed (err %d)\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
bt_audio_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
bt_audio_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
||||||
|
|
||||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||||
|
|
|
@ -153,6 +153,8 @@ config BT_AUDIO_BROADCAST_SINK
|
||||||
bool "Bluetooth Broadcast Sink Audio Support [EXPERIMENTAL]"
|
bool "Bluetooth Broadcast Sink Audio Support [EXPERIMENTAL]"
|
||||||
select EXPERIMENTAL
|
select EXPERIMENTAL
|
||||||
select BT_ISO_SYNC_RECEIVER
|
select BT_ISO_SYNC_RECEIVER
|
||||||
|
depends on BT_PERIPHERAL
|
||||||
|
depends on BT_PAC_SNK
|
||||||
help
|
help
|
||||||
This option enables support for Bluetooth Broadcast Sink Audio using
|
This option enables support for Bluetooth Broadcast Sink Audio using
|
||||||
Isochronous channels.
|
Isochronous channels.
|
||||||
|
@ -243,7 +245,7 @@ config BT_AUDIO_STREAM
|
||||||
config BT_AUDIO_CAPABILITY
|
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_PACS
|
||||||
|
|
||||||
rsource "Kconfig.pacs"
|
rsource "Kconfig.pacs"
|
||||||
rsource "Kconfig.ascs"
|
rsource "Kconfig.ascs"
|
||||||
|
|
|
@ -230,6 +230,19 @@ static int unicast_server_release_cb(struct bt_audio_stream *stream)
|
||||||
return cap->ops->release(stream);
|
return cap->ops->release(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bt_audio_unicast_server_cb unicast_server_cb = {
|
||||||
|
.config = unicast_server_config_cb,
|
||||||
|
.reconfig = unicast_server_reconfig_cb,
|
||||||
|
.qos = unicast_server_qos_cb,
|
||||||
|
.enable = unicast_server_enable_cb,
|
||||||
|
.start = unicast_server_start_cb,
|
||||||
|
.metadata = unicast_server_metadata_cb,
|
||||||
|
.disable = unicast_server_disable_cb,
|
||||||
|
.stop = unicast_server_stop_cb,
|
||||||
|
.release = unicast_server_release_cb
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER && CONFIG_BT_ASCS */
|
||||||
|
|
||||||
static int publish_capability_cb(struct bt_conn *conn, uint8_t dir,
|
static int publish_capability_cb(struct bt_conn *conn, uint8_t dir,
|
||||||
uint8_t index, struct bt_codec *codec)
|
uint8_t index, struct bt_codec *codec)
|
||||||
{
|
{
|
||||||
|
@ -309,18 +322,9 @@ static int get_available_contexts_cb(struct bt_conn *conn, enum bt_audio_dir dir
|
||||||
return get_available_contexts(dir, contexts);
|
return get_available_contexts(dir, contexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bt_audio_unicast_server_cb unicast_server_cb = {
|
static struct bt_audio_pacs_cb pacs_cb = {
|
||||||
.config = unicast_server_config_cb,
|
|
||||||
.reconfig = unicast_server_reconfig_cb,
|
|
||||||
.qos = unicast_server_qos_cb,
|
|
||||||
.enable = unicast_server_enable_cb,
|
|
||||||
.start = unicast_server_start_cb,
|
|
||||||
.metadata = unicast_server_metadata_cb,
|
|
||||||
.disable = unicast_server_disable_cb,
|
|
||||||
.stop = unicast_server_stop_cb,
|
|
||||||
.release = unicast_server_release_cb,
|
|
||||||
.get_available_contexts = get_available_contexts_cb,
|
|
||||||
.publish_capability = publish_capability_cb,
|
.publish_capability = publish_capability_cb,
|
||||||
|
.get_available_contexts = get_available_contexts_cb,
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC)
|
#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC)
|
||||||
.publish_location = publish_location_cb,
|
.publish_location = publish_location_cb,
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) || defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
|
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) || defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
|
||||||
|
@ -328,7 +332,6 @@ static struct bt_audio_unicast_server_cb unicast_server_cb = {
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE || CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
|
#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_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER && CONFIG_BT_ASCS */
|
|
||||||
|
|
||||||
sys_slist_t *bt_audio_capability_get(enum bt_audio_dir dir)
|
sys_slist_t *bt_audio_capability_get(enum bt_audio_dir dir)
|
||||||
{
|
{
|
||||||
|
@ -345,6 +348,7 @@ sys_slist_t *bt_audio_capability_get(enum bt_audio_dir dir)
|
||||||
/* Register Audio Capability */
|
/* Register Audio Capability */
|
||||||
int bt_audio_capability_register(struct bt_audio_capability *cap)
|
int bt_audio_capability_register(struct bt_audio_capability *cap)
|
||||||
{
|
{
|
||||||
|
static bool pacs_cb_registered;
|
||||||
sys_slist_t *lst;
|
sys_slist_t *lst;
|
||||||
|
|
||||||
if (!cap || !cap->codec) {
|
if (!cap || !cap->codec) {
|
||||||
|
@ -360,6 +364,19 @@ int bt_audio_capability_register(struct bt_audio_capability *cap)
|
||||||
"codec vid 0x%04x", cap, cap->dir, cap->codec->id,
|
"codec vid 0x%04x", cap, cap->dir, cap->codec->id,
|
||||||
cap->codec->cid, cap->codec->vid);
|
cap->codec->cid, cap->codec->vid);
|
||||||
|
|
||||||
|
if (!pacs_cb_registered) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_audio_pacs_register_cb(&pacs_cb);
|
||||||
|
if (err != 0) {
|
||||||
|
BT_DBG("Failed to register PACS callbacks: %d",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pacs_cb_registered = true;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) && defined(CONFIG_BT_ASCS)
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) && defined(CONFIG_BT_ASCS)
|
||||||
/* Using the capabilities instead of the unicast server directly will
|
/* Using the capabilities instead of the unicast server directly will
|
||||||
* require the capabilities to register the callbacks, which not only
|
* require the capabilities to register the callbacks, which not only
|
||||||
|
@ -438,8 +455,6 @@ int bt_audio_capability_unregister(struct bt_audio_capability *cap)
|
||||||
int bt_audio_capability_set_location(enum bt_audio_dir dir,
|
int bt_audio_capability_set_location(enum bt_audio_dir dir,
|
||||||
enum bt_audio_location location)
|
enum bt_audio_location location)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
||||||
} else if (dir == BT_AUDIO_DIR_SINK) {
|
} else if (dir == BT_AUDIO_DIR_SINK) {
|
||||||
|
@ -455,11 +470,16 @@ int bt_audio_capability_set_location(enum bt_audio_dir dir,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_AUDIO_UNICAST_SERVER)) {
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC) ||
|
||||||
err = bt_audio_unicast_server_location_changed(dir);
|
IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_audio_pacs_location_changed(dir);
|
||||||
if (err) {
|
if (err) {
|
||||||
BT_DBG("Location for dir %d wasn't notified: %d",
|
BT_DBG("Location for dir %d wasn't notified: %d",
|
||||||
dir, err);
|
dir, err);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,8 +557,8 @@ int bt_audio_capability_set_available_contexts(enum bt_audio_dir dir,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_AUDIO_UNICAST_SERVER)) {
|
if (IS_ENABLED(CONFIG_BT_PACS)) {
|
||||||
err = bt_audio_unicast_server_available_contexts_changed();
|
err = bt_pacs_available_contexts_changed();
|
||||||
if (err) {
|
if (err) {
|
||||||
BT_DBG("Available contexts weren't notified: %d", err);
|
BT_DBG("Available contexts weren't notified: %d", err);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <zephyr/zephyr.h>
|
#include <zephyr/zephyr.h>
|
||||||
#include <zephyr/sys/byteorder.h>
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/sys/check.h>
|
||||||
|
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
#include <zephyr/init.h>
|
#include <zephyr/init.h>
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
|
|
||||||
NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, CONFIG_BT_L2CAP_TX_MTU);
|
NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, CONFIG_BT_L2CAP_TX_MTU);
|
||||||
|
|
||||||
|
static const struct bt_audio_pacs_cb *pacs_cb;
|
||||||
|
|
||||||
static void pac_data_add(struct net_buf_simple *buf, uint8_t num,
|
static void pac_data_add(struct net_buf_simple *buf, uint8_t num,
|
||||||
struct bt_codec_data *data)
|
struct bt_codec_data *data)
|
||||||
{
|
{
|
||||||
|
@ -60,8 +63,8 @@ static void get_pac_records(struct bt_conn *conn, enum bt_audio_dir dir,
|
||||||
rsp = net_buf_simple_add(&read_buf, sizeof(*rsp));
|
rsp = net_buf_simple_add(&read_buf, sizeof(*rsp));
|
||||||
rsp->num_pac = 0;
|
rsp->num_pac = 0;
|
||||||
|
|
||||||
if (unicast_server_cb == NULL ||
|
if (pacs_cb == NULL ||
|
||||||
unicast_server_cb->publish_capability == NULL) {
|
pacs_cb->publish_capability == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +74,8 @@ static void get_pac_records(struct bt_conn *conn, enum bt_audio_dir dir,
|
||||||
struct bt_pac *pac;
|
struct bt_pac *pac;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = unicast_server_cb->publish_capability(conn, dir,
|
err = pacs_cb->publish_capability(conn, dir, rsp->num_pac,
|
||||||
rsp->num_pac,
|
&codec);
|
||||||
&codec);
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -133,16 +135,15 @@ static int available_contexts_get(struct bt_conn *conn, struct bt_pacs_context *
|
||||||
enum bt_audio_context context_snk, context_src;
|
enum bt_audio_context context_snk, context_src;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (unicast_server_cb == NULL ||
|
if (pacs_cb == NULL ||
|
||||||
unicast_server_cb->get_available_contexts == NULL) {
|
pacs_cb->get_available_contexts == NULL) {
|
||||||
BT_WARN("No callback for get_available_contexts");
|
BT_WARN("No callback for get_available_contexts");
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
|
||||||
err = unicast_server_cb->get_available_contexts(conn,
|
err = pacs_cb->get_available_contexts(conn, BT_AUDIO_DIR_SINK,
|
||||||
BT_AUDIO_DIR_SINK,
|
&context_snk);
|
||||||
&context_snk);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -152,9 +153,8 @@ static int available_contexts_get(struct bt_conn *conn, struct bt_pacs_context *
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
|
if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
|
||||||
err = unicast_server_cb->get_available_contexts(conn,
|
err = pacs_cb->get_available_contexts(conn, BT_AUDIO_DIR_SOURCE,
|
||||||
BT_AUDIO_DIR_SOURCE,
|
&context_src);
|
||||||
&context_src);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -226,13 +226,13 @@ static int get_pac_loc(struct bt_conn *conn, enum bt_audio_dir dir,
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (unicast_server_cb == NULL ||
|
if (pacs_cb == NULL ||
|
||||||
unicast_server_cb->publish_location == NULL) {
|
pacs_cb->publish_location == NULL) {
|
||||||
BT_WARN("No callback for publish_location");
|
BT_WARN("No callback for publish_location");
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = unicast_server_cb->publish_location(conn, dir, location);
|
err = pacs_cb->publish_location(conn, dir, location);
|
||||||
if (err != 0 || *location == 0) {
|
if (err != 0 || *location == 0) {
|
||||||
BT_DBG("err (%d) or invalid location value (%u)",
|
BT_DBG("err (%d) or invalid location value (%u)",
|
||||||
err, *location);
|
err, *location);
|
||||||
|
@ -309,8 +309,8 @@ static ssize_t snk_loc_write(struct bt_conn *conn,
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicast_server_cb == NULL ||
|
if (pacs_cb == NULL ||
|
||||||
unicast_server_cb->write_location == NULL) {
|
pacs_cb->write_location == NULL) {
|
||||||
BT_WARN("No callback for write_location");
|
BT_WARN("No callback for write_location");
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
|
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
|
||||||
}
|
}
|
||||||
|
@ -321,8 +321,7 @@ static ssize_t snk_loc_write(struct bt_conn *conn,
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
|
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = unicast_server_cb->write_location(conn, BT_AUDIO_DIR_SINK,
|
err = pacs_cb->write_location(conn, BT_AUDIO_DIR_SINK, location);
|
||||||
location);
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
BT_DBG("write_location returned %d", err);
|
BT_DBG("write_location returned %d", err);
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
|
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
|
||||||
|
@ -406,8 +405,8 @@ static ssize_t src_loc_write(struct bt_conn *conn,
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicast_server_cb == NULL ||
|
if (pacs_cb == NULL ||
|
||||||
unicast_server_cb->write_location == NULL) {
|
pacs_cb->write_location == NULL) {
|
||||||
BT_WARN("No callback for write_location");
|
BT_WARN("No callback for write_location");
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
|
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
|
||||||
}
|
}
|
||||||
|
@ -418,8 +417,7 @@ static ssize_t src_loc_write(struct bt_conn *conn,
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
|
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = unicast_server_cb->write_location(conn, BT_AUDIO_DIR_SOURCE,
|
err = pacs_cb->write_location(conn, BT_AUDIO_DIR_SOURCE, location);
|
||||||
location);
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
BT_DBG("write_location returned %d", err);
|
BT_DBG("write_location returned %d", err);
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
|
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
|
||||||
|
@ -630,7 +628,8 @@ void bt_pacs_remove_capability(enum bt_audio_dir dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC)
|
#if defined(CONFIG_BT_PAC_SNK_LOC) || defined(CONFIG_BT_PAC_SRC_LOC)
|
||||||
int bt_pacs_location_changed(enum bt_audio_dir dir)
|
/******* PUBLIC API *******/
|
||||||
|
int bt_audio_pacs_location_changed(enum bt_audio_dir dir)
|
||||||
{
|
{
|
||||||
struct k_work_delayable *work;
|
struct k_work_delayable *work;
|
||||||
|
|
||||||
|
@ -681,3 +680,18 @@ int bt_pacs_available_contexts_changed(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_audio_pacs_register_cb(const struct bt_audio_pacs_cb *cb)
|
||||||
|
{
|
||||||
|
CHECKIF(cb == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pacs_cb != NULL) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pacs_cb = cb;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -52,5 +52,3 @@ struct bt_pacs_context {
|
||||||
|
|
||||||
void bt_pacs_add_capability(enum bt_audio_dir dir);
|
void bt_pacs_add_capability(enum bt_audio_dir dir);
|
||||||
void bt_pacs_remove_capability(enum bt_audio_dir dir);
|
void bt_pacs_remove_capability(enum bt_audio_dir dir);
|
||||||
int bt_pacs_location_changed(enum bt_audio_dir dir);
|
|
||||||
int bt_pacs_available_contexts_changed(void);
|
|
||||||
|
|
|
@ -51,15 +51,3 @@ int bt_audio_unicast_server_unregister_cb(const struct bt_audio_unicast_server_c
|
||||||
|
|
||||||
return 0;
|
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_dir dir)
|
|
||||||
{
|
|
||||||
return bt_pacs_location_changed(dir);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC || CONFIG_BT_PAC_SRC_LOC */
|
|
||||||
|
|
||||||
int bt_audio_unicast_server_available_contexts_changed(void)
|
|
||||||
{
|
|
||||||
return bt_pacs_available_contexts_changed();
|
|
||||||
}
|
|
||||||
|
|
|
@ -437,8 +437,11 @@ static struct bt_audio_capability_ops lc3_ops = {
|
||||||
.stop = lc3_stop,
|
.stop = lc3_stop,
|
||||||
.release = lc3_release,
|
.release = lc3_release,
|
||||||
};
|
};
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) || defined(CONFIG_BT_AUDIO_BROADCAST_SINK)
|
||||||
static struct bt_audio_capability caps[MAX_PAC] = {
|
static struct bt_audio_capability caps[MAX_PAC] = {
|
||||||
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER)
|
||||||
{
|
{
|
||||||
.dir = BT_AUDIO_DIR_SOURCE,
|
.dir = BT_AUDIO_DIR_SOURCE,
|
||||||
.pref = BT_AUDIO_CAPABILITY_PREF(
|
.pref = BT_AUDIO_CAPABILITY_PREF(
|
||||||
|
@ -448,17 +451,20 @@ static struct bt_audio_capability caps[MAX_PAC] = {
|
||||||
.codec = &lc3_codec,
|
.codec = &lc3_codec,
|
||||||
.ops = &lc3_ops,
|
.ops = &lc3_ops,
|
||||||
},
|
},
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER */
|
||||||
{
|
{
|
||||||
.dir = BT_AUDIO_DIR_SINK,
|
.dir = BT_AUDIO_DIR_SINK,
|
||||||
|
.codec = &lc3_codec,
|
||||||
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER)
|
||||||
.pref = BT_AUDIO_CAPABILITY_PREF(
|
.pref = BT_AUDIO_CAPABILITY_PREF(
|
||||||
BT_AUDIO_CAPABILITY_UNFRAMED_SUPPORTED,
|
BT_AUDIO_CAPABILITY_UNFRAMED_SUPPORTED,
|
||||||
BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u,
|
BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u,
|
||||||
20000u, 40000u),
|
20000u, 40000u),
|
||||||
.codec = &lc3_codec,
|
|
||||||
.ops = &lc3_ops,
|
.ops = &lc3_ops,
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER */
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_BT_AUDIO_UNICAST */
|
#endif /* CONFIG_BT_AUDIO_UNICAST_SERVER || CONFIG_BT_AUDIO_BROADCAST_SINK */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_AUDIO_UNICAST_CLIENT)
|
#if defined(CONFIG_BT_AUDIO_UNICAST_CLIENT)
|
||||||
static uint8_t stream_dir(const struct bt_audio_stream *stream)
|
static uint8_t stream_dir(const struct bt_audio_stream *stream)
|
||||||
|
@ -1355,10 +1361,11 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_AUDIO_UNICAST)
|
#if defined(CONFIG_BT_AUDIO_UNICAST_SERVER) || defined(CONFIG_BT_AUDIO_BROADCAST_SINK)
|
||||||
for (i = 0; i < ARRAY_SIZE(caps); i++) {
|
for (i = 0; i < ARRAY_SIZE(caps); i++) {
|
||||||
bt_audio_capability_register(&caps[i]);
|
bt_audio_capability_register(&caps[i]);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_BT_AUDIO_UNICAST || CONFIG_BT_AUDIO_BROADCAST_SOURCE */
|
||||||
|
|
||||||
/* Mark all supported contexts as available */
|
/* Mark all supported contexts as available */
|
||||||
bt_audio_capability_set_available_contexts(BT_AUDIO_DIR_SINK,
|
bt_audio_capability_set_available_contexts(BT_AUDIO_DIR_SINK,
|
||||||
|
@ -1366,6 +1373,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
|
||||||
bt_audio_capability_set_available_contexts(BT_AUDIO_DIR_SOURCE,
|
bt_audio_capability_set_available_contexts(BT_AUDIO_DIR_SOURCE,
|
||||||
BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_AUDIO_UNICAST)
|
||||||
for (i = 0; i < ARRAY_SIZE(streams); i++) {
|
for (i = 0; i < ARRAY_SIZE(streams); i++) {
|
||||||
bt_audio_stream_cb_register(&streams[i], &stream_ops);
|
bt_audio_stream_cb_register(&streams[i], &stream_ops);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <zephyr/bluetooth/bluetooth.h>
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
#include <zephyr/bluetooth/audio/audio.h>
|
#include <zephyr/bluetooth/audio/audio.h>
|
||||||
|
#include <zephyr/bluetooth/audio/capabilities.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
extern enum bst_result_t bst_result;
|
extern enum bst_result_t bst_result;
|
||||||
|
@ -19,6 +20,9 @@ CREATE_FLAG(pa_sync_lost);
|
||||||
|
|
||||||
static struct bt_audio_broadcast_sink *g_sink;
|
static struct bt_audio_broadcast_sink *g_sink;
|
||||||
|
|
||||||
|
/* Mandatory support preset by both source and sink */
|
||||||
|
static struct bt_audio_lc3_preset preset = BT_AUDIO_LC3_BROADCAST_PRESET_16_2_1;
|
||||||
|
|
||||||
static bool scan_recv_cb(const struct bt_le_scan_recv_info *info,
|
static bool scan_recv_cb(const struct bt_le_scan_recv_info *info,
|
||||||
uint32_t broadcast_id)
|
uint32_t broadcast_id)
|
||||||
{
|
{
|
||||||
|
@ -90,6 +94,11 @@ static struct bt_audio_broadcast_sink_cb broadcast_sink_cbs = {
|
||||||
.pa_sync_lost = pa_sync_lost_cb
|
.pa_sync_lost = pa_sync_lost_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct bt_audio_capability capabilities = {
|
||||||
|
.dir = BT_AUDIO_DIR_SINK,
|
||||||
|
.codec = &preset.codec,
|
||||||
|
};
|
||||||
|
|
||||||
static int init(void)
|
static int init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -102,6 +111,12 @@ static int init(void)
|
||||||
|
|
||||||
printk("Bluetooth initialized\n");
|
printk("Bluetooth initialized\n");
|
||||||
|
|
||||||
|
err = bt_audio_capability_register(&capabilities);
|
||||||
|
if (err) {
|
||||||
|
FAIL("Capability register failed (err %d)\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
bt_audio_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
bt_audio_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
||||||
|
|
||||||
UNSET_FLAG(broadcaster_found);
|
UNSET_FLAG(broadcaster_found);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue