>_ DevTrendses

Idioma

Inicio

Lenguajes

Secciones

Frontend Backend Móvil DevOps AI / ML GameDev Blockchain Embebidos Seguridad
C-plus-plus

Cómo Convertir un Microcontrolador de 5$ en un Altavoz Bluetooth o Reproductor Inalámbrico

Si alguna vez has abierto los ejemplos oficiales de Espressif para audio Bluetooth, probablemente recuerdes esa ligera sensación de horror. Docenas de líneas de magia de bajo nivel, un montón de callbacks de Bluedroid, configuración de colas de FreeRTOS, y esa sensación constante de que un puntero está a punto de perderse en algún lugar.

El desarrollador suizo Phil Schatzmann se encontró exactamente con esta frustración y escribió la librería ESP32-A2DP. Oculta toda la complejidad del código repetitivo bajo el capó y proporciona una interfaz C++ limpia para streaming de audio.

esp32

Qué hay bajo el capó y cómo funciona

La librería maneja dos tareas principales:

  • A2DP Sink (receptor): el ESP32 se hace pasar por un altavoz inalámbrico o unos auriculares, recibe el stream desde tu teléfono y lo envía a un DAC externo, el DAC interno de la placa, o un buffer de memoria en bruto.
  • A2DP Source (transmisor): el microcontrolador en sí transmite audio (generado algorítmicamente, leído desde una tarjeta SD, o desde un micrófono) a altavoces Bluetooth externos.

El proyecto se basa en el perfil A2DP estándar y soporta la transmisión de señales de control mediante AVRCP. Esto significa que el microcontrolador puede cambiar pistas en tu teléfono, pausar la reproducción o leer metadatos (título de la pista, nombre del artista, duración).

En cuanto a la salida de audio, la librería funciona sobre el bus I2S. En ESP-IDF v5 y Arduino ESP32 v3, la API de I2S fue reescrita significativamente. Para evitar romper la compatibilidad al actualizar el framework, el autor recomienda enlazar la librería directamente a tu propio proyecto arduino-audio-tools, aunque puedes conformarte con la clase estándar I2SClass o simplemente obtener muestras PCM en bruto.

Cómo construir un receptor inalámbrico en cinco líneas

Aquí tienes un ejemplo mínimo para poner en marcha el receptor de audio:

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

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

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

void loop() {
}

Después de flashear, la placa aparece en la lista de dispositivos Bluetooth como "MyMusic". Por defecto, el stream de audio (16 bits, 44.1 kHz estéreo) va a los pines I2S GPIO14 (BCK), GPIO15 (WS) y GPIO22 (Data Out). Si tu cableado es diferente, los pines se configuran en dos líneas mediante el config i2s.defaultConfig().

Si no tienes un chip DAC externo a mano (como el popular PCM5102A o MAX98357A), puedes usar el DAC de 8 bits integrado en GPIO25 y GPIO26:

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

AnalogAudioStream out;
BluetoothA2DPSink a2dp_sink(out);

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

void loop() {}

El sonido a través del DAC integrado será un poco ruidoso para los audiófilos, pero es perfectamente válido para notificaciones de voz o radio en la cocina.

Leer metadatos y controlar pistas

Un detalle útil: la librería te permite obtener información de la pista mediante AVRCP. Si conectas una pequeña pantalla, puedes crear fácilmente una pantalla de información para un centro multimedia:

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() {}

Para controlar el reproductor de tu teléfono desde botones físicos, están disponibles los métodos play(), pause(), next(), previous(), fast_forward() y rewind().

Modo transmisor: cuando el ESP32 genera el sonido

Si necesitas enviar audio a auriculares Bluetooth o una barra de sonido, cambia a BluetoothA2DPSource. El stream se pasa a la librería mediante un callback:

#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() {}

Por cierto, puedes pasar una lista de nombres de dispositivos al método start() (vía std::vector<const char*>). La placa se conectará automáticamente al primero que encuentre de la lista.

Acceso al stream de audio en bruto y códecs

Si no necesitas I2S y necesitas procesar audio algorítmicamente directamente en el microcontrolador (por ejemplo, crear un espectáculo de luces mediante FFT o grabar un fragmento en memoria), puedes interceptar los paquetes PCM mediante set_stream_reader():

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");
}

El códec por defecto es SBC estándar. En versiones recientes, el autor añadió soporte experimental para conectar decodificadores externos mediante add_decoder(), incluyendo AAC (aunque para funcionalidad completa del lado del IDF, se requerirá ESP-IDF versión 6.1 o superior).

Limitaciones que deberías conocer

  • Los perfiles HFP y HSP (llamadas manos libres, llamadas con micrófono) no están soportados. El proyecto se centra estrictamente en la transmisión de streams multimedia.
  • La librería es exigente con los recursos de la pila Bluetooth. Combinar tráfico Wi-Fi pesado y streaming A2DP estable en un ESP32 básico puede ser complicado, y es posible que haya saltos en el audio.
  • La documentación en el repositorio es detallada, pero el autor es estricto con el formato de los informes de errores: antes de abrir un issue en GitHub, asegúrate de verificar las versiones de las librerías y el core de ESP32.

A quién le será útil

El proyecto será útil si quieres dar nueva vida a un viejo magnetófono, integrar un receptor inalámbrico en un amplificador vintage, o construir un sintetizador personalizado que transmita audio directamente a auriculares inalámbricos.

La librería es compatible con Arduino IDE, PlatformIO y el IDF de Espressif puro como componente. Para empezar, solo necesitas una placa ESP32 WROOM y una placa DAC basada en PCM5102A por unos pocos dólares.

Proyectos relacionados