From 5c599a62ea0e876189364ff2dd8a171c729d4ebe Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Tue, 27 Feb 2024 17:39:40 +0800 Subject: [PATCH] samples: bluetooth: a2dp_source: implement the a2dp source example. The sample implement the a2dp source that canconnect to one A2DP Bluetooth headset. This are shell commands to find and connect to Bluetooth headset in this sample, it plays one 1k sin media data after connection. Signed-off-by: Mark Wang --- samples/bluetooth/a2dp_source/CMakeLists.txt | 10 + samples/bluetooth/a2dp_source/README.rst | 40 +++ .../a2dp_source/boards/mimxrt1060_evk.overlay | 17 + samples/bluetooth/a2dp_source/prj.conf | 15 + samples/bluetooth/a2dp_source/sample.yaml | 7 + .../a2dp_source/src/a2dp_media_48KHz_1ksin.h | 136 +++++++ .../bluetooth/a2dp_source/src/app_connect.c | 132 +++++++ .../bluetooth/a2dp_source/src/app_connect.h | 27 ++ .../bluetooth/a2dp_source/src/app_discover.c | 107 ++++++ .../bluetooth/a2dp_source/src/app_discover.h | 22 ++ samples/bluetooth/a2dp_source/src/app_shell.c | 86 +++++ samples/bluetooth/a2dp_source/src/main.c | 331 ++++++++++++++++++ 12 files changed, 930 insertions(+) create mode 100644 samples/bluetooth/a2dp_source/CMakeLists.txt create mode 100644 samples/bluetooth/a2dp_source/README.rst create mode 100644 samples/bluetooth/a2dp_source/boards/mimxrt1060_evk.overlay create mode 100644 samples/bluetooth/a2dp_source/prj.conf create mode 100644 samples/bluetooth/a2dp_source/sample.yaml create mode 100644 samples/bluetooth/a2dp_source/src/a2dp_media_48KHz_1ksin.h create mode 100644 samples/bluetooth/a2dp_source/src/app_connect.c create mode 100644 samples/bluetooth/a2dp_source/src/app_connect.h create mode 100644 samples/bluetooth/a2dp_source/src/app_discover.c create mode 100644 samples/bluetooth/a2dp_source/src/app_discover.h create mode 100644 samples/bluetooth/a2dp_source/src/app_shell.c create mode 100644 samples/bluetooth/a2dp_source/src/main.c diff --git a/samples/bluetooth/a2dp_source/CMakeLists.txt b/samples/bluetooth/a2dp_source/CMakeLists.txt new file mode 100644 index 0000000000000..03194aa85726d --- /dev/null +++ b/samples/bluetooth/a2dp_source/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(a2dp_source) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/a2dp_source/README.rst b/samples/bluetooth/a2dp_source/README.rst new file mode 100644 index 0000000000000..7a6b8ed7f8155 --- /dev/null +++ b/samples/bluetooth/a2dp_source/README.rst @@ -0,0 +1,40 @@ +.. _bt_a2dp_source: + +Bluetooth: A2DP +#################### + +Overview +******** + +Application demonstrating usage of the A2dp Profile APIs. + +This sample can be found under :zephyr_file:`samples/bluetooth/a2dp_source` in +the Zephyr tree. + +Check :ref:`bluetooth samples section ` for details. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth BR/EDR (Classic) support + +Building and Running +******************** + +When building targeting mimxrt1060_evk board with the murata 1xk Controller. + +Building for an mimxrt1060_evk + murata 1xk +------------------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/a2dp_source/ + :board: mimxrt1060_evk + :goals: build + +Building for the sample +----------------------- + +1. input `bt discover` to discover BT devices. +2. input `bt connect ` to connect the found BT device, the is the result of step 1. +3. `bt disconnect` can be used to disconnect connection. diff --git a/samples/bluetooth/a2dp_source/boards/mimxrt1060_evk.overlay b/samples/bluetooth/a2dp_source/boards/mimxrt1060_evk.overlay new file mode 100644 index 0000000000000..f48eea9172ce5 --- /dev/null +++ b/samples/bluetooth/a2dp_source/boards/mimxrt1060_evk.overlay @@ -0,0 +1,17 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,bt-uart = &lpuart3; + }; +}; + +&lpuart3 { + status = "okay"; + current-speed = <3000000>; + hw-flow-control; +}; diff --git a/samples/bluetooth/a2dp_source/prj.conf b/samples/bluetooth/a2dp_source/prj.conf new file mode 100644 index 0000000000000..639c3b2a03bff --- /dev/null +++ b/samples/bluetooth/a2dp_source/prj.conf @@ -0,0 +1,15 @@ +CONFIG_BT=y +CONFIG_BT_L2CAP_TX_MTU=1000 +CONFIG_BT_BREDR=y +CONFIG_BT_AVDTP=y +CONFIG_BT_A2DP=y +CONFIG_BT_A2DP_SOURCE=y +CONFIG_LIBSBC_ENCODER=y +CONFIG_BT_DEVICE_NAME="a2dp-source-sample" +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_SHELL=y +CONFIG_SHELL_HELP=y +CONFIG_SHELL_MINIMAL=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=12 diff --git a/samples/bluetooth/a2dp_source/sample.yaml b/samples/bluetooth/a2dp_source/sample.yaml new file mode 100644 index 0000000000000..fe623bf3c5873 --- /dev/null +++ b/samples/bluetooth/a2dp_source/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth A2dp Source +tests: + sample.bluetooth.a2dp_source: + harness: bluetooth + platform_allow: mimxrt1060_evk + tags: bluetooth diff --git a/samples/bluetooth/a2dp_source/src/a2dp_media_48KHz_1ksin.h b/samples/bluetooth/a2dp_source/src/a2dp_media_48KHz_1ksin.h new file mode 100644 index 0000000000000..11f4951448f48 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/a2dp_media_48KHz_1ksin.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +static const uint8_t beethoven[] = { +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, + +0x0, 0x0, 0x0, 0x0, 0xb5, 0x10, 0xb5, 0x10, 0x21, 0x21, 0x21, 0x21, 0xfb, 0x30, 0xfb, 0x30, +0xff, 0x3f, 0xff, 0x3f, 0xeb, 0x4d, 0xeb, 0x4d, 0x82, 0x5a, 0x82, 0x5a, 0x8c, 0x65, 0x8c, 0x65, +0xd9, 0x6e, 0xd9, 0x6e, 0x41, 0x76, 0x41, 0x76, 0xa2, 0x7b, 0xa2, 0x7b, 0xe7, 0x7e, 0xe7, 0x7e, +0xff, 0x7f, 0xff, 0x7f, 0xe7, 0x7e, 0xe7, 0x7e, 0xa2, 0x7b, 0xa2, 0x7b, 0x41, 0x76, 0x41, 0x76, +0xd9, 0x6e, 0xd9, 0x6e, 0x8c, 0x65, 0x8c, 0x65, 0x82, 0x5a, 0x82, 0x5a, 0xeb, 0x4d, 0xeb, 0x4d, +0xff, 0x3f, 0xff, 0x3f, 0xfb, 0x30, 0xfb, 0x30, 0x21, 0x21, 0x21, 0x21, 0xb5, 0x10, 0xb5, 0x10, +0x0, 0x0, 0x0, 0x0, 0x4b, 0xef, 0x4b, 0xef, 0xdf, 0xde, 0xdf, 0xde, 0x5, 0xcf, 0x5, 0xcf, +0x0, 0xc0, 0x0, 0xc0, 0x15, 0xb2, 0x15, 0xb2, 0x7e, 0xa5, 0x7e, 0xa5, 0x74, 0x9a, 0x74, 0x9a, +0x27, 0x91, 0x27, 0x91, 0xbf, 0x89, 0xbf, 0x89, 0x5e, 0x84, 0x5e, 0x84, 0x19, 0x81, 0x19, 0x81, +0x1, 0x80, 0x1, 0x80, 0x19, 0x81, 0x19, 0x81, 0x5e, 0x84, 0x5e, 0x84, 0xbf, 0x89, 0xbf, 0x89, +0x27, 0x91, 0x27, 0x91, 0x74, 0x9a, 0x74, 0x9a, 0x7e, 0xa5, 0x7e, 0xa5, 0x15, 0xb2, 0x15, 0xb2, +0x0, 0xc0, 0x0, 0xc0, 0x5, 0xcf, 0x5, 0xcf, 0xdf, 0xde, 0xdf, 0xde, 0x4b, 0xef, 0x4b, 0xef, +}; diff --git a/samples/bluetooth/a2dp_source/src/app_connect.c b/samples/bluetooth/a2dp_source/src/app_connect.c new file mode 100644 index 0000000000000..7c30d6c0b5c74 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/app_connect.c @@ -0,0 +1,132 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "app_connect.h" + +extern void app_sdp_discover_a2dp_sink(void); +static void connected(struct bt_conn *conn, uint8_t err); +static void disconnected(struct bt_conn *conn, uint8_t reason); +static void security_changed(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err); + +struct bt_conn *default_conn; +bt_addr_t default_peer_addr; +static uint8_t default_connect_initialized; + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, +}; +extern struct bt_a2dp *default_a2dp; +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + if (default_conn != NULL) { + bt_conn_unref(default_conn); + default_conn = NULL; + } + printk("Connection failed (err 0x%02x)\n", err); + } else { + if (1U == default_connect_initialized) { + struct bt_conn_info info; + + default_connect_initialized = 0U; + bt_conn_get_info(conn, &info); + if (info.type == BT_CONN_TYPE_LE) { + return; + } + + default_conn = bt_conn_ref(conn); + /* + * Do an SDP Query on Successful ACL connection complete with the + * required device + */ + if (0 == memcmp(info.br.dst, &default_peer_addr, 6U)) { + app_sdp_discover_a2dp_sink(); + } + printk("Connected\n"); + } + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); + + if (default_conn != conn) { + return; + } + + if (default_conn) { + bt_conn_unref(default_conn); + default_conn = NULL; + } else { + return; + } +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (!err) { + printk("Security changed: %s level %u\n", addr, level); + } else { + if (err == BT_SECURITY_ERR_PIN_OR_KEY_MISSING) { + printk("\n"); + + printk("___________________________________________________________\n"); + printk("The peer device seems to have lost the bonding information.\n"); + printk("Kindly delete the bonding information of the peer from the\n"); + printk("and try again.\n\n"); + + printk("\n"); + } + printk("Security failed: %s level %u err %d\n", addr, level, err); + } +} + +void app_connect(uint8_t *addr) +{ + default_connect_initialized = 1U; + memcpy(&default_peer_addr, addr, 6U); + default_conn = bt_conn_create_br(&default_peer_addr, BT_BR_CONN_PARAM_DEFAULT); + if (!default_conn) { + default_connect_initialized = 0U; + printk("Connection failed\r\n"); + } else { + /* unref connection obj in advance as app user */ + bt_conn_unref(default_conn); + printk("Connection pending\r\n"); + } +} + +void app_disconnect(void) +{ + if (bt_conn_disconnect(default_conn, 0x13U)) { + printk("Disconnection failed\r\n"); + } +} + +void app_connect_init(void) +{ + bt_conn_cb_register(&conn_callbacks); +} diff --git a/samples/bluetooth/a2dp_source/src/app_connect.h b/samples/bluetooth/a2dp_source/src/app_connect.h new file mode 100644 index 0000000000000..47f19d30390a3 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/app_connect.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __APP_CONNECT_H__ +#define __APP_CONNECT_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +extern struct bt_conn *default_conn; +extern bt_addr_t default_peer_addr; + +/******************************************************************************* + * API + ******************************************************************************/ + +void app_connect_init(void); + +void app_connect(uint8_t *addr); + +void app_disconnect(void); + +#endif /* __APP_CONNECT_H__ */ diff --git a/samples/bluetooth/a2dp_source/src/app_discover.c b/samples/bluetooth/a2dp_source/src/app_discover.c new file mode 100644 index 0000000000000..cae072e7972a7 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/app_discover.c @@ -0,0 +1,107 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APP_INQUIRY_LENGTH (10) /* 10 * 1.28 Sec */ +#define APP_INQUIRY_NUM_RESPONSES (20) + +static uint32_t br_discover_result_count; +static struct bt_br_discovery_result br_discovery_results[APP_INQUIRY_NUM_RESPONSES]; + +static void br_device_found(size_t index, const bt_addr_t *addr, int8_t rssi, + const uint8_t cod[3], const uint8_t eir[240]) +{ + char br_addr[BT_ADDR_STR_LEN]; + char name[239]; + int len = 240; + + (void)memset(name, 0, sizeof(name)); + + while (len) { + if (len < 2) { + break; + } + + /* Look for early termination */ + if (!eir[0]) { + break; + } + + /* check if field length is correct */ + if (eir[0] > len - 1) { + break; + } + + switch (eir[1]) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(name, &eir[2], (eir[0] - 1) > (sizeof(name) - 1) ? + (sizeof(name) - 1) : (eir[0] - 1)); + break; + default: + break; + } + + /* Parse next AD Structure */ + len -= (eir[0] + 1); + eir += (eir[0] + 1); + } + + bt_addr_to_str(addr, br_addr, sizeof(br_addr)); + printk("[%d]: %s, RSSI %i %s\r\n", index + 1, br_addr, rssi, name); +} + +static void br_discovery_complete(struct bt_br_discovery_result *results, + size_t count) +{ + size_t index; + + br_discover_result_count = count; + printk("BR/EDR discovery complete\r\n"); + for (index = 0; index < count; ++index) { + br_device_found(index, &results[index].addr, results[index].rssi, + results[index].cod, results[index].eir); + } +} + +void app_discover(void) +{ + int err; + struct bt_br_discovery_param param; + + param.length = APP_INQUIRY_LENGTH; + param.limited = 0U; + err = bt_br_discovery_start(¶m, br_discovery_results, + APP_INQUIRY_NUM_RESPONSES, + br_discovery_complete); + if (err != 0) { + printk("Failed to start discovery\r\n"); + } else { + printk("Discovery started. Please wait ...\r\n"); + } +} + +uint8_t *app_get_addr(uint8_t select) +{ + if (select < br_discover_result_count) { + return &br_discovery_results[select].addr.val[0]; + } + + return NULL; +} diff --git a/samples/bluetooth/a2dp_source/src/app_discover.h b/samples/bluetooth/a2dp_source/src/app_discover.h new file mode 100644 index 0000000000000..ad61721a110d1 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/app_discover.h @@ -0,0 +1,22 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __APP_DISCOVER_H__ +#define __APP_DISCOVER_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * API + ******************************************************************************/ + +void app_discover(void); + +uint8_t *app_get_addr(uint8_t select); + +#endif /* __APP_DISCOVER_H__ */ diff --git a/samples/bluetooth/a2dp_source/src/app_shell.c b/samples/bluetooth/a2dp_source/src/app_shell.c new file mode 100644 index 0000000000000..41476dea3c28d --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/app_shell.c @@ -0,0 +1,86 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "app_discover.h" +#include "app_connect.h" + +static int cmd_a2dp_source_bt_discover(const struct shell *sh, size_t argc, char *argv[]) +{ + app_discover(); + return 0; +} + +static int cmd_a2dp_source_bt_connect(const struct shell *sh, size_t argc, char *argv[]) +{ + uint8_t select_index = 0; + char *ch = argv[1]; + uint8_t *addr; + + if (argc < 2) { + printk("the parameter count is wrong\r\n"); + return SHELL_CMD_HELP_PRINTED; + } + + for (select_index = 0; select_index < strlen(ch); ++select_index) { + if ((ch[select_index] < '0') || (ch[select_index] > '9')) { + printk("the parameter is wrong\r\n"); + return SHELL_CMD_HELP_PRINTED; + } + } + + switch (strlen(ch)) { + case 1: + select_index = ch[0] - '0'; + break; + case 2: + select_index = (ch[0] - '0') * 10 + (ch[1] - '0'); + break; + default: + printk("the parameter is wrong\r\n"); + break; + } + + if (select_index == 0U) { + printk("the parameter is wrong\r\n"); + } + addr = app_get_addr(select_index - 1); + app_connect(addr); + return 0; +} + +static int cmd_a2dp_source_bt_disconnect(const struct shell *sh, size_t argc, char *argv[]) +{ + app_disconnect(); + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(a2dp_source_bt_cmds, + SHELL_CMD(discover, NULL, "start to find BT devices", cmd_a2dp_source_bt_discover), + SHELL_CMD_ARG(connect, NULL, + "connect to the device that is found, for example: bt connectdevice n (from 1)", + cmd_a2dp_source_bt_connect, 2, 0), + SHELL_CMD(disconnect, NULL, "disconnect current connection", + cmd_a2dp_source_bt_disconnect), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(bt, &a2dp_source_bt_cmds, "a2dp source demo shell commands", NULL); diff --git a/samples/bluetooth/a2dp_source/src/main.c b/samples/bluetooth/a2dp_source/src/main.c new file mode 100644 index 0000000000000..f25d2a8cdada4 --- /dev/null +++ b/samples/bluetooth/a2dp_source/src/main.c @@ -0,0 +1,331 @@ +/* + * Copyright 2020 - 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "app_connect.h" +#include "a2dp_media_48KHz_1ksin.h" + +#define SDP_CLIENT_USER_BUF_LEN 512U +NET_BUF_POOL_FIXED_DEFINE(app_sdp_client_pool, CONFIG_BT_MAX_CONN, + SDP_CLIENT_USER_BUF_LEN, 8, NULL); + +static uint8_t app_sdp_a2sink_user(struct bt_conn *conn, struct bt_sdp_client_result *result); + +static struct bt_sdp_discover_params discov_a2dp_sink = { + .uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SINK_SVCLASS), + .func = app_sdp_a2sink_user, + .pool = &app_sdp_client_pool, +}; + +static void a2dp_playback_timeout_handler(struct k_timer *timer); +K_TIMER_DEFINE(a2dp_player_timer, a2dp_playback_timeout_handler, NULL); + +#define APPL_A2DP_MTU (672U) +#define DEFAULT_BIT_RATE (328u) + +static uint32_t a2dp_src_sf; + +static int64_t ref_time; +static uint32_t a2dp_src_missed_count; +static volatile uint8_t a2dp_src_playback; +static int tone_index; +uint8_t a2dp_src_nc; + +#define A2DP_SBC_BLOCK_MAX (512U) +uint32_t audio_time_interval; /* ms */ +uint32_t audio_frame_sample_count; +uint8_t a2dp_pcm_buffer[1920u]; /* 10ms max packet pcm data size. the max is 480 * 2 * 2 */ +uint8_t a2dp_sbc_encode_buffer_frame[A2DP_SBC_BLOCK_MAX]; +struct sbc_encoder encoder; +uint32_t send_samples_count; +uint16_t send_count; + +#define A2DP_SRC_PERIOD_MS 10 + +struct bt_a2dp *default_a2dp; +struct bt_a2dp_endpoint *default_a2dp_endpoint; +BT_A2DP_SBC_SOURCE_ENDPOINT(sbc_endpoint, A2DP_SBC_SAMP_FREQ_48000); + +static uint8_t *a2dp_pl_produce_media(uint32_t a2dp_src_num_samples) +{ + uint8_t *media = NULL; + uint16_t medialen; + + /* Music Audio is Stereo */ + medialen = (a2dp_src_num_samples * a2dp_src_nc * 2); + + /* For mono or dual configuration, skip alternative samples */ + if (1 == a2dp_src_nc) { + uint16_t index; + + media = (uint8_t *)&a2dp_pcm_buffer[0]; + + for (index = 0; index < a2dp_src_num_samples; index++) { + media[(2 * index)] = *((uint8_t *)beethoven + tone_index); + media[(2 * index) + 1] = *((uint8_t *)beethoven + tone_index + 1); + /* Update the tone index */ + tone_index += 4u; + if (tone_index >= sizeof(beethoven)) { + tone_index = 0U; + } + } + } else { + if ((tone_index + (a2dp_src_num_samples << 2)) > sizeof(beethoven)) { + media = (uint8_t *)&a2dp_pcm_buffer[0]; + memcpy(media, ((uint8_t *)beethoven + tone_index), + sizeof(beethoven) - tone_index); + memcpy(&media[sizeof(beethoven) - tone_index], + ((uint8_t *)beethoven), + ((a2dp_src_num_samples << 2) - (sizeof(beethoven) - tone_index))); + /* Update the tone index */ + tone_index = ((a2dp_src_num_samples << 2) - + (sizeof(beethoven) - tone_index)); + } else { + media = ((uint8_t *)beethoven + tone_index); + /* Update the tone index */ + tone_index += (a2dp_src_num_samples << 2); + if (tone_index >= sizeof(beethoven)) { + tone_index = 0U; + } + } + } + + return media; +} + +static void a2dp_playback_timeout_handler(struct k_timer *timer) +{ + int64_t period_ms; + uint32_t a2dp_src_num_samples; + uint8_t *pcm_data; + uint8_t index; + uint32_t pcm_frame_size; + uint32_t pcm_frame_samples; + uint32_t encoded_frame_size; + uint8_t *net_buffer; + struct net_buf *buf; + uint32_t sample_count = 0; + uint8_t frame_num = 0; + int ret; + struct bt_a2dp_codec_sbc_media_packet_hdr *sbc_hdr; + int err; + + /* If stopped then return */ + if (0U == a2dp_src_playback) { + return; + } + + period_ms = k_uptime_delta(&ref_time); + + buf = bt_a2dp_media_buf_alloc(NULL); + if (buf == NULL) { + return; + } + sbc_hdr = net_buf_add(buf, sizeof(struct bt_a2dp_codec_sbc_media_packet_hdr)); + memset(sbc_hdr, 0, sizeof(struct bt_a2dp_codec_sbc_media_packet_hdr)); + /* Get the number of samples */ + a2dp_src_num_samples = (uint16_t)((period_ms * a2dp_src_sf) / 1000); + a2dp_src_missed_count += (uint32_t)((period_ms * a2dp_src_sf) % 1000); + + /* Raw adjust for the drift */ + while (a2dp_src_missed_count >= (1000 * audio_frame_sample_count)) { + a2dp_src_num_samples += audio_frame_sample_count; + a2dp_src_missed_count -= (1000 * audio_frame_sample_count); + } + + pcm_data = a2dp_pl_produce_media(a2dp_src_num_samples); + if (pcm_data == NULL) { + return; + } + + pcm_frame_size = sbc_frame_bytes(&encoder); + pcm_frame_samples = sbc_frame_samples(&encoder); + encoded_frame_size = sbc_frame_encoded_bytes(&encoder); + for (index = 0; index < (a2dp_src_num_samples / audio_frame_sample_count); index++) { + net_buffer = net_buf_tail(buf); + if (buf->len + encoded_frame_size > bt_a2dp_get_media_mtu(default_a2dp_endpoint)) { + printk("mtu error"); + return; + } + + err = sbc_encode(&encoder, + (uint8_t *)&pcm_data[index * pcm_frame_size], + encoded_frame_size, &net_buffer[0]); + if (err) { + printk("sbc encode fail"); + continue; + } + buf->len += encoded_frame_size; + sample_count += pcm_frame_samples; + frame_num++; + } + + sbc_hdr->number_of_sbc_frames = frame_num; + ret = bt_a2dp_media_send(default_a2dp_endpoint, buf, send_count, send_samples_count); + if (ret < 0) { + printk(" Failed to send SBC audio data on streams(%d)\n", ret); + net_buf_unref(buf); + } else { + send_count++; + send_samples_count += sample_count; + } +} + +static void music_control_a2dp_start_callback(int err) +{ + /* Start Audio Source */ + a2dp_src_playback = 1U; + audio_frame_sample_count = sbc_frame_samples(&encoder); + + /* calculate the interval that contains multiple of frame. default is 10ms */ + audio_time_interval = ((10 * a2dp_src_sf / 1000) / audio_frame_sample_count); + audio_time_interval = audio_time_interval * audio_frame_sample_count * 1000 / a2dp_src_sf; + k_uptime_delta(&ref_time); + k_timer_start(&a2dp_player_timer, K_MSEC(audio_time_interval), K_MSEC(audio_time_interval)); +} + +void app_endpoint_configured(struct bt_a2dp_endpoint_configure_result *result) +{ + if (result->err == 0) { + default_a2dp_endpoint = &sbc_endpoint; + struct bt_a2dp_codec_sbc_params *config = + (struct bt_a2dp_codec_sbc_params *) + &result->config.media_config->codec_ie[0]; + + a2dp_src_sf = bt_a2dp_sbc_get_sampling_frequency(config); + a2dp_src_nc = bt_a2dp_sbc_get_channel_num(config); + + sbc_setup_encoder(&encoder, a2dp_src_sf, bt_a2dp_sbc_get_channel_mode(config), + bt_a2dp_sbc_get_block_length(config), bt_a2dp_sbc_get_subband_num(config), + bt_a2dp_sbc_get_allocation_method(config), DEFAULT_BIT_RATE); + bt_a2dp_start(default_a2dp_endpoint); + printk("a2dp start playing\r\n"); + } +} + +void app_configured(int err) +{ + if (err) { + printk("configuring fail\r\n"); + } +} + +void app_connected(struct bt_a2dp *a2dp, int err) +{ + if (!err) { + bt_a2dp_configure(a2dp, app_configured); + printk("a2dp connected success\r\n"); + } else { + if (default_a2dp != NULL) { + default_a2dp = NULL; + } + printk("a2dp connected fail\r\n"); + } +} + +void app_disconnected(struct bt_a2dp *a2dp) +{ + if (default_a2dp != NULL) { + default_a2dp = NULL; + } + a2dp_src_playback = 0U; + /* stop timer */ + k_timer_stop(&a2dp_player_timer); + printk("a2dp disconnected\r\n"); +} + +static uint8_t app_sdp_a2sink_user(struct bt_conn *conn, + struct bt_sdp_client_result *result) +{ + uint16_t param; + int res; + + if ((result) && (result->resp_buf)) { + printk("sdp success callback\r\n"); + res = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_L2CAP, ¶m); + if (res < 0) { + printk("PSM is not found\r\n"); + return BT_SDP_DISCOVER_UUID_CONTINUE; + } + if (param == BT_UUID_AVDTP_VAL) { + printk("A2DP Service found. Connecting ...\n"); + default_a2dp = bt_a2dp_connect(default_conn); + if (default_a2dp == NULL) { + printk("fail to connect a2dp\r\n"); + } + return BT_SDP_DISCOVER_UUID_STOP; + } + return BT_SDP_DISCOVER_UUID_CONTINUE; + } + + printk("sdp fail callback\r\n"); + return BT_SDP_DISCOVER_UUID_CONTINUE; +} + +void app_sdp_discover_a2dp_sink(void) +{ + int res; + + res = bt_sdp_discover(default_conn, &discov_a2dp_sink); + if (res) { + printk("SDP discovery failed: result\r\n"); + } else { + printk("SDP discovery started\r\n"); + } +} + +static void app_a2dp_init(void) +{ + struct bt_a2dp_connect_cb connect_cb; + + connect_cb.connected = app_connected; + connect_cb.disconnected = app_disconnected; + + sbc_endpoint.control_cbs.start_play = music_control_a2dp_start_callback; + sbc_endpoint.control_cbs.configured = app_endpoint_configured; + bt_a2dp_register_endpoint(&sbc_endpoint, BT_A2DP_AUDIO, BT_A2DP_SOURCE); + + bt_a2dp_register_connect_callback(&connect_cb); +} + +static void bt_ready(int err) +{ + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + app_connect_init(); + app_a2dp_init(); +} + +int main(void) +{ + int err; + + err = bt_enable(bt_ready); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + } + + return err; +}