Bluetooth: BAP: Add broadcast source callback structs
These callbacks are trigger for changes that affect the entire broadcast source, such as the BIG started and terminated events. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
e8bcb29f3f
commit
ab9ee0817d
10 changed files with 416 additions and 45 deletions
|
@ -2001,6 +2001,53 @@ int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgrou
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Struct to hold the Broadcast Source callbacks
|
||||
*
|
||||
* These can be registered for usage with bt_bap_broadcast_source_register_cb().
|
||||
*/
|
||||
struct bt_bap_broadcast_source_cb {
|
||||
/**
|
||||
* @brief The Broadcast Source has started and all of the streams are ready for audio data
|
||||
*
|
||||
* @param source The started Broadcast Source
|
||||
*/
|
||||
void (*started)(struct bt_bap_broadcast_source *source);
|
||||
|
||||
/**
|
||||
* @brief The Broadcast Source has stopped and none of the streams are ready for audio data
|
||||
*
|
||||
* @param source The stopped Broadcast Source
|
||||
* @param reason The reason why the Broadcast Source stopped (see the BT_HCI_ERR_* values)
|
||||
*/
|
||||
void (*stopped)(struct bt_bap_broadcast_source *source, uint8_t reason);
|
||||
|
||||
/** @internal Internally used field for list handling */
|
||||
sys_snode_t _node;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Registers callbacks for Broadcast Sources
|
||||
*
|
||||
* @param cb Pointer to the callback structure.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -EINVAL if @p cb is NULL
|
||||
* @retval -EEXIST if @p cb is already registered
|
||||
*/
|
||||
int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Unregisters callbacks for Broadcast Sources
|
||||
*
|
||||
* @param cb Pointer to the callback structure.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -EINVAL if @p cb is NULL
|
||||
* @retval -ENOENT if @p cb is not registered
|
||||
*/
|
||||
int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb);
|
||||
|
||||
/** Broadcast Source stream parameters */
|
||||
struct bt_bap_broadcast_source_stream_param {
|
||||
/** Audio stream */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Bluetooth Audio Broadcast Source */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/check.h>
|
||||
#include <zephyr/sys/slist.h>
|
||||
|
@ -55,6 +56,7 @@ static struct bt_bap_broadcast_subgroup
|
|||
broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
|
||||
[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
|
||||
static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
|
||||
static sys_slist_t bap_broadcast_source_cbs = SYS_SLIST_STATIC_INIT(&bap_broadcast_source_cbs);
|
||||
|
||||
/**
|
||||
* 2 octets UUID
|
||||
|
@ -440,8 +442,7 @@ static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_s
|
|||
*/
|
||||
streams_encoded = 0;
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
|
||||
if (!encode_base_subgroup(subgroup,
|
||||
&source->stream_data[streams_encoded],
|
||||
if (!encode_base_subgroup(subgroup, &source->stream_data[streams_encoded],
|
||||
&streams_encoded, buf)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -454,12 +455,10 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
|
|||
{
|
||||
struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup,
|
||||
next_subgroup, _node) {
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) {
|
||||
struct bt_bap_stream *stream, *next_stream;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream,
|
||||
next_stream, _node) {
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) {
|
||||
bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
|
||||
stream->ep->stream = NULL;
|
||||
stream->ep = NULL;
|
||||
|
@ -467,8 +466,7 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
|
|||
stream->qos = NULL;
|
||||
stream->group = NULL;
|
||||
|
||||
sys_slist_remove(&subgroup->streams, NULL,
|
||||
&stream->_node);
|
||||
sys_slist_remove(&subgroup->streams, NULL, &stream->_node);
|
||||
}
|
||||
sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
|
||||
}
|
||||
|
@ -777,8 +775,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
|
|||
bis_count++;
|
||||
}
|
||||
|
||||
err = broadcast_source_setup_stream(index, stream,
|
||||
codec_cfg, qos, source);
|
||||
err = broadcast_source_setup_stream(index, stream, codec_cfg, qos, source);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
|
||||
broadcast_source_cleanup(source);
|
||||
|
@ -1039,7 +1036,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour
|
|||
int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
|
||||
{
|
||||
struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
|
||||
struct bt_iso_big_create_param param = { 0 };
|
||||
struct bt_iso_big_create_param param = {0};
|
||||
struct bt_bap_broadcast_subgroup *subgroup;
|
||||
enum bt_bap_ep_state broadcast_state;
|
||||
struct bt_bap_stream *stream;
|
||||
|
@ -1078,8 +1075,7 @@ int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct
|
|||
param.latency = source->qos->latency;
|
||||
param.encryption = source->encryption;
|
||||
if (param.encryption) {
|
||||
(void)memcpy(param.bcode, source->broadcast_code,
|
||||
sizeof(param.bcode));
|
||||
(void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode));
|
||||
}
|
||||
#if defined(CONFIG_BT_ISO_TEST_PARAMS)
|
||||
param.irc = source->irc;
|
||||
|
@ -1131,8 +1127,6 @@ int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
|
|||
return err;
|
||||
}
|
||||
|
||||
source->big = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1188,3 +1182,102 @@ int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bt_bap_broadcast_source *get_broadcast_source_by_big(const struct bt_iso_big *big)
|
||||
{
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) {
|
||||
if (broadcast_sources[i].big == big) {
|
||||
return &broadcast_sources[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void big_started_cb(struct bt_iso_big *big)
|
||||
{
|
||||
struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
|
||||
struct bt_bap_broadcast_source_cb *listener;
|
||||
|
||||
if (source == NULL) {
|
||||
/* Not one of ours */
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
|
||||
if (listener->started != NULL) {
|
||||
listener->started(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void big_stopped_cb(struct bt_iso_big *big, uint8_t reason)
|
||||
{
|
||||
struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
|
||||
struct bt_bap_broadcast_source_cb *listener;
|
||||
|
||||
if (source == NULL) {
|
||||
/* Not one of ours */
|
||||
return;
|
||||
}
|
||||
|
||||
source->big = NULL;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
|
||||
if (listener->stopped != NULL) {
|
||||
listener->stopped(source, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb)
|
||||
{
|
||||
static bool iso_big_cb_registered;
|
||||
|
||||
CHECKIF(cb == NULL) {
|
||||
LOG_DBG("cb is NULL");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sys_slist_find(&bap_broadcast_source_cbs, &cb->_node, NULL)) {
|
||||
LOG_DBG("cb %p is already registered", cb);
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (!iso_big_cb_registered) {
|
||||
static struct bt_iso_big_cb big_cb = {
|
||||
.started = big_started_cb,
|
||||
.stopped = big_stopped_cb,
|
||||
};
|
||||
const int err = bt_iso_big_register_cb(&big_cb);
|
||||
|
||||
if (err != 0) {
|
||||
__ASSERT(false, "Failed to register ISO BIG callbacks: %d", err);
|
||||
}
|
||||
|
||||
iso_big_cb_registered = true;
|
||||
}
|
||||
|
||||
sys_slist_append(&bap_broadcast_source_cbs, &cb->_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb)
|
||||
{
|
||||
CHECKIF(cb == NULL) {
|
||||
LOG_DBG("cb is NULL");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sys_slist_find_and_remove(&bap_broadcast_source_cbs, &cb->_node)) {
|
||||
LOG_DBG("cb %p is not registered", cb);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,4 +15,5 @@ target_include_directories(testbinary PRIVATE include)
|
|||
target_sources(testbinary
|
||||
PRIVATE
|
||||
src/main.c
|
||||
src/test_callback_register.c
|
||||
)
|
||||
|
|
|
@ -1,28 +1,41 @@
|
|||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2023-2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/bluetooth/audio/lc3.h>
|
||||
#include <zephyr/bluetooth/byteorder.h>
|
||||
#include <zephyr/bluetooth/hci_types.h>
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
#include <zephyr/fff.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/net/buf.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
|
||||
#include "bluetooth.h"
|
||||
#include "bap_broadcast_source.h"
|
||||
#include "bap_stream.h"
|
||||
#include "bap_stream_expects.h"
|
||||
#include "bluetooth.h"
|
||||
#include "expects_util.h"
|
||||
#include "ztest_assert.h"
|
||||
#include "ztest_test.h"
|
||||
|
||||
DEFINE_FFF_GLOBALS;
|
||||
|
||||
static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture)
|
||||
{
|
||||
mock_bap_broadcast_source_init();
|
||||
mock_bap_stream_init();
|
||||
}
|
||||
|
||||
|
@ -136,8 +149,13 @@ static void *bap_broadcast_source_test_suite_setup(void)
|
|||
|
||||
static void bap_broadcast_source_test_suite_before(void *f)
|
||||
{
|
||||
int err;
|
||||
|
||||
memset(f, 0, sizeof(struct bap_broadcast_source_test_suite_fixture));
|
||||
bap_broadcast_source_test_suite_fixture_init(f);
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static void bap_broadcast_source_test_suite_after(void *f)
|
||||
|
@ -164,6 +182,8 @@ static void bap_broadcast_source_test_suite_after(void *f)
|
|||
free(param->params);
|
||||
free(param->qos);
|
||||
free(param);
|
||||
|
||||
bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
|
||||
}
|
||||
|
||||
static void bap_broadcast_source_test_suite_teardown(void *f)
|
||||
|
@ -224,6 +244,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send
|
|||
mock_bap_stream_connected_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_stream_ops.started", fixture->stream_cnt,
|
||||
mock_bap_stream_started_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_broadcast_source_cb.started", 1,
|
||||
mock_bap_broadcast_source_started_cb_fake.call_count);
|
||||
|
||||
for (size_t i = 0U; i < create_param->params_count; i++) {
|
||||
for (size_t j = 0U; j < create_param->params[i].params_count; j++) {
|
||||
|
@ -260,6 +282,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send
|
|||
mock_bap_stream_disconnected_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_stream_ops.stopped", fixture->stream_cnt,
|
||||
mock_bap_stream_stopped_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_broadcast_source_cb.stopped", 1,
|
||||
mock_bap_broadcast_source_stopped_cb_fake.call_count);
|
||||
|
||||
err = bt_bap_broadcast_source_delete(fixture->source);
|
||||
zassert_equal(0, err, "Unable to delete broadcast source: err %d", err);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/* test_callback_register.c - Test bt_bap_broadcast_source_register and unregister */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/fff.h>
|
||||
|
||||
#include "bap_broadcast_source.h"
|
||||
#include "ztest_assert.h"
|
||||
#include "ztest_test.h"
|
||||
|
||||
#define FFF_GLOBALS
|
||||
|
||||
static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture)
|
||||
{
|
||||
mock_bap_broadcast_source_init();
|
||||
}
|
||||
|
||||
ZTEST_RULE(mock_rule, mock_init_rule_before, NULL);
|
||||
|
||||
static void bap_broadcast_source_test_cb_register_suite_after(void *f)
|
||||
{
|
||||
bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
|
||||
}
|
||||
|
||||
ZTEST_SUITE(bap_broadcast_source_test_cb_register_suite, NULL, NULL, NULL,
|
||||
bap_broadcast_source_test_cb_register_suite_after, NULL);
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite, test_broadcast_source_register_cb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite,
|
||||
test_broadcast_source_register_cb_inval_param_null)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(NULL);
|
||||
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite,
|
||||
test_broadcast_source_register_cb_inval_double_register)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, -EEXIST, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite, test_broadcast_source_unregister_cb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||
|
||||
err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite,
|
||||
test_broadcast_source_unregister_cb_inval_param_null)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_unregister_cb(NULL);
|
||||
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
static ZTEST(bap_broadcast_source_test_cb_register_suite,
|
||||
test_broadcast_source_unregister_cb_inval_double_unregister)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||
|
||||
err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||
|
||||
err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
|
||||
zassert_equal(err, -ENOENT, "Unexpected return value %d", err);
|
||||
}
|
|
@ -14,6 +14,7 @@ add_library(uut STATIC
|
|||
${ZEPHYR_BASE}/subsys/bluetooth/audio/codec.c
|
||||
${ZEPHYR_BASE}/subsys/logging/log_minimal.c
|
||||
${ZEPHYR_BASE}/lib/net_buf/buf_simple.c
|
||||
bap_broadcast_source.c
|
||||
)
|
||||
|
||||
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
|
||||
#include "bap_broadcast_source.h"
|
||||
#include "zephyr/fff.h"
|
||||
|
||||
/* List of fakes used by this unit tester */
|
||||
#define FFF_FAKES_LIST(FAKE) \
|
||||
FAKE(mock_bap_broadcast_source_started_cb) \
|
||||
FAKE(mock_bap_broadcast_source_stopped_cb)
|
||||
|
||||
DEFINE_FAKE_VOID_FUNC(mock_bap_broadcast_source_started_cb, struct bt_bap_broadcast_source *);
|
||||
|
||||
DEFINE_FAKE_VOID_FUNC(mock_bap_broadcast_source_stopped_cb, struct bt_bap_broadcast_source *,
|
||||
uint8_t);
|
||||
|
||||
struct bt_bap_broadcast_source_cb mock_bap_broadcast_source_cb = {
|
||||
.started = mock_bap_broadcast_source_started_cb,
|
||||
.stopped = mock_bap_broadcast_source_stopped_cb,
|
||||
};
|
||||
|
||||
void mock_bap_broadcast_source_init(void)
|
||||
{
|
||||
FFF_FAKES_LIST(RESET_FAKE);
|
||||
}
|
23
tests/bluetooth/audio/mocks/include/bap_broadcast_source.h
Normal file
23
tests/bluetooth/audio/mocks/include/bap_broadcast_source.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef MOCKS_BAP_BROADCAST_SOURCE_H_
|
||||
#define MOCKS_BAP_BROADCAST_SOURCE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/fff.h>
|
||||
|
||||
extern struct bt_bap_broadcast_source_cb mock_bap_broadcast_source_cb;
|
||||
|
||||
void mock_bap_broadcast_source_init(void);
|
||||
|
||||
DECLARE_FAKE_VOID_FUNC(mock_bap_broadcast_source_started_cb, struct bt_bap_broadcast_source *);
|
||||
DECLARE_FAKE_VOID_FUNC(mock_bap_broadcast_source_stopped_cb, struct bt_bap_broadcast_source *,
|
||||
uint8_t);
|
||||
|
||||
#endif /* MOCKS_BAP_BROADCAST_SOURCE_H_ */
|
|
@ -1,10 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Codecoup
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
|
||||
#include "conn.h"
|
||||
|
@ -123,6 +126,19 @@ int mock_bt_iso_disconnected(struct bt_iso_chan *chan, uint8_t err)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
static struct bt_iso_big_cb *iso_cb;
|
||||
|
||||
int bt_iso_big_register_cb(struct bt_iso_big_cb *cb)
|
||||
{
|
||||
if (cb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iso_cb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param,
|
||||
struct bt_iso_big **out_big)
|
||||
{
|
||||
|
@ -153,6 +169,10 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param
|
|||
|
||||
*out_big = big;
|
||||
|
||||
if (iso_cb != NULL && iso_cb->started != NULL) {
|
||||
iso_cb->started(big);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -169,6 +189,10 @@ int bt_iso_big_terminate(struct bt_iso_big *big)
|
|||
mock_bt_iso_disconnected(bis, BT_HCI_ERR_LOCALHOST_TERM_CONN);
|
||||
}
|
||||
|
||||
if (iso_cb != NULL && iso_cb->stopped != NULL) {
|
||||
iso_cb->stopped(big, BT_HCI_ERR_LOCALHOST_TERM_CONN);
|
||||
}
|
||||
|
||||
free(big);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -35,6 +35,8 @@
|
|||
#define SUPPORTED_MAX_FRAMES_PER_SDU 1
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
CREATE_FLAG(flag_source_started);
|
||||
|
||||
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
||||
* the controller is never idle
|
||||
*/
|
||||
|
@ -62,8 +64,8 @@ static uint8_t bis_codec_data[] = {
|
|||
BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_CENTER)),
|
||||
};
|
||||
|
||||
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
static K_SEM_DEFINE(sem_stream_started, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
static K_SEM_DEFINE(sem_stream_stopped, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
|
||||
static void validate_stream_codec_cfg(const struct bt_bap_stream *stream)
|
||||
{
|
||||
|
@ -174,7 +176,7 @@ static void validate_stream_codec_cfg(const struct bt_bap_stream *stream)
|
|||
}
|
||||
}
|
||||
|
||||
static void started_cb(struct bt_bap_stream *stream)
|
||||
static void stream_started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream);
|
||||
struct bt_bap_ep_info info;
|
||||
|
@ -216,13 +218,13 @@ static void started_cb(struct bt_bap_stream *stream)
|
|||
|
||||
printk("Stream %p started\n", stream);
|
||||
validate_stream_codec_cfg(stream);
|
||||
k_sem_give(&sem_started);
|
||||
k_sem_give(&sem_stream_started);
|
||||
}
|
||||
|
||||
static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
static void steam_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_stopped);
|
||||
k_sem_give(&sem_stream_stopped);
|
||||
}
|
||||
|
||||
static void stream_sent_cb(struct bt_bap_stream *stream)
|
||||
|
@ -265,11 +267,23 @@ static void stream_sent_cb(struct bt_bap_stream *stream)
|
|||
}
|
||||
|
||||
static struct bt_bap_stream_ops stream_ops = {
|
||||
.started = started_cb,
|
||||
.stopped = stopped_cb,
|
||||
.started = stream_started_cb,
|
||||
.stopped = steam_stopped_cb,
|
||||
.sent = stream_sent_cb,
|
||||
};
|
||||
|
||||
static void source_started_cb(struct bt_bap_broadcast_source *source)
|
||||
{
|
||||
printk("Broadcast source %p started\n", source);
|
||||
SET_FLAG(flag_source_started);
|
||||
}
|
||||
|
||||
static void source_stopped_cb(struct bt_bap_broadcast_source *source, uint8_t reason)
|
||||
{
|
||||
printk("Broadcast source %p stopped with reason 0x%02X\n", source, reason);
|
||||
UNSET_FLAG(flag_source_started);
|
||||
}
|
||||
|
||||
static int setup_broadcast_source(struct bt_bap_broadcast_source **source, bool encryption)
|
||||
{
|
||||
struct bt_bap_broadcast_source_stream_param
|
||||
|
@ -467,10 +481,12 @@ static void test_broadcast_source_start(struct bt_bap_broadcast_source *source,
|
|||
}
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for streams to be started\n");
|
||||
printk("Waiting for %zu streams to be started\n", ARRAY_SIZE(broadcast_source_streams));
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) {
|
||||
k_sem_take(&sem_started, K_FOREVER);
|
||||
k_sem_take(&sem_stream_started, K_FOREVER);
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_source_started);
|
||||
}
|
||||
|
||||
static void test_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
|
||||
|
@ -520,10 +536,12 @@ static void test_broadcast_source_stop(struct bt_bap_broadcast_source *source)
|
|||
}
|
||||
|
||||
/* Wait for all to be stopped */
|
||||
printk("Waiting for streams to be stopped\n");
|
||||
printk("Waiting for %zu streams to be stopped\n", ARRAY_SIZE(broadcast_source_streams));
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) {
|
||||
k_sem_take(&sem_stopped, K_FOREVER);
|
||||
k_sem_take(&sem_stream_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
WAIT_FOR_UNSET_FLAG(flag_source_started);
|
||||
}
|
||||
|
||||
static void test_broadcast_source_delete(struct bt_bap_broadcast_source *source)
|
||||
|
@ -564,10 +582,12 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
static void init(void)
|
||||
{
|
||||
struct bt_bap_broadcast_source *source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
static struct bt_bap_broadcast_source_cb broadcast_source_cb = {
|
||||
.started = source_started_cb,
|
||||
.stopped = source_stopped_cb,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
|
@ -578,6 +598,21 @@ static void test_main(void)
|
|||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_bap_broadcast_source_register_cb(&broadcast_source_cb);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register broadcast source callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
struct bt_bap_broadcast_source *source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
int err;
|
||||
|
||||
init();
|
||||
|
||||
err = setup_broadcast_source(&source, false);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to setup broadcast source: %d\n", err);
|
||||
|
@ -650,13 +685,7 @@ static void test_main_encrypted(void)
|
|||
struct bt_le_ext_adv *adv;
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
init();
|
||||
|
||||
err = setup_broadcast_source(&source, true);
|
||||
if (err != 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue