arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AudioBLEClientESP32.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
10namespace audio_tools {
11
12class AudioBLEClient;
13static AudioBLEClient *selfAudioBLEClient = nullptr;
14
23class AudioBLEClient : public AudioBLEStream,
24 public BLEClientCallbacks,
25 public BLEAdvertisedDeviceCallbacks {
26public:
27 AudioBLEClient(int mtu = BLE_MTU) : AudioBLEStream(mtu) {
28 selfAudioBLEClient = this;
29 max_transfer_size = mtu;
30 }
31
33 bool begin(const char *localName, int seconds) {
34 TRACEI();
35 // Init BLE device
36 BLEDevice::init(localName);
37
38 // Retrieve a Scanner and set the callback we want to use to be informed
39 // when we have detected a new device.
40 BLEScan *pBLEScan = BLEDevice::getScan();
41 pBLEScan->setAdvertisedDeviceCallbacks(this);
42 pBLEScan->setActiveScan(true);
43 pBLEScan->start(seconds);
44 return true;
45 }
46
47 void end() override {
48 TRACEI();
49 flush();
50 BLEDevice::deinit();
51 }
52
53 size_t readBytes(uint8_t *data, size_t len) override {
54 TRACED();
55 setupBLEClient();
56 if (!is_client_connected || !is_client_set_up)
57 return 0;
58 if (!ch01_char->canRead())
59 return 0;
60 // changed to auto to be version independent (it changed from std::string to
61 // String)
62 auto str = ch01_char->readValue();
63 if (str.length() > 0) {
64 memcpy(data, str.c_str(), str.length());
65 }
66 return str.length();
67 }
68
69 int available() override { return BLE_MTU - BLE_MTU_OVERHEAD; }
70
71 size_t write(const uint8_t *data, size_t len) override {
72 TRACED();
73 setupBLEClient();
74 if (!is_client_connected || !is_client_set_up)
75 return 0;
76 if (!ch02_char->canWrite()){
77 return 0;
78 }
79
80 if (is_framed){
81 writeChannel2Characteristic(data, len);
82 delay(1);
83 } else {
84 // send only data with max mtu
85 for (int j=0; j<len; j++){
86 write_buffer.write(data[j]);
87 if (write_buffer.isFull()){
88 writeChannel2Characteristic(write_buffer.data(), write_buffer.available());
89 write_buffer.reset();
90 }
91 }
92 }
93 return len;
94 }
95
96 int availableForWrite() override {
97 return is_framed ? (BLE_MTU - BLE_MTU_OVERHEAD) : DEFAULT_BUFFER_SIZE;
98 }
99
100 bool connected() override {
101 if (!setupBLEClient()) {
102 LOGE("setupBLEClient failed");
103 }
104 return is_client_connected;
105 }
106
107 void setWriteThrottle(int ms){
108 write_throttle = ms;
109 }
110
111 void setConfirmWrite(bool flag){
112 write_confirmation_flag = flag;
113 }
114
115protected:
116 // client
117 BLEClient *p_client = nullptr;
118 BLEAdvertising *p_advertising = nullptr;
119 BLERemoteService *p_remote_service = nullptr;
120 BLEAddress *p_server_address = nullptr;
121 BLERemoteCharacteristic *ch01_char = nullptr; // read
122 BLERemoteCharacteristic *ch02_char = nullptr; // write
123 BLERemoteCharacteristic *info_char = nullptr;
124 BLEAdvertisedDevice advertised_device;
125 BLEUUID BLUEID_AUDIO_SERVICE_UUID{BLE_AUDIO_SERVICE_UUID};
126 BLEUUID BLUEID_CH1_UUID{BLE_CH1_UUID};
127 BLEUUID BLUEID_CH2_UUID{BLE_CH2_UUID};
128 BLEUUID BLUEID_INFO_UUID{BLE_INFO_UUID};
129 SingleBuffer<uint8_t> write_buffer{0};
130 int write_throttle = 0;
131 bool write_confirmation_flag = false;
132
133 volatile bool is_client_connected = false;
134 bool is_client_set_up = false;
135
136 void onConnect(BLEClient *pClient) override {
137 TRACEI();
138 is_client_connected = true;
139 }
140
141 void onDisconnect(BLEClient *pClient) override {
142 TRACEI();
143 is_client_connected = false;
144 };
145
146 void writeAudioInfoCharacteristic(AudioInfo info) override {
147 TRACEI();
148 // send update via BLE
149 info_char->writeValue((uint8_t *)&info, sizeof(AudioInfo));
150 }
151
152 void writeChannel2Characteristic(const uint8_t*data, size_t len){
153 if (ch02_char->canWrite()) {
154 ch02_char->writeValue((uint8_t *)data, len, write_confirmation_flag);
155 delay(write_throttle);
156 }
157 }
158
159 bool readAudioInfoCharacteristic(){
160 if (!info_char->canRead())
161 return false;
162 auto str = info_char->readValue();
163 if (str.length() > 0) {
164 setAudioInfo((const uint8_t*)str.c_str(), str.length());
165 return true;
166 }
167 return false;
168 }
169
170 // Scanning Results
171 void onResult(BLEAdvertisedDevice advertisedDevice) override {
172 TRACEI();
173 // Check if the name of the advertiser matches
174 if (advertisedDevice.haveServiceUUID() &&
175 advertisedDevice.isAdvertisingService(BLUEID_AUDIO_SERVICE_UUID)) {
176 LOGI("Service '%s' found!", BLE_AUDIO_SERVICE_UUID);
177 // save advertised_device in class variable
178 advertised_device = advertisedDevice;
179 // Scan can be stopped, we found what we are looking for
180 advertised_device.getScan()->stop();
181 }
182 delay(10);
183 }
184
185 static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic,
186 uint8_t *pData, size_t length, bool isNotify) {
187 TRACEI();
188 if (pBLERemoteCharacteristic->getUUID().toString() ==
189 selfAudioBLEClient->BLE_INFO_UUID) {
190 selfAudioBLEClient->setAudioInfo(pData, length);
191 }
192 }
193
194 bool setupBLEClient() {
195 if (is_client_set_up)
196 return true;
197
198 TRACEI();
199
200 // setup buffer
201 if (write_buffer.size()==0){
202 write_buffer.resize(getMTU() - BLE_MTU_OVERHEAD);
203 }
204
205 if (p_client == nullptr)
206 p_client = BLEDevice::createClient();
207
208 // onConnect and on onDisconnect support
209 p_client->setClientCallbacks(this);
210
211 // Connect to the remove BLE Server.
212 LOGI("Connecting to %s ...",
213 advertised_device.getAddress().toString().c_str());
214 // p_client->connect(advertised_device.getAddress(),BLE_ADDR_TYPE_RANDOM);
215 p_client->connect(&advertised_device);
216 if (!p_client->isConnected()) {
217 LOGE("Connect failed");
218 return false;
219 }
220 LOGI("Connected to %s ...",
221 advertised_device.getAddress().toString().c_str());
222
223 LOGI("Setting mtu to %d", max_transfer_size);
224 assert(max_transfer_size > 0);
225 p_client->setMTU(max_transfer_size);
226
227 // Obtain a reference to the service we are after in the remote BLE
228 // server.
229 if (p_remote_service == nullptr) {
230 p_remote_service = p_client->getService(BLUEID_AUDIO_SERVICE_UUID);
231 if (p_remote_service == nullptr) {
232 LOGE("Failed to find our service UUID: %s", BLE_AUDIO_SERVICE_UUID);
233 return (false);
234 }
235 }
236
237 if (ch01_char == nullptr) {
238 ch01_char = p_remote_service->getCharacteristic(BLUEID_CH1_UUID);
239 if (ch01_char == nullptr) {
240 LOGE("Failed to find char. UUID: %s", BLE_CH1_UUID);
241 return false;
242 }
243 }
244
245 if (ch02_char == nullptr) {
246 ch02_char = p_remote_service->getCharacteristic(BLUEID_CH2_UUID);
247 if (ch02_char == nullptr) {
248 LOGE("Failed to find char. UUID: %s", BLE_CH2_UUID);
249 return false;
250 }
251 }
252
253 if (is_audio_info_active && info_char == nullptr) {
254 info_char = p_remote_service->getCharacteristic(BLUEID_INFO_UUID);
255 if (info_char == nullptr) {
256 LOGE("Failed to find char. UUID: %s", BLE_INFO_UUID);
257 return false;
258 }
259 info_char->registerForNotify(notifyCallback);
260 readAudioInfoCharacteristic();
261
262 }
263 LOGI("Connected to server: %s", is_client_connected ? "true" : "false");
264 is_client_set_up = true;
265 is_client_connected = true;
266 return is_client_connected;
267 }
268
269 int getMTU() override { return BLE_MTU; }
270
271
272};
273
274} // namespace audio_tools
bool begin(const char *localName, int seconds)
starts a BLE client
Definition AudioBLEClientESP32.h:33
void setAudioInfo(AudioInfo info)
Defines the input AudioInfo.
Definition AudioBLEStream.h:27
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:200
int available() override
provides the number of entries that are available to read
Definition Buffers.h:227
bool isFull() override
checks if the buffer is full
Definition Buffers.h:234
T * data()
Provides address of actual data.
Definition Buffers.h:261
void reset() override
clears the buffer
Definition Buffers.h:263
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10