ESP32 是一款微控制器,提供藍牙 A2DP API,可用於接收聲音資料(例如手機的聲音資料),並透過回呼方法使其可用。輸出是從 SBC 格式解碼的 PCM 資料流。該文件可以在這裡找到。
I2S 是一種電氣串列匯流排介面標準,用於將數位音訊設備連接在一起。它用於在電子設備中的集成電路之間傳送 PCM 音訊資料。
因此,我們可以將藍牙的輸入提供給 I2S 輸出:可以在 Github 上找到 Espressif 的範例。
不幸的是,這個例子並沒有讓我高興,所以我決定將其轉換為一個簡單的Arduino 庫,該庫非常容易從 Arduino 軟體 IDE 中使用。
顧名思義,它支援 A2DP 藍牙協議,僅提供音訊串流!
它還支援音訊/視訊遠端控製設定檔 (AVRCP) 以及 A2DP。
不支援免持檔案 (HFP)、耳機設定檔 (HSP) 和不帶 A2DP 的獨立 AVRCP!
Espressif 即將淘汰舊版 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 相比,這些預設引腳已變更!
您可以在start
之前輕鬆定義自己的引腳。
# 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 使用通常格式為 44.1kHz 取樣率、兩通道 16 位元取樣資料的 PCM 資料。
// 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
狀態和可使用 u_ 7_2_ 7_y2_7_S7_47_47_s 7_y_7_s7_S7_s 7_y_7_s7_s7_S可能播放狀態播放狀態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 (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 () {
}
在範例中,您可以找到在 sin() 函數的幫助下產生聲音的實作。您也可以指定多個備用藍牙名稱。系統僅連接到第一個可用的系統:
void setup () {
static std::vector< char *> bt_names = { " MyMusic " , " RadioPlayer " , " MusicPlayer " };
a2dp_source. start (bt_names, get_sound_data);
}
您也可以直接以 uint8_t 的簡單陣列形式提供資料:
# 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 () {
}
例如可以透過以下方式製備陣列:
您可能想使用分區方案進行編譯:巨大的應用程式!
在上面的範例中,我們透過一個通道提供資料。這樣做的優點是它使用的空間比 2 通道錄音少得多,您可以透過以下方式使用它:
SoundData *data = new TwoChannelSoundData((Frame*)StarWars10_raw,StarWars10_raw_len/4);
在建構函式中,您可以傳遞附加參數:
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);
該程式庫使用 ESP32 記錄器,您可以在 Arduino 的「工具」-「核心偵錯日誌」中啟動該記錄器。
目前程式碼完全依賴 ESP-IDF(也由 Arduino ESP32 核心提供)。沒有其他依賴項,其中包括 Arduino API!
因此我們支持:
然而,該限制限制了所提供的範例。
在克隆專案之前,請閱讀 Wiki 中的以下資訊。
您可以單獨使用這個庫,但它是我的音訊工具專案的一部分。因此,您可以輕鬆地透過聲音效果、使用濾波器、使用替代音訊接收器或音訊來源、執行 FFT 等來增強此功能。
我花了很多時間來提供全面且完整的文件。因此,在 Github 上發布任何新問題之前,請先閱讀文件並檢查問題和討論。
僅針對錯誤開放問題,如果不是錯誤,請使用討論:提供有關以下方面的足夠信息
使其他人能夠理解並重現您的問題。
最後,最重要的是不要向我發送任何電子郵件或在我的個人網站上發布問題!
從使用此庫的項目中獲取一些靈感,並與社區分享您的項目。
對於 Arduino,您可以將程式庫下載為 zip 並呼叫 include Library -> zip library。或者你可以 git 克隆這個專案到 Arduino 庫資料夾中,例如
cd ~ /Documents/Arduino/libraries
git clone https://github.com/pschatzmann/ESP32-A2DP.git
git clone https://github.com/pschatzmann/arduino-audio-tools.git
對於提供的範例,您還需要安裝音訊工具庫。
其他框架請參考 Wiki
變更歷史可以在 Wiki 中找到
這個軟體是完全免費的,但是你可以透過獎勵我一些獎勵來讓我開心