Der ESP32 ist ein Mikrocontroller, der eine API für Bluetooth A2DP bereitstellt, mit der Sie Tondaten z. B. von Ihrem Mobiltelefon empfangen und über eine Callback-Methode zur Verfügung stellen können. Die Ausgabe ist ein PCM-Datenstrom, dekodiert aus dem SBC-Format. Die Dokumentation finden Sie hier.
I2S ist ein elektrischer serieller Busschnittstellenstandard, der für die Verbindung digitaler Audiogeräte verwendet wird. Es wird verwendet, um PCM-Audiodaten zwischen integrierten Schaltkreisen in einem elektronischen Gerät zu übertragen.
Wir können also einfach den Eingang von Bluetooth an den I2S-Ausgang weiterleiten: Ein Beispiel hierfür von Espressif finden Sie auf Github.
Leider gefiel mir dieses Beispiel nicht, also beschloss ich, es in eine einfache Arduino-Bibliothek umzuwandeln, die sehr einfach von einer Arduino-Software-IDE aus zu verwenden ist.
Wie der Name dieser Bibliothek schon sagt, unterstützt sie das A2DP-Bluetooth-Protokoll, das nur Audio-Streaming ermöglicht!
Es unterstützt außerdem Audio/Video Remote Control Profile (AVRCP) zusammen mit A2DP.
Das Hands-Free Profile (HFP), Headset Profile (HSP) und eigenständiges AVRCP ohne A2DP werden nicht unterstützt!
Espressif stellt die alte I2S-API ein: Daher wird meine alte I2S-Integration mit Arduino v3.0.0 (IDF v5) nicht mehr verfügbar sein. Die alte Syntax funktioniert weiterhin, solange Sie kein Upgrade durchführen.
Um eine einzigartige, versionunabhängige Ausgabe-API zu unterstützen, wird empfohlen, die AudioTools-Bibliothek zu installieren und zu verwenden. Daher wurden die Dokumentation und alle Beispiele aktualisiert, um diesen neuen Ansatz zu verwenden.
Sie können jedoch auch in jede andere Klasse ausgeben, die von Arduino Print erbt: z. B. die Arduino ESP32 I2SClass, oder Sie können den unten beschriebenen Datenrückruf verwenden.
Dies kann beispielsweise zum Bau eines eigenen Bluetooth-Lautsprechers verwendet werden.
Hier ist das einfachste Beispiel, das nur die richtigen Standardeinstellungen verwendet:
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
I2SStream i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
Dadurch wird ein neues Bluetooth-Gerät mit dem Namen „MyMusic“ erstellt und die Ausgabe wird an die folgenden Standard-I2S-Pins gesendet, die mit einem externen DAC verbunden werden müssen:
Bitte beachten Sie, dass sich diese Standard-Pins im Vergleich zur alten API geändert haben!
Sie können Ihre eigenen Pins ganz einfach vor dem start
definieren.
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
I2SStream i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
auto cfg = i2s. defaultConfig ();
cfg. pin_bck = 14 ;
cfg. pin_ws = 15 ;
cfg. pin_data = 22 ;
i2s. begin (cfg);
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
Sie können auch die Arduino ESP32 I2S API nutzen: Sie müssen hierfür keine zusätzliche Bibliothek installieren.
# include " ESP_I2S.h "
# include " BluetoothA2DPSink.h "
const uint8_t I2S_SCK = 5 ; /* Audio data bit clock */
const uint8_t I2S_WS = 25 ; /* Audio data left and right clock */
const uint8_t I2S_SDOUT = 26 ; /* ESP32 audio data output (to speakers) */
I2SClass i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
i2s. setPins (I2S_SCK, I2S_WS, I2S_SDOUT);
if (!i2s. begin (I2S_MODE_STD, 44100 , I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
Serial. println ( " Failed to initialize I2S! " );
while ( 1 ); // do nothing
}
a2dp_sink. start ( " MyMusic " );
}
void loop () {}
Bitte beachten Sie, dass diese API auch von der installierten Version abhängt: Das obige Beispiel gilt für ESP32 >= 3.0.0!
Sie können die Ausgabe auch direkt an den internen DAC des ESP32 senden, indem Sie den AnalogAudioStream aus den AudioTools verwenden:
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
AnalogAudioStream out;
BluetoothA2DPSink a2dp_sink (out);
void setup () {
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
Der Ausgang geht nun an die DAC-Pins GPIO25 (Kanal 1) und GPIO26 (Kanal 2).
Sie können benachrichtigt werden, wenn ein Paket empfangen wird. Die API verwendet PCM-Daten, die normalerweise als Zweikanal-16-Bit-Abtastdaten mit einer Abtastrate von 44,1 kHz formatiert sind.
// In the setup function:
a2dp_sink.set_on_data_received(data_received_callback);
// Then somewhere in your sketch:
void data_received_callback () {
Serial. println ( " Data packet received " );
}
Oder Sie greifen auf das Paket zu:
// In the setup function:
a2dp_sink.set_stream_reader(read_data_stream);
// Then somewhere in your sketch:
void read_data_stream ( const uint8_t *data, uint32_t length)
{
int16_t *samples = ( int16_t *) data;
uint32_t sample_count = length/ 2 ;
// Do something with the data packet
}
In der Methode a2dp_sink.set_stream_reader()
können Sie einen optionalen Parameter bereitstellen, der definiert, ob die Ausgabe an I2S aktiv oder deaktiviert sein soll. Sie können diese Methode also beispielsweise verwenden, um I2S auszuschalten, indem Sie einfach a2dp_sink.set_stream_reader(read_data_stream, false)
Sie können eine Methode registrieren, die aufgerufen wird, wenn das System AVRC-Metadaten empfängt ( esp_avrc_md_attr_mask_t
). Hier ist ein Beispiel
void avrc_metadata_callback ( uint8_t data1, const uint8_t *data2) {
Serial. printf ( " AVRC metadata rsp: attribute id 0x%x, %s n " , data1, data2);
}
a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
a2dp_sink.start( " BT " );
Standardmäßig sollten Sie die wichtigsten Informationen erhalten. Sie können dies jedoch anpassen, indem Sie die Methode set_avrc_metadata_attribute_mask
aufrufen. Wenn Sie beispielsweise nur den Titel und die Spielzeit benötigen, können Sie Folgendes aufrufen:
set_avrc_metadata_attribute_mask (ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_PLAYING_TIME);
bevor Sie die A2DP-Senke starten. Beachten Sie, dass es sich bei data2 tatsächlich um eine char*-Zeichenfolge handelt. Auch wenn ESP_AVRC_MD_ATTR_PLAYING_TIME
als Millisekunden der Mediendauer dokumentiert ist, müssen Sie sie analysieren, bevor Sie Berechnungen anstellen. Weitere Informationen finden Sie im Metadatenbeispiel.
Ähnlich wie avrc_metadata_callback
unterstützt ESP IDF v4+ ausgewählte esp_avrc_rn_param_t
-Rückrufe wie set_avrc_rn_playstatus_callback
, set_avrc_rn_play_pos_callback
und set_avrc_rn_track_change_callback
, die verwendet werden können, um den Wiedergabestatus esp_avrc_playback_stat_t playback
, die Wiedergabeposition uint32_t play_pos
und abzurufen uint8_t elm_id
verfolgt jeweils das Änderungsflag. Weitere Einzelheiten finden Sie im Beispiel playing_status_callbacks.
Ich habe die folgenden AVRC-Befehle hinzugefügt, mit denen Sie Ihre A2DP-Quelle „steuern“ können:
Damit können Sie beispielsweise Ihren Bluetooth-Lautsprecher mit Ihren Audiodaten versorgen.
Wir können auch Ton erzeugen und ihn beispielsweise an einen Bluetooth-Lautsprecher senden.
Der unterstützte Audio-Codec in ESP32 A2DP ist SBC: Die API verwendet PCM-Daten, die normalerweise als Zweikanal-16-Bit-Abtastdaten mit einer Abtastrate von 44,1 kHz formatiert sind.
Wenn Sie BluetoothA2DPSource starten, müssen Sie den Bluetooth-Namen, mit dem Sie eine Verbindung herstellen möchten, und eine „Rückruffunktion“ übergeben, die die Tondaten generiert:
# include " BluetoothA2DPSource.h "
BluetoothA2DPSource a2dp_source;
// callback
int32_t get_sound_data (Frame *data, int32_t frameCount) {
// generate your sound data
// return the effective length (in frames) of the generated sound (which usually is identical with the requested len)
// 1 frame is 2 channels * 2 bytes = 4 bytes
return frameCount;
}
void setup () {
a2dp_source. start ( " MyMusic " , get_sound_data);
}
void loop () {
}
In den Beispielen finden Sie eine Implementierung, die mit Hilfe der Funktion sin() Sound erzeugt. Sie können auch mehrere alternative Bluetooth-Namen angeben. Das System verbindet sich einfach mit dem ersten verfügbaren:
void setup () {
static std::vector< char *> bt_names = { " MyMusic " , " RadioPlayer " , " MusicPlayer " };
a2dp_source. start (bt_names, get_sound_data);
}
Sie können die Daten auch direkt als einfaches Array von uint8_t bereitstellen:
# include " BluetoothA2DPSource.h "
extern const uint8_t StarWars10_raw[];
extern const unsigned int StarWars10_raw_len;
BluetoothA2DPSource a2dp_source;
SoundData *music = new OneChannelSoundData(( int16_t *)StarWars30_raw, StarWars30_raw_len/ 2 );
void setup () {
a2dp_source. start ( " RadioPlayer " );
a2dp_source. write_data (music);
}
void loop () {
}
Das Array kann z. B. folgendermaßen vorbereitet werden:
Vielleicht möchten Sie mit dem Partitionsschema kompilieren: Riesige App!
Im obigen Beispiel stellen wir die Daten mit einem Kanal bereit. Dies hat den Vorteil, dass viel weniger Platz benötigt wird als bei einer 2-Kanal-Aufnahme, die Sie wie folgt nutzen können:
SoundData *data = new TwoChannelSoundData((Frame*)StarWars10_raw,StarWars10_raw_len/4);
Im Konstruktor können Sie zusätzliche Parameter übergeben:
TwoChannelSoundData (Frame *data, int32_t frameCount, bool loop= false );
OneChannelSoundData ( int16_t *data, int32_t frameCount, bool loop= false , ChannelInfo channelInfo=Both);
OneChannel8BitSoundData ( int8_t *data, int32_t frameCount, bool loop= false , ChannelInfo channelInfo=Both);
Diese Bibliothek verwendet den ESP32-Logger, den Sie in Arduino unter - Tools - Core Debug Log aktivieren können.
Der aktuelle Code ist ausschließlich vom ESP-IDF abhängig (der auch vom Arduino ESP32-Kern bereitgestellt wird). Es gibt keine weiteren Abhängigkeiten und dazu gehört auch die Arduino API!
Deshalb unterstützen wir:
Diese Einschränkung schränkt jedoch die bereitgestellten Beispiele ein.
Bevor Sie das Projekt klonen, lesen Sie bitte die folgenden Informationen, die im Wiki zu finden sind.
Sie können diese Bibliothek eigenständig verwenden, sie ist jedoch Teil meines Audio-Tools-Projekts. So können Sie diese Funktionalität ganz einfach mit Soundeffekten erweitern, Filter verwenden, alternative Audiosenken oder Audioquellen nutzen, FFT durchführen usw. Hier ist ein einfaches Beispiel, wie Sie die Audiodaten mit FFT analysieren können.
Ich habe viel Zeit darauf verwendet, eine umfassende und vollständige Dokumentation bereitzustellen. Lesen Sie daher bitte zuerst die Dokumentation und überprüfen Sie die Probleme und Diskussionen, bevor Sie neue auf Github veröffentlichen.
Öffnen Sie Probleme nur für Fehler. Wenn es sich nicht um einen Fehler handelt, verwenden Sie eine Diskussion: Geben Sie ausreichend Informationen darüber an
damit andere Ihr Problem verstehen und reproduzieren können.
Und vor allem: Schicken Sie mir keine E-Mails und stellen Sie keine Fragen auf meiner persönlichen Website!
Lassen Sie sich von Projekten inspirieren, die diese Bibliothek nutzten, und teilen Sie Ihre Projekte mit der Community.
Für Arduino können Sie die Bibliothek als zip herunterladen und include Library -> zip-Bibliothek aufrufen. Oder Sie können dieses Projekt z. B. mit in den Arduino-Bibliotheksordner klonen
cd ~ /Documents/Arduino/libraries
git clone https://github.com/pschatzmann/ESP32-A2DP.git
git clone https://github.com/pschatzmann/arduino-audio-tools.git
Für die bereitgestellten Beispiele müssen Sie auch die Audio-Tools-Bibliothek installieren.
Weitere Frameworks finden Sie im Wiki
Die Änderungshistorie finden Sie im Wiki
Diese Software ist völlig kostenlos, aber Sie können mich glücklich machen, indem Sie mich mit einer Belohnung belohnen