Using ESP32 under Arduino IDE as bluetooth SOURCE

I have an ESP32 device and an Arduino-IDE project working. I am looking to have the device play sound effects (either .wav or .mp3) to a normal Bluetooth speaker. I have found many examples where the device was the receiver (SINK) and some where data was just streamed from the ESP, but I have not found any libraries or examples that PAIR with an external speaker and send sounds/music. Any help would be appreciated. This is all new territory for me

John

have you looked thru File>Examples>BLE?

Am looking at both the ble and Bluetooth serial example sets. I see a Bluetooth serial example that removes “bonded” (with I assume means paired) devices but I must be missing the code that adds a bonded device. Can you point me in the right direction ?

A2DP Source (Music Sender)
This can be used to feed e.g. your Bluetooth Speaker with your audio data.

I have no experience with it.

I do but only as a receiver. It works very well.

I have made a bunch of progress... Using A2DP_source, I can now successfully play a wav file (once) to the speaker. The wav is just a bell ringing twice. Plays fine. When I try to play it again, only half of the file plays (can't tell which half since both are the same). Any ideas? If I disconnect and reconnect, then it takes forever! Want to keep it connected but just have it go silent until the next event.

FWIW - I'm sure someone will want you to post your sketch

Yeah. Will remove all the workarounds I have added, retest and post this evening.

Here is my code...I would attach the bell.wav file as will but I don't think this allows me to do that.

#include "BluetoothA2DPSource.h"
#include <math.h> 
#include <Wire.h>
#include "SD_MMC.h"

uint32_t  sampleCount;
uint32_t currFrame = 0;
Frame *samples;

struct {
  char      chunkId[4];
  uint32_t  chunkSize;
  char      format[4];
  char      subChunk1Id[4];
  uint32_t  subChunk1Size;
  uint16_t  audioFormat;
  uint16_t  channelCount;
  uint32_t  sampleRate;
  uint32_t  byteRate;
  uint16_t  blockAlign;
  uint16_t  bitsPerSample;
  char      subChunk2Id[4];
  uint32_t  subChunk2Size;
} waveHeader;

struct inpButton {
  int inputNumber;
  unsigned long activationTime;
  unsigned long delayTime;
  int currentState;
};

struct inpButton addButton = { 36, 0, 10, LOW };

BluetoothA2DPSource a2dp_source;

// The supported audio codec in ESP32 A2DP is SBC. SBC audio stream is encoded
// from PCM data normally formatted as 44.1kHz sampling rate, two-channel 16-bit sample data
int32_t get_data_frames(Frame *frame, int32_t frame_count) {
    //
    // Take the max of the number left and the incoming count
    //
    if (frame_count == 0) return 0;
    if (currFrame >= sampleCount) return 0;

    int framesToCopy = frame_count;
    if (currFrame + frame_count > sampleCount) 
    {
      framesToCopy = sampleCount - currFrame;
    }
    memcpy((void *) frame, (void *) &samples[currFrame], framesToCopy * sizeof(Frame));
    currFrame += framesToCopy;
    return framesToCopy;
}


void setup() {
  Serial.begin(115200);
  pinMode(addButton.inputNumber, INPUT);

  while (1) {
    if (!SD_MMC.begin()) {  // Check if SD card is mounted successfully
        Serial.println("Insert SD card!");
        delay(1000);
        continue;
        }
    break;
  }
    File file;
    file = SD_MMC.open("/bell.wav", FILE_READ);
    file.readBytes(((char *) &waveHeader), sizeof(waveHeader));
    //
    // Each sample is channelCount * 2 bytes;
    //
    sampleCount = waveHeader.subChunk2Size / (2 * waveHeader.channelCount);
    samples = (Frame *) (malloc(sampleCount * sizeof(Frame)));
    for (int i = 0; i < sampleCount; i++)
    {
      file.readBytes((char *) &samples[i].channel1, 2);
      if (waveHeader.channelCount == 1) 
        samples[i].channel2 = samples[i].channel1;
      else
        file.readBytes((char *) &samples[i].channel2, 2);      
    }
    file.close();  // Close the file
    SD_MMC.end();
    Serial.println("File read complete");

  a2dp_source.set_auto_reconnect(true);
  a2dp_source.set_data_callback_in_frames(get_data_frames);
  a2dp_source.set_volume(60);
  a2dp_source.start("M3");
}
void loop() {
    unsigned long clockTime = millis();
      if (currFrame >= sampleCount && buttonAction(clockTime, &addButton)) {
        currFrame = 0;
      }
  // to prevent watchdog in release > 1.0.6
  delay(1);
}

bool buttonAction(unsigned long clockTime, struct inpButton *thisButton) {
  if (thisButton->activationTime > clockTime) return false;
  int newState = digitalRead(thisButton->inputNumber);
  if (newState == thisButton->currentState) return false;
  //
  // State has changed!
  //
  thisButton->currentState = newState;
  if (newState == LOW) return false;
  //
  // State is HIGH -- set delay and return true
  //
  thisButton->activationTime = clockTime + thisButton->delayTime;
  return true;
}

How does it go if you play your bell track more simply?
Without all the buttonAction jazz?
I see that you're using delay() and millis().
(delay() messes up millis(), BTW.)

With your loop()
polling for a pushbutton click.
If you get a click play the test track.

If I play the bell continuously, then it sounds correct. It's when I stop and restart that it messes up.

I have tried:

  1. Looping within the callback until it's time to play again
  2. Returning zero frames from the callback until it's time to play
  3. Returning 1 frame with zeros
  4. Returning all frames with zeros

All seem to give the same results. I have also tried a different bluetooth speaker and it doesn't connect at all. I suspect it needs a more involved pair/bind implementation.