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:
parent
8779dbf56f
commit
a84d2b2e1a
7 changed files with 225 additions and 0 deletions
11
samples/bluetooth/broadcast_audio_source/CMakeLists.txt
Normal file
11
samples/bluetooth/broadcast_audio_source/CMakeLists.txt
Normal 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)
|
27
samples/bluetooth/broadcast_audio_source/README.rst
Normal file
27
samples/bluetooth/broadcast_audio_source/README.rst
Normal 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.
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_BT_CTLR_ADV_EXT=y
|
||||||
|
CONFIG_BT_CTLR_ADV_PERIODIC=y
|
||||||
|
CONFIG_BT_CTLR_ADV_ISO=y
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_BT_CTLR_ADV_EXT=y
|
||||||
|
CONFIG_BT_CTLR_ADV_PERIODIC=y
|
||||||
|
CONFIG_BT_CTLR_ADV_ISO=y
|
9
samples/bluetooth/broadcast_audio_source/prj.conf
Normal file
9
samples/bluetooth/broadcast_audio_source/prj.conf
Normal 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"
|
8
samples/bluetooth/broadcast_audio_source/sample.yaml
Normal file
8
samples/bluetooth/broadcast_audio_source/sample.yaml
Normal 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
|
164
samples/bluetooth/broadcast_audio_source/src/main.c
Normal file
164
samples/bluetooth/broadcast_audio_source/src/main.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue