ESP32 เป็นไมโครคอนโทรลเลอร์ที่มี API สำหรับ Bluetooth A2DP ซึ่งสามารถใช้เพื่อรับข้อมูลเสียง เช่น จากโทรศัพท์มือถือของคุณ และทำให้พร้อมใช้งานผ่านวิธีการโทรกลับ เอาต์พุตเป็นสตรีมข้อมูล PCM ถอดรหัสจากรูปแบบ SBC สามารถดูเอกสารได้ที่นี่
I2S เป็นมาตรฐานอินเทอร์เฟซบัสอนุกรมทางไฟฟ้าที่ใช้สำหรับเชื่อมต่ออุปกรณ์เสียงดิจิทัลเข้าด้วยกัน ใช้ในการสื่อสารข้อมูลเสียง PCM ระหว่างวงจรรวมในอุปกรณ์อิเล็กทรอนิกส์
ดังนั้นเราจึงสามารถป้อนอินพุตจาก Bluetooth ไปยังเอาต์พุต I2S ได้: ตัวอย่างนี้จาก Espressif สามารถพบได้บน Github
น่าเสียดายที่ตัวอย่างนี้ไม่ทำให้ฉันมีความสุข ดังนั้นฉันจึงตัดสินใจแปลงมันเป็น ไลบรารี Arduino ธรรมดาที่ใช้งานง่ายมากจาก Arduino Software IDE
ตามชื่อของ libariy นี้ รองรับโปรโตคอล A2DP Bluetooth ซึ่งให้บริการสตรีมเสียงเท่านั้น!
นอกจากนี้ยังรองรับโปรไฟล์การควบคุมระยะไกลเสียง/วิดีโอ (AVRCP) ร่วมกับ A2DP
ไม่ รองรับโปรไฟล์แฮนด์ฟรี (HFP), โปรไฟล์ชุดหูฟัง (HSP) และ AVRCP แบบสแตนด์อโลนที่ไม่มี A2DP!
Espressif กำลังจะเลิกใช้ I2S API รุ่นเก่า: ดังนั้นด้วย Arduino v3.0.0 (IDF v5) การผสานรวม I2S เก่าของฉันจะไม่สามารถใช้ได้อีกต่อไป ไวยากรณ์แบบเดิมยังคงใช้งานได้ตราบเท่าที่คุณไม่อัปเกรด
เพื่อสนับสนุน API เอาต์พุตเฉพาะซึ่งเป็นเวอร์ชันที่ไม่ขึ้นอยู่กับเวอร์ชัน ขอแนะนำให้ติดตั้งและใช้ไลบรารี AudioTools ดังนั้นเอกสารประกอบและตัวอย่างทั้งหมดจึงได้รับการอัปเดตเพื่อใช้แนวทางใหม่นี้
อย่างไรก็ตาม คุณยังสามารถส่งออกไปยังคลาสอื่นๆ ที่สืบทอดมาจาก Arduino Print ได้ เช่น Arduino ESP32 I2SClass หรือคุณสามารถใช้การเรียกกลับข้อมูลที่อธิบายไว้ด้านล่าง
สามารถใช้เช่นเพื่อสร้างลำโพง Bluetooth ของคุณเอง
นี่คือตัวอย่างที่ง่ายที่สุดที่ใช้การตั้งค่าเริ่มต้นที่เหมาะสม:
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
I2SStream i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
สิ่งนี้จะสร้างอุปกรณ์ Bluetooth ใหม่ชื่อ "MyMusic" และเอาต์พุตจะถูกส่งไปยังพิน I2S เริ่มต้นต่อไปนี้ซึ่งจำเป็นต้องเชื่อมต่อกับ DAC ภายนอก:
โปรดทราบว่าพินเริ่มต้นเหล่านี้มีการเปลี่ยนแปลงเมื่อเทียบกับ 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!
คุณยังสามารถส่งเอาต์พุตโดยตรงไปยัง DAC ภายในของ ESP32 ได้โดยใช้ AnalogAudioStream จาก AudioTools:
# 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 ทำงานหรือปิดใช้งาน ดังนั้นคุณสามารถใช้วิธีนี้เพื่อปิด 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 sink โปรดทราบว่า data2 จริงๆ แล้วเป็นสตริงอักขระ* ดังนั้นแม้ว่า 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
ตามลำดับ ดูตัวอย่างการเล่น_status_callbacksสำหรับรายละเอียดเพิ่มเติม
ฉันได้เพิ่มคำสั่ง AVRC ต่อไปนี้ซึ่งคุณสามารถใช้เพื่อ 'ควบคุม' แหล่งที่มา A2DP ของคุณ:
สามารถใช้เพื่อป้อนข้อมูลเสียงเช่นลำโพง Bluetooth ของคุณ
เรายังสามารถสร้างเสียงและส่งไปยังลำโพงบลูทูธได้อีกด้วย
ตัวแปลงสัญญาณเสียงที่รองรับใน ESP32 A2DP คือ SBC: API ใช้ข้อมูล PCM ที่ปกติจัดรูปแบบเป็นอัตราการสุ่มตัวอย่าง 44.1kHz ข้อมูลตัวอย่าง 16 บิตแบบสองช่องสัญญาณ
เมื่อคุณเริ่ม BluetoothA2DPSource คุณจะต้องส่งชื่อ Bluetooth ที่คุณต้องการเชื่อมต่อและ 'ฟังก์ชันการโทรกลับ' ที่สร้างข้อมูลเสียง:
# 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() คุณยังสามารถระบุชื่อ Bluetooth อื่นได้หลายชื่อ ระบบจะเชื่อมต่อกับระบบแรกที่มีอยู่:
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 () {
}
คุณสามารถจัดเตรียมอาร์เรย์ได้ดังต่อไปนี้:
คุณอาจต้องการคอมไพล์ด้วย Partition Scheme: Huge App!
ในตัวอย่างข้างต้น เราให้ข้อมูลด้วยช่องทางเดียว มีข้อดีคือใช้พื้นที่น้อยกว่าการบันทึกแบบ 2 ช่องมาก ซึ่งคุณสามารถใช้ในลักษณะต่อไปนี้:
SoundData *data = new TwoChannelSoundData((Frame*)StarWars10_raw,StarWars10_raw_len/4);
ใน Constructor คุณสามารถส่งพารามิเตอร์เพิ่มเติมได้:
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 core) ไม่มีการพึ่งพาอื่นใดและรวมถึง Arduino API ด้วย!
ดังนั้นเราจึงสนับสนุน:
ข้อจำกัดนี้จำกัดตามตัวอย่างที่ให้ไว้
ก่อนที่คุณจะโคลนโครงการ โปรดอ่านข้อมูลต่อไปนี้ซึ่งสามารถพบได้ใน Wiki
คุณสามารถใช้ไลบรารีนี้แบบสแตนด์อโลนได้ แต่เป็นส่วนหนึ่งของโปรเจ็กต์เครื่องมือเสียงของฉัน ดังนั้นคุณจึงสามารถปรับปรุงฟังก์ชันนี้ได้อย่างง่ายดายด้วยเอฟเฟกต์เสียง ใช้ฟิลเตอร์ ใช้แหล่งเสียงหรือแหล่งเสียงอื่น ทำ FFT ฯลฯ ต่อไปนี้คือตัวอย่างง่ายๆ วิธีที่คุณสามารถวิเคราะห์ข้อมูลเสียงด้วย FFT
ฉันใช้เวลามากในการจัดทำเอกสารที่ครบถ้วนและครบถ้วน ดังนั้นโปรดอ่านเอกสารประกอบก่อน และตรวจสอบปัญหาและการอภิปรายก่อนที่จะโพสต์รายการใหม่บน Github
เปิดประเด็นสำหรับข้อบกพร่องเท่านั้น และหากไม่ใช่ข้อบกพร่อง ให้ใช้การสนทนา: ให้ข้อมูลเพียงพอเกี่ยวกับ
เพื่อให้ผู้อื่นเข้าใจและจำลองปัญหาของคุณ
ท้ายที่สุด เหนือสิ่งอื่นใด อย่า ส่งอีเมลหรือโพสต์คำถามใด ๆ บนเว็บไซต์ส่วนตัวของฉัน!
รับแรงบันดาลใจจากโครงการที่ใช้ห้องสมุดนี้และแบ่งปันโครงการของคุณกับชุมชน
สำหรับ Arduino คุณสามารถดาวน์โหลดไลบรารี่เป็น zip และโทรรวม Library -> zip Library หรือคุณสามารถคอมไพล์โปรเจ็กต์นี้ลงในโฟลเดอร์ไลบรารี 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
ซอฟต์แวร์นี้ฟรีทั้งหมด แต่คุณสามารถทำให้ฉันมีความสุขได้ด้วยการให้รางวัลแก่ฉันด้วยของว่าง