Closed y-nk closed 1 week ago
I don't see any reason why v3.0.4 should not work.
The A2DP library uses the Arduino ESP32 logger, so if you want to see any warnings or errors you need to activate the logger in the Arduino Tools menu
@pschatzmann
EDIT2: I see the logs, but there's just no logging appended after some point:
17:03:04.680 -> rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
17:03:04.680 -> configsip: 0, SPIWP:0xee
17:03:04.680 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
17:03:04.680 -> mode:DIO, clock div:1
17:03:04.680 -> load:0x3fff0030,len:4832
17:03:04.680 -> load:0x40078000,len:16460
17:03:04.722 -> load:0x40080400,len:4
17:03:04.722 -> load:0x40080404,len:3504
17:03:04.722 -> entry 0x400805cc
17:03:05.339 -> [I] SoundGenerator.h : 156 - SineWaveGenerator::begin(channels=2, sample_rate=44100)
17:03:05.339 -> [I] SoundGenerator.h : 149 - bool audio_tools::SineWaveGenerator<T>::begin() [with T = short int]
17:03:05.339 -> [I] AudioTypes.h : 128 - SoundGenerator: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
17:03:05.371 -> [I] Buffers.h : 372 - resize: 4
17:03:05.371 -> [I] SoundGenerator.h : 164 - SineWaveGenerator::begin(channels=2, sample_rate=44100, frequency=493.88)
17:03:05.371 -> [I] SoundGenerator.h : 149 - bool audio_tools::SineWaveGenerator<T>::begin() [with T = short int]
17:03:05.371 -> [I] AudioTypes.h : 128 - SoundGenerator: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
17:03:05.404 -> [I] SoundGenerator.h : 192 - setFrequency: 493.88
17:03:05.404 -> [I] SoundGenerator.h : 193 - active: true
17:03:05.404 -> starting A2DP...
That is a typical log chunk i see after booting the ESP32. I still wonder what could be a reason why there's no audible output then π€?
EDIT: As suggested in the wiki I've tried to add a visualiser (i guess over Serial plotter) in my sketch, but nothing is showing on the plotter (so far). serial is also totally silent after "starting A2DP..."
print.
/**
* @file basic-generator-a2dp.ino
* @author Phil Schatzmann
* @brief We send a test sine signal to a bluetooth speaker
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioLibs/A2DPStream.h"
const char* name = "Bose Color II SoundLink"; // Replace with your bluetooth speaker name
+AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator, set max amplitude (=volume)
GeneratedSoundStream<int16_t> in_stream(sineWave); // Stream generated from sine wave
BluetoothA2DPSource a2dp_source; // A2DP Sender
+CsvOutput<int32_t> csvStream(Serial);
+StreamCopy copier(csvStream, in_stream); // copy i2sStream to csvStream
// callback used by A2DP to provide the sound data - usually len is 128 * 2 channel int16 frames
int32_t get_sound_data(uint8_t * data, int32_t len) {
- return in_stream.readBytes((uint8_t*)data, len);
+ int32_t result = in_stream.readBytes(data, len);
+ LOGI("get_sound_data %d->%d",len, result);
+ return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start input
auto cfg = in_stream.defaultConfig();
cfg.bits_per_sample = 16;
cfg.channels = 2;
cfg.sample_rate = 44100;
in_stream.begin(cfg);
sineWave.begin(cfg, N_B4);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(true);
a2dp_source.start_raw(name, get_sound_data);
+ csvStream.begin(info);
}
// Arduino loop - repeated processing
void loop() {
delay(1000);
}
With this i'll see the LOGI
call properly flooding my logger with [I] basic-generator-a2dp.ino : 23 - get_sound_data 512->512
lines but still no lines shown on the plotter or heard on the speaker.
I have found that maybe the issue is that the data is not playable. I'm now looking at an example to build an mp3 encoded sine wave using your mp3 encoder https://github.com/pschatzmann/arduino-liblame.
It took me a couple of hours, but i got a compiling sketch (posting this in case somebody finds it useful).
#include <AudioTools.h>
#include <AudioLibs/A2DPStream.h>
#include <AudioCodecs/CodecMP3LAME.h>
const char* name = "Bose Color II SoundLink";
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> in_stream(sineWave);
BufferedStream out_stream(1024);
AudioInfo info(44100, 2, 16);
MP3EncoderLAME mp3;
EncodedAudioOutput enc_stream(&out_stream, &mp3);
Throttle throttle(enc_stream);
static int frame_size = 498;
StreamCopy copier(throttle, in_stream, frame_size);
BluetoothA2DPSource a2dp_source;
// callback used by A2DP to provide the sound data - usually len is 128 * 2 channel int16 frames
int32_t get_sound_data(uint8_t * data, int32_t len) {
int32_t result = out_stream.readBytes((uint8_t*)data, len);
// LOGI("get_sound_data %d->%d",len, result);
return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
throttle.begin(info);
in_stream.begin(info);
sineWave.begin(info, N_B4);
enc_stream.begin(info);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(true);
a2dp_source.start_raw(name, get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
copier.copy();
}
The flow i aimed to design was:
Sine β SineStream β Copier β Throttle β EncodedAudioOutput β BufferedStream β BluetoothA2DPSource
The problem i was not expecting was my board doesn't have SPIRAM which is required by the LAME encoder. This was easily spotted in the logs, hopefully.
[Error] lame.c : 2792 - calloc(1,85840) -> 0x0
available MALLOC_CAP_8BIT: 110580 / MALLOC_CAP_32BIT: 110580 / MALLOC_CAP_SPIRAM: 0
I will switch to AAC/SBC and see if sound shows up, just to confirm that it was a codec issue.
Weirdly, a drop-in replacement with the SBC does not produce sound either:
#include <AudioTools.h>
#include <AudioLibs/A2DPStream.h>
#include <AudioCodecs/CodecSBC.h>
const char* name = "Bose Color II SoundLink";
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> in_stream(sineWave);
BufferedStream out_stream(1024);
AudioInfo info(44100, 2, 16);
SBCEncoder encoder;
EncodedAudioOutput enc_stream(&out_stream, &encoder);
Throttle throttle(enc_stream);
static int frame_size = 498;
StreamCopy copier(throttle, in_stream, frame_size);
BluetoothA2DPSource a2dp_source;
int32_t get_sound_data(uint8_t * data, int32_t len) {
int32_t result = out_stream.readBytes((uint8_t*)data, len);
// LOGI("get_sound_data %d->%d",len, result);
return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
Serial.println("Building pipeline...");
throttle.begin(info);
in_stream.begin(info);
sineWave.begin(info, N_B4);
enc_stream.begin(info);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(true);
a2dp_source.start_raw(name, get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
copier.copy();
}
we can see the copier gets some data in/out: [I] StreamCopy.h : 158 - StreamCopy::copy 498 -> 496 -> 496 bytes - in 1 hops
but nothing further. either it's throttled to infinity, or the encoder does something else.
It's quite hard to debug what's happening in a pipeline, so far there's no way for me to know/discover what's happening. I'll keep hacking around until i get results.
Dropping the throttler does not help further:
#include <AudioTools.h>
#include <AudioLibs/A2DPStream.h>
#include <AudioCodecs/CodecSBC.h>
const char* name = "Bose Color II SoundLink";
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> in_stream(sineWave);
BufferedStream out_stream(1024);
AudioInfo info(44100, 2, 16);
SBCEncoder encoder;
EncodedAudioOutput enc_stream(&out_stream, &encoder);
static int frame_size = 498;
StreamCopy copier(enc_stream, in_stream, frame_size);
BluetoothA2DPSource a2dp_source;
int32_t get_sound_data(uint8_t * data, int32_t len) {
int32_t result = out_stream.readBytes((uint8_t*)data, len);
// LOGI("get_sound_data %d->%d",len, result);
return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
Serial.println("Building pipeline...");
in_stream.begin(info);
sineWave.begin(info, N_B4);
enc_stream.begin(info);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(true);
a2dp_source.start_raw(name, get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
copier.copy();
}
I've gone to an easier script. Due to memory limitation i cannot upload the full StarWars30.h
content, so i had to split it in 2 (i literally split the array in 2, final size is 660640).
Now doing:
#include "StarWars30.h"
#include <AudioTools.h>
#include <AudioLibs/A2DPStream.h>
const char* name = "Bose Color II SoundLink";
MemoryStream music(StarWars30_raw, StarWars30_raw_len);
BluetoothA2DPSource a2dp_source;
int32_t get_sound_data(uint8_t * data, int32_t len) {
int32_t result = music.readBytes((uint8_t*)data, len);
LOGI("get_sound_data %d->%d",len, result);
return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(true);
a2dp_source.start_raw(name, get_sound_data);
music.begin();
}
void loop() {}
Logs show there's something wrong (i guess) since the result
is always 0
: [I] test_audio_tool.ino : 19 - get_sound_data 352->0
if i may,few questions.
@josef2600
My output device is a bluetooth speaker (the "Bose Color II SoundLink") which is connected by using BluetoothA2DPSource
. There's no need for DAC/PWM/I2S, the BluetoothA2DPSource's target is the sink. (you can check the examples/communication/ad2p/basic_generator...
)
Settings are provided by BluetoothA2DPSource
, you only need to pass the device name.
I would expect the SineGenerator
to create PCM values but as stated here the output device seems not to support PCM (only AAC, MP3 and SBC)
@pschatzmann may i ask for some pointers at a solution? is the hardware an issue (board, speaker) or rather the software? and more importantly, how would i debug that? I had never succeeded so far at having a sine showing in the plotter.
The Wiki contains a chapter on how to find this out: https://github.com/pschatzmann/arduino-audio-tools/wiki/It's-not-working
The ESP32 A2DP API only supports PCM data as input which will be converted to SBC internally. (As you can find in the Readme of the A2DP library).
Finally you never seemed to analyse the A2DP logs....
@pschatzmann thank you and sorry for mentioning you. I'll follow your pointers and will update... until it works π
EDIT: if a2dp only supports PCM as input, then does that mean we can't send mp3s (stored on an sdcard)? or with additional decoder stream in between?
EDIT2: i'd wish to convert this into a discussion but i dont think i'm allowed to.
Problem Description
As stated in the wiki, I've started my exploration by using examples. I've changed the name of the device, also changed log level to
::Info
as recommended. Device got automatically connected at boot, which I found was a good thing, but then no sound came out.I've added a simple
Serial.println()
in theget_sound_data
function and i can't ~see any lines pulled~ hear any sound from speaker, so i guess the ~stream~ example is broken?Device Description
I'm using ESP Wroom, esp32 core 3.0.4 (Wiki mentions 2.0.17 being latest, is v3 supported?). Board is unknown chinese but I found some ref online mentioning "hw-394" and that the profile to use should be ESP32-WROOM-DA board.
Sketch
Other Steps to Reproduce
Build and run
What is your development environment
Arduino IDE (2.3.2)
I have checked existing issues, discussions and online documentation