Play music on a bluetooth speaker from an esp32

UM, THIS works
/*
  Streaming of sound data with Bluetooth to other Bluetooth device.
  We generate 2 tones which will be sent to the 2 channels.
  
  Copyright (C) 2020 Phil Schatzmann
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "BluetoothA2DPSource.h"
#include <math.h> 

#define c3_frequency  500

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) {
    static float m_time = 0.0;
    float m_amplitude = 10000.0;  // -32,768 to 32,767
    float m_deltaTime = 1.0 / 44100.0;
    float m_phase = 0.0;
    float pi_2 = PI * 2.0;
    // fill the channel data
    for (int sample = 0; sample < frame_count; ++sample) {
        float angle = pi_2 * c3_frequency * m_time + m_phase;
        frame[sample].channel1 = m_amplitude * sin(angle);
        frame[sample].channel2 = frame[sample].channel1;
        m_time += m_deltaTime;
    }
    // to prevent watchdog
    delay(1);

    return frame_count;
}


void setup() {
  a2dp_source.set_auto_reconnect(false);
  a2dp_source.set_data_callback_in_frames(get_data_frames);
  a2dp_source.set_volume(30);
  a2dp_source.start("JBL TUNE500BT");  
}

void loop() {
  // to prevent watchdog in release > 1.0.6
  delay(1000);
}

hello, so this is a code where the esp32 connect to my JBL headphones and it produces a 500hz noise and it works. Now I tried using an SD card to play real music from the esp32 but got many problems and barriers. Does anyone have the solution to import just the perfect logics or libraries to somehow convert the MP3 or WAV music from the SD card to some data that can be sent from the esp32 to my headphones?

thank you :grinning_face:

I2S with your ESP32 here...

But that is to connect a wired speaker. Though it does provide some instruction to create an MP3 player.

AI assistant pointed me to the library that is used in your sketch Looks promising.

If you manage to read and play the MP3 file, you should also be able to send it to bluetooth i think.

That is all true, however! You are sending a small block of bytes using Bluetooth with NO capability to control the timing of those bytes getting converted to audio. The OP needs more research on the protocol used to send data to the Bluetooth speaker with commercial products.

thanks for replying. I dont really want to play high quality MP3, WAV can be nice or some low quality but listenable music is also fine (just testing for purposes). I checked the MP3 I2S protocol and I already tested it earlier before the project started. I researched a lot to somehow convert the data and send to my headphones but I didn’t got a single ant of it. also I asked AI about it but the solutions it gave were also wrong. I’ll try my best to make it possible. Just to be clear, I dont want mobile to esp32, I’m planning esp32 to my headphones

again, thanks for replying. :grinning_face_with_smiling_eyes:
regards, Andy

That i understand. The information i found is far from easy to read and also a bit beyond me without diving into it completely.

Somehow the audio format on disk needs to be converted before it is transmitted.

If it was my project i could spend a bit more time than i can at the moment (busy, busy busy...)

Ok so from the basic code you posted.

the *frame is the variable that get's filled with the appropriate data. In this example the sine wave gets generated over the period of time and spread out over frames that correspond to the frame-rate.

If you would read samples from a file with a fixed frame rate, you could simply read the frames and pass them to the buffer. (i think)

It is a callback function to begin with and it is telling us how many frames it wants. ( I suppose it determines how much space there is in the buffer)

The format it expects is 44.1KHz dual 16-bit, which is the same as CD or WAV (16-bit), so starting at that format there would not be much converting to do, basically read the header from the file and get on with reading and passing the frame samples and possibly some conversion related to the endianness.

That said WAV files are big and reading them from disk or may be not fast enough.

The next step in my approach would be to take a small section of WAV file (a few KB, you could record a small file or edit something using audicity) and load it into notepad++ and open it in HEX view (Plugins -> HEX-Editor -> View in HEX) and see if i could identify the header section to confirm the file is as i expect it to be.
If i have identified that section i have also identified where the samples start. It is easy enough to copy the samples from my source to the *frame destination for the number of frames that is requested.
You will need to keep in mind that you keep feeding the buffer with frames, but first have a section of samples that you want to play instead of the sinewave.

I chose a small windows notification (chord) and i did find the DataBlocID and the number of samples follows that.
Other info can be found before that. Now i am not here to do your job, but to help only. Can you extract the other information from the header ? (observe the little endian, so all values are lsB first.)

The callback is expecting frames with a fixed framerate. It provides the amount of frames it expects, and if my understanding is correct, the actual amount of frames passed to the buffer, is returned to the object.
So if less frames are available to send (say end of song) the number of frames that were passed to the buffer is the return value.

Now i made a really good effort in explaining as much as i could @robo234, i hope my explanation isn't wasted on you. It interests me to actually use an ESP32 for audio and i never really have done so, but as i said, i am rather busy with some other things.

No, It wasn’t wasted. actually you understanded what I am doing and cleared my problems. And Its OK to do your things rather than wasting time on this forum. I’ll try my best to make this project succesfull. If you need any other information, you can post it in the forum and i’ll respond.

thank you :grinning_face:

Oh great ! So you have succeeded ?

you can say “succeded” but the mp3 transmissin is like 1 bit per second. i’ll send the ready code later

Oh that is a bit slow.