mirror of
https://github.com/pschatzmann/arduino-audio-tools.git
synced 2024-09-21 18:37:28 +00:00
DRAFT BLE Arduino
This commit is contained in:
parent
dcb88c85fc
commit
8629540499
@ -15,10 +15,8 @@
|
||||
#include "Sandbox/BLE/AudioBLE.h"
|
||||
|
||||
AudioInfo info(16000, 1, 16);
|
||||
SineWaveGenerator<int16_t>
|
||||
sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
|
||||
GeneratedSoundStream<int16_t>
|
||||
sound(sineWave); // Stream generated from sine wave
|
||||
SineWaveGenerator<int16_t> sineWave(32000);
|
||||
GeneratedSoundStream<int16_t> sound(sineWave);
|
||||
Throttle throttle(sound);
|
||||
AudioBLEClient ble;
|
||||
ADPCMEncoder adpcm(AV_CODEC_ID_ADPCM_IMA_WAV);
|
||||
|
@ -1374,7 +1374,7 @@ class Throttle : public AudioStream {
|
||||
uint64_t durationUsEff = micros() - start_time;
|
||||
uint64_t durationUsToBe = getDelayUs(sum_frames);
|
||||
int64_t waitUs = durationUsToBe - durationUsEff + cfg.correction_us;
|
||||
LOGI("wait us: %ld", (long) waitUs);
|
||||
LOGI("wait us: %ld", static_cast<long>(waitUs));
|
||||
if (waitUs > 0) {
|
||||
int64_t waitMs = waitUs / 1000;
|
||||
if (waitMs > 0) delay(waitMs);
|
||||
|
@ -1,9 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP32
|
||||
//# include "AudioBLEServer.h"
|
||||
//# include "AudioBLEClient.h"
|
||||
# include "AudioBLEServerESP32.h"
|
||||
# include "AudioBLEClientESP32.h"
|
||||
#else
|
||||
# include "AudioBLEServer.h"
|
||||
# include "AudioBLEClient.h"
|
||||
#else
|
||||
# error Device not supported
|
||||
#endif
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "AudioBLEStream.h"
|
||||
//#include <BLE2902.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <ArduinoBLE.h>
|
||||
|
||||
namespace audio_tools {
|
||||
|
||||
@ -19,9 +16,7 @@ static AudioBLEClient *selfAudioBLEClient = nullptr;
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
class AudioBLEClient : public AudioBLEStream,
|
||||
public BLEClientCallbacks,
|
||||
public BLEAdvertisedDeviceCallbacks {
|
||||
class AudioBLEClient : public AudioBLEStream {
|
||||
public:
|
||||
AudioBLEClient(int mtu = BLE_MTU) : AudioBLEStream(mtu) {
|
||||
selfAudioBLEClient = this;
|
||||
@ -32,59 +27,52 @@ public:
|
||||
bool begin(const char *localName, int seconds) {
|
||||
TRACEI();
|
||||
// Init BLE device
|
||||
BLEDevice::init(localName);
|
||||
|
||||
// Retrieve a Scanner and set the callback we want to use to be informed
|
||||
// when we have detected a new device.
|
||||
BLEScan *pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(this);
|
||||
pBLEScan->setActiveScan(true);
|
||||
pBLEScan->start(seconds);
|
||||
BLE.begin();
|
||||
BLE.setLocalName(localName);
|
||||
BLE.scanForUuid(BLE_AUDIO_SERVICE_UUID);
|
||||
return true;
|
||||
}
|
||||
|
||||
void end() override {
|
||||
TRACEI();
|
||||
flush();
|
||||
BLEDevice::deinit();
|
||||
BLE.end();
|
||||
}
|
||||
|
||||
size_t readBytes(uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
setupBLEClient();
|
||||
if (!is_client_connected || !is_client_set_up)
|
||||
if (!setupBLEClient()) {
|
||||
return 0;
|
||||
if (!ch01_char->canRead())
|
||||
return 0;
|
||||
// changed to auto to be version independent (it changed from std::string to
|
||||
// String)
|
||||
auto str = ch01_char->readValue();
|
||||
if (str.length() > 0) {
|
||||
memcpy(data, str.c_str(), str.length());
|
||||
}
|
||||
return str.length();
|
||||
|
||||
if (!ch01_char.canRead())
|
||||
return 0;
|
||||
|
||||
return ch01_char.readValue(data, dataSize);
|
||||
}
|
||||
|
||||
int available() override { return BLE_MTU - BLE_MTU_OVERHEAD; }
|
||||
|
||||
size_t write(const uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
setupBLEClient();
|
||||
if (!is_client_connected || !is_client_set_up)
|
||||
return 0;
|
||||
if (!ch02_char->canWrite()){
|
||||
if (!setupBLEClient()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_framed){
|
||||
if (!ch02_char.canWrite()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_framed) {
|
||||
writeChannel2Characteristic(data, dataSize);
|
||||
delay(1);
|
||||
} else {
|
||||
// send only data with max mtu
|
||||
for (int j=0; j<dataSize; j++){
|
||||
for (int j = 0; j < dataSize; j++) {
|
||||
write_buffer.write(data[j]);
|
||||
if (write_buffer.isFull()){
|
||||
writeChannel2Characteristic(write_buffer.data(), write_buffer.available());
|
||||
if (write_buffer.isFull()) {
|
||||
writeChannel2Characteristic(write_buffer.data(),
|
||||
write_buffer.available());
|
||||
write_buffer.reset();
|
||||
}
|
||||
}
|
||||
@ -92,177 +80,106 @@ public:
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
int availableForWrite() override {
|
||||
return is_framed ? (BLE_MTU - BLE_MTU_OVERHEAD) : DEFAULT_BUFFER_SIZE;
|
||||
int availableForWrite() override {
|
||||
return is_framed ? (BLE_MTU - BLE_MTU_OVERHEAD) : DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
bool connected() override {
|
||||
if (!setupBLEClient()) {
|
||||
LOGE("setupBLEClient failed");
|
||||
}
|
||||
return is_client_connected;
|
||||
}
|
||||
bool connected() override { return setupBLEClient(); }
|
||||
|
||||
void setWriteThrottle(int ms){
|
||||
write_throttle = ms;
|
||||
}
|
||||
void setWriteThrottle(int ms) { write_throttle = ms; }
|
||||
|
||||
void setConfirmWrite(bool flag){
|
||||
write_confirmation_flag = flag;
|
||||
}
|
||||
void setConfirmWrite(bool flag) { write_confirmation_flag = flag; }
|
||||
|
||||
protected:
|
||||
// client
|
||||
BLEClient *p_client = nullptr;
|
||||
BLEAdvertising *p_advertising = nullptr;
|
||||
BLERemoteService *p_remote_service = nullptr;
|
||||
BLEAddress *p_server_address = nullptr;
|
||||
BLERemoteCharacteristic *ch01_char = nullptr; // read
|
||||
BLERemoteCharacteristic *ch02_char = nullptr; // write
|
||||
BLERemoteCharacteristic *info_char = nullptr;
|
||||
BLEAdvertisedDevice advertised_device;
|
||||
BLEUUID BLUEID_AUDIO_SERVICE_UUID{BLE_AUDIO_SERVICE_UUID};
|
||||
BLEUUID BLUEID_CH1_UUID{BLE_CH1_UUID};
|
||||
BLEUUID BLUEID_CH2_UUID{BLE_CH2_UUID};
|
||||
BLEUUID BLUEID_INFO_UUID{BLE_INFO_UUID};
|
||||
BLEDevice peripheral;
|
||||
BLECharacteristic ch01_char;
|
||||
BLECharacteristic ch02_char;
|
||||
BLECharacteristic info_char;
|
||||
SingleBuffer<uint8_t> write_buffer{0};
|
||||
int write_throttle = 0;
|
||||
bool write_confirmation_flag = false;
|
||||
|
||||
volatile bool is_client_connected = false;
|
||||
bool is_client_set_up = false;
|
||||
|
||||
void onConnect(BLEClient *pClient) override {
|
||||
TRACEI();
|
||||
is_client_connected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient *pClient) override {
|
||||
TRACEI();
|
||||
is_client_connected = false;
|
||||
};
|
||||
|
||||
void writeAudioInfoCharacteristic(AudioInfo info) override {
|
||||
TRACEI();
|
||||
// send update via BLE
|
||||
info_char->writeValue((uint8_t *)&info, sizeof(AudioInfo));
|
||||
info_char.writeValue((uint8_t *)&info, sizeof(AudioInfo));
|
||||
}
|
||||
|
||||
void writeChannel2Characteristic(const uint8_t*data, size_t len){
|
||||
if (ch02_char->canWrite()) {
|
||||
ch02_char->writeValue((uint8_t *)data, len, write_confirmation_flag);
|
||||
void writeChannel2Characteristic(const uint8_t *data, size_t len) {
|
||||
if (ch02_char.canWrite()) {
|
||||
ch02_char.writeValue((uint8_t *)data, len, write_confirmation_flag);
|
||||
delay(write_throttle);
|
||||
}
|
||||
}
|
||||
|
||||
bool readAudioInfoCharacteristic(){
|
||||
if (!info_char->canRead())
|
||||
bool readAudioInfoCharacteristic() {
|
||||
if (!info_char.canRead())
|
||||
return false;
|
||||
auto str = info_char->readValue();
|
||||
if (str.length() > 0) {
|
||||
setAudioInfo((const uint8_t*)str.c_str(), str.length());
|
||||
const uint8_t *str = info_char.value();
|
||||
int len = info_char.valueLength();
|
||||
if (len > 0) {
|
||||
setAudioInfo(str, len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scanning Results
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) override {
|
||||
TRACEI();
|
||||
// Check if the name of the advertiser matches
|
||||
if (advertisedDevice.haveServiceUUID() &&
|
||||
advertisedDevice.isAdvertisingService(BLUEID_AUDIO_SERVICE_UUID)) {
|
||||
LOGI("Service '%s' found!", BLE_AUDIO_SERVICE_UUID);
|
||||
// save advertised_device in class variable
|
||||
advertised_device = advertisedDevice;
|
||||
// Scan can be stopped, we found what we are looking for
|
||||
advertised_device.getScan()->stop();
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
|
||||
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic,
|
||||
uint8_t *pData, size_t length, bool isNotify) {
|
||||
TRACEI();
|
||||
if (pBLERemoteCharacteristic->getUUID().toString() ==
|
||||
selfAudioBLEClient->BLE_INFO_UUID) {
|
||||
selfAudioBLEClient->setAudioInfo(pData, length);
|
||||
}
|
||||
static void onInfoUpdated(BLEDevice central,
|
||||
BLECharacteristic characteristic) {
|
||||
selfAudioBLEClient->setAudioInfo(characteristic.value(),
|
||||
characteristic.valueLength());
|
||||
}
|
||||
|
||||
bool setupBLEClient() {
|
||||
if (is_client_set_up)
|
||||
// if we are already connected there is nothing to do
|
||||
if (peripheral.connected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACEI();
|
||||
|
||||
// setup buffer
|
||||
if (write_buffer.size()==0){
|
||||
if (write_buffer.size() == 0) {
|
||||
write_buffer.resize(getMTU() - BLE_MTU_OVERHEAD);
|
||||
}
|
||||
|
||||
if (p_client == nullptr)
|
||||
p_client = BLEDevice::createClient();
|
||||
|
||||
// onConnect and on onDisconnect support
|
||||
p_client->setClientCallbacks(this);
|
||||
|
||||
// Connect to the remove BLE Server.
|
||||
LOGI("Connecting to %s ...",
|
||||
advertised_device.getAddress().toString().c_str());
|
||||
// p_client->connect(advertised_device.getAddress(),BLE_ADDR_TYPE_RANDOM);
|
||||
p_client->connect(&advertised_device);
|
||||
if (!p_client->isConnected()) {
|
||||
LOGE("Connect failed");
|
||||
peripheral = BLE.available();
|
||||
if (!peripheral) {
|
||||
return false;
|
||||
}
|
||||
LOGI("Connected to %s ...",
|
||||
advertised_device.getAddress().toString().c_str());
|
||||
|
||||
LOGI("Setting mtu to %d", max_transfer_size);
|
||||
assert(max_transfer_size > 0);
|
||||
p_client->setMTU(max_transfer_size);
|
||||
BLE.stopScan();
|
||||
|
||||
// Obtain a reference to the service we are after in the remote BLE
|
||||
// server.
|
||||
if (p_remote_service == nullptr) {
|
||||
p_remote_service = p_client->getService(BLUEID_AUDIO_SERVICE_UUID);
|
||||
if (p_remote_service == nullptr) {
|
||||
LOGE("Failed to find our service UUID: %s", BLE_AUDIO_SERVICE_UUID);
|
||||
return (false);
|
||||
}
|
||||
if (!peripheral.connect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ch01_char == nullptr) {
|
||||
ch01_char = p_remote_service->getCharacteristic(BLUEID_CH1_UUID);
|
||||
if (ch01_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_CH1_UUID);
|
||||
return false;
|
||||
}
|
||||
if (peripheral.discoverAttributes()) {
|
||||
LOGI("Attributes discovered");
|
||||
} else {
|
||||
LOGE("Attribute discovery failed!");
|
||||
peripheral.disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ch02_char == nullptr) {
|
||||
ch02_char = p_remote_service->getCharacteristic(BLUEID_CH2_UUID);
|
||||
if (ch02_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_CH2_UUID);
|
||||
return false;
|
||||
}
|
||||
ch01_char = peripheral.characteristic(BLE_CH1_UUID);
|
||||
if (!ch01_char) {
|
||||
peripheral.disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_audio_info_active && info_char == nullptr) {
|
||||
info_char = p_remote_service->getCharacteristic(BLUEID_INFO_UUID);
|
||||
if (info_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_INFO_UUID);
|
||||
return false;
|
||||
}
|
||||
info_char->registerForNotify(notifyCallback);
|
||||
readAudioInfoCharacteristic();
|
||||
|
||||
ch02_char = peripheral.characteristic(BLE_CH2_UUID);
|
||||
if (!ch02_char) {
|
||||
peripheral.disconnect();
|
||||
return false;
|
||||
}
|
||||
LOGI("Connected to server: %s", is_client_connected ? "true" : "false");
|
||||
is_client_set_up = true;
|
||||
is_client_connected = true;
|
||||
return is_client_connected;
|
||||
|
||||
if (is_audio_info_active) {
|
||||
info_char = peripheral.characteristic(BLE_INFO_UUID);
|
||||
info_char.setEventHandler(BLEUpdated, onInfoUpdated);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
269
src/Sandbox/BLE/AudioBLEClientESP32.h
Normal file
269
src/Sandbox/BLE/AudioBLEClientESP32.h
Normal file
@ -0,0 +1,269 @@
|
||||
#pragma once
|
||||
|
||||
#include "AudioBLEStream.h"
|
||||
//#include <BLE2902.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
|
||||
namespace audio_tools {
|
||||
|
||||
class AudioBLEClient;
|
||||
static AudioBLEClient *selfAudioBLEClient = nullptr;
|
||||
|
||||
/**
|
||||
* @brief A simple BLE client that implements the serial protocol, so that it
|
||||
* can be used to send and recevie audio. In BLE terminology this is a Central
|
||||
* @ingroup communications
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
class AudioBLEClient : public AudioBLEStream,
|
||||
public BLEClientCallbacks,
|
||||
public BLEAdvertisedDeviceCallbacks {
|
||||
public:
|
||||
AudioBLEClient(int mtu = BLE_MTU) : AudioBLEStream(mtu) {
|
||||
selfAudioBLEClient = this;
|
||||
max_transfer_size = mtu;
|
||||
}
|
||||
|
||||
/// starts a BLE client
|
||||
bool begin(const char *localName, int seconds) {
|
||||
TRACEI();
|
||||
// Init BLE device
|
||||
BLEDevice::init(localName);
|
||||
|
||||
// Retrieve a Scanner and set the callback we want to use to be informed
|
||||
// when we have detected a new device.
|
||||
BLEScan *pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(this);
|
||||
pBLEScan->setActiveScan(true);
|
||||
pBLEScan->start(seconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
void end() override {
|
||||
TRACEI();
|
||||
flush();
|
||||
BLEDevice::deinit();
|
||||
}
|
||||
|
||||
size_t readBytes(uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
setupBLEClient();
|
||||
if (!is_client_connected || !is_client_set_up)
|
||||
return 0;
|
||||
if (!ch01_char->canRead())
|
||||
return 0;
|
||||
// changed to auto to be version independent (it changed from std::string to
|
||||
// String)
|
||||
auto str = ch01_char->readValue();
|
||||
if (str.length() > 0) {
|
||||
memcpy(data, str.c_str(), str.length());
|
||||
}
|
||||
return str.length();
|
||||
}
|
||||
|
||||
int available() override { return BLE_MTU - BLE_MTU_OVERHEAD; }
|
||||
|
||||
size_t write(const uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
setupBLEClient();
|
||||
if (!is_client_connected || !is_client_set_up)
|
||||
return 0;
|
||||
if (!ch02_char->canWrite()){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_framed){
|
||||
writeChannel2Characteristic(data, dataSize);
|
||||
delay(1);
|
||||
} else {
|
||||
// send only data with max mtu
|
||||
for (int j=0; j<dataSize; j++){
|
||||
write_buffer.write(data[j]);
|
||||
if (write_buffer.isFull()){
|
||||
writeChannel2Characteristic(write_buffer.data(), write_buffer.available());
|
||||
write_buffer.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
int availableForWrite() override {
|
||||
return is_framed ? (BLE_MTU - BLE_MTU_OVERHEAD) : DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
bool connected() override {
|
||||
if (!setupBLEClient()) {
|
||||
LOGE("setupBLEClient failed");
|
||||
}
|
||||
return is_client_connected;
|
||||
}
|
||||
|
||||
void setWriteThrottle(int ms){
|
||||
write_throttle = ms;
|
||||
}
|
||||
|
||||
void setConfirmWrite(bool flag){
|
||||
write_confirmation_flag = flag;
|
||||
}
|
||||
|
||||
protected:
|
||||
// client
|
||||
BLEClient *p_client = nullptr;
|
||||
BLEAdvertising *p_advertising = nullptr;
|
||||
BLERemoteService *p_remote_service = nullptr;
|
||||
BLEAddress *p_server_address = nullptr;
|
||||
BLERemoteCharacteristic *ch01_char = nullptr; // read
|
||||
BLERemoteCharacteristic *ch02_char = nullptr; // write
|
||||
BLERemoteCharacteristic *info_char = nullptr;
|
||||
BLEAdvertisedDevice advertised_device;
|
||||
BLEUUID BLUEID_AUDIO_SERVICE_UUID{BLE_AUDIO_SERVICE_UUID};
|
||||
BLEUUID BLUEID_CH1_UUID{BLE_CH1_UUID};
|
||||
BLEUUID BLUEID_CH2_UUID{BLE_CH2_UUID};
|
||||
BLEUUID BLUEID_INFO_UUID{BLE_INFO_UUID};
|
||||
SingleBuffer<uint8_t> write_buffer{0};
|
||||
int write_throttle = 0;
|
||||
bool write_confirmation_flag = false;
|
||||
|
||||
volatile bool is_client_connected = false;
|
||||
bool is_client_set_up = false;
|
||||
|
||||
void onConnect(BLEClient *pClient) override {
|
||||
TRACEI();
|
||||
is_client_connected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient *pClient) override {
|
||||
TRACEI();
|
||||
is_client_connected = false;
|
||||
};
|
||||
|
||||
void writeAudioInfoCharacteristic(AudioInfo info) override {
|
||||
TRACEI();
|
||||
// send update via BLE
|
||||
info_char->writeValue((uint8_t *)&info, sizeof(AudioInfo));
|
||||
}
|
||||
|
||||
void writeChannel2Characteristic(const uint8_t*data, size_t len){
|
||||
if (ch02_char->canWrite()) {
|
||||
ch02_char->writeValue((uint8_t *)data, len, write_confirmation_flag);
|
||||
delay(write_throttle);
|
||||
}
|
||||
}
|
||||
|
||||
bool readAudioInfoCharacteristic(){
|
||||
if (!info_char->canRead())
|
||||
return false;
|
||||
auto str = info_char->readValue();
|
||||
if (str.length() > 0) {
|
||||
setAudioInfo((const uint8_t*)str.c_str(), str.length());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scanning Results
|
||||
void onScanResult(BLEAdvertisedDevice advertisedDevice) override {
|
||||
TRACEI();
|
||||
// Check if the name of the advertiser matches
|
||||
if (advertisedDevice.haveServiceUUID() &&
|
||||
advertisedDevice.isAdvertisingService(BLUEID_AUDIO_SERVICE_UUID)) {
|
||||
LOGI("Service '%s' found!", BLE_AUDIO_SERVICE_UUID);
|
||||
// save advertised_device in class variable
|
||||
advertised_device = advertisedDevice;
|
||||
// Scan can be stopped, we found what we are looking for
|
||||
advertised_device.getScan()->stop();
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
|
||||
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic,
|
||||
uint8_t *pData, size_t length, bool isNotify) {
|
||||
TRACEI();
|
||||
if (pBLERemoteCharacteristic->getUUID().toString() ==
|
||||
selfAudioBLEClient->BLE_INFO_UUID) {
|
||||
selfAudioBLEClient->setAudioInfo(pData, length);
|
||||
}
|
||||
}
|
||||
|
||||
bool setupBLEClient() {
|
||||
if (is_client_set_up)
|
||||
return true;
|
||||
|
||||
TRACEI();
|
||||
|
||||
// setup buffer
|
||||
if (write_buffer.size()==0){
|
||||
write_buffer.resize(getMTU() - BLE_MTU_OVERHEAD);
|
||||
}
|
||||
|
||||
if (p_client == nullptr)
|
||||
p_client = BLEDevice::createClient();
|
||||
|
||||
// onConnect and on onDisconnect support
|
||||
p_client->setClientCallbacks(this);
|
||||
|
||||
// Connect to the remove BLE Server.
|
||||
LOGI("Connecting to %s ...",
|
||||
advertised_device.getAddress().toString().c_str());
|
||||
// p_client->connect(advertised_device.getAddress(),BLE_ADDR_TYPE_RANDOM);
|
||||
p_client->connect(&advertised_device);
|
||||
if (!p_client->isConnected()) {
|
||||
LOGE("Connect failed");
|
||||
return false;
|
||||
}
|
||||
LOGI("Connected to %s ...",
|
||||
advertised_device.getAddress().toString().c_str());
|
||||
|
||||
LOGI("Setting mtu to %d", max_transfer_size);
|
||||
assert(max_transfer_size > 0);
|
||||
p_client->setMTU(max_transfer_size);
|
||||
|
||||
// Obtain a reference to the service we are after in the remote BLE
|
||||
// server.
|
||||
if (p_remote_service == nullptr) {
|
||||
p_remote_service = p_client->getService(BLUEID_AUDIO_SERVICE_UUID);
|
||||
if (p_remote_service == nullptr) {
|
||||
LOGE("Failed to find our service UUID: %s", BLE_AUDIO_SERVICE_UUID);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
if (ch01_char == nullptr) {
|
||||
ch01_char = p_remote_service->getCharacteristic(BLUEID_CH1_UUID);
|
||||
if (ch01_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_CH1_UUID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch02_char == nullptr) {
|
||||
ch02_char = p_remote_service->getCharacteristic(BLUEID_CH2_UUID);
|
||||
if (ch02_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_CH2_UUID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_audio_info_active && info_char == nullptr) {
|
||||
info_char = p_remote_service->getCharacteristic(BLUEID_INFO_UUID);
|
||||
if (info_char == nullptr) {
|
||||
LOGE("Failed to find char. UUID: %s", BLE_INFO_UUID);
|
||||
return false;
|
||||
}
|
||||
info_char->registerForNotify(notifyCallback);
|
||||
readAudioInfoCharacteristic();
|
||||
|
||||
}
|
||||
LOGI("Connected to server: %s", is_client_connected ? "true" : "false");
|
||||
is_client_set_up = true;
|
||||
is_client_connected = true;
|
||||
return is_client_connected;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace audio_tools
|
@ -1,55 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "AudioBLEStream.h"
|
||||
//#include <BLE2902.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <ArduinoBLE.h>
|
||||
|
||||
namespace audio_tools {
|
||||
|
||||
class AudioBLEServer;
|
||||
class AudioBLEServer *selfAudioBLEServer = nullptr;
|
||||
|
||||
/**
|
||||
* @brief A simple BLE server that implements the serial protocol, so that it
|
||||
* can be used to send and recevie audio. In BLE terminologiy this is a Peripheral.
|
||||
* can be used to send and recevie audio. In BLE terminologiy this is a
|
||||
* Peripheral.
|
||||
* This implementation uses the ArduinoBLE library!
|
||||
* @ingroup communications
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
class AudioBLEServer : public AudioBLEStream,
|
||||
public BLECharacteristicCallbacks,
|
||||
public BLEServerCallbacks {
|
||||
class AudioBLEServer : public AudioBLEStream {
|
||||
public:
|
||||
AudioBLEServer(int mtu = BLE_MTU) : AudioBLEStream(mtu) {}
|
||||
AudioBLEServer(int mtu = BLE_MTU) : AudioBLEStream(mtu) {
|
||||
selfAudioBLEServer = this;
|
||||
}
|
||||
|
||||
// starts a BLE server with the indicated name
|
||||
bool begin(const char *name) {
|
||||
TRACEI();
|
||||
ble_server_name = name;
|
||||
BLEDevice::init(name);
|
||||
|
||||
p_server = BLEDevice::createServer();
|
||||
p_server->setCallbacks(this);
|
||||
if (!BLE.begin()) {
|
||||
LOGE("starting BLE failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the local name peripheral advertises
|
||||
BLE.setLocalName(ble_server_name);
|
||||
|
||||
// assign event handlers for connected, disconnected to peripheral
|
||||
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
|
||||
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
|
||||
|
||||
// setup serice with characteristics
|
||||
setupBLEService();
|
||||
p_advertising = BLEDevice::getAdvertising();
|
||||
p_advertising->addServiceUUID(BLE_AUDIO_SERVICE_UUID);
|
||||
BLEDevice::startAdvertising();
|
||||
|
||||
// start advertising
|
||||
BLE.advertise();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void end() override {
|
||||
TRACEI();
|
||||
flush();
|
||||
BLEDevice::deinit();
|
||||
BLE.end();
|
||||
}
|
||||
|
||||
size_t readBytes(uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
if (!checkCentralConnected())
|
||||
return 0;
|
||||
size_t read_size = getReadSize(dataSize);
|
||||
return receive_buffer.readArray(data, read_size);
|
||||
}
|
||||
|
||||
int available() override {
|
||||
if (!checkCentralConnected())
|
||||
return 0;
|
||||
if (is_framed)
|
||||
return receive_sizes.peek();
|
||||
return this->receive_buffer.available();
|
||||
@ -57,9 +74,8 @@ public:
|
||||
|
||||
size_t write(const uint8_t *data, size_t dataSize) override {
|
||||
LOGD("AudioBLEStream::write: %d", dataSize);
|
||||
if (!connected()) {
|
||||
if (!checkCentralConnected())
|
||||
return 0;
|
||||
}
|
||||
if (is_framed && availableForWrite() < dataSize) {
|
||||
return 0;
|
||||
}
|
||||
@ -67,30 +83,109 @@ public:
|
||||
}
|
||||
|
||||
int availableForWrite() override {
|
||||
int result = transmit_buffer.availableForWrite();
|
||||
if (!checkCentralConnected())
|
||||
return 0;
|
||||
setupTXBuffer();
|
||||
int result = transmit_buffer.availableForWrite();
|
||||
// make sure we copy always a consistent amount of data
|
||||
if (result < DEFAULT_BUFFER_SIZE) result = 0;
|
||||
return result ;
|
||||
if (result < DEFAULT_BUFFER_SIZE)
|
||||
result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool connected() override { return p_server->getConnectedCount() > 0; }
|
||||
|
||||
bool connected() override { return checkCentralConnected(); }
|
||||
|
||||
protected:
|
||||
// server
|
||||
BLEServer *p_server = nullptr;
|
||||
BLEService *p_service = nullptr;
|
||||
BLEAdvertising *p_advertising = nullptr;
|
||||
BLECharacteristic *ch01_char;
|
||||
BLECharacteristic *ch02_char;
|
||||
BLECharacteristic *info_char;
|
||||
BLEDescriptor ch01_desc{"2901"};
|
||||
BLEDescriptor ch02_desc{"2901"};
|
||||
BLEDescriptor info_desc{"2901"};
|
||||
BLEService service{BLE_AUDIO_SERVICE_UUID}; // create service
|
||||
BLECharacteristic ch01_char{BLE_CH1_UUID, BLERead,
|
||||
BLE_MTU - BLE_MTU_OVERHEAD};
|
||||
BLECharacteristic ch02_char{BLE_CH2_UUID, BLEWrite,
|
||||
BLE_MTU - BLE_MTU_OVERHEAD};
|
||||
BLECharacteristic info_char{BLE_INFO_UUID, BLERead | BLEWrite | BLENotify,
|
||||
80};
|
||||
BLEDescriptor ch01_desc{"2901", "channel 1"};
|
||||
BLEDescriptor ch02_desc{"2901", "channel 2"};
|
||||
BLEDescriptor info_desc{"2901", "info"};
|
||||
|
||||
RingBuffer<uint8_t> receive_buffer{0};
|
||||
RingBuffer<uint16_t> receive_sizes{0};
|
||||
RingBuffer<uint8_t> transmit_buffer{0};
|
||||
RingBuffer<uint16_t> transmit_buffer_sizes{0};
|
||||
|
||||
static void blePeripheralConnectHandler(BLEDevice device) {
|
||||
selfAudioBLEServer->onConnect(device);
|
||||
}
|
||||
|
||||
static void blePeripheralDisconnectHandler(BLEDevice device) {
|
||||
selfAudioBLEServer->onDisconnect(device);
|
||||
}
|
||||
|
||||
static void bleOnWrite(BLEDevice device, BLECharacteristic characteristic) {
|
||||
selfAudioBLEServer->onWrite(characteristic);
|
||||
}
|
||||
|
||||
static void bleOnRead(BLEDevice device, BLECharacteristic characteristic) {
|
||||
TRACED();
|
||||
selfAudioBLEServer->onRead(characteristic);
|
||||
}
|
||||
|
||||
void onConnect(BLEDevice device) { TRACEI(); }
|
||||
|
||||
void onDisconnect(BLEDevice device) {
|
||||
TRACEI();
|
||||
BLE.advertise();
|
||||
}
|
||||
|
||||
/// store the next batch of data
|
||||
void onWrite(BLECharacteristic characteristic) {
|
||||
TRACED();
|
||||
setupRXBuffer();
|
||||
// changed to auto to be version independent (it changed from std::string to
|
||||
// String)
|
||||
if (Str(BLE_INFO_UUID).equals(characteristic.uuid())) {
|
||||
setAudioInfo((uint8_t *)characteristic.value(),
|
||||
characteristic.valueLength());
|
||||
} else {
|
||||
receiveAudio((uint8_t *)characteristic.value(),
|
||||
characteristic.valueLength());
|
||||
}
|
||||
}
|
||||
|
||||
/// provide the next batch of audio data
|
||||
void onRead(BLECharacteristic characteristic) {
|
||||
TRACED();
|
||||
auto uuid = Str(characteristic.uuid());
|
||||
if (uuid == BLE_CH1_UUID || uuid == BLE_CH2_UUID) {
|
||||
TRACEI();
|
||||
setupTXBuffer();
|
||||
int len = std::min(getMTU() - BLE_MTU_OVERHEAD,
|
||||
(int)transmit_buffer.available());
|
||||
if (is_framed) {
|
||||
len = transmit_buffer_sizes.read();
|
||||
}
|
||||
LOGI("%s: len: %d, buffer: %d", uuid.c_str(), len,
|
||||
transmit_buffer.size());
|
||||
if (len>0){
|
||||
assert(len==512);
|
||||
uint8_t tmp[len];
|
||||
transmit_buffer.readArray(tmp, len);
|
||||
characteristic.writeValue(tmp, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool checkCentralConnected() {
|
||||
BLEDevice central = BLE.central();
|
||||
|
||||
// if a central is connected to the peripheral:
|
||||
if (central)
|
||||
return central.connected();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void receiveAudio(const uint8_t *data, size_t size) {
|
||||
while (receive_buffer.availableForWrite() < size) {
|
||||
// wait for ringbuffer to get freed up
|
||||
@ -106,16 +201,17 @@ protected:
|
||||
// send update via BLE
|
||||
Str str = toStr(info);
|
||||
LOGI("AudioInfo: %s", str.c_str());
|
||||
info_char->setValue((uint8_t *)str.c_str(), str.length() + 1);
|
||||
info_char->notify();
|
||||
info_char.setValue((uint8_t *)str.c_str(), str.length() + 1);
|
||||
}
|
||||
|
||||
int getMTU() override {
|
||||
TRACED();
|
||||
if (max_transfer_size == 0) {
|
||||
int peer_max_transfer_size =
|
||||
p_server->getPeerMTU(p_server->getConnId()) - BLE_MTU_OVERHEAD;
|
||||
max_transfer_size = std::min(BLE_MTU - BLE_MTU, peer_max_transfer_size);
|
||||
// int peer_max_transfer_size =
|
||||
// p_server->getPeerMTU(p_server->getConnId()) - BLE_MTU_OVERHEAD;
|
||||
// max_transfer_size = std::min(BLE_MTU - BLE_MTU,
|
||||
// peer_max_transfer_size);
|
||||
max_transfer_size = BLE_MTU - BLE_MTU_OVERHEAD;
|
||||
|
||||
LOGI("max_transfer_size: %d", max_transfer_size);
|
||||
}
|
||||
@ -124,91 +220,42 @@ protected:
|
||||
|
||||
void setupBLEService() {
|
||||
TRACEI();
|
||||
// characteristic property is what the other device does.
|
||||
// set the UUID for the service this peripheral advertises
|
||||
BLE.setAdvertisedService(service);
|
||||
|
||||
if (p_service == nullptr) {
|
||||
p_service = p_server->createService(BLE_AUDIO_SERVICE_UUID);
|
||||
ch01_char.addDescriptor(ch01_desc);
|
||||
ch02_char.addDescriptor(ch02_desc);
|
||||
|
||||
ch01_char = p_service->createCharacteristic(
|
||||
BLE_CH1_UUID, BLECharacteristic::PROPERTY_READ );
|
||||
ch01_desc.setValue("Channel 1");
|
||||
ch01_char->addDescriptor(&ch01_desc);
|
||||
ch01_char->setCallbacks(this);
|
||||
// add the characteristic to the service
|
||||
service.addCharacteristic(ch01_char);
|
||||
service.addCharacteristic(ch02_char);
|
||||
|
||||
ch02_char = p_service->createCharacteristic(
|
||||
BLE_CH2_UUID, BLECharacteristic::PROPERTY_WRITE);
|
||||
ch02_desc.setValue("Channel 2");
|
||||
ch02_char->addDescriptor(&ch02_desc);
|
||||
ch02_char->setCallbacks(this);
|
||||
// assign event handlers for characteristic
|
||||
ch02_char.setEventHandler(BLEWritten, bleOnWrite);
|
||||
ch01_char.setEventHandler(BLERead, bleOnRead);
|
||||
|
||||
// optional setup of audio info notifications
|
||||
if (is_audio_info_active && info_char == nullptr) {
|
||||
|
||||
info_char = p_service->createCharacteristic(
|
||||
BLE_INFO_UUID, BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE);
|
||||
info_desc.setValue("Audio Info");
|
||||
info_char->addDescriptor(&info_desc);
|
||||
info_char->setCallbacks(this);
|
||||
|
||||
}
|
||||
|
||||
p_service->start();
|
||||
|
||||
getMTU();
|
||||
|
||||
if (info_char != nullptr) {
|
||||
writeAudioInfoCharacteristic(info);
|
||||
}
|
||||
if (is_audio_info_active) {
|
||||
info_char.addDescriptor(info_desc);
|
||||
service.addCharacteristic(info_char);
|
||||
}
|
||||
}
|
||||
|
||||
void onConnect(BLEServer *pServer) override {
|
||||
TRACEI();
|
||||
}
|
||||
// add service
|
||||
BLE.addService(service);
|
||||
|
||||
void onDisconnect(BLEServer *pServer) override {
|
||||
TRACEI();
|
||||
BLEDevice::startAdvertising();
|
||||
}
|
||||
|
||||
/// store the next batch of data
|
||||
void onWrite(BLECharacteristic *pCharacteristic) override {
|
||||
TRACED();
|
||||
setupRXBuffer();
|
||||
// changed to auto to be version independent (it changed from std::string to String)
|
||||
auto value = pCharacteristic->getValue();
|
||||
if (pCharacteristic->getUUID().toString() == BLE_INFO_UUID) {
|
||||
setAudioInfo((uint8_t *)&value[0], value.length());
|
||||
} else {
|
||||
receiveAudio((uint8_t *)&value[0], value.length());
|
||||
// provide AudioInfo
|
||||
if (is_audio_info_active) {
|
||||
writeAudioInfoCharacteristic(info);
|
||||
}
|
||||
}
|
||||
|
||||
/// provide the next batch of audio data
|
||||
void onRead(BLECharacteristic *pCharacteristic) override {
|
||||
TRACED();
|
||||
// changed to auto to be version independent (it changed from std::string to String)
|
||||
auto uuid = pCharacteristic->getUUID().toString();
|
||||
if (uuid == BLE_CH1_UUID || uuid == BLE_CH2_UUID) {
|
||||
setupTXBuffer();
|
||||
int len = std::min(getMTU() - BLE_MTU_OVERHEAD, (int)transmit_buffer.available());
|
||||
if (is_framed) {
|
||||
len = transmit_buffer_sizes.read();
|
||||
}
|
||||
LOGD("%s: len: %d, buffer: %d", uuid.c_str(), len,
|
||||
transmit_buffer.size());
|
||||
uint8_t tmp[len];
|
||||
transmit_buffer.readArray(tmp, len);
|
||||
pCharacteristic->setValue(tmp, len);
|
||||
}
|
||||
// Read callback works only when we provide some initial data
|
||||
uint8_t tmp[512]={0xFF};
|
||||
ch01_char.writeValue(tmp, 512, false);
|
||||
}
|
||||
|
||||
void setupTXBuffer() {
|
||||
if (transmit_buffer.size() == 0) {
|
||||
LOGI("Setting transmit_buffer to %d for mtu %d", RX_BUFFER_SIZE, getMTU());
|
||||
LOGI("Setting transmit_buffer to %d for mtu %d", RX_BUFFER_SIZE,
|
||||
getMTU());
|
||||
transmit_buffer.resize(TX_BUFFER_SIZE);
|
||||
if (is_framed) {
|
||||
transmit_buffer_sizes.resize(TX_COUNT);
|
||||
@ -246,5 +293,4 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace audio_tools
|
250
src/Sandbox/BLE/AudioBLEServerESP32.h
Normal file
250
src/Sandbox/BLE/AudioBLEServerESP32.h
Normal file
@ -0,0 +1,250 @@
|
||||
#pragma once
|
||||
|
||||
#include "AudioBLEStream.h"
|
||||
//#include <BLE2902.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
|
||||
namespace audio_tools {
|
||||
/**
|
||||
* @brief A simple BLE server that implements the serial protocol, so that it
|
||||
* can be used to send and recevie audio. In BLE terminologiy this is a Peripheral.
|
||||
* @ingroup communications
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
class AudioBLEServer : public AudioBLEStream,
|
||||
public BLECharacteristicCallbacks,
|
||||
public BLEServerCallbacks {
|
||||
public:
|
||||
AudioBLEServer(int mtu = BLE_MTU) : AudioBLEStream(mtu) {}
|
||||
|
||||
// starts a BLE server with the indicated name
|
||||
bool begin(const char *name) {
|
||||
TRACEI();
|
||||
ble_server_name = name;
|
||||
BLEDevice::init(name);
|
||||
|
||||
p_server = BLEDevice::createServer();
|
||||
p_server->setCallbacks(this);
|
||||
|
||||
setupBLEService();
|
||||
p_advertising = BLEDevice::getAdvertising();
|
||||
p_advertising->addServiceUUID(BLE_AUDIO_SERVICE_UUID);
|
||||
BLEDevice::startAdvertising();
|
||||
return true;
|
||||
}
|
||||
|
||||
void end() override {
|
||||
TRACEI();
|
||||
flush();
|
||||
BLEDevice::deinit();
|
||||
}
|
||||
|
||||
size_t readBytes(uint8_t *data, size_t dataSize) override {
|
||||
TRACED();
|
||||
size_t read_size = getReadSize(dataSize);
|
||||
return receive_buffer.readArray(data, read_size);
|
||||
}
|
||||
|
||||
int available() override {
|
||||
if (is_framed)
|
||||
return receive_sizes.peek();
|
||||
return this->receive_buffer.available();
|
||||
}
|
||||
|
||||
size_t write(const uint8_t *data, size_t dataSize) override {
|
||||
LOGD("AudioBLEStream::write: %d", dataSize);
|
||||
if (!connected()) {
|
||||
return 0;
|
||||
}
|
||||
if (is_framed && availableForWrite() < dataSize) {
|
||||
return 0;
|
||||
}
|
||||
return transmit_buffer.writeArray(data, dataSize);
|
||||
}
|
||||
|
||||
int availableForWrite() override {
|
||||
int result = transmit_buffer.availableForWrite();
|
||||
// make sure we copy always a consistent amount of data
|
||||
if (result < DEFAULT_BUFFER_SIZE) result = 0;
|
||||
return result ;
|
||||
}
|
||||
|
||||
bool connected() override { return p_server->getConnectedCount() > 0; }
|
||||
|
||||
protected:
|
||||
// server
|
||||
BLEServer *p_server = nullptr;
|
||||
BLEService *p_service = nullptr;
|
||||
BLEAdvertising *p_advertising = nullptr;
|
||||
BLECharacteristic *ch01_char;
|
||||
BLECharacteristic *ch02_char;
|
||||
BLECharacteristic *info_char;
|
||||
BLEDescriptor ch01_desc{"2901"};
|
||||
BLEDescriptor ch02_desc{"2901"};
|
||||
BLEDescriptor info_desc{"2901"};
|
||||
RingBuffer<uint8_t> receive_buffer{0};
|
||||
RingBuffer<uint16_t> receive_sizes{0};
|
||||
RingBuffer<uint8_t> transmit_buffer{0};
|
||||
RingBuffer<uint16_t> transmit_buffer_sizes{0};
|
||||
|
||||
virtual void receiveAudio(const uint8_t *data, size_t size) {
|
||||
while (receive_buffer.availableForWrite() < size) {
|
||||
// wait for ringbuffer to get freed up
|
||||
delay(10);
|
||||
}
|
||||
if (is_framed)
|
||||
receive_sizes.write(size);
|
||||
receive_buffer.writeArray(data, size);
|
||||
}
|
||||
|
||||
void writeAudioInfoCharacteristic(AudioInfo info) {
|
||||
TRACEI();
|
||||
// send update via BLE
|
||||
Str str = toStr(info);
|
||||
LOGI("AudioInfo: %s", str.c_str());
|
||||
info_char->setValue((uint8_t *)str.c_str(), str.length() + 1);
|
||||
info_char->notify();
|
||||
}
|
||||
|
||||
int getMTU() override {
|
||||
TRACED();
|
||||
if (max_transfer_size == 0) {
|
||||
int peer_max_transfer_size =
|
||||
p_server->getPeerMTU(p_server->getConnId()) - BLE_MTU_OVERHEAD;
|
||||
max_transfer_size = std::min(BLE_MTU - BLE_MTU, peer_max_transfer_size);
|
||||
|
||||
LOGI("max_transfer_size: %d", max_transfer_size);
|
||||
}
|
||||
return max_transfer_size;
|
||||
}
|
||||
|
||||
void setupBLEService() {
|
||||
TRACEI();
|
||||
// characteristic property is what the other device does.
|
||||
|
||||
if (p_service == nullptr) {
|
||||
p_service = p_server->createService(BLE_AUDIO_SERVICE_UUID);
|
||||
|
||||
ch01_char = p_service->createCharacteristic(
|
||||
BLE_CH1_UUID, BLECharacteristic::PROPERTY_READ );
|
||||
ch01_desc.setValue("Channel 1");
|
||||
ch01_char->addDescriptor(&ch01_desc);
|
||||
ch01_char->setCallbacks(this);
|
||||
|
||||
ch02_char = p_service->createCharacteristic(
|
||||
BLE_CH2_UUID, BLECharacteristic::PROPERTY_WRITE);
|
||||
ch02_desc.setValue("Channel 2");
|
||||
ch02_char->addDescriptor(&ch02_desc);
|
||||
ch02_char->setCallbacks(this);
|
||||
|
||||
// optional setup of audio info notifications
|
||||
if (is_audio_info_active && info_char == nullptr) {
|
||||
|
||||
info_char = p_service->createCharacteristic(
|
||||
BLE_INFO_UUID, BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE);
|
||||
info_desc.setValue("Audio Info");
|
||||
info_char->addDescriptor(&info_desc);
|
||||
info_char->setCallbacks(this);
|
||||
|
||||
}
|
||||
|
||||
p_service->start();
|
||||
|
||||
getMTU();
|
||||
|
||||
if (info_char != nullptr) {
|
||||
writeAudioInfoCharacteristic(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onConnect(BLEServer *pServer) override {
|
||||
TRACEI();
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer *pServer) override {
|
||||
TRACEI();
|
||||
BLEDevice::startAdvertising();
|
||||
}
|
||||
|
||||
/// store the next batch of data
|
||||
void onWrite(BLECharacteristic *pCharacteristic) override {
|
||||
TRACED();
|
||||
setupRXBuffer();
|
||||
// changed to auto to be version independent (it changed from std::string to String)
|
||||
auto value = pCharacteristic->getValue();
|
||||
if (pCharacteristic->getUUID().toString() == BLE_INFO_UUID) {
|
||||
setAudioInfo((uint8_t *)&value[0], value.length());
|
||||
} else {
|
||||
receiveAudio((uint8_t *)&value[0], value.length());
|
||||
}
|
||||
}
|
||||
|
||||
/// provide the next batch of audio data
|
||||
void onRead(BLECharacteristic *pCharacteristic) override {
|
||||
TRACED();
|
||||
// changed to auto to be version independent (it changed from std::string to String)
|
||||
auto uuid = pCharacteristic->getUUID().toString();
|
||||
if (uuid == BLE_CH1_UUID || uuid == BLE_CH2_UUID) {
|
||||
setupTXBuffer();
|
||||
int len = std::min(getMTU() - BLE_MTU_OVERHEAD, (int)transmit_buffer.available());
|
||||
if (is_framed) {
|
||||
len = transmit_buffer_sizes.read();
|
||||
}
|
||||
LOGD("%s: len: %d, buffer: %d", uuid.c_str(), len,
|
||||
transmit_buffer.size());
|
||||
uint8_t tmp[len];
|
||||
transmit_buffer.readArray(tmp, len);
|
||||
pCharacteristic->setValue(tmp, len);
|
||||
}
|
||||
}
|
||||
|
||||
void setupTXBuffer() {
|
||||
if (transmit_buffer.size() == 0) {
|
||||
LOGI("Setting transmit_buffer to %d for mtu %d", RX_BUFFER_SIZE, getMTU());
|
||||
transmit_buffer.resize(TX_BUFFER_SIZE);
|
||||
if (is_framed) {
|
||||
transmit_buffer_sizes.resize(TX_COUNT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupRXBuffer() {
|
||||
if (receive_buffer.size() == 0) {
|
||||
LOGI("Setting receive_buffer to %d for mtu %d", RX_BUFFER_SIZE, getMTU());
|
||||
receive_buffer.resize(RX_BUFFER_SIZE);
|
||||
if (is_framed) {
|
||||
receive_sizes.resize(RX_COUNT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t getReadSize(size_t dataSize) {
|
||||
size_t read_size = dataSize;
|
||||
if (is_framed) {
|
||||
read_size = 0;
|
||||
if (receive_sizes.available() > 0) {
|
||||
read_size = receive_sizes.read();
|
||||
}
|
||||
if (dataSize < read_size) {
|
||||
LOGE("read size too small: %d - it must be >= %d", dataSize, read_size);
|
||||
return 0;
|
||||
}
|
||||
if (receive_buffer.available() < read_size) {
|
||||
LOGE("missing data in buffer");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return read_size;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace audio_tools
|
2140
src/Sandbox/BLE/AudioStreams.h
Normal file
2140
src/Sandbox/BLE/AudioStreams.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user