arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AudioBLEServerESP32.h
1#pragma once
2
3#include "AudioBLEStream.h"
4#include "ConstantsESP32.h"
5//#include <BLE2902.h>
6#include <BLEDevice.h>
7#include <BLEServer.h>
8#include <BLEUtils.h>
9#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
10
11namespace audio_tools {
20class AudioBLEServer : public AudioBLEStream,
21 public BLECharacteristicCallbacks,
22 public BLEServerCallbacks {
23public:
24 AudioBLEServer(int mtu = BLE_MTU) : AudioBLEStream(mtu) {}
25
26 // starts a BLE server with the indicated name
27 bool begin(const char *name) {
28 TRACEI();
29 ble_server_name = name;
30 BLEDevice::init(name);
31
32 p_server = BLEDevice::createServer();
33 p_server->setCallbacks(this);
34
35 setupBLEService();
36 p_advertising = BLEDevice::getAdvertising();
37 p_advertising->addServiceUUID(BLE_AUDIO_SERVICE_UUID);
38 BLEDevice::startAdvertising();
39 return true;
40 }
41
42 void end() override {
43 TRACEI();
44 flush();
45 BLEDevice::deinit();
46 }
47
48 size_t readBytes(uint8_t *data, size_t len) override {
49 TRACED();
50 size_t read_size = getReadSize(len);
51 return receive_buffer.readArray(data, read_size);
52 }
53
54 int available() override {
55 if (is_framed)
56 return receive_sizes.peek();
57 return this->receive_buffer.available();
58 }
59
60 size_t write(const uint8_t *data, size_t dataSize) override {
61 LOGD("AudioBLEStream::write: %d", dataSize);
62 if (!connected()) {
63 return 0;
64 }
65 if (is_framed && availableForWrite() < dataSize) {
66 return 0;
67 }
68 return transmit_buffer.writeArray(data, dataSize);
69 }
70
71 int availableForWrite() override {
72 int result = transmit_buffer.availableForWrite();
73 // make sure we copy always a consistent amount of data
74 if (result < DEFAULT_BUFFER_SIZE) result = 0;
75 return result ;
76 }
77
78 bool connected() override { return p_server->getConnectedCount() > 0; }
79
80protected:
81 // server
82 BLEServer *p_server = nullptr;
83 BLEService *p_service = nullptr;
84 BLEAdvertising *p_advertising = nullptr;
85 BLECharacteristic *ch01_char;
86 BLECharacteristic *ch02_char;
87 BLECharacteristic *info_char;
88 BLEDescriptor ch01_desc{"2901"};
89 BLEDescriptor ch02_desc{"2901"};
90 BLEDescriptor info_desc{"2901"};
91 RingBuffer<uint8_t> receive_buffer{0};
92 RingBuffer<uint16_t> receive_sizes{0};
93 RingBuffer<uint8_t> transmit_buffer{0};
94 RingBuffer<uint16_t> transmit_buffer_sizes{0};
95
96 virtual void receiveAudio(const uint8_t *data, size_t size) {
97 while (receive_buffer.availableForWrite() < size) {
98 // wait for ringbuffer to get freed up
99 delay(10);
100 }
101 if (is_framed)
102 receive_sizes.write(size);
103 receive_buffer.writeArray(data, size);
104 }
105
106 void writeAudioInfoCharacteristic(AudioInfo info) {
107 TRACEI();
108 // send update via BLE
109 StrView str = toStr(info);
110 LOGI("AudioInfo: %s", str.c_str());
111 info_char->setValue((uint8_t *)str.c_str(), str.length() + 1);
112 info_char->notify();
113 }
114
115 int getMTU() override {
116 TRACED();
117 if (max_transfer_size == 0) {
118 int peer_max_transfer_size =
119 p_server->getPeerMTU(p_server->getConnId()) - BLE_MTU_OVERHEAD;
120 max_transfer_size = std::min(BLE_MTU - BLE_MTU, peer_max_transfer_size);
121
122 LOGI("max_transfer_size: %d", max_transfer_size);
123 }
124 return max_transfer_size;
125 }
126
127 void setupBLEService() {
128 TRACEI();
129 // characteristic property is what the other device does.
130
131 if (p_service == nullptr) {
132 p_service = p_server->createService(BLE_AUDIO_SERVICE_UUID);
133
134 ch01_char = p_service->createCharacteristic(
135 BLE_CH1_UUID, BLECharacteristic::PROPERTY_READ );
136 ch01_desc.setValue("Channel 1");
137 ch01_char->addDescriptor(&ch01_desc);
138 ch01_char->setCallbacks(this);
139
140 ch02_char = p_service->createCharacteristic(
141 BLE_CH2_UUID, BLECharacteristic::PROPERTY_WRITE);
142 ch02_desc.setValue("Channel 2");
143 ch02_char->addDescriptor(&ch02_desc);
144 ch02_char->setCallbacks(this);
145
146 // optional setup of audio info notifications
147 if (is_audio_info_active && info_char == nullptr) {
148
149 info_char = p_service->createCharacteristic(
150 BLE_INFO_UUID, BLECharacteristic::PROPERTY_NOTIFY |
151 BLECharacteristic::PROPERTY_READ |
152 BLECharacteristic::PROPERTY_NOTIFY |
153 BLECharacteristic::PROPERTY_INDICATE);
154 info_desc.setValue("Audio Info");
155 info_char->addDescriptor(&info_desc);
156 info_char->setCallbacks(this);
157
158 }
159
160 p_service->start();
161
162 getMTU();
163
164 if (info_char != nullptr) {
165 writeAudioInfoCharacteristic(info);
166 }
167 }
168 }
169
170 void onConnect(BLEServer *pServer) override {
171 TRACEI();
172 }
173
174 void onDisconnect(BLEServer *pServer) override {
175 TRACEI();
176 BLEDevice::startAdvertising();
177 }
178
180 void onWrite(BLECharacteristic *pCharacteristic) override {
181 TRACED();
182 setupRXBuffer();
183 // changed to auto to be version independent (it changed from std::string to String)
184 auto value = pCharacteristic->getValue();
185 if (pCharacteristic->getUUID().toString() == BLE_INFO_UUID) {
186 setAudioInfo((uint8_t *)&value[0], value.length());
187 } else {
188 receiveAudio((uint8_t *)&value[0], value.length());
189 }
190 }
191
193 void onRead(BLECharacteristic *pCharacteristic) override {
194 TRACED();
195 // changed to auto to be version independent (it changed from std::string to String)
196 auto uuid = pCharacteristic->getUUID().toString();
197 if (uuid == BLE_CH1_UUID || uuid == BLE_CH2_UUID) {
198 setupTXBuffer();
199 int len = std::min(getMTU() - BLE_MTU_OVERHEAD, (int)transmit_buffer.available());
200 if (is_framed) {
201 len = transmit_buffer_sizes.read();
202 }
203 LOGD("%s: len: %d, buffer: %d", uuid.c_str(), len,
204 transmit_buffer.size());
205 uint8_t tmp[len];
206 transmit_buffer.readArray(tmp, len);
207 pCharacteristic->setValue(tmp, len);
208 }
209 }
210
211 void setupTXBuffer() {
212 if (transmit_buffer.size() == 0) {
213 LOGI("Setting transmit_buffer to %d for mtu %d", RX_BUFFER_SIZE, getMTU());
214 transmit_buffer.resize(TX_BUFFER_SIZE);
215 if (is_framed) {
216 transmit_buffer_sizes.resize(TX_COUNT);
217 }
218 }
219 }
220
221 void setupRXBuffer() {
222 if (receive_buffer.size() == 0) {
223 LOGI("Setting receive_buffer to %d for mtu %d", RX_BUFFER_SIZE, getMTU());
224 receive_buffer.resize(RX_BUFFER_SIZE);
225 if (is_framed) {
226 receive_sizes.resize(RX_COUNT);
227 }
228 }
229 }
230
231 size_t getReadSize(size_t dataSize) {
232 size_t read_size = dataSize;
233 if (is_framed) {
234 read_size = 0;
235 if (receive_sizes.available() > 0) {
236 read_size = receive_sizes.read();
237 }
238 if (dataSize < read_size) {
239 LOGE("read size too small: %d - it must be >= %d", dataSize, read_size);
240 return 0;
241 }
242 if (receive_buffer.available() < read_size) {
243 LOGE("missing data in buffer");
244 return 0;
245 }
246 }
247 return read_size;
248 }
249};
250
251
252} // namespace audio_tools
void onRead(BLECharacteristic *pCharacteristic) override
provide the next batch of audio data
Definition AudioBLEServerESP32.h:193
void onWrite(BLECharacteristic *pCharacteristic) override
store the next batch of data
Definition AudioBLEServerESP32.h:180
void setAudioInfo(AudioInfo info)
Defines the input AudioInfo.
Definition AudioBLEStream.h:27
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:37
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:59
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:328
virtual int availableForWrite()
provides the number of entries that are available to write
Definition Buffers.h:380
virtual int available()
provides the number of entries that are available to read
Definition Buffers.h:377
bool read(T &result) override
reads a single value
Definition Buffers.h:315
virtual bool write(T data)
write add an entry to the buffer
Definition Buffers.h:358
virtual size_t size()
Returns the maximum capacity of the buffer.
Definition Buffers.h:394
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10