Skip to content

Commit

Permalink
DRAFT BLE
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed Nov 2, 2023
1 parent d923639 commit b41f746
Show file tree
Hide file tree
Showing 16 changed files with 602 additions and 47 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @file example-serial-receive.ino
* @author Phil Schatzmann
* @brief Receiving audio via BLE and writing to I2S
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/


#include "AudioTools.h"
#include "AudioLibs/AudioKit.h"
#include "AudioCodecs/CodecADPCM.h" // https://github.com/pschatzmann/adpcm
#include "Sandbox/BLE/AudioBLE.h"

AudioInfo info(8000, 1, 16);
AudioBLEClient ble;
AudioKitStream i2s;
ADPCMDecoder adpcm(AV_CODEC_ID_ADPCM_IMA_WAV);
EncodedAudioStream decoder(&i2s, &adpcm);
StreamCopy copier(decoder, ble);

void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);

// start I2S
auto config = i2s.defaultConfig(TX_MODE);
config.copyFrom(info);
i2s.begin(config);

// start decoder
decoder.begin(info);

// start BLE client - wait at most 10 minutes
ble.begin("ble-send", 60*10);

Serial.println("started...");
}

void loop() {
if (ble)
copier.copy();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @file communications-ble-send.ino
* @author Phil Schatzmann
* @brief Sending audio via BLE
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/

#include "AudioTools.h"
#include "AudioCodecs/CodecADPCM.h" // https://github.com/pschatzmann/adpcm
#include "Sandbox/BLE/AudioBLE.h"

AudioInfo info(8000, 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
AudioBLEServer ble;
ADPCMEncoder adpcm(AV_CODEC_ID_ADPCM_IMA_WAV);
EncodedAudioStream encoder(&ble, &adpcm);
StreamCopy copier(encoder, sound);

void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);

sineWave.begin(info, N_B4);

encoder.begin(info);

ble.begin("ble-send");
}

void loop() {
if (ble) copier.copy();
}
4 changes: 4 additions & 0 deletions src/AudioCodecs/AudioEncoded.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ class EncodedAudioOutput : public AudioStream {
return 0;
}

if(availableForWrite()==0){
return 0;
}

size_t result = writer_ptr->write(data, len);
LOGD("EncodedAudioOutput::write: %d -> %d", (int)len, (int)result);
custom_log_level.reset();
Expand Down
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions src/Sandbox/BLE/AudioBLE.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#ifdef ESP32
# include "AudioBLEServer.h"
# include "AudioBLEClient.h"
#else
# error Device not supported
#endif

162 changes: 162 additions & 0 deletions src/Sandbox/BLE/AudioBLEClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#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 BLEAdvertisedDeviceCallbacks {
public:
AudioBLEClient(int mtu = BLE_BUFFER_SIZE) : AudioBLEStream(mtu) {
selfAudioBLEClient = this;
}

/// starts a BLE client
bool begin(const char *serverName, int seconds) {
TRACEI();
ble_server_name = serverName;
// Init BLE device
BLEDevice::init("client");

// 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();
// changed to auto to be version independent (it changed from std::string to String)
auto str = ch02_char->readValue();
memcpy(data, str.c_str(), str.length());
return str.length();
}

int available() override { return BLE_BUFFER_SIZE; }

size_t write(const uint8_t *data, size_t dataSize) override {
ch01_char->writeValue((uint8_t *)data, dataSize, false);
return dataSize;
}

int availableForWrite() override { return BLE_BUFFER_SIZE; }

virtual bool connected() override { return is_client_connected; }

protected:
// client
BLEClient *p_client = nullptr;
BLEAdvertising *p_advertising = nullptr;
BLERemoteService *p_remote_service = nullptr;
BLEAddress *p_server_address = nullptr;
BLERemoteCharacteristic *ch01_char = nullptr;
BLERemoteCharacteristic *ch02_char = nullptr;
BLERemoteCharacteristic *info_char = nullptr;
BLEAdvertisedDevice advertised_device;
bool is_client_connected = false;

void writeAudioInfoCharacteristic(AudioInfo info) override {
TRACEI();
// send update via BLE
info_char->writeValue((uint8_t *)&info, sizeof(AudioInfo));
}

// Scanning Results
void onResult(BLEAdvertisedDevice advertisedDevice) override {
TRACEI();
// Check if the name of the advertiser matches
if (advertisedDevice.getName() == ble_server_name) {
TRACEI();
advertised_device = advertisedDevice;
// Scan can be stopped, we found what we are looking for
advertised_device.getScan()->stop();
// Address of advertiser is the one we need
// p_server_address = new BLEAddress(advertisedDevice.getAddress());

LOGI("Device '%s' found: Connecting!",
advertised_device.toString().c_str());
setupBLEClient();
}
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() {
TRACEI();

if (p_client == nullptr)
p_client = BLEDevice::createClient();

// 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;
}
p_client->setMTU(max_transfer_size);

LOGI("Connected to server: %s", is_client_connected ? "true" : "false");

// 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(BLE_SERIAL_SERVICE_UUID);
if (p_remote_service == nullptr) {
LOGE("Failed to find our service UUID: %s", BLE_SERIAL_SERVICE_UUID);
return (false);
}
}

if (ch01_char == nullptr) {
ch01_char = p_remote_service->getCharacteristic(BLE_CH1_UUID);
}

if (ch02_char == nullptr) {
ch02_char= p_remote_service->getCharacteristic(BLE_CH2_UUID);
}

if (is_audio_info_active && info_char == nullptr) {
info_char = p_remote_service->getCharacteristic(BLE_INFO_UUID);
info_char->registerForNotify(notifyCallback);
}
is_client_connected = true;
return is_client_connected;
}
};

} // namespace audio_tools
Loading

0 comments on commit b41f746

Please sign in to comment.