>_ DevTrendsde

Sprache

Start

Sprachen

Bereiche

Frontend Backend Mobile DevOps AI / ML GameDev Blockchain Embedded Sicherheit
C-plus-plus

So verwandeln Sie einen 5-Dollar-Mikrocontroller in einen Bluetooth-Lautsprecher oder kabellosen Player

Wenn Sie schon einmal die offiziellen Espressif-Beispiele für Bluetooth-Audio geöffnet haben, erinnern Sie sich wahrscheinlich an dieses leichte Gefühl des Horrors. Dutzende Zeilen von Low-Level-Magie, eine Handvoll Bluedroid-Callbacks, FreeRTOS-Queue-Konfiguration und ein ständiges Gefühl, dass ein Pointer gleich irgendwohin abdriften wird.

Der Schweizer Entwickler Phil Schatzmann stieß genau auf diese Frustration und schrieb die ESP32-A2DP-Bibliothek. Sie verbirgt den gesamten komplexen Boilerplate-Code unter der Haube und bietet eine saubere C++-Schnittstelle für Audio-Streaming.

esp32

Was steckt unter der Haube und wie es funktioniert

Die Bibliothek erledigt zwei Hauptaufgaben:

  • A2DP Sink (Empfänger): ESP32 gibt sich als kabelloser Lautsprecher oder Kopfhörer aus, empfängt den Stream von Ihrem Telefon und gibt ihn an einen externen DAC, den internen DAC des Boards oder einen Raw-Memory-Buffer aus.
  • A2DP Source (Sender): Der Mikrocontroller selbst sendet Audio (algorithmisch generiert, von einer SD-Karte gelesen oder von einem Mikrofon) an externe Bluetooth-Lautsprecher.

Das Projekt basiert auf dem Standard-A2DP-Profil und unterstützt die Übertragung von Steuersignalen über AVRCP. Das bedeutet, der Mikrocontroller kann Titel auf Ihrem Telefon wechseln, die Wiedergabe pausieren oder Metadaten auslesen (Titel, Künstlername, Dauer).

Was den Audio-Ausgang betrifft, arbeitet die Bibliothek über den I2S-Bus. In ESP-IDF v5 und Arduino ESP32 v3 wurde die I2S-API erheblich überarbeitet. Um die Kompatibilität bei Framework-Updates nicht zu brechen, empfiehlt der Autor, die Bibliothek direkt in Ihr eigenes Projekt einzubinden arduino-audio-tools, obwohl Sie auch mit der Standard-Klasse I2SClass auskommen oder einfach rohe PCM-Samples abgreifen können.

So bauen Sie einen kabellosen Empfänger in fünf Zeilen

Hier ist ein minimales Beispiel, um den Audio-Empfänger zum Laufen zu bringen:

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
    Serial.begin(115200);
    a2dp_sink.start("MyMusic");
}

void loop() {
}

Nach dem Flashen erscheint das Board in der Bluetooth-Geräteliste als „MyMusic". Standardmäßig wird der Audio-Stream (16-Bit, 44,1 kHz Stereo) an die I2S-Pins GPIO14 (BCK), GPIO15 (WS) und GPIO22 (Data Out) ausgegeben. Wenn Ihre Verdrahtung anders aussieht, werden die Pins in zwei Zeilen über das Config i2s.defaultConfig() eingestellt.

Wenn Sie keinen externen DAC-Chip (wie den beliebten PCM5102A oder MAX98357A) zur Hand haben, können Sie den eingebauten 8-Bit-DAC an GPIO25 und GPIO26 verwenden:

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

AnalogAudioStream out;
BluetoothA2DPSink a2dp_sink(out);

void setup() {
    Serial.begin(115200);
    a2dp_sink.start("MyMusic");
}

void loop() {}

Sound über den eingebauten DAC wird für Audiophile etwas noisig sein, aber für Sprachbenachrichtigungen oder Radio in der Küche ist er völlig in Ordnung.

Metadaten auslesen und Titel steuern

Ein nützliches Detail: Die Bibliothek ermöglicht es Ihnen, Titelinfos über AVRCP abzurufen. Wenn Sie ein kleines Display anschließen, können Sie leicht einen Info-Bildschirm für ein Media-Center erstellen:

void avrc_metadata_callback(uint8_t data1, const uint8_t *data2) {
    Serial.printf("Метаданные: id 0x%x, текст: %s\n", data1, data2);
}

void setup() {
    Serial.begin(115200);
    a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
    a2dp_sink.start("ESP32_Receiver");
}

void loop() {}

Um den Player auf Ihrem Telefon über physische Tasten zu steuern, stehen die Methoden play(), pause(), next(), previous(), fast_forward() und rewind() zur Verfügung.

Sendermodus: wenn ESP32 den Sound erzeugt

Wenn Sie Audio an Bluetooth-Kopfhörer oder eine Soundbar senden müssen, wechseln Sie zu BluetoothA2DPSource. Der Stream wird der Bibliothek über einen Callback zugeführt:

#include "BluetoothA2DPSource.h"

BluetoothA2DPSource a2dp_source;

int32_t get_sound_data(uint8_t *data, int32_t byteCount) {
    // Здесь заполняем буфер PCM данными
    return byteCount;
}

void setup() {
    a2dp_source.set_data_callback(get_sound_data);
    a2dp_source.start("Target_Speaker");  
}

void loop() {}

Übrigens können Sie der start()-Methode eine Liste von Gerätenamen übergeben (über std::vector<const char*>). Das Board verbindet sich automatisch mit dem ersten Gerät aus der Liste, das es findet.

Zugriff auf den Raw-Audiostream und Codecs

Wenn Sie I2S nicht benötigen und Audio direkt auf dem Mikrocontroller algorithmisch verarbeiten müssen (um beispielsweise eine Lichtshow über FFT zu erstellen oder ein Fragment in den Speicher aufzuzeichnen), können Sie PCM-Pakete über set_stream_reader() abfangen:

void read_data_stream(const uint8_t *data, uint32_t length) {
    int16_t *samples = (int16_t*) data;
    uint32_t sample_count = length / 2;
    // Обработка семплов
}

void setup() {
    a2dp_sink.set_stream_reader(read_data_stream, false); // false отключает вывод на I2S
    a2dp_sink.start("DSP_Node");
}

Der Standard-Codec ist SBC. In neueren Versionen hat der Autor experimentelle Unterstützung für die Verbindung externer Decoder über add_decoder() hinzugefügt, einschließlich AAC (allerdings wird für die volle Funktionalität auf IDF-Seite ESP-IDF Version 6.1 oder höher benötigt).

Einschränkungen, die Sie kennen sollten

  • HFP- und HSP-Profile (Freisprechen, Anrufe mit Mikrofon) werden nicht unterstützt. Das Projekt dreht sich strikt um die Übertragung von Media-Streams.
  • Die Bibliothek ist anspruchsvoll was Bluetooth-Stack-Ressourcen angeht. Schwere Wi-Fi-Nutzung und stabiles A2DP-Streaming auf einem einfachen ESP32 zu kombinieren, kann knifflig sein, und Audio-Stottern ist möglich.
  • Die Dokumentation im Repository ist detailliert, aber der Autor ist streng bei der Formatierung von Bug-Reports: bevor Sie ein Issue auf GitHub öffnen, überprüfen Sie unbedingt die Versionen der Bibliotheken und des ESP32-Core.

Wem das nützlich sein wird

Das Projekt ist praktisch, wenn Sie einem alten Kassettenrekorder neues Leben einhauchen, einen kabellosen Empfänger in einen Vintage-Verstärker integrieren oder einen Custom-Synthesizer bauen möchten, der Audio direkt an kabellose Kopfhörer streamt.

Die Bibliothek ist kompatibel mit Arduino IDE, PlatformIO und purem Espressif IDF als Komponente. Um loszulegen, brauchen Sie nur ein ESP32-WROOM-Board und ein PCM5102-basiertes DAC-Board für ein paar Dollar.

Ähnliche Projekte