用于 ESP32 的简单 Arduino 蓝牙音乐接收器和发送器库

ESP32 是一款微控制器,为蓝牙 A2DP 提供 API,可用于接收声音数据,例如从您的手机,并通过回调方法提供。输出是 PCM 数据流,从 SBC 格式解码。

I2S 是一种电气串行总线接口标准,用于将数字音频设备连接在一起。它用于在电子设备中的集成电路之间传输 PCM 音频数据。

因此,我们可以将蓝牙的输入馈送到 I2S 输出:乐鑫的示例可以在 Github 上找到。

不幸的是,这个例子并没有让我高兴,所以我决定将其转换为一个简单的 Arduino 库 ,该库非常易于从 Arduino 软件 IDE 中使用。

支持的蓝牙协议

顾名思义,它支持仅提供音频流的 A2DP 蓝牙协议 

它还支持音频/视频远程控制配置文件 (AVRCP) 和 A2DP。

不支持免提配置文件 (HFP)、耳机配置文件 (HSP) 和不带 A2DP 的独立 AVRCP!

I2S API / 依赖项

乐鑫将停用旧版 I2S API:因此,在 Arduino v3.0.0 (IDF v5) 中, 我的旧 I2S 集成将不再可用。只要您不升级,旧语法仍然有效。

为了支持与版本无关的唯一输出 API,建议安装和使用 AudioTools 库。因此,文档和所有示例都已更新以使用这种新方法。

但是,您也可以输出到继承自 Arduino Print 的任何其他类:例如 Arduino ESP32 I2SClass,或者您可以使用下面描述的数据回调 

A2DP Sink(音乐接收器)

例如,这可用于构建您自己的蓝牙扬声器。

使用默认引脚的简单 I2S 示例(A2DS Sink)

这是最简单的示例,它只使用正确的默认设置:

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

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

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

void loop() {
}

这将创建一个名为“MyMusic”的新蓝牙设备,输出将发送到以下需要连接到外部 DAC 的默认 I2S 引脚:

  • bck_io_num = 14
  • ws_io_num = 15
  • data_out_num = 22

请注意,与旧版 API 相比,这些默认引脚已更改!

定义引脚

您可以在开始前轻松定义自己的引脚。

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

使用 ESP32 I2S API 输出

您还可以使用 Arduino ESP32 I2S API:您无需为此安装任何其他库。

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

请注意,此 API 还取决于安装的版本:上面的示例适用于 ESP32 >= 3.0.0!

输出到内部 DAC

您还可以使用 AudioTools 中的 AnalogAudioStream 将输出直接发送到 ESP32 的内部 DAC:

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

AnalogAudioStream out;
BluetoothA2DPSink a2dp_sink(out);

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

void loop() {
}

输出现在连接到 DAC 引脚 GPIO25(通道 1)和 GPIO26(通道 2)。

使用回调访问接收器数据流

收到数据包时,您可能会收到通知。该 API 使用的 PCM 数据通常格式为 44.1kHz 采样率、双通道 16 位采样数据。

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

或者您可以访问数据包:

// 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
}

在 a2dp_sink.set_stream_reader() 方法中,您可以提供一个可选参数来定义您希望 I2S 的输出是活动还是非活动 - 因此,您可以使用此方法例如,只需调用 a2dp_sink.set_stream_reader(read_data_stream, false)

支持元数据

可以注册一个方法,当系统收到任何 AVRC 元数据 (esp_avrc_md_attr_mask_t) 时将调用该方法。这是一个例子

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

默认情况下,您应该获得最重要的信息,但是您可以通过调用以下 set_avrc_metadata_attribute_mask 方法来调整此信息,例如,如果您只需要标题和播放时间,您可以调用:

set_avrc_metadata_attribute_mask(ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_PLAYING_TIME);

在启动 A2DP 接收器之前。请注意,data2 实际上是一个 char* 字符串,因此即使 ESP_AVRC_MD_ATTR_PLAYING_TIME 被记录为媒体持续时间的毫秒,您也需要在对其进行数学运算之前对其进行解析。有关详细信息,请参阅元数据示例。

支持通知

与 avrc_metadata_callback 类似,ESP IDF v4+ 支持选定的 esp_avrc_rn_param_t 回调,如 set_avrc_rn_playstatus_callback set_avrc_rn_play_pos_callback , set_avrc_rn_track_change_callback 可用于分别获取 esp_avrc_playback_stat_t playback 播放状态、uint32_t play_pos 播放位置和轨道更改标志 uint8_t elm_id。有关更多详细信息,请参阅 playing_status_callbacks 示例。

支持 AVRC 命令

我添加了以下 AVRC 命令,您可以使用它们来“控制”您的 A2DP 源:

  • play();  
  • pause();  
  • stop();  
  • next();  
  • previous();  
  • fast_forward(); 
  • rewind();  

A2DP Source (Music Sender)

这可用于向您的蓝牙扬声器提供音频数据。

使用回调从 A2DS 数据源发送数据

我们还可以生成声音并将其发送到蓝牙扬声器。

ESP32 A2DP 中支持的音频编解码器是 SBC:API 使用通常格式为 44.1kHz 采样率、双通道 16 位采样数据的 PCM 数据。

当您启动 BluetoothA2DPSource 时,您需要传递要连接的蓝牙名称和提供声音数据的“回呼功能”:

#include "BluetoothA2DPSource.h"

BluetoothA2DPSource a2dp_source;

// callback 
int32_t get_sound_data(uint8 *data, int32_t byteCount) {
    // generate your sound data 
    // return the effective length in bytes
    return byteCount;
}

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

void loop() {}

除了 set_data_callback 回调方法,您还可以使用 set_data_callback_in_frames,它使用帧而不是字节。在 Arduino 中,您还可以提供流(例如文件)作为数据源或提供流的回调。

在示例中,您可以找到借助 sin() 函数生成声音的实现。

您还可以指定多个备选蓝牙名称。系统仅连接到第一个可用的:

void setup() {
  static std::vector bt_names = {"MyMusic","RadioPlayer","MusicPlayer"};
  a2dp_source.set_data_callback(get_sound_data)
  a2dp_source.start(bt_names); 
} 

更多信息可以在相关的类文档中找到!

Logging

该库使用 ESP32 记录器,您可以在 Arduino 中 - 工具 - 核心调试日志中激活该记录器。

架构/依赖项

当前代码完全依赖于 ESP-IDF(也由 Arduino ESP32 内核提供)。没有其他依赖项,这包括 Arduino API!

因此,我们支持:

  • Arduino
  • PlatformIO
  • Espressif IDF

然而,此限制限制了所提供的示例。

在克隆项目之前,请阅读以下信息,这些信息可以在 Wiki 中找到。

数字声音处理

您可以独立使用这个库,但它是我的音频工具项目的一部分。因此,您可以轻松地通过音效增强此功能、使用滤波器或均衡器、使用替代音频接收器或音频源、执行 FFT 等。这是一个简单的示例 ,如何使用 FFT 分析音频数据。

文档

资源均来自互联网,如有侵权,请联系我们删除;
资源版权归原作者所有,如需商用,请联系作者;
19:55   阅读(1)
标签: 创客 ESP32 Arduino

涨知识
欧姆定律

欧姆定律是指在同一电路中,通过某段导体的电流跟这段导体两端的电压成正比,跟这段导体的电阻成反比。该定律是由德国物理学家乔治·西蒙·欧姆1826年4月发表的《金属导电定律的测定》论文提出的。

相关资源
小鹏物联网智能浇花套件-用户手册

小鹏物联网智能浇花套件-用户手册 V1.0


3D打印的遥控船

ESP32遥控船,不仅可以在湖面上自由巡游,还能作为鱼饵板在钓鱼时使用。


Arduino和Raspberry Pi的模块化支持 - custoblocks

CustoBlocks 是一套模块化组件,旨在帮助用户构建定制化的框架结构。它允许用户像拼积木一样,将不同的模块连接起来,创造出满足特定需求的个性化框架。


Fritzing中ESP32元件库

本资源文件包含了多个ESP32模型的元件,方便用户在Fritzing中进行电路设计和仿真。


米思齐手册

米思齐手册,包含28个小实验。


Arduino UNO 乐高兼容底座3D模型

Arduino UNO 乐高兼容底座3D模型


乐高科技适配RaspberyPi,Arduino的底座3D模式

乐高科技适配RaspberyPi,Arduino的底座3D模式。


适用于ESP32和ESP8266板、树莓派Pico的外壳

适用于ESP32和ESP8266板、树莓派Pico的外壳3D模型


ESP32-CAM箱式外壳

ESP32-CAM箱式外壳


ESP32开发指南

ESP32开发指南V1.2