Initial commit for nrf5340_audio
This commit is contained in:
8
broadcast_source/CMakeLists.txt
Normal file
8
broadcast_source/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
target_sources(app PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.c)
|
||||
45
broadcast_source/Kconfig.defaults
Normal file
45
broadcast_source/Kconfig.defaults
Normal file
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
## ISO related configs ##
|
||||
config BT_CAP_INITIATOR
|
||||
default y
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 1
|
||||
|
||||
# Broadcasting Device - 0x0885
|
||||
config BT_DEVICE_APPEARANCE
|
||||
default 2181
|
||||
|
||||
config BT_ISO_BROADCASTER
|
||||
default y
|
||||
|
||||
config BT_BAP_BROADCAST_SOURCE
|
||||
default y
|
||||
|
||||
config BT_ISO_TX_BUF_COUNT
|
||||
default 2
|
||||
|
||||
config BT_BAP_BROADCAST_SRC_STREAM_COUNT
|
||||
default 2
|
||||
|
||||
config BT_ISO_MAX_CHAN
|
||||
default 2
|
||||
|
||||
config BT_ISO_MAX_BIG
|
||||
default 2
|
||||
|
||||
config BT_AUDIO_TX
|
||||
default y
|
||||
|
||||
|
||||
## LC3 related configs ##
|
||||
config LC3_BITRATE
|
||||
default BT_AUDIO_BITRATE_BROADCAST_SRC
|
||||
|
||||
config LC3_ENC_CHAN_MAX
|
||||
default 2
|
||||
96
broadcast_source/README.rst
Normal file
96
broadcast_source/README.rst
Normal file
@@ -0,0 +1,96 @@
|
||||
.. _nrf53_audio_broadcast_source_app:
|
||||
|
||||
nRF5340 Audio: Broadcast source
|
||||
###############################
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
The nRF5340 Audio broadcast source application implements the :ref:`BIS gateway mode <nrf53_audio_app_overview>`.
|
||||
|
||||
In this mode, transmitting broadcast audio happens using Broadcast Isochronous Stream (BIS) and Broadcast Isochronous Group (BIG).
|
||||
Play and pause are emulated by enabling and disabling stream, respectively.
|
||||
|
||||
The following limitations apply to this application:
|
||||
|
||||
* One BIG with two BIS streams.
|
||||
* Audio input: USB or I2S (Line in or using Pulse Density Modulation).
|
||||
* Configuration: 16 bit, several bit rates ranging from 32 kbps to 124 kbps.
|
||||
|
||||
.. _nrf53_audio_broadcast_source_app_requirements:
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
The application shares the :ref:`requirements common to all nRF5340 Audio application <nrf53_audio_app_requirements>`.
|
||||
|
||||
.. _nrf53_audio_broadcast_source_app_ui:
|
||||
|
||||
User interface
|
||||
**************
|
||||
|
||||
Most of the user interface mappings are common across all nRF5340 Audio applications.
|
||||
See the :ref:`nrf53_audio_app_ui` page for detailed overview.
|
||||
|
||||
This application uses specific mapping for the following user interface elements:
|
||||
|
||||
* Pressed on the broadcast source device during playback:
|
||||
|
||||
* **PLAY/PAUSE** - Starts or pauses the playback of the stream.
|
||||
* **BTN 4** - Toggles between the normal audio stream and different test tones generated on the device.
|
||||
Use this tone to check the synchronization of headsets.
|
||||
|
||||
* **LED1** - Blinking blue - Device has started broadcasting audio.
|
||||
* **RGB** - Solid green - The device is programmed as the gateway.
|
||||
|
||||
.. _nrf53_audio_broadcast_source_app_configuration:
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
The application requires the ``CONFIG_TRANSPORT_BIS`` Kconfig option to be set to ``y`` in the :file:`applications/nrf5340_audio/prj.conf` file for `Building and running`_ to succeed.
|
||||
|
||||
For other configuration options, see :ref:`nrf53_audio_app_configuration` and :ref:`nrf53_audio_app_fota`.
|
||||
|
||||
For information about how to configure applications in the |NCS|, see :ref:`configure_application`.
|
||||
|
||||
.. _nrf53_audio_broadcast_source_app_building:
|
||||
|
||||
Building and running
|
||||
********************
|
||||
|
||||
This application can be found under :file:`applications/nrf5340_audio/broadcast_source` in the nRF Connect SDK folder structure, but it uses :file:`.conf` files at :file:`applications/nrf5340_audio/`.
|
||||
|
||||
The nRF5340 Audio DK comes preprogrammed with basic firmware that indicates if the kit is functional.
|
||||
See :ref:`nrf53_audio_app_dk_testing_out_of_the_box` for more information.
|
||||
|
||||
To build the application, complete the following steps:
|
||||
|
||||
1. Select the BIS mode by setting the ``CONFIG_TRANSPORT_BIS`` Kconfig option to ``y`` in the :file:`applications/nrf5340_audio/prj.conf` file for the debug version and in the :file:`applications/nrf5340_audio/prj_release.conf` file for the release version.
|
||||
#. Complete the steps for building and programming common to all audio applications using one of the following methods:
|
||||
|
||||
* :ref:`nrf53_audio_app_building_script`
|
||||
* :ref:`nrf53_audio_app_building_standard`
|
||||
|
||||
After programming, the broadcast source automatically starts broadcasting the default 48-kHz audio stream.
|
||||
|
||||
.. _nrf53_audio_broadcast_source_app_testing:
|
||||
|
||||
Testing
|
||||
*******
|
||||
|
||||
.. note::
|
||||
|nrf5340_audio_external_devices_note|
|
||||
|
||||
To test the broadcast source application, complete the following steps:
|
||||
|
||||
1. Make sure you have another nRF5340 Audio DK for testing purposes.
|
||||
#. Program the other DK with the :ref:`broadcast sink <nrf53_audio_broadcast_sink_app>` application.
|
||||
The broadcast sink device automatically synchronizes with the broadcast source after programming.
|
||||
#. Proceed to testing the broadcast source using the :ref:`nrf53_audio_broadcast_source_app_ui` buttons and LEDs.
|
||||
|
||||
Dependencies
|
||||
************
|
||||
|
||||
For the list of dependencies, check the application's source files.
|
||||
606
broadcast_source/main.c
Normal file
606
broadcast_source/main.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include "streamctrl.h"
|
||||
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/zbus/zbus.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include "broadcast_source.h"
|
||||
#include "zbus_common.h"
|
||||
#include "nrf5340_audio_dk.h"
|
||||
#include "led.h"
|
||||
#include "button_assignments.h"
|
||||
#include "macros_common.h"
|
||||
#include "audio_system.h"
|
||||
#include "bt_mgmt.h"
|
||||
#include "fw_info_app.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(main, CONFIG_MAIN_LOG_LEVEL);
|
||||
|
||||
ZBUS_SUBSCRIBER_DEFINE(button_evt_sub, CONFIG_BUTTON_MSG_SUB_QUEUE_SIZE);
|
||||
|
||||
ZBUS_MSG_SUBSCRIBER_DEFINE(le_audio_evt_sub);
|
||||
|
||||
ZBUS_CHAN_DECLARE(button_chan);
|
||||
ZBUS_CHAN_DECLARE(le_audio_chan);
|
||||
ZBUS_CHAN_DECLARE(bt_mgmt_chan);
|
||||
ZBUS_CHAN_DECLARE(sdu_ref_chan);
|
||||
|
||||
ZBUS_OBS_DECLARE(sdu_ref_msg_listen);
|
||||
|
||||
static struct k_thread button_msg_sub_thread_data;
|
||||
static struct k_thread le_audio_msg_sub_thread_data;
|
||||
|
||||
static k_tid_t button_msg_sub_thread_id;
|
||||
static k_tid_t le_audio_msg_sub_thread_id;
|
||||
|
||||
struct bt_le_ext_adv *ext_adv;
|
||||
|
||||
K_THREAD_STACK_DEFINE(button_msg_sub_thread_stack, CONFIG_BUTTON_MSG_SUB_STACK_SIZE);
|
||||
K_THREAD_STACK_DEFINE(le_audio_msg_sub_thread_stack, CONFIG_LE_AUDIO_MSG_SUB_STACK_SIZE);
|
||||
|
||||
static enum stream_state strm_state = STATE_PAUSED;
|
||||
|
||||
/* Buffer for the UUIDs. */
|
||||
#define EXT_ADV_UUID_BUF_SIZE (128)
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data, EXT_ADV_UUID_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data2, EXT_ADV_UUID_BUF_SIZE);
|
||||
|
||||
/* Buffer for periodic advertising BASE data. */
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data, 128);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data2, 128);
|
||||
|
||||
/* Extended advertising buffer. */
|
||||
static struct bt_data ext_adv_buf[CONFIG_BT_ISO_MAX_BIG][CONFIG_EXT_ADV_BUF_MAX];
|
||||
|
||||
/* Periodic advertising buffer. */
|
||||
static struct bt_data per_adv_buf[CONFIG_BT_ISO_MAX_BIG];
|
||||
|
||||
#if (CONFIG_AURACAST)
|
||||
/* Total size of the PBA buffer includes the 16-bit UUID, 8-bit features and the
|
||||
* meta data size.
|
||||
*/
|
||||
#define BROADCAST_SRC_PBA_BUF_SIZE \
|
||||
(BROADCAST_SOURCE_PBA_HEADER_SIZE + CONFIG_BT_AUDIO_BROADCAST_PBA_METADATA_SIZE)
|
||||
|
||||
/* Number of metadata items that can be assigned. */
|
||||
#define BROADCAST_SOURCE_PBA_METADATA_VACANT \
|
||||
(CONFIG_BT_AUDIO_BROADCAST_PBA_METADATA_SIZE / (sizeof(struct bt_data)))
|
||||
|
||||
/* Make sure pba_buf is large enough for a 16bit UUID and meta data
|
||||
* (any addition to pba_buf requires an increase of this value)
|
||||
*/
|
||||
uint8_t pba_data[CONFIG_BT_ISO_MAX_BIG][BROADCAST_SRC_PBA_BUF_SIZE];
|
||||
|
||||
/**
|
||||
* @brief Broadcast source static extended advertising data.
|
||||
*/
|
||||
static struct broadcast_source_ext_adv_data ext_adv_data[] = {
|
||||
{.uuid_buf = &uuid_data,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[0]},
|
||||
{.uuid_buf = &uuid_data2,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[1]}};
|
||||
#else
|
||||
/**
|
||||
* @brief Broadcast source static extended advertising data.
|
||||
*/
|
||||
static struct broadcast_source_ext_adv_data ext_adv_data[] = {{.uuid_buf = &uuid_data},
|
||||
{.uuid_buf = &uuid_data2}};
|
||||
#endif /* (CONFIG_AURACAST) */
|
||||
|
||||
/**
|
||||
* @brief Broadcast source static periodic advertising data.
|
||||
*/
|
||||
static struct broadcast_source_per_adv_data per_adv_data[] = {{.base_buf = &base_data},
|
||||
{.base_buf = &base_data2}};
|
||||
|
||||
/* Function for handling all stream state changes */
|
||||
static void stream_state_set(enum stream_state stream_state_new)
|
||||
{
|
||||
strm_state = stream_state_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle button activity.
|
||||
*/
|
||||
static void button_msg_sub_thread(void)
|
||||
{
|
||||
int ret;
|
||||
const struct zbus_channel *chan;
|
||||
|
||||
while (1) {
|
||||
ret = zbus_sub_wait(&button_evt_sub, &chan, K_FOREVER);
|
||||
ERR_CHK(ret);
|
||||
|
||||
struct button_msg msg;
|
||||
|
||||
ret = zbus_chan_read(chan, &msg, ZBUS_READ_TIMEOUT_MS);
|
||||
ERR_CHK(ret);
|
||||
|
||||
LOG_DBG("Got btn evt from queue - id = %d, action = %d", msg.button_pin,
|
||||
msg.button_action);
|
||||
|
||||
if (msg.button_action != BUTTON_PRESS) {
|
||||
LOG_WRN("Unhandled button action");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.button_pin) {
|
||||
case BUTTON_PLAY_PAUSE:
|
||||
if (strm_state == STATE_STREAMING) {
|
||||
ret = broadcast_source_stop(0);
|
||||
if (ret) {
|
||||
LOG_WRN("Failed to stop broadcaster: %d", ret);
|
||||
}
|
||||
} else if (strm_state == STATE_PAUSED) {
|
||||
ret = broadcast_source_start(0, ext_adv);
|
||||
if (ret) {
|
||||
LOG_WRN("Failed to start broadcaster: %d", ret);
|
||||
}
|
||||
} else {
|
||||
LOG_WRN("In invalid state: %d", strm_state);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BUTTON_4:
|
||||
if (IS_ENABLED(CONFIG_AUDIO_TEST_TONE)) {
|
||||
if (strm_state != STATE_STREAMING) {
|
||||
LOG_WRN("Not in streaming state");
|
||||
break;
|
||||
}
|
||||
|
||||
ret = audio_system_encode_test_tone_step();
|
||||
if (ret) {
|
||||
LOG_WRN("Failed to play test tone, ret: %d", ret);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("Unexpected/unhandled button id: %d", msg.button_pin);
|
||||
}
|
||||
|
||||
STACK_USAGE_PRINT("button_msg_thread", &button_msg_sub_thread_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle Bluetooth LE audio events.
|
||||
*/
|
||||
static void le_audio_msg_sub_thread(void)
|
||||
{
|
||||
int ret;
|
||||
const struct zbus_channel *chan;
|
||||
|
||||
while (1) {
|
||||
struct le_audio_msg msg;
|
||||
|
||||
ret = zbus_sub_wait_msg(&le_audio_evt_sub, &chan, &msg, K_FOREVER);
|
||||
ERR_CHK(ret);
|
||||
|
||||
LOG_DBG("Received event = %d, current state = %d", msg.event, strm_state);
|
||||
|
||||
switch (msg.event) {
|
||||
case LE_AUDIO_EVT_STREAMING:
|
||||
LOG_DBG("LE audio evt streaming");
|
||||
|
||||
audio_system_encoder_start();
|
||||
|
||||
if (strm_state == STATE_STREAMING) {
|
||||
LOG_DBG("Got streaming event in streaming state");
|
||||
break;
|
||||
}
|
||||
|
||||
audio_system_start();
|
||||
stream_state_set(STATE_STREAMING);
|
||||
ret = led_blink(LED_APP_1_BLUE);
|
||||
ERR_CHK(ret);
|
||||
|
||||
break;
|
||||
|
||||
case LE_AUDIO_EVT_NOT_STREAMING:
|
||||
LOG_DBG("LE audio evt not_streaming");
|
||||
|
||||
audio_system_encoder_stop();
|
||||
|
||||
if (strm_state == STATE_PAUSED) {
|
||||
LOG_DBG("Got not_streaming event in paused state");
|
||||
break;
|
||||
}
|
||||
|
||||
stream_state_set(STATE_PAUSED);
|
||||
audio_system_stop();
|
||||
ret = led_on(LED_APP_1_BLUE);
|
||||
ERR_CHK(ret);
|
||||
|
||||
break;
|
||||
|
||||
case LE_AUDIO_EVT_STREAM_SENT:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("Unexpected/unhandled le_audio event: %d", msg.event);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
STACK_USAGE_PRINT("le_audio_msg_thread", &le_audio_msg_sub_thread_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create zbus subscriber threads.
|
||||
*
|
||||
* @return 0 for success, error otherwise.
|
||||
*/
|
||||
static int zbus_subscribers_create(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
button_msg_sub_thread_id = k_thread_create(
|
||||
&button_msg_sub_thread_data, button_msg_sub_thread_stack,
|
||||
CONFIG_BUTTON_MSG_SUB_STACK_SIZE, (k_thread_entry_t)button_msg_sub_thread, NULL,
|
||||
NULL, NULL, K_PRIO_PREEMPT(CONFIG_BUTTON_MSG_SUB_THREAD_PRIO), 0, K_NO_WAIT);
|
||||
ret = k_thread_name_set(button_msg_sub_thread_id, "BUTTON_MSG_SUB");
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to create button_msg thread");
|
||||
return ret;
|
||||
}
|
||||
|
||||
le_audio_msg_sub_thread_id = k_thread_create(
|
||||
&le_audio_msg_sub_thread_data, le_audio_msg_sub_thread_stack,
|
||||
CONFIG_LE_AUDIO_MSG_SUB_STACK_SIZE, (k_thread_entry_t)le_audio_msg_sub_thread, NULL,
|
||||
NULL, NULL, K_PRIO_PREEMPT(CONFIG_LE_AUDIO_MSG_SUB_THREAD_PRIO), 0, K_NO_WAIT);
|
||||
ret = k_thread_name_set(le_audio_msg_sub_thread_id, "LE_AUDIO_MSG_SUB");
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to create le_audio_msg thread");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = zbus_chan_add_obs(&sdu_ref_chan, &sdu_ref_msg_listen, ZBUS_ADD_OBS_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add timestamp listener");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Zbus listener to receive events from bt_mgmt.
|
||||
*
|
||||
* @param[in] chan Zbus channel.
|
||||
*
|
||||
* @note Will in most cases be called from BT_RX context,
|
||||
* so there should not be too much processing done here.
|
||||
*/
|
||||
static void bt_mgmt_evt_handler(const struct zbus_channel *chan)
|
||||
{
|
||||
int ret;
|
||||
const struct bt_mgmt_msg *msg;
|
||||
|
||||
msg = zbus_chan_const_msg(chan);
|
||||
|
||||
switch (msg->event) {
|
||||
case BT_MGMT_EXT_ADV_WITH_PA_READY:
|
||||
LOG_INF("Ext adv ready");
|
||||
|
||||
ext_adv = msg->ext_adv;
|
||||
|
||||
ret = broadcast_source_start(msg->index, ext_adv);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to start broadcaster: %d", ret);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("Unexpected/unhandled bt_mgmt event: %d", msg->event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ZBUS_LISTENER_DEFINE(bt_mgmt_evt_listen, bt_mgmt_evt_handler);
|
||||
|
||||
/**
|
||||
* @brief Link zbus producers and observers.
|
||||
*
|
||||
* @return 0 for success, error otherwise.
|
||||
*/
|
||||
static int zbus_link_producers_observers(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_ZBUS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = zbus_chan_add_obs(&button_chan, &button_evt_sub, ZBUS_ADD_OBS_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add button sub");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = zbus_chan_add_obs(&le_audio_chan, &le_audio_evt_sub, ZBUS_ADD_OBS_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add le_audio sub");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = zbus_chan_add_obs(&bt_mgmt_chan, &bt_mgmt_evt_listen, ZBUS_ADD_OBS_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add bt_mgmt listener");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief The following configures the data for the extended advertising.
|
||||
* This includes the Broadcast Audio Announcements [BAP 3.7.2.1] and Broadcast_ID
|
||||
* [BAP 3.7.2.1.1] in the AUX_ADV_IND Extended Announcements.
|
||||
*
|
||||
* @param big_index Index of the Broadcast Isochronous Group (BIG) to get
|
||||
* advertising data for.
|
||||
* @param ext_adv_data Pointer to the extended advertising buffers.
|
||||
* @param ext_adv_buf Pointer to the bt_data used for extended advertising.
|
||||
* @param ext_adv_buf_size Size of @p ext_adv_buf.
|
||||
* @param ext_adv_count Pointer to the number of elements added to @p adv_buf.
|
||||
*
|
||||
* @return 0 for success, error otherwise.
|
||||
*/
|
||||
static int ext_adv_populate(uint8_t big_index, struct broadcast_source_ext_adv_data *ext_adv_data,
|
||||
struct bt_data *ext_adv_buf, size_t ext_adv_buf_size,
|
||||
size_t *ext_adv_count)
|
||||
{
|
||||
int ret;
|
||||
size_t ext_adv_buf_cnt = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_AUDIO_USE_BROADCAST_NAME_ALT)) {
|
||||
if (sizeof(CONFIG_BT_AUDIO_BROADCAST_NAME_ALT) >
|
||||
ARRAY_SIZE(ext_adv_data->brdcst_name_buf)) {
|
||||
LOG_ERR("CONFIG_BT_AUDIO_BROADCAST_NAME_ALT is too long");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t brdcst_name_size = sizeof(CONFIG_BT_AUDIO_BROADCAST_NAME_ALT) - 1;
|
||||
|
||||
memcpy(ext_adv_data->brdcst_name_buf, CONFIG_BT_AUDIO_BROADCAST_NAME_ALT,
|
||||
brdcst_name_size);
|
||||
} else {
|
||||
if (sizeof(CONFIG_BT_AUDIO_BROADCAST_NAME) >
|
||||
ARRAY_SIZE(ext_adv_data->brdcst_name_buf)) {
|
||||
LOG_ERR("CONFIG_BT_AUDIO_BROADCAST_NAME is too long");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t brdcst_name_size = sizeof(CONFIG_BT_AUDIO_BROADCAST_NAME) - 1;
|
||||
|
||||
memcpy(ext_adv_data->brdcst_name_buf, CONFIG_BT_AUDIO_BROADCAST_NAME,
|
||||
brdcst_name_size);
|
||||
}
|
||||
|
||||
ext_adv_buf[ext_adv_buf_cnt].type = BT_DATA_UUID16_ALL;
|
||||
ext_adv_buf[ext_adv_buf_cnt].data = ext_adv_data->uuid_buf->data;
|
||||
ext_adv_buf_cnt++;
|
||||
|
||||
ret = bt_mgmt_manufacturer_uuid_populate(ext_adv_data->uuid_buf,
|
||||
CONFIG_BT_DEVICE_MANUFACTURER_ID);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add adv data with manufacturer ID: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool fixed_id = !IS_ENABLED(CONFIG_BT_AUDIO_USE_BROADCAST_ID_RANDOM);
|
||||
|
||||
uint32_t broadcast_id = CONFIG_BT_AUDIO_BROADCAST_ID_FIXED;
|
||||
|
||||
ret = broadcast_source_ext_adv_populate(big_index, fixed_id, broadcast_id, ext_adv_data,
|
||||
&ext_adv_buf[ext_adv_buf_cnt],
|
||||
ext_adv_buf_size - ext_adv_buf_cnt);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to add ext adv data for broadcast source: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ext_adv_buf_cnt += ret;
|
||||
|
||||
/* Add the number of UUIDs */
|
||||
ext_adv_buf[0].data_len = ext_adv_data->uuid_buf->len;
|
||||
|
||||
LOG_DBG("Size of adv data: %d, num_elements: %d", sizeof(struct bt_data) * ext_adv_buf_cnt,
|
||||
ext_adv_buf_cnt);
|
||||
|
||||
*ext_adv_count = ext_adv_buf_cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief The following configures the data for the periodic advertising.
|
||||
* This includes the Basic Audio Announcement, including the
|
||||
* BASE [BAP 3.7.2.2] and BIGInfo.
|
||||
*
|
||||
* @param big_index Index of the Broadcast Isochronous Group (BIG) to get
|
||||
* advertising data for.
|
||||
* @param pre_adv_data Pointer to the periodic advertising buffers.
|
||||
* @param per_adv_buf Pointer to the bt_data used for periodic advertising.
|
||||
* @param per_adv_buf_size Size of @p ext_adv_buf.
|
||||
* @param per_adv_count Pointer to the number of elements added to @p adv_buf.
|
||||
*
|
||||
* @return 0 for success, error otherwise.
|
||||
*/
|
||||
static int per_adv_populate(uint8_t big_index, struct broadcast_source_per_adv_data *pre_adv_data,
|
||||
struct bt_data *per_adv_buf, size_t per_adv_buf_size,
|
||||
size_t *per_adv_count)
|
||||
{
|
||||
int ret;
|
||||
size_t per_adv_buf_cnt = 0;
|
||||
|
||||
ret = broadcast_source_per_adv_populate(big_index, pre_adv_data, per_adv_buf,
|
||||
per_adv_buf_size - per_adv_buf_cnt);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to add per adv data for broadcast source: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
per_adv_buf_cnt += ret;
|
||||
|
||||
LOG_DBG("Size of per adv data: %d, num_elements: %d",
|
||||
sizeof(struct bt_data) * per_adv_buf_cnt, per_adv_buf_cnt);
|
||||
|
||||
*per_adv_count = per_adv_buf_cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t stream_state_get(void)
|
||||
{
|
||||
return strm_state;
|
||||
}
|
||||
|
||||
void streamctrl_send(void const *const data, size_t size, uint8_t num_ch)
|
||||
{
|
||||
int ret;
|
||||
static int prev_ret;
|
||||
|
||||
struct le_audio_encoded_audio enc_audio = {.data = data, .size = size, .num_ch = num_ch};
|
||||
|
||||
if (strm_state == STATE_STREAMING) {
|
||||
ret = broadcast_source_send(0, 0, enc_audio);
|
||||
|
||||
if (ret != 0 && ret != prev_ret) {
|
||||
if (ret == -ECANCELED) {
|
||||
LOG_WRN("Sending operation cancelled");
|
||||
} else {
|
||||
LOG_WRN("Problem with sending LE audio data, ret: %d", ret);
|
||||
}
|
||||
}
|
||||
|
||||
prev_ret = ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_CUSTOM_BROADCASTER
|
||||
/* Example of how to create a custom broadcaster */
|
||||
/**
|
||||
* Remember to increase:
|
||||
* CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT
|
||||
* CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT (set in hci_ipc.conf)
|
||||
* CONFIG_BT_ISO_TX_BUF_COUNT
|
||||
* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT
|
||||
* CONFIG_BT_ISO_MAX_CHAN
|
||||
*/
|
||||
#error Feature is incomplete and should only be used as a guideline for now
|
||||
static struct bt_bap_lc3_preset lc3_preset_48 = BT_BAP_LC3_BROADCAST_PRESET_48_4_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
|
||||
static void broadcast_create(struct broadcast_source_big *broadcast_param)
|
||||
{
|
||||
static enum bt_audio_location location[2] = {BT_AUDIO_LOCATION_FRONT_LEFT,
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT};
|
||||
static struct subgroup_config subgroups[2];
|
||||
|
||||
subgroups[0].group_lc3_preset = lc3_preset_48;
|
||||
subgroups[0].num_bises = 2;
|
||||
subgroups[0].context = BT_AUDIO_CONTEXT_TYPE_MEDIA;
|
||||
subgroups[0].location = location;
|
||||
|
||||
subgroups[1].group_lc3_preset = lc3_preset_48;
|
||||
subgroups[1].num_bises = 2;
|
||||
subgroups[1].context = BT_AUDIO_CONTEXT_TYPE_MEDIA;
|
||||
subgroups[1].location = location;
|
||||
|
||||
broadcast_param->packing = BT_ISO_PACKING_INTERLEAVED;
|
||||
|
||||
broadcast_param->encryption = false;
|
||||
|
||||
bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(
|
||||
&subgroups[0].group_lc3_preset.codec_cfg);
|
||||
bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(
|
||||
&subgroups[1].group_lc3_preset.codec_cfg);
|
||||
|
||||
uint8_t spanish_src[3] = "spa";
|
||||
uint8_t english_src[3] = "eng";
|
||||
|
||||
bt_audio_codec_cfg_meta_set_stream_lang(&subgroups[0].group_lc3_preset.codec_cfg,
|
||||
(uint32_t)sys_get_le24(english_src));
|
||||
bt_audio_codec_cfg_meta_set_stream_lang(&subgroups[1].group_lc3_preset.codec_cfg,
|
||||
(uint32_t)sys_get_le24(spanish_src));
|
||||
|
||||
broadcast_param->subgroups = subgroups;
|
||||
broadcast_param->num_subgroups = 2;
|
||||
}
|
||||
#endif /* CONFIG_CUSTOM_BROADCASTER */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
static struct broadcast_source_big broadcast_param;
|
||||
|
||||
LOG_DBG("Main started");
|
||||
|
||||
size_t ext_adv_buf_cnt = 0;
|
||||
size_t per_adv_buf_cnt = 0;
|
||||
|
||||
ret = nrf5340_audio_dk_init();
|
||||
ERR_CHK(ret);
|
||||
|
||||
ret = fw_info_app_print();
|
||||
ERR_CHK(ret);
|
||||
|
||||
ret = bt_mgmt_init();
|
||||
ERR_CHK(ret);
|
||||
|
||||
ret = audio_system_init();
|
||||
ERR_CHK(ret);
|
||||
|
||||
ret = zbus_subscribers_create();
|
||||
ERR_CHK_MSG(ret, "Failed to create zbus subscriber threads");
|
||||
|
||||
ret = zbus_link_producers_observers();
|
||||
ERR_CHK_MSG(ret, "Failed to link zbus producers and observers");
|
||||
|
||||
broadcast_source_default_create(&broadcast_param);
|
||||
|
||||
/* Only one BIG supported at the moment */
|
||||
ret = broadcast_source_enable(&broadcast_param, 0);
|
||||
ERR_CHK_MSG(ret, "Failed to enable broadcaster(s)");
|
||||
|
||||
ret = audio_system_config_set(
|
||||
bt_audio_codec_cfg_freq_to_freq_hz(CONFIG_BT_AUDIO_PREF_SAMPLE_RATE_VALUE),
|
||||
CONFIG_BT_AUDIO_BITRATE_BROADCAST_SRC, VALUE_NOT_SET);
|
||||
ERR_CHK_MSG(ret, "Failed to set sample- and bitrate");
|
||||
|
||||
/* Get advertising set for BIG0 */
|
||||
ret = ext_adv_populate(0, &ext_adv_data[0], ext_adv_buf[0], ARRAY_SIZE(ext_adv_buf[0]),
|
||||
&ext_adv_buf_cnt);
|
||||
ERR_CHK(ret);
|
||||
|
||||
ret = per_adv_populate(0, &per_adv_data[0], &per_adv_buf[0], 1, &per_adv_buf_cnt);
|
||||
ERR_CHK(ret);
|
||||
|
||||
/* Start broadcaster */
|
||||
ret = bt_mgmt_adv_start(0, ext_adv_buf[0], ext_adv_buf_cnt, &per_adv_buf[0],
|
||||
per_adv_buf_cnt, false);
|
||||
ERR_CHK_MSG(ret, "Failed to start first advertiser");
|
||||
|
||||
LOG_INF("Broadcast source: %s started", CONFIG_BT_AUDIO_BROADCAST_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
broadcast_source/overlay-broadcast_source.conf
Normal file
28
broadcast_source/overlay-broadcast_source.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_TRANSPORT_BIS=y
|
||||
CONFIG_AUDIO_DEV=2
|
||||
|
||||
CONFIG_BT_CAP_INITIATOR=y
|
||||
CONFIG_BT_AUDIO=y
|
||||
|
||||
CONFIG_BT_DEVICE_APPEARANCE=2181
|
||||
|
||||
CONFIG_BT_ISO_BROADCASTER=y
|
||||
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
|
||||
CONFIG_BT_ISO_TX_BUF_COUNT=2
|
||||
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2
|
||||
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
CONFIG_BT_ISO_MAX_BIG=2
|
||||
|
||||
CONFIG_LC3_ENC_CHAN_MAX=2
|
||||
CONFIG_ENTROPY_GENERATOR=y
|
||||
Reference in New Issue
Block a user