samples: Bluetooth: Add broadcast audio source sample

Add a sample using the Basic Audio Profile (BAP)
broadcast source role, that advertises mock audio
data over ISO.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2022-03-18 14:18:42 +01:00 committed by Carles Cufí
commit a84d2b2e1a
7 changed files with 225 additions and 0 deletions

View file

@ -0,0 +1,11 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(unicast_audio_server)
target_sources(app PRIVATE
src/main.c
)
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)

View file

@ -0,0 +1,27 @@
.. _bluetooth_broadcast_audio_source:
Bluetooth: Broadcast Audio Source
#################################
Overview
********
Application demonstrating the LE Audio broadcast audio source functionality.
Will start advertising extended advertising with audio flags, periodic advertising with the
broadcast audio source endpoint (BASE) and finally the BIGinfo together with
(mock) Audio (ISO) data.
The broadcast source will reset every 30 seconds to show the full API.
Requirements
************
* BlueZ running on the host, or
* A board with Bluetooth Low Energy 5.2 support
Building and Running
********************
This sample can be found under
:zephyr_file:`samples/bluetooth/broadcast_audio_source` in the Zephyr tree.
See :ref:`bluetooth samples section <bluetooth-samples>` for details.

View file

@ -0,0 +1,3 @@
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_PERIODIC=y
CONFIG_BT_CTLR_ADV_ISO=y

View file

@ -0,0 +1,3 @@
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_PERIODIC=y
CONFIG_BT_CTLR_ADV_ISO=y

View file

@ -0,0 +1,9 @@
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_AUDIO=y
CONFIG_BT_AUDIO_BROADCAST_SOURCE=y
CONFIG_BT_AUDIO_BROADCAST_SRC_STREAM_COUNT=1
CONFIG_BT_ISO_TX_BUF_COUNT=2
CONFIG_BT_DEVICE_NAME="Broadcast Audio Source"

View file

@ -0,0 +1,8 @@
sample:
description: Bluetooth Low Energy Broadcast Audio Source sample
name: Bluetooth Low Energy Broadcast Audio Source sample
tests:
sample.bluetooth.broadcast_audio_source:
harness: bluetooth
platform_allow: qemu_cortex_m3 qemu_x86 nrf52_bsim
tags: bluetooth

View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <bluetooth/bluetooth.h>
#include <bluetooth/audio/audio.h>
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
* the controller is never idle
*/
#define BROADCAST_ENQUEUE_COUNT 2U
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_AUDIO_BROADCAST_SRC_STREAM_COUNT)
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
"BROADCAST_ENQUEUE_COUNT * CONFIG_BT_AUDIO_BROADCAST_SRC_STREAM_COUNT");
static struct bt_audio_lc3_preset preset_16_2_1 = BT_AUDIO_LC3_BROADCAST_PRESET_16_2_1;
static struct bt_audio_stream streams[CONFIG_BT_AUDIO_BROADCAST_SRC_STREAM_COUNT];
static struct bt_audio_broadcast_source *broadcast_source;
NET_BUF_POOL_FIXED_DEFINE(tx_pool,
TOTAL_BUF_NEEDED,
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU];
static bool stopping;
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams));
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
#define BROADCAST_SOURCE_LIFETIME 30U /* seconds */
static void stream_started_cb(struct bt_audio_stream *stream)
{
k_sem_give(&sem_started);
}
static void stream_stopped_cb(struct bt_audio_stream *stream)
{
k_sem_give(&sem_stopped);
}
static void stream_sent_cb(struct bt_audio_stream *stream)
{
static uint32_t sent_cnt;
struct net_buf *buf;
int ret;
if (stopping) {
return;
}
buf = net_buf_alloc(&tx_pool, K_FOREVER);
if (buf == NULL) {
printk("Could not allocate buffer when sending on %p\n",
stream);
return;
}
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
net_buf_add_mem(buf, mock_data, preset_16_2_1.qos.sdu);
ret = bt_audio_stream_send(stream, buf);
if (ret < 0) {
/* This will end broadcasting on this stream. */
printk("Unable to broadcast data on %p: %d\n", stream, ret);
net_buf_unref(buf);
return;
}
sent_cnt++;
if ((sent_cnt % 1000U) == 0U) {
printk("Sent %u total ISO packets\n", sent_cnt);
}
}
struct bt_audio_stream_ops stream_ops = {
.started = stream_started_cb,
.stopped = stream_stopped_cb,
.sent = stream_sent_cb
};
void main(void)
{
int err;
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
streams[i].ops = &stream_ops;
}
for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) {
/* Initialize mock data */
mock_data[i] = i;
}
while (true) {
printk("Creating broadcast source\n");
err = bt_audio_broadcast_source_create(streams,
ARRAY_SIZE(streams),
&preset_16_2_1.codec,
&preset_16_2_1.qos,
&broadcast_source);
if (err != 0) {
printk("Unable to create broadcast source: %d\n", err);
return;
}
printk("Starting broadcast source\n");
stopping = false;
err = bt_audio_broadcast_source_start(broadcast_source);
if (err != 0) {
printk("Unable to start broadcast source: %d\n", err);
return;
}
/* Wait for all to be started */
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
k_sem_take(&sem_started, K_FOREVER);
}
printk("Broadcast source started\n");
/* Initialize sending */
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) {
stream_sent_cb(&streams[i]);
}
}
printk("Waiting %u seconds before stopped\n",
BROADCAST_SOURCE_LIFETIME);
k_sleep(K_SECONDS(BROADCAST_SOURCE_LIFETIME));
printk("Stopping broadcast source\n");
stopping = true;
err = bt_audio_broadcast_source_stop(broadcast_source);
if (err != 0) {
printk("Unable to stop broadcast source: %d\n", err);
return;
}
/* Wait for all to be stopped */
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
k_sem_take(&sem_stopped, K_FOREVER);
}
printk("Broadcast source stopped\n");
printk("Deleting broadcast source\n");
err = bt_audio_broadcast_source_delete(broadcast_source);
if (err != 0) {
printk("Unable to delete broadcast source: %d\n", err);
return;
}
printk("Broadcast source deleted\n");
broadcast_source = NULL;
}
}