I2S 是一种电气串行总线接口标准,用于将数字音频设备连接在一起。它用于在电子设备中的集成电路之间传输 PCM 音频数据。
因此,我们可以将蓝牙的输入馈送到 I2S 输出:乐鑫的示例可以在 Github 上找到。
不幸的是,这个例子并没有让我高兴,所以我决定将其转换为一个简单的 Arduino 库 ,该库非常易于从 Arduino 软件 IDE 中使用。
顾名思义,它支持仅提供音频流的 A2DP 蓝牙协议 !
它还支持音频/视频远程控制配置文件 (AVRCP) 和 A2DP。
不支持免提配置文件 (HFP)、耳机配置文件 (HSP) 和不带 A2DP 的独立 AVRCP!
乐鑫将停用旧版 I2S API:因此,在 Arduino v3.0.0 (IDF v5) 中, 我的旧 I2S 集成将不再可用。只要您不升级,旧语法仍然有效。
为了支持与版本无关的唯一输出 API,建议安装和使用 AudioTools 库。因此,文档和所有示例都已更新以使用这种新方法。
但是,您也可以输出到继承自 Arduino Print 的任何其他类:例如 Arduino ESP32 I2SClass,或者您可以使用下面描述的数据回调 。
例如,这可用于构建您自己的蓝牙扬声器。
这是最简单的示例,它只使用正确的默认设置:
#include "AudioTools.h" #include "BluetoothA2DPSink.h" I2SStream i2s; BluetoothA2DPSink a2dp_sink(i2s); void setup() { a2dp_sink.start("MyMusic"); } void loop() { }
这将创建一个名为“MyMusic”的新蓝牙设备,输出将发送到以下需要连接到外部 DAC 的默认 I2S 引脚:
请注意,与旧版 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() { }
您还可以使用 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!
您还可以使用 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 命令,您可以使用它们来“控制”您的 A2DP 源:
这可用于向您的蓝牙扬声器提供音频数据。
我们还可以生成声音并将其发送到蓝牙扬声器。
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::vectorbt_names = {"MyMusic","RadioPlayer","MusicPlayer"}; a2dp_source.set_data_callback(get_sound_data) a2dp_source.start(bt_names); }
更多信息可以在相关的类文档中找到!
该库使用 ESP32 记录器,您可以在 Arduino 中 - 工具 - 核心调试日志中激活该记录器。
当前代码完全依赖于 ESP-IDF(也由 Arduino ESP32 内核提供)。没有其他依赖项,这包括 Arduino API!
因此,我们支持:
然而,此限制限制了所提供的示例。
在克隆项目之前,请阅读以下信息,这些信息可以在 Wiki 中找到。
您可以独立使用这个库,但它是我的音频工具项目的一部分。因此,您可以轻松地通过音效增强此功能、使用滤波器或均衡器、使用替代音频接收器或音频源、执行 FFT 等。这是一个简单的示例 ,如何使用 FFT 分析音频数据。
欧姆定律是指在同一电路中,通过某段导体的电流跟这段导体两端的电压成正比,跟这段导体的电阻成反比。该定律是由德国物理学家乔治·西蒙·欧姆1826年4月发表的《金属导电定律的测定》论文提出的。
小鹏物联网智能浇花套件-用户手册 V1.0
ESP32遥控船,不仅可以在湖面上自由巡游,还能作为鱼饵板在钓鱼时使用。
CustoBlocks 是一套模块化组件,旨在帮助用户构建定制化的框架结构。它允许用户像拼积木一样,将不同的模块连接起来,创造出满足特定需求的个性化框架。
本资源文件包含了多个ESP32模型的元件,方便用户在Fritzing中进行电路设计和仿真。
米思齐手册,包含28个小实验。
Arduino UNO 乐高兼容底座3D模型
乐高科技适配RaspberyPi,Arduino的底座3D模式。
适用于ESP32和ESP8266板、树莓派Pico的外壳3D模型
ESP32-CAM箱式外壳
ESP32开发指南V1.2